This repository has been archived by the owner on Sep 9, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 20
feat: next level of the datastore #2
Merged
Changes from 10 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
c0286a3
feat: next level of the datastore
dignifiedquire c1c7eb6
chore: add license
dignifiedquire b6d941b
feat(key): use buffers as underlying data source
dignifiedquire 7c5a373
fix(sharding): raw ops for fs backend
dignifiedquire 2e17000
docs(readme): updates
dignifiedquire 12ca197
chore: address some of the cr
dignifiedquire 59d65f4
chore: remove pull-stream stub for now
dignifiedquire fa171d8
feat: implement namespace store
dignifiedquire 69e9240
extract wrapper implementations into js-datastore-core
dignifiedquire d4e693a
docs(readme): expand api docs
dignifiedquire 6e86edc
docs(readme): use other method of describing types
dignifiedquire File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[ignore] | ||
.*/radium/.* | ||
.*/standard-changelog/.* | ||
.*/conventional-changelog-core/.* | ||
|
||
[include] | ||
|
||
[libs] | ||
flow-typed/.* | ||
|
||
[options] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
**/node_modules/ | ||
**/*.log | ||
test/repo-tests* | ||
|
||
# Logs | ||
logs | ||
*.log | ||
|
||
coverage | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
build | ||
|
||
# Dependency directory | ||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git | ||
node_modules | ||
|
||
lib | ||
dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
sudo: false | ||
language: node_js | ||
|
||
matrix: | ||
include: | ||
- node_js: 4 | ||
env: CXX=g++-4.8 | ||
- node_js: 6 | ||
env: | ||
- SAUCE=true | ||
- CXX=g++-4.8 | ||
- node_js: stable | ||
env: CXX=g++-4.8 | ||
|
||
script: | ||
- npm run lint | ||
- npm run flow | ||
- npm test | ||
|
||
before_script: | ||
- export DISPLAY=:99.0 | ||
- sh -e /etc/init.d/xvfb start | ||
|
||
addons: | ||
firefox: 'latest' | ||
apt: | ||
sources: | ||
- ubuntu-toolchain-r-test | ||
packages: | ||
- g++-4.8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2017 IPFS | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,92 +1,228 @@ | ||
# node-datastore interface | ||
# interface-datastore | ||
|
||
datastore is a generic layer of abstraction for data store and database access. It is a simple API with the aim to enable application development in a datastore-agnostic way, allowing datastores to be swapped seamlessly without changing application code. Thus, one can leverage different datastores with different strengths without committing the application to one datastore throughout its lifetime. | ||
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) | ||
[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) | ||
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) | ||
[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) | ||
[![Build Status](https://travis-ci.org/ipfs/interface-datastore.svg)](https://travis-ci.org/ipfs/interface-datastore) [![Circle CI](https://circleci.com/gh/ipfs/interface-datastore.svg?style=svg)](https://circleci.com/gh/ipfs/interface-datastore) | ||
[![Coverage Status](https://coveralls.io/repos/github/ipfs/interface-datastore/badge.svg?branch=master)](https://coveralls.io/github/ipfs/interface-datastore?branch=master) [![Dependency Status](https://david-dm.org/diasdavid/js-peer-id.svg?style=flat-square)](https://david-dm.org/ipfs/interface-datastore) | ||
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard) | ||
![](https://img.shields.io/badge/npm-%3E%3D3.0.0-orange.svg?style=flat-square) | ||
![](https://img.shields.io/badge/Node.js-%3E%3D4.0.0-orange.svg?style=flat-square) | ||
|
||
In addition, grouped datastores significantly simplify interesting data access patterns (such as caching and sharding). | ||
> Implementation of the [datastore](https://github.com/ipfs/go-datastore) interface in JavaScript | ||
|
||
Based on [datastore.py](https://github.com/jbenet/datastore). | ||
|
||
Note: this is similar to [rvagg/abstract-leveldown](https://github.com/rvagg/abstract-leveldown/). Though I wrote [my original datastore](https://github.com/jbenet/datastore) many years ago. :) | ||
## Table of Contents | ||
|
||
## Example | ||
- [Implementations](#implementations) | ||
- [Install](#install) | ||
- [Usage](#usage) | ||
- [Api](#api) | ||
- [Contribute](#contribute) | ||
- [License](#license) | ||
|
||
### Usage | ||
## Implementations | ||
|
||
See [datastore.memory/try.js](https://github.com/jbenet/node-datastore.memory/blob/master/try.js): | ||
- Backed Implementations | ||
- Memory: [`src/memory`](src/memory.js) | ||
- level: [`datastore-level`](https://github.com/ipfs/js-datastore-level) (supports any levelup compatible backend) | ||
- File System: [`datstore-fs`](https://github.com/ipfs/js-datastore-fs) | ||
- Wrapper Implementations | ||
- Mount: [`datastore-core/src/mount`](https://github.com/ipfs/js-datastore-core/tree/master/src/mount.js) | ||
- Keytransform: [`datstore-core/src/keytransform`](https://github.com/ipfs/js-datastore-core/tree/master/src/keytransform.js) | ||
- Sharding: [`datastore-core/src/sharding`](https://github.com/ipfs/js-datastore-core/tree/master/src/sharding.js) | ||
- Tiered: [`datstore-core/src/tiered`](https://github.com/ipfs/js-datastore-core/tree/master/src/tirered.js) | ||
- Namespace: [`datastore-core/src/namespace`](https://github.com/ipfs/js-datastore-core/tree/master/src/namespace.js) | ||
|
||
If you want the same functionality as [go-ds-flatfs](https://github.com/ipfs/go-ds-flatfs), use sharding with fs. | ||
|
||
```js | ||
var memDS = require('datastore.memory') | ||
ds.put('foo', 'bar', function(err, val, key) { | ||
if (err) throw err | ||
console.log('put ' + key + ': ' + val) | ||
assert(val === 'bar') | ||
const FsStore = require('datastore-fs) | ||
const ShardingStore = require('datastore-core').ShardingDatatstore | ||
const NextToLast = require('datastore-core').shard.NextToLast | ||
|
||
const fs = new FsStore('path/to/store') | ||
ShardingStore.createOrOpen(fs, new NextToLast(2), (err, flatfs) => { | ||
// flatfs now works like go-flatfs | ||
}) | ||
``` | ||
|
||
## Install | ||
|
||
``` | ||
$ npm install interface-datastore | ||
``` | ||
|
||
## Usage | ||
|
||
ds.has('foo', function(err, has, key) { | ||
if (err) throw err | ||
console.log(key + ' exists? ' + has) | ||
assert(has === true) | ||
### Wrapping Stores | ||
|
||
```js | ||
const MemoryStore = require('interface-datastore').MemoryDatastore | ||
const MountStore = require('datastore-core').MountDatastore | ||
const Key = require('interface-datastore').Key | ||
|
||
const store = new MountStore({prefix: new Key('/a'), datastore: new MemoryStore()}) | ||
``` | ||
|
||
### Testsuite | ||
|
||
Available under [`src/tests.js`](src/tests.js) | ||
|
||
```js | ||
describe('mystore', () => { | ||
require('interface-datastore/src/tests)({ | ||
setup (callback) { | ||
callback(null, instanceOfMyStore) | ||
}, | ||
teardown (callback) { | ||
// cleanup resources | ||
callback() | ||
} | ||
}) | ||
}) | ||
``` | ||
|
||
## API | ||
|
||
### Keys | ||
|
||
To allow a better abstraction on how to address values, there is a `Key` class which is used as identifier. It's easy to create a key from a `Buffer` or a `string`. | ||
|
||
```js | ||
const a = new Key('a') | ||
const b = new Key(new Buffer('hello')) | ||
``` | ||
|
||
The key scheme is inspired by file systems and Google App Engine key model. Keys are meant to be unique across a system. They are typical hierarchical, incorporating more and more specific namespaces. Thus keys can be deemed 'children' or 'ancestors' of other keys: | ||
|
||
- `new Key('/Comedy')` | ||
- `new Key('/Comedy/MontyPython')` | ||
|
||
Also, every namespace can be parametrized to embed relevant object information. For example, the Key `name` (most specific namespace) could include the object type: | ||
|
||
- `new Key('/Comedy/MontyPython/Actor:JohnCleese')` | ||
- `new Key('/Comedy/MontyPython/Sketch:CheeseShop')` | ||
- `new Key('/Comedy/MontyPython/Sketch:CheeseShop/Character:Mousebender')` | ||
|
||
|
||
### Methods | ||
|
||
> The exact types can be found in [`src/index.js`](src/index.js). | ||
|
||
These methods will be present on every datastore. `Key` always means an instance of the above mentioned Key type. Every datastore is generic over the `Value` type, though currently all backing implementations are implemented only for [`Buffer`](https://nodejs.org/docs/latest/api/buffer.html). | ||
|
||
ds.get('foo', function(err, val, key) { | ||
if (err) throw err | ||
console.log('get ' + key + ': ' + val) | ||
assert(val === 'bar') | ||
### `put(Key, Value, (err: ?Error) => void): void` | ||
|
||
Store a value with the given key. | ||
|
||
```js | ||
store.put(new Key('awesome'), new Buffer('datastores'), (err) => { | ||
if (err) { | ||
throw err | ||
} | ||
console.log('put content') | ||
}) | ||
``` | ||
|
||
ds.delete('foo', function(err, key) { | ||
if (err) throw err | ||
console.log(key + ' deleted') | ||
### `get(Key, (err: ?Error, val: ?Value) => void): void` | ||
|
||
Retrieve the value stored under the given key. | ||
|
||
```js | ||
store.get(new Key('awesome'), (err, value) => { | ||
if (err) { | ||
throw err | ||
} | ||
console.log(got content: %s', value.toString()) | ||
// => got content: datastore | ||
}) | ||
``` | ||
|
||
ds.has('foo', function(err, has, key) { | ||
if (err) throw err | ||
console.log(key + ' exists? ' + has) | ||
assert(has === false) | ||
### `delete(Key, (err: ?Error) => void): void` | ||
|
||
Delete the content stored under the given key. | ||
|
||
```js | ||
store.delete(new Key('awesome'), (err) => { | ||
if (err) { | ||
throw err | ||
} | ||
console.log(deleted awesome content :(') | ||
}) | ||
``` | ||
|
||
### Implementation | ||
### `query(Query<Value>): QueryResult<Value>)` | ||
|
||
See [datastore.memory/index.js](https://github.com/jbenet/node-datastore.memory/blob/master/index.js): | ||
Search the store for some values. Returns a [pull-stream](https://pull-stream.github.io/) with each item being a `Value`. | ||
|
||
```js | ||
var DS = require('datastore.abstract') | ||
// retrieve __all__ values from the store | ||
pull( | ||
store.query({}), | ||
pull.collect((err, list) => { | ||
if (err) { | ||
console.error(err) | ||
} | ||
console.log('ALL THE VALUES', list) | ||
}) | ||
) | ||
``` | ||
|
||
module.exports = MemDS | ||
#### `Query` | ||
|
||
function MemDS() { | ||
if (!(this instanceof MemDS)) | ||
return new MemDS | ||
DS.call(this) | ||
this.values = {} | ||
} | ||
Object in the form with the following optional properties | ||
|
||
DS.inherits(MemDS) | ||
- `prefix?: string` | ||
- `filters?: Array<Filter<Value>>` | ||
- `orders?: Array<Order<Value>>` | ||
- `limit?: number` | ||
- `offset?: number` | ||
- `keysOnly?: bool` | ||
|
||
MemDS.prototype._get = function(key, cb) { | ||
var val = this.values[key.toString()] | ||
if (val !== undefined) cb(null, val, key) | ||
else cb(MemDS.errors.NotFound, null, key) | ||
} | ||
### batch(): Batch<Value> | ||
|
||
MemDS.prototype._put = function(key, val, cb) { | ||
this.values[key.toString()] = val | ||
cb(null, val, key) | ||
} | ||
This will return an object with which you can chain multiple operations together, with them only being executed on calling `commit`. | ||
|
||
MemDS.prototype._delete = function(key, cb) { | ||
delete this.values[key.toString()] | ||
cb(null, key) | ||
} | ||
```js | ||
const b = store.batch() | ||
|
||
MemDS.prototype._has = function(key, cb) { | ||
var has = (this.values[key.toString()] !== undefined) | ||
cb(null, has, key) | ||
for (let i = 0; i < 100; i++) { | ||
b.put(new Key(`hello${i}`), new Buffer(`hello world ${i}`)) | ||
} | ||
|
||
b.commit((err) => { | ||
if (err) { | ||
throw err | ||
} | ||
console.log(put 100 values') | ||
}) | ||
|
||
``` | ||
|
||
#### `put(Key, Value): void` | ||
|
||
Queue a put operation to the store. | ||
|
||
#### `delete(Key): void` | ||
|
||
Queue a delete operation to the store. | ||
|
||
#### `commit((err: ?Error) => void): void` | ||
|
||
Write all queued operations to the underyling store. The batch object should not be used after calling this. | ||
|
||
### `close((err: ?Error) => void): void` | ||
|
||
Close the datastore, this should always be called to ensure resources are cleaned up. | ||
|
||
## Contribute | ||
|
||
PRs accepted. | ||
|
||
Small note: If editing the Readme, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. | ||
|
||
## License | ||
|
||
MIT | ||
MIT 2017 © IPFS |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
machine: | ||
node: | ||
version: stable | ||
|
||
dependencies: | ||
pre: | ||
- google-chrome --version | ||
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - | ||
- sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' | ||
- sudo apt-get update | ||
- sudo apt-get --only-upgrade install google-chrome-stable | ||
- google-chrome --version |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The README needs a reference to https://github.com/ipfs/go-datastore and also, list out all the methods that are not implemented, if any.