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

Commit a843329

Browse files
authored
Merge pull request #12 from ipfs/refactor/async-iterators
refactor: async iterators
2 parents 56e3121 + 3777399 commit a843329

File tree

6 files changed

+156
-195
lines changed

6 files changed

+156
-195
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ dist
4040
test/test-repo/datastore
4141
init-default
4242
datastore-test
43+
.vscode

package.json

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,20 @@
4141
},
4242
"homepage": "https://github.com/ipfs/js-datastore-level#readme",
4343
"dependencies": {
44-
"datastore-core": "~0.6.0",
44+
"datastore-core": "~0.7.0",
4545
"encoding-down": "^6.0.2",
46-
"interface-datastore": "~0.6.0",
47-
"level-js": "github:timkuijsten/level.js#idbunwrapper",
46+
"interface-datastore": "~0.7.0",
4847
"leveldown": "^5.0.0",
49-
"levelup": "^4.0.1",
50-
"pull-stream": "^3.6.9"
48+
"levelup": "^4.0.1"
5149
},
5250
"devDependencies": {
53-
"aegir": "^15.3.1",
54-
"async": "^2.6.1",
51+
"aegir": "^19.0.3",
5552
"chai": "^4.2.0",
56-
"cids": "~0.5.5",
53+
"cids": "~0.7.1",
5754
"dirty-chai": "^2.0.1",
58-
"flow-bin": "~0.81.0",
59-
"memdown": "^1.4.1",
55+
"flow-bin": "~0.99.0",
56+
"level-js": "^4.0.1",
57+
"memdown": "^4.0.0",
6058
"rimraf": "^2.6.2"
6159
},
6260
"contributors": [

src/index.js

Lines changed: 84 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@
33

44
/* :: import type {Callback, Batch, Query, QueryResult, QueryEntry} from 'interface-datastore' */
55

6-
const pull = require('pull-stream')
76
const levelup = require('levelup')
8-
9-
const asyncFilter = require('interface-datastore').utils.asyncFilter
10-
const asyncSort = require('interface-datastore').utils.asyncSort
11-
const Key = require('interface-datastore').Key
12-
const Errors = require('interface-datastore').Errors
7+
const { Key, Errors, utils } = require('interface-datastore')
138
const encode = require('encoding-down')
149

10+
const { filter, map, take, sortAll } = utils
11+
1512
/**
1613
* A datastore backed by leveldb.
1714
*/
@@ -50,59 +47,53 @@ class LevelDatastore {
5047
)
5148
}
5249

