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

Commit

Permalink
deps!: update to interface-datastore 8.x.x (#172)
Browse files Browse the repository at this point in the history
- Updates datastore interface
- Converts project to typescript

BREAKING CHANGE: this module now implements interface-datastore@8.x.x
  • Loading branch information
achingbrain authored Mar 13, 2023
1 parent c35186f commit 178d235
Show file tree
Hide file tree
Showing 40 changed files with 135 additions and 576 deletions.
18 changes: 6 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"exports": {
".": {
"types": "./dist/src/index.d.ts",
"import": "./src/index.js"
"import": "./dist/src/index.js"
}
},
"eslintConfig": {
Expand Down Expand Up @@ -161,24 +161,18 @@
"dep-check": "aegir dep-check"
},
"dependencies": {
"abstract-level": "^1.0.3",
"datastore-core": "^8.0.1",
"interface-datastore": "^7.0.0",
"datastore-core": "^9.0.1",
"interface-datastore": "^8.0.0",
"it-filter": "^2.0.0",
"it-map": "^2.0.0",
"it-sort": "^2.0.0",
"it-take": "^2.0.0",
"level": "^8.0.0"
},
"devDependencies": {
"@ipld/dag-cbor": "^8.0.0",
"@types/rimraf": "^3.0.2",
"aegir": "^37.5.1",
"interface-datastore-tests": "^3.0.0",
"aegir": "^38.1.7",
"interface-datastore-tests": "^4.0.0",
"ipfs-utils": "^9.0.4",
"level-mem": "^6.0.1",
"memory-level": "^1.0.0",
"multiformats": "^10.0.2",
"rimraf": "^3.0.2"
"memory-level": "^1.0.0"
}
}
177 changes: 77 additions & 100 deletions src/index.js → src/index.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
import { Key } from 'interface-datastore'
import { Batch, Key, KeyQuery, Pair, Query } from 'interface-datastore'
import { BaseDatastore, Errors } from 'datastore-core'
import filter from 'it-filter'
import map from 'it-map'
import take from 'it-take'
import sort from 'it-sort'
import { Level } from 'level'
import type { DatabaseOptions, OpenOptions, IteratorOptions } from 'level'

/**
* @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
* @typedef {import('abstract-level').AbstractLevel<any, string, Uint8Array>} LevelDb
*/
interface BatchPut {
type: 'put'
key: string
value: Uint8Array
}

interface BatchDel {
type: 'del'
key: string
}

type BatchOp = BatchPut | BatchDel

