Skip to content
This repository has been archived by the owner on Dec 20, 2024. It is now read-only.

Commit

Permalink
Support promises and abstract-level
Browse files Browse the repository at this point in the history
  • Loading branch information
vweevers committed Nov 4, 2021
1 parent 7cad6e0 commit 3074af8
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 21 deletions.
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# level-concat-iterator

> Concatenate items from an iterator into an array.
> Concatenate entries from an iterator into an array.
[![level badge][level-badge]](https://github.com/Level/awesome)
[![npm](https://img.shields.io/npm/v/level-concat-iterator.svg?label=&logo=npm)](https://www.npmjs.com/package/level-concat-iterator)
Expand All @@ -23,21 +23,29 @@ const db = level('./db')
db.put('foo', 'bar', function (err) {
if (err) throw err

concat(db.iterator(), function (err, data) {
concat(db.iterator(), function (err, entries) {
if (err) throw err

console.log(data)
// [{ key: 'foo', value: 'bar' }]
console.log(entries)
})
})
```

With promises:

```js
await db.put('foo', 'bar')
const entries = await concat(db.iterator())
```

**If you are upgrading:** please see [`UPGRADING.md`](UPGRADING.md).

## API

### `concat(iterator, cb)`
### `concat(iterator[, callback])`

Takes an `abstract-leveldown` compatible `iterator` as first parameter and calls back with an array of keys and values. Calls back with an error if `iterator.next(cb)` or `iterator.end(cb)` errors.
Takes an `abstract-leveldown` compatible `iterator` as first parameter and calls the `callback` with an array of entries, where each entry is an object in the form `{ key, value }`. Calls the `callback` with an error if `iterator.next()` or `iterator.end()` errors. If no callback is provided, a promise is returned.

## Contributing

Expand Down
4 changes: 2 additions & 2 deletions example.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ const db = level('./db')
db.put('foo', 'bar', function (err) {
if (err) throw err

concat(db.iterator(), function (err, data) {
concat(db.iterator(), function (err, entries) {
if (err) throw err

console.log(data)
console.log(entries)
})
})
34 changes: 21 additions & 13 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
'use strict'

module.exports = function (iterator, cb) {
const data = []
const next = function () {
iterator.next(function (err, key, value) {
if (err || (key === undefined && value === undefined)) {
return iterator.end(function (err2) {
cb(err || err2, data)
})
}
data.push({ key, value })
next()
})
const { fromCallback } = require('catering')
const kPromise = Symbol('promise')

module.exports = function (iterator, callback) {
callback = fromCallback(callback, kPromise)

// Use close() method of abstract-level or end() of abstract-leveldown
const close = typeof iterator.close === 'function' ? 'close' : 'end'
const entries = []

const onnext = function (err, key, value) {
if (err || (key === undefined && value === undefined)) {
return iterator[close](function (err2) {
callback(err || err2, entries)
})
}
entries.push({ key, value })
iterator.next(onnext)
}
next()

iterator.next(onnext)
return callback[kPromise]
}
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "level-concat-iterator",
"version": "3.0.0",
"description": "Concatenate items from an iterator into an array.",
"description": "Concatenate entries from an iterator into an array.",
"author": "Lars-Magnus Skog <ralphtheninja@riseup.net>",
"license": "MIT",
"main": "index.js",
Expand All @@ -19,6 +19,9 @@
"LICENSE.md",
"UPGRADING.md"
],
"dependencies": {
"catering": "^2.1.0"
},
"devDependencies": {
"airtap": "^4.0.3",
"airtap-playwright": "^1.0.1",
Expand Down
87 changes: 87 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,25 @@ test('calls back with error if iterator.next errors', function (t) {
})
})

test('rejects promise if iterator.next errors', function (t) {
t.plan(3)

const iterator = {
next (cb) {
t.pass('iterator.next called')
process.nextTick(cb, new Error('iterator.next'))
},
end (cb) {
t.pass('iterator.end called')
process.nextTick(cb)
}
}

collect(iterator).catch(function (err) {
t.is(err.message, 'iterator.next', 'correct error')
})
})

test('happy path calls back with an array', function (t) {
t.plan(6)

Expand Down Expand Up @@ -53,6 +72,34 @@ test('happy path calls back with an array', function (t) {
})
})

test('happy path resolves promise with an array', async function (t) {
t.plan(5)

let i = 0
const entries = [
{ key: 'key1', value: 'value1' },
{ key: 'key2', value: 'value2' }
]

const iterator = {
next (cb) {
t.pass('iterator.next called')
if (i < entries.length) {
process.nextTick(cb, null, entries[i].key, entries[i].value)
++i
} else {
process.nextTick(cb)
}
},
end (cb) {
t.pass('iterator.end called')
process.nextTick(cb)
}
}

t.same(await collect(iterator), entries)
})

test('calls back with error and data if iterator.end errors', function (t) {
t.plan(6)

Expand Down Expand Up @@ -84,6 +131,25 @@ test('calls back with error and data if iterator.end errors', function (t) {
})
})

test('rejects promise if iterator.end errors', function (t) {
t.plan(3)

const iterator = {
next (cb) {
t.pass('iterator.next called')
process.nextTick(cb)
},
end (cb) {
t.pass('iterator.end called')
process.nextTick(cb, new Error('iterator.end'))
}
}

collect(iterator).catch(function (err) {
t.is(err.message, 'iterator.end', 'correct error')
})
})

test('calls back with error and partial data if iterator.end errors', function (t) {
t.plan(5)

Expand Down Expand Up @@ -114,3 +180,24 @@ test('calls back with error and partial data if iterator.end errors', function (
t.same(result, [].concat(data[0]))
})
})

test('prefers iterator.close() over iterator.end()', async function (t) {
t.plan(2)

const iterator = {
next (cb) {
t.pass('iterator.next called')
process.nextTick(cb)
},
close (cb) {
t.pass('iterator.close called')
process.nextTick(cb)
},
end (cb) {
t.fail('iterator.end called')
process.nextTick(cb)
}
}

await collect(iterator)
})

0 comments on commit 3074af8

Please sign in to comment.