Skip to content

Commit

Permalink
[upd] add README, tuple and improve tests. 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
marcooliveira committed Jul 15, 2015
1 parent 2f8dd38 commit c7392e6
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 4 deletions.
7 changes: 7 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Copyright (c) 2015 Indigo United <[email protected]>

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.
170 changes: 170 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,173 @@ Atomic operators for LevelDB.

[![Build Status](https://travis-ci.org/IndigoUnited/node-level-atomics.svg?branch=master)](https://travis-ci.org/IndigoUnited/node-level-atomics) [![Coverage Status](https://coveralls.io/repos/IndigoUnited/node-level-atomics/badge.svg)](https://coveralls.io/r/IndigoUnited/node-level-atomics) [![Codacy Badge](https://www.codacy.com/project/badge/97a9d41428694d1a978dedb9b36037c7)](https://www.codacy.com/app/me_19/node-level-atomics)

## Installing

`npm install level-atomics`

## Introduction

This module adds a bunch of typical atomic operations, like insert, replace and counter (increment/decrement) to LevelDB, and adds capacity to multiple parallel operations, like multi gets, multi inserts, and so on.

```js
var level = require('level');
var atomics = require('level-atomics');

var db = atomics(level('./tmp', {
valueEncoding: 'json' // not required, but makes it easier to handle numbers
}));

db.get(['a', 'b', 'c'], function (err, res, misses) {
if (err) {
return console.error('Something went wrong:', err);
}

if (misses.length > 1) {
console.log('These keys do not exist:', misses);
} else {
console.log(res.a);
console.log(res.b);
console.log(res.c);
}
});

db.counter({
some_key: 10
}, function (err, res, misses) {
if (err) {
return console.error('Something went wrong:', err);
}

console.log(res.some_key); // will log 10
});

```

## API

- [`append`](#db_append) *soon*
- [`counter`](#db_counter)
- [`get`](#db_get)
- [`insert`](#db_insert)
- [`lock`](#db_lock) *soon*
- [`prepend`](#db_prepend) *soon*
- [`remove`](#db_remove) *soon*
- [`replace`](#db_replace)
- [`unlock`](#db_unlock)
- [`upsert`](#db_upsert) *soon*

---

<a name="db_counter"></a>
#### `counter(tuples, [options,] callback) → db`

Increments or decrements the keys' numeric value.

Note that JavaScript does not support 64-bit integers. You might receive an inaccurate value if the number is greater than 53-bits (JavaScript's maximum integer precision).

- `tuples`: tuple (object with keys and respective deltas).
- `options`: same options as (level.put)[https://github.com/Level/levelup#options-1].
- `callback(err, results, cas, misses)`
- `results`: object with keys and respective values.
- `misses`: array of keys that don't exist.

---

<a name="db_get"></a>
#### `get(keys, [options,] callback) → db`

Retrieve keys.

- `keys`: array or string.
- `options`: same options as (level.get)[https://github.com/Level/levelup#options-2].
- `callback(err, results, cas, misses)`
- `results`: object with keys and respective values.
- `misses`: array of keys that don't exist.

---

<a name="db_insert"></a>
#### `insert(tuples, [options,] callback) → db`

Will fail if the key already exists. Any key that already exists is returned in the callback in the `existing` parameter.

- `tuples`: tuple (object with keys and respective values)
- `options`: same options as (level.put)[https://github.com/Level/levelup#options-1].
- `callback(err, cas, existing)`
- `existing`: array of keys that already existed, and thus failed to be added.

---

<a name="db_replace"></a>
#### `replace(tuples, [options,] callback) → db`

Identical to [`upsert`](#upsert), but will only succeed if the key exists already (i.e. the inverse of [`insert`](#insert)).

- `tuples`: tuple (object with keys and respective values)
- `options`: same options as (level.put)[https://github.com/Level/levelup#options-1].
- `callback(err, cas, misses)`
- `misses`: array of keys that don't exist.

---

### Tuples

A tuple is an object with key and respective values, like so:

```js
{
a: 1,
b: 2,
c: 3
}
```

Many operations allow you to provide tuples for *multi operations*. As an example, you could provide the tuple above to `insert`, and the keys `a`, `b` and `c` would be inserted with the respective values.

As syntax sugar, and to avoid creating temporary objects like this:

```js
// ...

var someKey = 'foo';
var someValue = 'bar';
var tmp = {};
tmp[someKey] = someValue;
db.insert(tmp, function (err, res) {
// ...
});

// ...
```

You can instead do the following:

```js
// ...

var someKey = 'foo';
var someValue = 'bar';

var tuple = require('level-atomics').tuple;

db.insert(tuple(someKey, someValue), function (err, res) {
// ...
});

//...
```

You can provide to the `tuple` helper just a key and a value, or you can provide a couple of arrays of equal length, and `tuple` will map each of they keys to the respective values, like so:

```js
tuple(['a', 'b', 'c'], [1, 2, 3]);

// will return
//
// {
// a: 1,
// b: 2,
// c: 3
// }
```

32 changes: 30 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ var async = require('async');

var kvOps = {};

function wrap(db) {
function atomics(db) {
// mix in the methods
for (var k in kvOps) {
// some methods overlap, save the original ones under '_' + method
Expand All @@ -22,6 +22,8 @@ function wrap(db) {
return db;
}

atomics.tuple = _tuple;

// kvOps.append = function (keys, fragment, callback) {

// };
Expand Down Expand Up @@ -54,6 +56,8 @@ kvOps.counter = function (tuples, options, callback) {
}.bind(this));

async.parallel(tasks, callback);

return this;
};

kvOps.get = function (keys, options, callback) {
Expand Down Expand Up @@ -86,6 +90,8 @@ kvOps.get = function (keys, options, callback) {

return callback(null, finalRes, misses);
});

return this;
};

kvOps.insert = function (tuples, options, callback) {
Expand Down Expand Up @@ -128,6 +134,8 @@ kvOps.insert = function (tuples, options, callback) {

return callback(null, existing);
});

return this;
};

// kvOps.prepend = function (keys, fragment, callback) {
Expand Down Expand Up @@ -174,6 +182,8 @@ kvOps.replace = function (tuples, options, callback) {

return callback(null, existing);
});

return this;
};

// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -208,4 +218,22 @@ function _array(x) {
return isArray(x) ? x : [x];
}

module.exports = wrap;
function _tuple(k, v) {
var res = {};

// if it's a set of keys and respective values
if (isArray(k)) {
for (var i = k.length - 1; i >= 0; i--) {
res[k[i]] = v[i];
}

return res;
}

// just a key and a value
res[k] = v;

return res;
}

module.exports = atomics;
2 changes: 2 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ var counterSpecs = require('./specs/counter');
var insertSpecs = require('./specs/insert');
var replaceSpecs = require('./specs/replace');
var getSpecs = require('./specs/get');
var tupleSpecs = require('./specs/tuple');

// -----------------------------------------------------------------------------

Expand All @@ -23,6 +24,7 @@ describe('counter', counterSpecs);
describe('insert', insertSpecs);
describe('replace', replaceSpecs);
describe('get', getSpecs);
describe('tuple', tupleSpecs);

// -----------------------------------------------------------------------------

4 changes: 2 additions & 2 deletions test/specs/counter.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ module.exports = function () {
it('should initialize multiple keys with 0', function (done) {
db.counter({
mycounter1: 25,
mycounter2: 25
mycounter2: 10
}, function (err, res) {
__throw(err);

expect(res.mycounter1).to.be(25);
expect(res.mycounter2).to.be(25);
expect(res.mycounter2).to.be(10);

return done();
});
Expand Down
32 changes: 32 additions & 0 deletions test/specs/tuple.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict';

var expect = require('expect.js');
var __throw = require('../util/__throw');
var db = require('../util/db');
var tuple = require('../../index').tuple;

module.exports = function () {
db = db.get();

it('should initialize single key with 0 when incrementing', function (done) {
db.counter(tuple('mycounter', 25), function (err, res) {
__throw(err);

expect(res.mycounter).to.be(25);

return done();
});
});


it('should initialize multiple keys with 0', function (done) {
db.counter(tuple(['mycounter1', 'mycounter2'], [25, 10]), function (err, res) {
__throw(err);

expect(res.mycounter1).to.be(25);
expect(res.mycounter2).to.be(10);

return done();
});
});
};

0 comments on commit c7392e6

Please sign in to comment.