/**
* A datastore backed by leveldb
*/
export class LevelDatastore extends BaseDatastore {
/**
* @param {string | LevelDb} path
* @param {import('level').DatabaseOptions<string, Uint8Array> & import('level').OpenOptions} [opts]
*/
constructor (path, opts = {}) {
public db: Level<string, Uint8Array>
private readonly opts: OpenOptions

constructor (path: string | Level<string, Uint8Array>, opts: DatabaseOptions<string, Uint8Array> & OpenOptions = {}) {
super()

/** @type {LevelDb} */
this.db = typeof path === 'string'
? new Level(path, {
...opts,
Expand All @@ -36,91 +38,77 @@ export class LevelDatastore extends BaseDatastore {
})
: path

/** @type {import('level').OpenOptions} */
this.opts = {
createIfMissing: true,
compression: false, // same default as go
...opts
}
}

async open () {
async open (): Promise<void> {
try {
await this.db.open(this.opts)
} catch (/** @type {any} */ err) {
} catch (err: any) {
throw Errors.dbOpenFailedError(err)
}
}

/**
* @param {Key} key
* @param {Uint8Array} value
*/
async put (key, value) {
async put (key: Key, value: Uint8Array): Promise<void> {
try {
await this.db.put(key.toString(), value)
} catch (/** @type {any} */ err) {
} catch (err: any) {
throw Errors.dbWriteFailedError(err)
}
}

/**
* @param {Key} key
* @returns {Promise<Uint8Array>}
*/
async get (key) {
async get (key: Key): Promise<Uint8Array> {
let data
try {
data = await this.db.get(key.toString())
} catch (/** @type {any} */ err) {
if (err.notFound) throw Errors.notFoundError(err)
} catch (err: any) {
if (err.notFound != null) {
throw Errors.notFoundError(err)
}

throw Errors.dbWriteFailedError(err)
}
return data
}

/**
* @param {Key} key
* @returns {Promise<boolean>}
*/
async has (key) {
async has (key: Key): Promise<boolean> {
try {
await this.db.get(key.toString())
} catch (/** @type {any} */ err) {
if (err.notFound) return false
} catch (err: any) {
if (err.notFound != null) {
return false
}

throw err
}
return true
}

/**
* @param {Key} key
* @returns {Promise<void>}
*/
async delete (key) {
async delete (key: Key): Promise<void> {
try {
await this.db.del(key.toString())
} catch (/** @type {any} */ err) {
} catch (err: any) {
throw Errors.dbDeleteFailedError(err)
}
}

close () {
return this.db && this.db.close()
async close (): Promise<void> {
await this.db.close()
}

/**
* @returns {Batch}
*/
batch () {
/** @type {Array<{ type: 'put', key: string, value: Uint8Array; } | { type: 'del', key: string }>} */
const ops = []
batch (): Batch {
const ops: BatchOp[] = []

return {
put: (key, value) => {
ops.push({
type: 'put',
key: key.toString(),
value: value
value
})
},
delete: (key) => {
Expand All @@ -129,16 +117,17 @@ export class LevelDatastore extends BaseDatastore {
key: key.toString()
})
},
commit: () => {
return this.db.batch(ops)
commit: async () => {
if (this.db.batch == null) {
throw new Error('Batch operations unsupported by underlying Level')
}

await this.db.batch(ops)
}
}
}

/**
* @param {Query} q
*/
query (q) {
query (q: Query): AsyncIterable<Pair> {
let it = this._query({
values: true,
prefix: q.prefix
Expand All @@ -153,22 +142,19 @@ export class LevelDatastore extends BaseDatastore {
}

const { offset, limit } = q
if (offset) {
if (offset != null) {
let i = 0
it = filter(it, () => i++ >= offset)
}

if (limit) {
if (limit != null) {
it = take(it, limit)
}

return it
}

/**
* @param {KeyQuery} q
*/
queryKeys (q) {
queryKeys (q: KeyQuery): AsyncIterable<Key> {
let it = map(this._query({
values: false,
prefix: q.prefix
Expand All @@ -183,27 +169,20 @@ export class LevelDatastore extends BaseDatastore {
}

const { offset, limit } = q
if (offset) {
if (offset != null) {
let i = 0
it = filter(it, () => i++ >= offset)
}

if (limit) {
if (limit != null) {
it = take(it, limit)
}

return it
}

/**
* @param {object} opts
* @param {boolean} opts.values
* @param {string} [opts.prefix]
* @returns {AsyncIterable<Pair>}
*/
_query (opts) {
/** @type {import('level').IteratorOptions<string, Uint8Array>} */
const iteratorOpts = {
_query (opts: { values: boolean, prefix?: string }): AsyncIterable<Pair> {
const iteratorOpts: IteratorOptions<string, Uint8Array> = {
keys: true,
keyEncoding: 'buffer',
values: opts.values
Expand All @@ -220,7 +199,7 @@ export class LevelDatastore extends BaseDatastore {

const iterator = this.db.iterator(iteratorOpts)

if (iterator[Symbol.asyncIterator]) {
if (iterator[Symbol.asyncIterator] != null) {
return levelIteratorToIterator(iterator)
}

Expand All @@ -234,47 +213,45 @@ export class LevelDatastore extends BaseDatastore {
}
}

/**
* @param {import('level').Iterator<LevelDb, string, Uint8Array>} li - Level iterator
* @returns {AsyncIterable<Pair>}
*/
async function * levelIteratorToIterator (li) {
async function * levelIteratorToIterator (li: AsyncIterable<[string, Uint8Array]> & { close: () => Promise<void> }): AsyncIterable<Pair> {
for await (const [key, value] of li) {
yield { key: new Key(key, false), value }
}

await li.close()
}

/**
* @typedef {object} LevelIterator
* @property {(cb: (err: Error, key: string | Uint8Array | null, value: any)=> void)=>void} next
* @property {(cb: (err: Error) => void) => void } end
*/
interface OldLevelIterator {
next: (cb: (err: Error, key: string | Uint8Array | null, value: any) => void) => void
end: (cb: (err: Error) => void) => void
}

/**
* @param {LevelIterator} li - Level iterator
* @returns {AsyncIterable<Pair>}
*/
function oldLevelIteratorToIterator (li) {
function oldLevelIteratorToIterator (li: OldLevelIterator): AsyncIterable<Pair> {
return {
[Symbol.asyncIterator] () {
return {
next: () => new Promise((resolve, reject) => {
next: async () => await new Promise((resolve, reject) => {
li.next((err, key, value) => {
if (err) return reject(err)
if (err != null) {
reject(err); return
}
if (key == null) {
return li.end(err => {
if (err) return reject(err)
li.end(err => {
if (err != null) {
reject(err)
return
}
resolve({ done: true, value: undefined })
})
}); return
}
resolve({ done: false, value: { key: new Key(key, false), value } })
})
}),
return: () => new Promise((resolve, reject) => {
return: async () => await new Promise((resolve, reject) => {
li.end(err => {
if (err) return reject(err)
if (err != null) {
reject(err); return
}
resolve({ done: true, value: undefined })
})
})
Expand Down
8 changes: 4 additions & 4 deletions test/browser.js → test/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { interfaceDatastoreTests } from 'interface-datastore-tests'
describe('LevelDatastore', () => {
describe('interface-datastore (leveljs)', () => {
interfaceDatastoreTests({
setup: () => new LevelDatastore('hello-' + Math.random()),
setup: () => new LevelDatastore(`hello-${Math.random()}`),
teardown: () => {}
})
})
Expand All @@ -18,13 +18,13 @@ describe('LevelDatastore', () => {
setup () {
return new MountDatastore([{
prefix: new Key('/a'),
datastore: new LevelDatastore('one-' + Math.random())
datastore: new LevelDatastore(`one-${Math.random()}`)
}, {
prefix: new Key('/q'),
datastore: new LevelDatastore('two-' + Math.random())
datastore: new LevelDatastore(`two-${Math.random()}`)
}, {
prefix: new Key('/z'),
datastore: new LevelDatastore('three-' + Math.random())
datastore: new LevelDatastore(`three-${Math.random()}`)
}])
},
teardown () {}
Expand Down
Loading

0 comments on commit 178d235

Please sign in to comment.