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
  • Loading branch information
achingbrain committed Apr 15, 2021
1 parent 929ab13 commit e22dc9b
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 29 deletions.
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@
},
"homepage": "https://github.com/ipfs/js-datastore-level#readme",
"dependencies": {
"datastore-core": "^3.0.0",
"interface-datastore": "^3.0.3",
"datastore-core": "ipfs/js-datastore-core#feat/split-query-into-query-and-query-keys",
"interface-datastore": "ipfs/interface-datastore#feat/split-query-into-query-and-query-keys",
"it-filter": "^1.0.2",
"it-map": "^1.0.5",
"it-take": "^1.0.1",
"level": "^6.0.1"
},
"devDependencies": {
Expand Down
87 changes: 60 additions & 27 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
const {
Key, Errors, Adapter,
utils: {
filter, map, take, sortAll
sortAll
}
} = require('interface-datastore')
const filter = require('it-filter')
const map = require('it-map')
const take = require('it-take')

/**
* @typedef {import('interface-datastore').Datastore} Datastore
* @typedef {import('interface-datastore').Pair} Pair
* @typedef {import('interface-datastore').Batch} Batch
* @typedef {import('interface-datastore').Query} Query
* @typedef {import('interface-datastore').KeyQuery} KeyQuery
* @typedef {import('interface-datastore').Options} QueryOptions
*/

Expand Down Expand Up @@ -159,41 +163,42 @@ class LevelDatastore extends Adapter {

/**
* @param {Query} q
* @returns {AsyncIterable<Pair>}
*/
query (q) {
let values = true
if (q.keysOnly != null) {
values = !q.keysOnly
let it = this._query({
values: true,
prefix: q.prefix
})

if (Array.isArray(q.filters)) {
it = q.filters.reduce((it, f) => filter(it, f), it)
}

const opts = {
keys: true,
values: values,
keyAsBuffer: true
if (Array.isArray(q.orders)) {
it = q.orders.reduce((it, f) => sortAll(it, f), it)
}

// Let the db do the prefix matching
if (q.prefix != null) {
const prefix = q.prefix.toString()
// Match keys greater than or equal to `prefix` and
// @ts-ignore
opts.gte = prefix
// less than `prefix` + \xFF (hex escape sequence)
// @ts-ignore
opts.lt = prefix + '\xFF'
const { offset, limit } = q
if (offset) {
let i = 0
it = filter(it, () => i++ >= offset)
}

let it = levelIteratorToIterator(
this.db.iterator(opts)
)
if (limit) {
it = take(it, limit)
}

it = map(it, ({ key, value }) => {
if (values) {
return { key, value }
}
return /** @type {Pair} */({ key })
})
return it
}

/**
* @param {KeyQuery} q
*/
queryKeys (q) {
let it = map(this._query({
values: false,
prefix: q.prefix
}), ({ key }) => key)

if (Array.isArray(q.filters)) {
it = q.filters.reduce((it, f) => filter(it, f), it)
Expand All @@ -202,6 +207,7 @@ class LevelDatastore extends Adapter {
if (Array.isArray(q.orders)) {
it = q.orders.reduce((it, f) => sortAll(it, f), it)
}

const { offset, limit } = q
if (offset) {
let i = 0
Expand All @@ -214,6 +220,33 @@ class LevelDatastore extends Adapter {

return it
}

/**
* @param {object} opts
* @param {boolean} opts.values
* @param {string} [opts.prefix]
* @returns {AsyncIterable<Pair>}
*/
_query (opts) {
const iteratorOpts = {
keys: true,
keyAsBuffer: true,
values: opts.values
}

// Let the db do the prefix matching
if (opts.prefix != null) {
const prefix = opts.prefix.toString()
// Match keys greater than or equal to `prefix` and
// @ts-ignore
iteratorOpts.gte = prefix
// less than `prefix` + \xFF (hex escape sequence)
// @ts-ignore
iteratorOpts.lt = prefix + '\xFF'
}

return levelIteratorToIterator(this.db.iterator(iteratorOpts))
}
}

/**
Expand Down

0 comments on commit e22dc9b

Please sign in to comment.