53-
open (callback /* : Callback<void> */) /* : void */ {
54-
this.db.open((err) => {
55-
if (err) {
56-
return callback(Errors.dbOpenFailedError(err))
57-
}
58-
callback()
59-
})
50+
async open () /* : Promise */ {
51+
try {
52+
await this.db.open()
53+
} catch (err) {
54+
throw Errors.dbOpenFailedError(err)
55+
}
6056
}
6157

62-
put (key /* : Key */, value /* : Buffer */, callback /* : Callback<void> */) /* : void */ {
63-
this.db.put(key.toString(), value, (err) => {
64-
if (err) {
65-
return callback(Errors.dbWriteFailedError(err))
66-
}
67-
callback()
68-
})
58+
async put (key /* : Key */, value /* : Buffer */) /* : Promise */ {
59+
try {
60+
await this.db.put(key.toString(), value)
61+
} catch (err) {
62+
throw Errors.dbWriteFailedError(err)
63+
}
6964
}
7065

71-
get (key /* : Key */, callback /* : Callback<Buffer> */) /* : void */ {
72-
this.db.get(key.toString(), (err, data) => {
73-
if (err) {
74-
return callback(Errors.notFoundError(err))
75-
}
76-
callback(null, data)
77-
})
66+
async get (key /* : Key */) /* : Promise */ {
67+
let data
68+
try {
69+
data = await this.db.get(key.toString())
70+
} catch (err) {
71+
if (err.notFound) throw Errors.notFoundError(err)
72+
throw Errors.dbWriteFailedError(err)
73+
}
74+
return data
7875
}
7976

80-
has (key /* : Key */, callback /* : Callback<bool> */) /* : void */ {
81-
this.db.get(key.toString(), (err, res) => {
82-
if (err) {
83-
if (err.notFound) {
84-
callback(null, false)
85-
return
86-
}
87-
callback(err)
88-
return
89-
}
90-
91-
callback(null, true)
92-
})
77+
async has (key /* : Key */) /* : Promise<Boolean> */ {
78+
try {
79+
await this.db.get(key.toString())
80+
} catch (err) {
81+
if (err.notFound) return false
82+
throw err
83+
}
84+
return true
9385
}
9486

95-
delete (key /* : Key */, callback /* : Callback<void> */) /* : void */ {
96-
this.db.del(key.toString(), (err) => {
97-
if (err) {
98-
return callback(Errors.dbDeleteFailedError(err))
99-
}
100-
callback()
101-
})
87+
async delete (key /* : Key */) /* : Promise */ {
88+
try {
89+
await this.db.del(key.toString())
90+
} catch (err) {
91+
throw Errors.dbDeleteFailedError(err)
92+
}
10293
}
10394

104-
close (callback /* : Callback<void> */) /* : void */ {
105-
this.db.close(callback)
95+
close () /* : Promise */ {
96+
return this.db.close()
10697
}
10798

10899
batch () /* : Batch<Buffer> */ {
@@ -121,8 +112,8 @@ class LevelDatastore {
121112
key: key.toString()
122113
})
123114
},
124-
commit: (callback /* : Callback<void> */) /* : void */ => {
125-
this.db.batch(ops, callback)
115+
commit: () /* : Promise */ => {
116+
return this.db.batch(ops)
126117
}
127118
}
128119
}
@@ -133,70 +124,65 @@ class LevelDatastore {
133124
values = !q.keysOnly
134125
}
135126

136-
const iter = this.db.db.iterator({
137-
keys: true,
138-
values: values,
139-
keyAsBuffer: true
140-
})
141-
142-
const rawStream = (end, cb) => {
143-
if (end) {
144-
return iter.end((err) => {
145-
cb(err || end)
146-
})
147-
}
148-
149-
iter.next((err, key, value) => {
150-
if (err) {
151-
return cb(err)
152-
}
153-
154-
if (err == null && key == null && value == null) {
155-
return iter.end((err) => {
156-
cb(err || true)
157-
})
158-
}
159-
160-
const res /* : QueryEntry<Buffer> */ = {
161-
key: new Key(key, false)
162-
}
163-
164-
if (values) {
165-
res.value = Buffer.from(value)
166-
}
167-
168-
cb(null, res)
127+
let it = levelIteratorToIterator(
128+
this.db.db.iterator({
129+
keys: true,
130+
values: values,
131+
keyAsBuffer: true
169132
})
170-
}
133+
)
171134

172-
let tasks = [rawStream]
173-
let filters = []
135+
it = map(it, ({ key, value }) => {
136+
const res /* : QueryEntry<Buffer> */ = { key: new Key(key, false) }
137+
if (values) {
138+
res.value = Buffer.from(value)
139+
}
140+
return res
141+
})
174142

175143
if (q.prefix != null) {
176-
const prefix = q.prefix
177-
filters.push((e, cb) => cb(null, e.key.toString().startsWith(prefix)))
144+
it = filter(it, e => e.key.toString().startsWith(q.prefix))
178145
}
179146

180-
if (q.filters != null) {
181-
filters = filters.concat(q.filters)
147+
if (Array.isArray(q.filters)) {
148+
it = q.filters.reduce((it, f) => filter(it, f), it)
182149
}
183150

184-
tasks = tasks.concat(filters.map(f => asyncFilter(f)))
185-
186-
if (q.orders != null) {
187-
tasks = tasks.concat(q.orders.map(o => asyncSort(o)))
151+
if (Array.isArray(q.orders)) {
152+
it = q.orders.reduce((it, f) => sortAll(it, f), it)
188153
}
189154

190155
if (q.offset != null) {
191156
let i = 0
192-
tasks.push(pull.filter(() => i++ >= q.offset))
157+
it = filter(it, () => i++ >= q.offset)
193158
}
194159

195160
if (q.limit != null) {
196-
tasks.push(pull.take(q.limit))
161+
it = take(it, q.limit)
197162
}
198163

199-
return pull.apply(null, tasks)
164+
return it
165+
}
166+
}
167+
168+
function levelIteratorToIterator (li) {
169+
return {
170+
next: () => new Promise((resolve, reject) => {
171+
li.next((err, key, value) => {
172+
if (err) return reject(err)
173+
if (key == null) return resolve({ done: true })
174+
resolve({ done: false, value: { key, value } })
175+
})
176+
}),
177+
return: () => new Promise((resolve, reject) => {
178+
li.end(err => {
179+
if (err) return reject(err)
180+
resolve({ done: true })
181+
})
182+
}),
183+
[Symbol.asyncIterator] () {
184+
return this
185+
}
200186
}
201187
}
202188

test/browser.js

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
/* eslint-env mocha */
33
'use strict'
44

5-
const each = require('async/each')
6-
const MountStore = require('datastore-core').MountDatastore
7-
const Key = require('interface-datastore').Key
5+
const { MountDatastore } = require('datastore-core')
6+
const { Key } = require('interface-datastore')
87

98
// leveldown will be swapped for level-js
109
const leveljs = require('leveldown')
@@ -14,31 +13,39 @@ const LevelStore = require('../src')
1413
describe('LevelDatastore', () => {
1514
describe('interface-datastore (leveljs)', () => {
1615
require('interface-datastore/src/tests')({
17-
setup (callback) {
18-
callback(null, new LevelStore('hello', {db: leveljs}))
19-
},
20-
teardown (callback) {
21-
leveljs.destroy('hello', callback)
22-
}
16+
setup: () => new LevelStore('hello', { db: leveljs }),
17+
teardown: () => new Promise((resolve, reject) => {
18+
leveljs.destroy('hello', err => {
19+
if (err) return reject(err)
20+
resolve()
21+
})
22+
})
2323
})
2424
})
2525

2626
describe('interface-datastore (mount(leveljs, leveljs, leveljs))', () => {
2727
require('interface-datastore/src/tests')({
28-
setup (callback) {
29-
callback(null, new MountStore([{
28+
setup () {
29+
return new MountDatastore([{
3030
prefix: new Key('/a'),
31-
datastore: new LevelStore('one', {db: leveljs})
31+
datastore: new LevelStore('one', { db: leveljs })
3232
}, {
3333
prefix: new Key('/q'),
34-
datastore: new LevelStore('two', {db: leveljs})
34+
datastore: new LevelStore('two', { db: leveljs })
3535
}, {
3636
prefix: new Key('/z'),
37-
datastore: new LevelStore('three', {db: leveljs})
38-
}]))
37+
datastore: new LevelStore('three', { db: leveljs })
38+
}])
3939
},
40-
teardown (callback) {
41-
each(['one', 'two', 'three'], leveljs.destroy.bind(leveljs), callback)
40+
teardown () {
41+
return Promise.all(['one', 'two', 'three'].map(dir => {
42+
return new Promise((resolve, reject) => {
43+
leveljs.destroy(dir, err => {
44+
if (err) return reject(err)
45+
resolve()
46+
})
47+
})
48+
}))
4249
}
4350
})
4451
})

0 commit comments

Comments
 (0)