diff --git a/README.md b/README.md index 60838330..03a38b06 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Node-DLC is a an implementation of Bitcoin DLC Protocol in the Node.js runtime, - [@node-dlc/logger](https://github.com/atomicfinance/node-dlc/tree/master/packages/logger) - [@node-dlc/messaging](https://github.com/atomicfinance/node-dlc/tree/master/packages/messaging) - [@node-dlc/rocksdb](https://github.com/atomicfinance/node-dlc/tree/master/packages/rocksdb) +- [@node-dlc/classic-level](https://github.com/atomicfinance/node-dlc/tree/master/packages/classic-level) - [@node-dlc/transport](https://github.com/atomicfinance/node-dlc/tree/master/packages/transport) ## Dependencies diff --git a/packages/classic-level/README.md b/packages/classic-level/README.md new file mode 100644 index 00000000..ff58aeca --- /dev/null +++ b/packages/classic-level/README.md @@ -0,0 +1,26 @@ +# @node-dlc/classic-level + +This package provides a basic datalayer built on top of [classic-level](https://github.com/Level/classic-level). It mirrors the interface used by the RocksDB based stores but does not require the `rocksdb` native module. + +## Usage + +```ts +import { ClassicLevelBase } from '@node-dlc/classic-level'; + +class MyStore extends ClassicLevelBase { + async save(key: Buffer, value: Buffer) { + await this._db.put(key, value); + } + + async load(key: Buffer) { + return this._safeGet(key); + } +} + +const store = new MyStore('./mydb'); +await store.open(); +await store.save(Buffer.from('a'), Buffer.from('b')); +const value = await store.load(Buffer.from('a')); +``` + +The API is the same as the RocksDB based `RocksdbBase` class. Internally it uses `classic-level` instead of the deprecated `rocksdb` package. diff --git a/packages/classic-level/__tests__/classic-level.spec.ts b/packages/classic-level/__tests__/classic-level.spec.ts new file mode 100644 index 00000000..eb1f225d --- /dev/null +++ b/packages/classic-level/__tests__/classic-level.spec.ts @@ -0,0 +1,37 @@ +// tslint:disable: no-unused-expression + +import { expect } from 'chai'; +import { ClassicLevelBase } from '../lib'; +import { rmdir } from './util'; + +class TestStore extends ClassicLevelBase { + async save(key: Buffer, value: Buffer) { + await this._db.put(key, value); + } + async load(key: Buffer) { + return this._safeGet(key); + } +} + +describe('ClassicLevelBase', () => { + let sut: TestStore; + + before(async () => { + rmdir('.testdb'); + sut = new TestStore('.testdb'); + await sut.open(); + }); + + after(async () => { + await sut.close(); + rmdir('.testdb'); + }); + + it('should save and load a value', async () => { + const key = Buffer.from('key'); + const value = Buffer.from('value'); + await sut.save(key, value); + const actual = await sut.load(key); + expect(actual).to.deep.equal(value); + }); +}); diff --git a/packages/classic-level/__tests__/tsconfig.json b/packages/classic-level/__tests__/tsconfig.json new file mode 100644 index 00000000..fb3b63fe --- /dev/null +++ b/packages/classic-level/__tests__/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "noEmit": true + }, + "include": ["**/*.ts"], + "exclude": [] +} diff --git a/packages/classic-level/__tests__/util.ts b/packages/classic-level/__tests__/util.ts new file mode 100644 index 00000000..b534cba7 --- /dev/null +++ b/packages/classic-level/__tests__/util.ts @@ -0,0 +1,13 @@ +import fs from 'fs'; +import path from 'path'; + +export function rmdir(dir: string) { + if (!fs.existsSync(dir)) return; + const files = fs.readdirSync(dir); + for (const file of files) { + const filepath = path.join(dir, file); + if (fs.lstatSync(filepath).isDirectory()) rmdir(filepath); + else fs.unlinkSync(filepath); + } + fs.rmdirSync(dir); +} diff --git a/packages/classic-level/lib/classic-level-base.ts b/packages/classic-level/lib/classic-level-base.ts new file mode 100644 index 00000000..70239e61 --- /dev/null +++ b/packages/classic-level/lib/classic-level-base.ts @@ -0,0 +1,27 @@ +import { ClassicLevel } from 'classic-level'; + +export class ClassicLevelBase { + protected _db: ClassicLevel; + constructor(private _location: string) {} + + public async open(): Promise { + this._db = new ClassicLevel(this._location, { + keyEncoding: 'buffer', + valueEncoding: 'buffer', + }); + await this._db.open(); + } + + public async close(): Promise { + if (this._db) await this._db.close(); + } + + protected async _safeGet(key: Buffer): Promise { + try { + return (await this._db.get(key)) as T; + } catch (err: any) { + if (err.notFound) return undefined; + throw err; + } + } +} diff --git a/packages/classic-level/lib/index.ts b/packages/classic-level/lib/index.ts new file mode 100644 index 00000000..d7544d32 --- /dev/null +++ b/packages/classic-level/lib/index.ts @@ -0,0 +1 @@ +export * from './classic-level-base'; diff --git a/packages/classic-level/package.json b/packages/classic-level/package.json new file mode 100644 index 00000000..452e88ef --- /dev/null +++ b/packages/classic-level/package.json @@ -0,0 +1,30 @@ +{ + "name": "@node-dlc/classic-level", + "version": "0.23.6", + "description": "Classic Level datalayer", + "scripts": { + "test": "../../node_modules/.bin/nyc --reporter=lcov --reporter=text --extension=.ts ../../node_modules/.bin/mocha --require ts-node/register --recursive \"__tests__/**/*.spec.*\"", + "lint": "../../node_modules/.bin/eslint --ignore-path ../../.eslintignore -c ../../.eslintrc.js .", + "lint:fix": "../../node_modules/.bin/eslint --fix --ignore-path ../../.eslintignore -c ../../.eslintrc.js .", + "build": "../../node_modules/.bin/tsc --project tsconfig.json", + "prepublish": "npm run build" + }, + "keywords": [ + "dlc", + "classic-level" + ], + "author": "Atomic Finance ", + "homepage": "https://github.com/atomicfinance/node-dlc/tree/master/packages/classic-level", + "license": "MIT", + "main": "dist/index.js", + "repository": { + "type": "git", + "url": "git+https://github.com/atomicfinance/node-dlc.git" + }, + "dependencies": { + "classic-level": "^1.0.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/classic-level/tsconfig.json b/packages/classic-level/tsconfig.json new file mode 100644 index 00000000..1ed05ec6 --- /dev/null +++ b/packages/classic-level/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist" + }, + "include": ["./lib"] +}