Skip to content

Commit

Permalink
Breaking: upgrade to abstract-level 2.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
vweevers committed Oct 21, 2024
1 parent c94f9a4 commit dc5c04a
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 99 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/sauce.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- name: Set up node
uses: actions/setup-node@v3
with:
node-version: 14
node-version: 16
- name: Install
run: npm install
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node: [12, 14, 16]
node: [16, 18, 20]
name: Node ${{ matrix.node }}
steps:
- name: Checkout
Expand Down
13 changes: 0 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,6 @@ for await (const [key, value] of db.iterator({ gt: 'a' })) {
}
```

With callbacks:

```js
db.put('example', { hello: 'world' }, (err) => {
if (err) throw err

db.get('example', (err, value) => {
if (err) throw err
console.log(value) // { hello: 'world' }
})
})
```

<!-- ## Browser support
[![Sauce Test Status](https://app.saucelabs.com/browser-matrix/level-ci.svg)](https://app.saucelabs.com/u/level-ci) -->
Expand Down
4 changes: 4 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

This document describes breaking changes and how to upgrade. For a complete list of changes including minor and patch releases, please refer to the [`CHANGELOG`](CHANGELOG.md).

## 2.0.0

This release upgrades to `abstract-level` 2.0.0 which adds [hooks](https://github.com/Level/abstract-level#hooks) and drops callbacks, not-found errors and support of Node.js < 16. Please refer to the [upgrade guide of `abstract-level`](https://github.com/Level/abstract-level/blob/v2.0.0/UPGRADING.md).

## 1.0.0

**Introducing `memory-level`: a fork of [`memdown`](https://github.com/Level/memdown) that removes the need for [`level-mem`](https://github.com/Level/mem), [`levelup`](https://github.com/Level/levelup) and more. It implements the [`abstract-level`](https://github.com/Level/abstract-level) interface instead of [`abstract-leveldown`](https://github.com/Level/abstract-leveldown) and thus has the same API as `level-mem` and `levelup` including encodings, promises and events. In addition, you can now choose to use Uint8Array instead of Buffer. Sublevels are builtin.**
Expand Down
5 changes: 1 addition & 4 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import {
AbstractLevel,
AbstractDatabaseOptions,
AbstractOpenOptions,
NodeCallback
AbstractOpenOptions
} from 'abstract-level'

/**
Expand All @@ -22,8 +21,6 @@ export class MemoryLevel<KDefault = string, VDefault = string>

open (): Promise<void>
open (options: OpenOptions): Promise<void>
open (callback: NodeCallback<void>): void
open (options: OpenOptions, callback: NodeCallback<void>): void
}

/**
Expand Down
107 changes: 48 additions & 59 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,26 @@ function lte (value) {
return compare(value, this[kUpperBound]) <= 0
}

// TODO (v2): support signal
class MemoryIterator extends AbstractIterator {
constructor (db, options) {
super(db, options)
this[kInit](db[kTree], options)
}

_next (callback) {
if (!this[kIterator].valid) return this.nextTick(callback)
async _next () {
if (!this[kIterator].valid) return undefined

const key = this[kIterator].key
const value = this[kIterator].value

if (!this[kTest](key)) return this.nextTick(callback)
if (!this[kTest](key)) return undefined

this[kIterator][this[kAdvance]]()
this.nextTick(callback, null, key, value)
return [key, value]
}

_nextv (size, options, callback) {
async _nextv (size, options) {
const it = this[kIterator]
const entries = []

Expand All @@ -83,10 +84,10 @@ class MemoryIterator extends AbstractIterator {
it[this[kAdvance]]()
}

this.nextTick(callback, null, entries)
return entries
}

_all (options, callback) {
async _all (options) {
const size = this.limit - this.count
const it = this[kIterator]
const entries = []
Expand All @@ -96,7 +97,7 @@ class MemoryIterator extends AbstractIterator {
it[this[kAdvance]]()
}

this.nextTick(callback, null, entries)
return entries
}
}

Expand All @@ -106,17 +107,17 @@ class MemoryKeyIterator extends AbstractKeyIterator {
this[kInit](db[kTree], options)
}

_next (callback) {
if (!this[kIterator].valid) return this.nextTick(callback)
async _next () {
if (!this[kIterator].valid) return undefined

const key = this[kIterator].key
if (!this[kTest](key)) return this.nextTick(callback)
if (!this[kTest](key)) return undefined

this[kIterator][this[kAdvance]]()
this.nextTick(callback, null, key)
return key
}

_nextv (size, options, callback) {
async _nextv (size, options) {
const it = this[kIterator]
const keys = []

Expand All @@ -125,10 +126,10 @@ class MemoryKeyIterator extends AbstractKeyIterator {
it[this[kAdvance]]()
}

this.nextTick(callback, null, keys)
return keys
}

_all (options, callback) {
async _all (options) {
const size = this.limit - this.count
const it = this[kIterator]
const keys = []
Expand All @@ -138,7 +139,7 @@ class MemoryKeyIterator extends AbstractKeyIterator {
it[this[kAdvance]]()
}

this.nextTick(callback, null, keys)
return keys
}
}

Expand All @@ -148,19 +149,19 @@ class MemoryValueIterator extends AbstractValueIterator {
this[kInit](db[kTree], options)
}

_next (callback) {
if (!this[kIterator].valid) return this.nextTick(callback)
async _next (options) {
if (!this[kIterator].valid) return undefined

const key = this[kIterator].key
const value = this[kIterator].value

if (!this[kTest](key)) return this.nextTick(callback)
if (!this[kTest](key)) return undefined

this[kIterator][this[kAdvance]]()
this.nextTick(callback, null, value)
return value
}

_nextv (size, options, callback) {
async _nextv (size, options) {
const it = this[kIterator]
const values = []

Expand All @@ -169,10 +170,10 @@ class MemoryValueIterator extends AbstractValueIterator {
it[this[kAdvance]]()
}

this.nextTick(callback, null, values)
return values
}

_all (options, callback) {
async _all (options) {
const size = this.limit - this.count
const it = this[kIterator]
const values = []
Expand All @@ -182,7 +183,7 @@ class MemoryValueIterator extends AbstractValueIterator {
it[this[kAdvance]]()
}

this.nextTick(callback, null, values)
return values
}
}

Expand Down Expand Up @@ -270,6 +271,7 @@ class MemoryLevel extends AbstractLevel {
}

// To help migrating from level-mem to abstract-level
// TODO (v2): remove
if (typeof location === 'function' || typeof options === 'function' || typeof _ === 'function') {
throw new ModuleError('The levelup-style callback argument has been removed', {
code: 'LEVEL_LEGACY'
Expand Down Expand Up @@ -297,39 +299,30 @@ class MemoryLevel extends AbstractLevel {
this[kTree] = createRBT(compare)
}

_put (key, value, options, callback) {
async _put (key, value, options) {
const it = this[kTree].find(key)

if (it.valid) {
this[kTree] = it.update(value)
} else {
this[kTree] = this[kTree].insert(key, value)
}

this.nextTick(callback)
}

_get (key, options, callback) {
const value = this[kTree].get(key)

if (typeof value === 'undefined') {
// TODO: use error code (not urgent, abstract-level normalizes this)
return this.nextTick(callback, new Error('NotFound'))
}

this.nextTick(callback, null, value)
async _get (key, options) {
// Is undefined if not found
return this[kTree].get(key)
}

_getMany (keys, options, callback) {
this.nextTick(callback, null, keys.map(key => this[kTree].get(key)))
async _getMany (keys, options) {
return keys.map(key => this[kTree].get(key))
}

_del (key, options, callback) {
async _del (key, options) {
this[kTree] = this[kTree].remove(key)
this.nextTick(callback)
}

_batch (operations, options, callback) {
async _batch (operations, options) {
let tree = this[kTree]

for (const op of operations) {
Expand All @@ -344,38 +337,35 @@ class MemoryLevel extends AbstractLevel {
}

this[kTree] = tree
this.nextTick(callback)
}

_clear (options, callback) {
async _clear (options) {
if (options.limit === -1 && !Object.keys(options).some(isRangeOption)) {
// Delete everything by creating a new empty tree.
this[kTree] = createRBT(compare)
return this.nextTick(callback)
return
}

const iterator = this._keys({ ...options })
const limit = iterator.limit

let count = 0

const loop = () => {
while (true) {
// TODO: add option to control "batch size"
for (let i = 0; i < 500; i++) {
if (++count > limit) return callback()
if (!iterator[kIterator].valid) return callback()
if (!iterator[kTest](iterator[kIterator].key)) return callback()
if (++count > limit) return
if (!iterator[kIterator].valid) return
if (!iterator[kTest](iterator[kIterator].key)) return

// Must also include changes made in parallel to clear()
this[kTree] = this[kTree].remove(iterator[kIterator].key)
iterator[kIterator][iterator[kAdvance]]()
}

// Some time to breathe
this.nextTick(loop)
await breathe()
}

this.nextTick(loop)
}

_iterator (options) {
Expand All @@ -393,18 +383,17 @@ class MemoryLevel extends AbstractLevel {

exports.MemoryLevel = MemoryLevel

// Use setImmediate() in Node.js to allow IO in between our callbacks
let breathe

// Use setImmediate() in Node.js to allow IO in between work
if (typeof process !== 'undefined' && !process.browser && typeof global !== 'undefined' && typeof global.setImmediate === 'function') {
const setImmediate = global.setImmediate

// Automatically applies to iterators, sublevels and chained batches as well
MemoryLevel.prototype.nextTick = function (fn, ...args) {
if (args.length === 0) {
setImmediate(fn)
} else {
setImmediate(() => fn(...args))
}
breathe = function () {
return new Promise(setImmediate)
}
} else {
breathe = async function () {}
}

function isRangeOption (k) {
Expand Down
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"main": "index.js",
"types": "./index.d.ts",
"scripts": {
"test": "standard && hallmark && (nyc -s node test.js | faucet) && nyc report",
"test": "standard && hallmark && (nyc -s node test.js | tap-arc) && nyc report",
"test-pessimistic": "node test.js | tap-arc -pv",
"test-browsers": "airtap --coverage --verbose test.js",
"test-browsers-local": "airtap --coverage -p local test.js",
"coverage": "nyc report -r lcovonly"
Expand All @@ -19,22 +20,22 @@
"CHANGELOG.md"
],
"dependencies": {
"abstract-level": "^1.0.0",
"abstract-level": "^2.0.0",
"functional-red-black-tree": "^1.0.1",
"module-error": "^1.0.1"
},
"devDependencies": {
"@voxpelli/tsconfig": "^4.0.0",
"@voxpelli/tsconfig": "^15.0.0",
"airtap": "^4.0.3",
"airtap-playwright": "^1.0.1",
"airtap-sauce": "^1.1.0",
"buffer": "^6.0.3",
"faucet": "^0.0.3",
"hallmark": "^4.0.0",
"nyc": "^15.1.0",
"standard": "^17.0.0",
"tap-arc": "^0.3.5",
"tape": "^5.0.1",
"typescript": "^4.5.5"
"typescript": "^5.6.3"
},
"repository": {
"type": "git",
Expand All @@ -49,6 +50,6 @@
"memory"
],
"engines": {
"node": ">=12"
"node": ">=16"
}
}
Loading

0 comments on commit dc5c04a

Please sign in to comment.