Skip to content
This repository has been archived by the owner on Mar 23, 2023. It is now read-only.

Commit

Permalink
feat: split .query into .query and .queryKeys
Browse files Browse the repository at this point in the history
Applies changes from ipfs/interface-datastore/pull/87 and removes
redundant utilities.
  • Loading branch information
achingbrain committed Apr 15, 2021
1 parent a546afb commit 9b2ea10
Show file tree
Hide file tree
Showing 11 changed files with 195 additions and 66 deletions.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@
},
"dependencies": {
"debug": "^4.1.1",
"interface-datastore": "^3.0.1"
"interface-datastore": "ipfs/interface-datastore#feat/split-query-into-query-and-query-keys",
"it-filter": "^1.0.2",
"it-map": "^1.0.5",
"it-merge": "^1.0.1",
"it-take": "^1.0.1"
},
"engines": {
"node": ">=12.0.0"
Expand Down
24 changes: 19 additions & 5 deletions src/keytransform.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
'use strict'

const { Adapter, utils } = require('interface-datastore')
const map = utils.map
const { Adapter } = require('interface-datastore')
const map = require('it-map')

/**
* @typedef {import('interface-datastore').Datastore} Datastore
* @typedef {import('interface-datastore').Options} Options
* @typedef {import('interface-datastore').Batch} Batch
* @typedef {import('interface-datastore').Query} Query
* @typedef {import('interface-datastore').KeyQuery} KeyQuery
* @typedef {import('interface-datastore').Key} Key
* @typedef {import('./types').KeyTransform} KeyTransform
*/
Expand Down Expand Up @@ -90,9 +92,21 @@ class KeyTransformDatastore extends Adapter {
* @param {Options} [options]
*/
query (q, options) {
return map(this.child.query(q, options), e => {
e.key = this.transform.invert(e.key)
return e
return map(this.child.query(q, options), ({ key, value }) => {
return {
key: this.transform.invert(key),
value
}
})
}

/**
* @param {KeyQuery} q
* @param {Options} [options]
*/
queryKeys (q, options) {
return map(this.child.queryKeys(q, options), key => {
return this.transform.invert(key)
})
}

Expand Down
64 changes: 44 additions & 20 deletions src/mount.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

const {
Adapter, Key, Errors, utils: {
filter,
take,
sortAll,
replaceStartWith
}
} = require('interface-datastore')
const filter = require('it-filter')
const take = require('it-take')
const merge = require('it-merge')

const Keytransform = require('./keytransform')

Expand All @@ -17,7 +18,8 @@ const Keytransform = require('./keytransform')
* @typedef {import('interface-datastore').Options} Options
* @typedef {import('interface-datastore').Batch} Batch
* @typedef {import('interface-datastore').Query} Query
* @typedef {import('interface-datastore').Pair} Pair
* @typedef {import('interface-datastore').KeyQuery} KeyQuery
* @typedef {import('./types').KeyTransform} KeyTransform
*/

/**
Expand All @@ -27,13 +29,12 @@ const Keytransform = require('./keytransform')

/**
* A datastore that can combine multiple stores inside various
* key prefixs.
* key prefixes
*
* @implements {Datastore}
*/
class MountDatastore extends Adapter {
/**
*
* @param {Array<{prefix: Key, datastore: Datastore}>} mounts
*/
constructor (mounts) {
Expand All @@ -47,7 +48,7 @@ class MountDatastore extends Adapter {
}

/**
* Lookup the matching datastore for the given key.
* Lookup the matching datastore for the given key
*
* @private
* @param {Key} key
Expand Down Expand Up @@ -186,12 +187,11 @@ class MountDatastore extends Adapter {

return ks.query({
prefix: prefix,
filters: q.filters,
keysOnly: q.keysOnly
filters: q.filters
}, options)
})

let it = _many(qs)
let it = merge(...qs)
if (q.filters) q.filters.forEach(f => { it = filter(it, f) })
if (q.orders) q.orders.forEach(o => { it = sortAll(it, o) })
if (q.offset != null) {
Expand All @@ -202,20 +202,44 @@ class MountDatastore extends Adapter {

return it
}
}

/**
* @param {ArrayLike<AwaitIterable<Pair>>} iterable
* @returns {AsyncIterable<Pair>}
*/
function _many (iterable) {
return (async function * () {
for (let i = 0; i < iterable.length; i++) {
for await (const v of iterable[i]) {
yield v
/**
* @param {KeyQuery} q
* @param {Options} [options]
*/
queryKeys (q, options) {
const qs = this.mounts.map(m => {
const ks = new Keytransform(m.datastore, {
convert: (key) => {
throw new Error('should never be called')
},
invert: (key) => {
return m.prefix.child(key)
}
})

let prefix
if (q.prefix != null) {
prefix = replaceStartWith(q.prefix, m.prefix.toString())
}

return ks.queryKeys({
prefix: prefix,
filters: q.filters
}, options)
})

let it = merge(...qs)
if (q.filters) q.filters.forEach(f => { it = filter(it, f) })
if (q.orders) q.orders.forEach(o => { it = sortAll(it, o) })
if (q.offset != null) {
let i = 0
it = filter(it, () => i++ >= /** @type {number} */ (q.offset))
}
})()
if (q.limit != null) it = take(it, q.limit)

return it
}
}

module.exports = MountDatastore
14 changes: 14 additions & 0 deletions src/namespace.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const KeytransformDatastore = require('./keytransform')
/**
* @typedef {import('interface-datastore').Datastore} Datastore
* @typedef {import('interface-datastore').Query} Query
* @typedef {import('interface-datastore').KeyQuery} KeyQuery
* @typedef {import('interface-datastore').Options} Options
* @typedef {import('interface-datastore').Batch} Batch
* @typedef {import('./types').KeyTransform} KeyTransform
Expand Down Expand Up @@ -57,6 +58,19 @@ class NamespaceDatastore extends KeytransformDatastore {
}
return super.query(q, options)
}

/**
* @param {KeyQuery} q
* @param {Options} [options]
*/
queryKeys (q, options) {
if (q.prefix && this.prefix.toString() !== '/') {
return super.queryKeys(Object.assign({}, q, {
prefix: this.prefix.child(new Key(q.prefix)).toString()
}))
}
return super.queryKeys(q, options)
}
}

module.exports = NamespaceDatastore
4 changes: 2 additions & 2 deletions src/shard.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const { Key, utils: { utf8Decoder } } = require('interface-datastore')
const { Key } = require('interface-datastore')
const readme = require('./shard-readme')

/**
Expand Down Expand Up @@ -149,7 +149,7 @@ const readShardFun = async (path, store) => {
// @ts-ignore
const get = typeof store.getRaw === 'function' ? store.getRaw.bind(store) : store.get.bind(store)
const res = await get(key)
return parseShardFun(utf8Decoder.decode(res || '').trim())
return parseShardFun(new TextDecoder().decode(res || '').trim())
}

module.exports = {
Expand Down
102 changes: 85 additions & 17 deletions src/sharding.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const { Adapter, Key, utils: { utf8Encoder }, Errors } = require('interface-datastore')
const { Adapter, Key, Errors } = require('interface-datastore')
const sh = require('./shard')
const KeytransformStore = require('./keytransform')

Expand All @@ -11,6 +11,11 @@ const shardReadmeKey = new Key(sh.README_FN)
* @typedef {import('interface-datastore').Options} Options
* @typedef {import('interface-datastore').Batch} Batch
* @typedef {import('interface-datastore').Query} Query
* @typedef {import('interface-datastore').QueryFilter} QueryFilter
* @typedef {import('interface-datastore').QueryOrder} QueryOrder
* @typedef {import('interface-datastore').KeyQuery} KeyQuery
* @typedef {import('interface-datastore').KeyQueryFilter} KeyQueryFilter
* @typedef {import('interface-datastore').KeyQueryOrder} KeyQueryOrder
* @typedef {import('interface-datastore').Pair} Pair
* @typedef {import('./types').Shard} Shard
*
Expand Down Expand Up @@ -107,8 +112,8 @@ class ShardingDatastore extends Adapter {
// @ts-ignore i have no idea what putRaw is or saw any implementation
const put = typeof store.putRaw === 'function' ? store.putRaw.bind(store) : store.put.bind(store)
await Promise.all([
put(shardKey, utf8Encoder.encode(shard.toString() + '\n')),
put(shardReadmeKey, utf8Encoder.encode(sh.readme))
put(shardKey, new TextEncoder().encode(shard.toString() + '\n')),
put(shardReadmeKey, new TextEncoder().encode(sh.readme))
])

return shard
Expand Down Expand Up @@ -167,15 +172,15 @@ class ShardingDatastore extends Adapter {
*/
query (q, options) {
const tq = {
keysOnly: q.keysOnly,
offset: q.offset,
limit: q.limit,
/** @type Array<(items: Pair[]) => Await<Pair[]>> */
/** @type {QueryOrder[]} */
orders: [],
/** @type {QueryFilter[]} */
filters: [
/** @type {(item: Pair) => boolean} */
/** @type {QueryFilter} */
e => e.key.toString() !== shardKey.toString(),
/** @type {(item: Pair) => boolean} */
/** @type {QueryFilter} */
e => e.key.toString() !== shardReadmeKey.toString()
]
}
Expand All @@ -188,27 +193,90 @@ class ShardingDatastore extends Adapter {
}

if (q.filters != null) {
// @ts-ignore - can't find a way to easily type this
const filters = q.filters.map((f) => (e) => {
return f(Object.assign({}, e, {
key: this._invertKey(e.key)
}))
const filters = q.filters.map(f => {
/** @type {QueryFilter} */
const filter = ({ key, value }) => {
return f({
key: this._invertKey(key),
value
})
}

return filter
})
tq.filters = tq.filters.concat(filters)
}

if (q.orders != null) {
tq.orders = q.orders.map((o) => async (res) => {
res.forEach((e) => { e.key = this._invertKey(e.key) })
const ordered = await o(res)
ordered.forEach((e) => { e.key = this._convertKey(e.key) })
return ordered
tq.orders = q.orders.map(o => {
/** @type {QueryOrder} */
const order = (a, b) => {
return o({
key: this._invertKey(a.key),
value: a.value
}, {
key: this._invertKey(b.key),
value: b.value
})
}

return order
})
}

return this.child.query(tq, options)
}

/**
* @param {KeyQuery} q
* @param {Options} [options]
*/
queryKeys (q, options) {
const tq = {
offset: q.offset,
limit: q.limit,
/** @type {KeyQueryOrder[]} */
orders: [],
/** @type {KeyQueryFilter[]} */
filters: [
/** @type {KeyQueryFilter} */
key => key.toString() !== shardKey.toString(),
/** @type {KeyQueryFilter} */
key => key.toString() !== shardReadmeKey.toString()
]
}

const { prefix } = q
if (prefix != null) {
tq.filters.push((key) => {
return this._invertKey(key).toString().startsWith(prefix)
})
}

if (q.filters != null) {
const filters = q.filters.map(f => {
/** @type {KeyQueryFilter} */
const filter = (key) => {
return f(this._invertKey(key))
}

return filter
})
tq.filters = tq.filters.concat(filters)
}

if (q.orders != null) {
tq.orders = q.orders.map(o => {
/** @type {KeyQueryOrder} */
const order = (a, b) => o(this._invertKey(a), this._invertKey(b))

return order
})
}

return this.child.queryKeys(tq, options)
}

close () {
return this.child.close()
}
Expand Down
Loading

0 comments on commit 9b2ea10

Please sign in to comment.