Skip to content
This repository has been archived by the owner on Sep 9, 2021. It is now read-only.

Commit

Permalink
feat: add adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
achingbrain committed May 7, 2020
1 parent 0b17cff commit 4223581
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 106 deletions.
39 changes: 30 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
## Table of Contents <!-- omit in toc -->

- [Implementations](#implementations)
- [Adapter](#adapter)
- [Install](#install)
- [Usage](#usage)
- [Wrapping Stores](#wrapping-stores)
Expand Down Expand Up @@ -54,7 +55,7 @@
- [Example](#example-8)
- [`put(key, value)`](#putkey-value)
- [`delete(key)`](#deletekey)
- [`commit([options])` -> `AsyncIterator<?>`](#commitoptions---asynciterator)
- [`commit([options])` -> `Promise<void>`](#commitoptions---promisevoid)
- [Arguments](#arguments-8)
- [Example](#example-9)
- [`open()` -> `Promise`](#open---promise)
Expand Down Expand Up @@ -88,6 +89,32 @@ const fs = new FsStore('path/to/store')
const flatfs = await ShardingStore.createOrOpen(fs, new NextToLast(2))
```

## Adapter

An adapter is made available to make implementing your own datastore easier:

```javascript
const { Adapter } = require('interface-datastore')

class MyDatastore extends Adapter {
constructor () {
super()
}

async put (key, val) {
// your implementation here
}

async get (key) {
// your implementation here
}

// etc...
}
```

See the [MemoryDatastore](./src/memory.js) for an example of how it is used.

## Install

```sh
Expand Down Expand Up @@ -385,7 +412,7 @@ Queue a delete operation to the store.
| ---- | ---- | ----------- |
| key | [Key][] | The key to remove the value for |

#### `commit([options])` -> `AsyncIterator<?>`
#### `commit([options])` -> `Promise<void>`

Write all queued operations to the underyling store. The batch object should not be used after calling this.

Expand All @@ -404,13 +431,7 @@ const batch = store.batch()
batch.put(new Key('to-put'), Buffer.from('hello world'))
batch.del(new Key('to-remove'))

for await (const res of batch.commit()) {
if (res.key) {
console.info('put', res.key)
} else {
console.info('del', res)
}
}
await batch.commit()
```

### `open()` -> `Promise`
Expand Down
175 changes: 175 additions & 0 deletions src/adapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
'use strict'

const { filter, sortAll, take, map } = require('./utils')
const drain = require('it-drain')

class InterfaceDatastoreAdapter {
async open () { // eslint-disable-line require-await

}

async close () { // eslint-disable-line require-await

}

/**
* Store the passed value under the passed key
*
* @param {Key} key
* @param {Buffer} val
* @param {Object} options
* @returns {Promise<void>}
*/
async put (key, val, options = {}) { // eslint-disable-line require-await

}

/**
* Store the given key/value pairs
*
* @param {AsyncIterator<{ key: Key, value: Buffer }>} source
* @param {Object} options
* @returns {AsyncIterator<{ key: Key, value: Buffer }>}
*/
async * putMany (source, options = {}) {
for await (const { key, value } of source) {
await this.put(key, value, options)
yield { key, value }
}
}

/**
* Retrieve the value for the passed key
*
* @param {Key} key
* @param {Object} options
* @returns {Promise<Buffer>}
*/
async get (key, options = {}) { // eslint-disable-line require-await

}

/**
* Retrieve values for the passed keys
*
* @param {AsyncIterator<Key>} source
* @param {Object} options
* @returns {AsyncIterator<Buffer>}
*/
async * getMany (source, options = {}) {
for await (const key of source) {
yield this.get(key, options)
}
}

/**
* Check for the existence of a value for the passed key
*
* @param {Key} key
* @returns {Promise<bool>}
*/
async has (key) { // eslint-disable-line require-await

}

/**
* Remove the record for the passed key
*
* @param {Key} key
* @param {Object} options
* @returns {Promise<void>}
*/
async delete (key, options = {}) { // eslint-disable-line require-await

}

/**
* Remove values for the passed keys
*
* @param {AsyncIterator<Key>} source
* @param {Object} options
* @returns {AsyncIterator<Key>}
*/
async * deleteMany (source, options = {}) {
for await (const key of source) {
await this.delete(key, options)
yield key
}
}

/**
* Create a new batch object.
*
* @returns {Object}
*/
batch () {
let puts = []
let dels = []

return {
put (key, value) {
puts.push({ key, value })
},
delete (key) {
dels.push(key)
},
commit: async (options) => {
await drain(this.putMany(puts, options))
puts = []
await drain(this.deleteMany(dels, options))
dels = []
}
}
}

/**
* Yield all datastore values
*
* @param {Object} q
* @param {Object} options
* @returns {AsyncIterable<{ key: Key, value: Buffer }>}
*/
async * _all (q, options) { // eslint-disable-line require-await

}

/**
* Query the store.
*
* @param {Object} q
* @param {Object} options
* @returns {AsyncIterable<Buffer>}
*/
async * query (q, options) { // eslint-disable-line require-await
let it = this._all(q, options)

if (q.prefix != null) {
it = filter(it, e => e.key.toString().startsWith(q.prefix))
}

if (Array.isArray(q.filters)) {
it = q.filters.reduce((it, f) => filter(it, f), it)
}

if (Array.isArray(q.orders)) {
it = q.orders.reduce((it, f) => sortAll(it, f), it)
}

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

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

if (q.keysOnly === true) {
it = map(it, e => ({ key: e.key }))
}

yield * it
}
}

module.exports = InterfaceDatastoreAdapter
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ const Key = require('./key')
const MemoryDatastore = require('./memory')
const utils = require('./utils')
const Errors = require('./errors')
const Adapter = require('./adapter')

exports.Key = Key
exports.MemoryDatastore = MemoryDatastore
exports.utils = utils
exports.Errors = Errors
exports.Adapter = Adapter
101 changes: 7 additions & 94 deletions src/memory.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,28 @@
'use strict'

const { filter, sortAll, take, map } = require('./utils')
const Key = require('./key')
const Adapter = require('./adapter')

// Errors
const Errors = require('./errors')

function throwIfAborted (signal) {
if (signal && signal.aborted) {
throw Error.abortedError()
}
}

class MemoryDatastore {
class MemoryDatastore extends Adapter {
constructor () {
super()

this.data = {}
}

async open () {}

async put (key, val) { // eslint-disable-line require-await
this.data[key.toString()] = val
}

async * putMany (source, options = {}) {
throwIfAborted(options.signal)

for await (const { key, value } of source) {
throwIfAborted(options.signal)
await this.put(key, value)
yield { key, value }
}
}

async get (key) {
const exists = await this.has(key)
if (!exists) throw Errors.notFoundError()
return this.data[key.toString()]
}

async * getMany (source, options = {}) {
throwIfAborted(options.signal)

for await (const key of source) {
throwIfAborted(options.signal)
yield this.get(key)
}
}

async has (key) { // eslint-disable-line require-await
return this.data[key.toString()] !== undefined
}
Expand All @@ -56,72 +31,10 @@ class MemoryDatastore {
delete this.data[key.toString()]
}

async * deleteMany (source, options = {}) {
throwIfAborted(options.signal)

for await (const key of source) {
throwIfAborted(options.signal)
await this.delete(key)
yield key
}
* _all () {
yield * Object.entries(this.data)
.map(([key, value]) => ({ key: new Key(key), value }))
}

batch () {
let puts = []
let dels = []

const self = this

return {
put (key, value) {
puts.push({ key, value })
},
delete (key) {
dels.push(key)
},
async * commit (options) { // eslint-disable-line require-await
yield * self.putMany(puts, options)
puts = []
yield * self.deleteMany(dels, options)
dels = []
}
}
}

query (q) {
let it = Object.entries(this.data)

it = map(it, entry => ({ key: new Key(entry[0]), value: entry[1] }))

if (q.prefix != null) {
it = filter(it, e => e.key.toString().startsWith(q.prefix))
}

if (Array.isArray(q.filters)) {
it = q.filters.reduce((it, f) => filter(it, f), it)
}

if (Array.isArray(q.orders)) {
it = q.orders.reduce((it, f) => sortAll(it, f), it)
}

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

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

if (q.keysOnly === true) {
it = map(it, e => ({ key: e.key }))
}

return it
}

async close () {}
}

module.exports = MemoryDatastore
Loading

0 comments on commit 4223581

Please sign in to comment.