Skip to content
This repository was archived by the owner on Sep 9, 2021. It is now read-only.

Commit 4bb5ebc

Browse files
feat: split .query into .query and .queryKeys (#87)
The return type of the `.query` function varies depending on whether `keysOnly` is passed as part of the query params. This makes mapping the return type difficult as it's dependent on the function input. Here we: 1. Constrain the return type of `.query` to just key/value pairs 1. Add a new `.queryKeys` method that returns only keys 1. Add the implementation in the adapter to just chain to the existing `.query` method and map the result 1. Remove redundant utils 1. Remove redundant TextEncoder/Decoder exports 1. Change the query sort method to be a regular js sort function 1. Export types for query sort/filter methods Co-authored-by: Vasco Santos <[email protected]>
1 parent a68c067 commit 4bb5ebc

File tree

11 files changed

+310
-146
lines changed

11 files changed

+310
-146
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
with:
3636
node-version: ${{ matrix.node }}
3737
- run: npm install
38-
- run: npx nyc --reporter=lcov aegir test -t node -- --bail
38+
- run: npx aegir test -t node --cov --bail
3939
- uses: codecov/codecov-action@v1
4040
test-chrome:
4141
needs: check
@@ -50,7 +50,7 @@ jobs:
5050
steps:
5151
- uses: actions/checkout@v2
5252
- run: npm install
53-
- run: npx aegir test -t browser -t webworker --bail -- --browsers FirefoxHeadless
53+
- run: npx aegir test -t browser -t webworker --bail -- --browser firefox
5454
test-electron-main:
5555
needs: check
5656
runs-on: ubuntu-latest

package.json

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,15 @@
1010
"dist"
1111
],
1212
"scripts": {
13-
"prepare": "aegir build --no-bundle && cp src/types.d.ts dist/src/types.d.ts",
13+
"prepare": "aegir build --no-bundle",
1414
"lint": "aegir lint",
1515
"test": "aegir test",
1616
"test:node": "aegir test --target node",
1717
"test:browser": "aegir test --target browser",
1818
"release": "aegir release --docs",
1919
"release-minor": "aegir release --type minor --docs",
2020
"release-major": "aegir release --type major --docs",
21-
"coverage": "aegir coverage",
22-
"coverage-publish": "aegir coverage --provider codecov",
21+
"coverage": "aegir test --cov",
2322
"docs": "aegir docs"
2423
},
2524
"repository": {
@@ -39,15 +38,19 @@
3938
"homepage": "https://github.com/ipfs/interface-datastore#readme",
4039
"devDependencies": {
4140
"@types/err-code": "^2.0.0",
42-
"aegir": "^33.1.0"
41+
"aegir": "^33.1.0",
42+
"it-map": "^1.0.5"
4343
},
4444
"dependencies": {
4545
"err-code": "^3.0.1",
4646
"ipfs-utils": "^6.0.0",
4747
"iso-random-stream": "^2.0.0",
4848
"it-all": "^1.0.2",
4949
"it-drain": "^1.0.1",
50-
"nanoid": "^3.0.2"
50+
"it-filter": "^1.0.2",
51+
"it-take": "^1.0.1",
52+
"nanoid": "^3.0.2",
53+
"uint8arrays": "^2.1.5"
5154
},
5255
"eslintConfig": {
5356
"extends": "ipfs"

src/adapter.js

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
'use strict'
22

3-
const { filter, sortAll, take, map } = require('./utils')
3+
const { sortAll } = require('./utils')
44
const drain = require('it-drain')
5+
const filter = require('it-filter')
6+
const take = require('it-take')
57

68
/**
79
* @typedef {import('./key')} Key
810
* @typedef {import('./types').Pair} Pair
911
* @typedef {import('./types').Datastore} Datastore
1012
* @typedef {import('./types').Options} Options
1113
* @typedef {import('./types').Query} Query
14+
* @typedef {import('./types').KeyQuery} KeyQuery
1215
* @typedef {import('./types').Batch} Batch
1316
*/
1417

@@ -134,6 +137,8 @@ class Adapter {
134137
}
135138

136139
/**
140+
* Extending classes should override `query` or implement this method
141+
*
137142
* @param {Query} q
138143
* @param {Options} [options]
139144
* @returns {AsyncIterable<Pair>}
@@ -143,6 +148,18 @@ class Adapter {
143148
throw new Error('._all is not implemented')
144149
}
145150

151+
/**
152+
* Extending classes should override `queryKeys` or implement this method
153+
*
154+
* @param {KeyQuery} q
155+
* @param {Options} [options]
156+
* @returns {AsyncIterable<Key>}
157+
*/
158+
// eslint-disable-next-line require-yield
159+
async * _allKeys (q, options) {
160+
throw new Error('._allKeys is not implemented')
161+
}
162+
146163
/**
147164
* @param {Query} q
148165
* @param {Options} [options]
@@ -173,8 +190,37 @@ class Adapter {
173190
it = take(it, q.limit)
174191
}
175192

176-
if (q.keysOnly === true) {
177-
return map(it, (e) => /** @type {Pair} */({ key: e.key }))
193+
return it
194+
}
195+
196+
/**
197+
* @param {KeyQuery} q
198+
* @param {Options} [options]
199+
*/
200+
queryKeys (q, options) {
201+
let it = this._allKeys(q, options)
202+
203+
if (q.prefix != null) {
204+
it = filter(it, (key) =>
205+
key.toString().startsWith(/** @type {string} */ (q.prefix))
206+
)
207+
}
208+
209+
if (Array.isArray(q.filters)) {
210+
it = q.filters.reduce((it, f) => filter(it, f), it)
211+
}
212+
213+
if (Array.isArray(q.orders)) {
214+
it = q.orders.reduce((it, f) => sortAll(it, f), it)
215+
}
216+
217+
if (q.offset != null) {
218+
let i = 0
219+
it = filter(it, () => i++ >= /** @type {number} */ (q.offset))
220+
}
221+
222+
if (q.limit != null) {
223+
it = take(it, q.limit)
178224
}
179225

180226
return it

src/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
* @typedef {import('./types').Batch} Batch
66
* @typedef {import('./types').Options} Options
77
* @typedef {import('./types').Query} Query
8+
* @typedef {import('./types').QueryFilter} QueryFilter
9+
* @typedef {import('./types').QueryOrder} QueryOrder
10+
* @typedef {import('./types').KeyQuery} KeyQuery
11+
* @typedef {import('./types').KeyQueryFilter} KeyQueryFilter
12+
* @typedef {import('./types').KeyQueryOrder} KeyQueryOrder
813
* @typedef {import('./types').Pair} Pair
914
*/
1015

src/key.js

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
'use strict'
22

33
const { nanoid } = require('nanoid')
4-
const { utf8Encoder, utf8Decoder } = require('./utils')
4+
5+
const uint8ArrayToString = require('uint8arrays/to-string')
6+
const uint8ArrayFromString = require('uint8arrays/from-string')
57

68
const symbol = Symbol.for('@ipfs/interface-datastore/key')
79
const pathSepS = '/'
8-
const pathSepB = utf8Encoder.encode(pathSepS)
10+
const pathSepB = new TextEncoder().encode(pathSepS)
911
const pathSep = pathSepB[0]
1012

1113
/**
@@ -31,7 +33,7 @@ class Key {
3133
*/
3234
constructor (s, clean) {
3335
if (typeof s === 'string') {
34-
this._buf = utf8Encoder.encode(s)
36+
this._buf = uint8ArrayFromString(s)
3537
} else if (s instanceof Uint8Array) {
3638
this._buf = s
3739
} else {
@@ -54,15 +56,11 @@ class Key {
5456
/**
5557
* Convert to the string representation
5658
*
57-
* @param {string} [encoding='utf8'] - The encoding to use.
59+
* @param {import('uint8arrays/to-string').SupportedEncodings} [encoding='utf8'] - The encoding to use.
5860
* @returns {string}
5961
*/
6062
toString (encoding = 'utf8') {
61-
if (encoding === 'utf8' || encoding === 'utf-8') {
62-
return utf8Decoder.decode(this._buf)
63-
}
64-
65-
return new TextDecoder(encoding).decode(this._buf)
63+
return uint8ArrayToString(this._buf, encoding)
6664
}
6765

6866
/**

src/memory.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ class MemoryDatastore extends Adapter {
6565
yield * Object.entries(this.data)
6666
.map(([key, value]) => ({ key: new Key(key), value }))
6767
}
68+
69+
async * _allKeys () {
70+
yield * Object.entries(this.data)
71+
.map(([key]) => new Key(key))
72+
}
6873
}
6974

7075
module.exports = MemoryDatastore

0 commit comments

Comments
 (0)