Skip to content

Commit

Permalink
initial
Browse files Browse the repository at this point in the history
  • Loading branch information
stagas committed Nov 19, 2013
0 parents commit 74f4df7
Show file tree
Hide file tree
Showing 7 changed files with 612 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
level-test
17 changes: 17 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

install: package.json
@npm install --production

dev: package.json
@npm install

test:
@mocha -r should -R spec test

test-watch:
@mocha -w -r should -R spec test

clean:
rm -rf node_modules

.PHONY: test clean
85 changes: 85 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@

# level-indexing

level indexing and finding

## Installing

`npm install level-indexing`

## Example

```js
var assert = require('assert');

var level = require('level');
var sublevel = require('sublevel');
var indexing = require('level-indexing');

// sublevel instance
var db = sublevel(level('./level-test'));

// users sublevel (needs json value encoding)
var users = db.sublevel('users', { valueEncoding: 'json' });

// use indexing
indexing(users);

// index some properties
users
.index('username')
.index('email');

// a user object
var user = {
id: 1,
username: 'foobar',
email: 'foo@bar'
};

users.put(user.id, user, function(err){
// properties are now indexed
users.by('username', 'foobar', function(err, value){
assert.deepEqual(user, value);
});

users.byEmail('foo@bar', function(err, value){
assert.deepEqual(user, value);
});

users.find(1, function(err, value){
assert.deepEqual(user, value);
});

users.find('foobar', function(err, value){
assert.deepEqual(user, value);
});

users.find('foo@bar', function(err, value){
assert.deepEqual(user, value);
});
});
```

## API

### indexing(sublevel)

Enable indexing on a sublevel db instance.

### index(name)

Indexes a property `name`.

### by(index, key, fn)

Gets a value from `index` by `key`. Key can be
an object with a property of `index`.

### find(key, fn)

Finds `key` in all indexes. Key can be an object.

## License

MIT
54 changes: 54 additions & 0 deletions example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@

/**
* Example.
*/

var assert = require('assert');

var level = require('level');
var sublevel = require('sublevel');
var indexing = require('./');

// sublevel instance
var db = sublevel(level('./level-test'));

// users sublevel (needs json value encoding)
var users = db.sublevel('users', { valueEncoding: 'json' });

// use indexing
indexing(users);

// index some properties
users
.index('username')
.index('email');

// a user object
var user = {
id: 1,
username: 'foobar',
email: 'foo@bar'
};

users.put(user.id, user, function(err){
// properties are now indexed
users.by('username', 'foobar', function(err, value){
assert.deepEqual(user, value);
});

users.byEmail('foo@bar', function(err, value){
assert.deepEqual(user, value);
});

users.find(1, function(err, value){
assert.deepEqual(user, value);
});

users.find('foobar', function(err, value){
assert.deepEqual(user, value);
});

users.find('foo@bar', function(err, value){
assert.deepEqual(user, value);
});
});
170 changes: 170 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@

/*!
*
* level-indexing
*
* level indexing and finding
*
* MIT
*
*/

/**
* Enable indexing on a sublevel instance.
*
* @param {Sub} db
* @return {Sub}
* @api public
*/

module.exports = function(db){
db.indexes = db.indexes || [];
db.index = index;
db.getBy = db.by = by;
db.find = find;
return db;
};

/**
* Indexes a property `name`.
*
* @param {String} name
* @return {Sub}
* @api public
*/

function index(name){
var self = this;
var sub = this.sublevel(name, { valueEncoding: 'utf8' });
var put = this.put;
var del = this.del;

this.indexes.push(name);

// convenience methods
var Name = name[0].toUpperCase() + name.substr(1);
this['getBy' + Name] =
this['by' + Name] = function(key, options, fn){
return this.by(name, key, options, fn);
};

this.put = function(key, value, options, fn){
if (!(name in value)) return done();

var prop = value[name];
sub.put(prop, key, done);

function done(err){
if (err) return (fn || options)(err);
put.call(self, key, value, options, fn);
}
};

this.del = function(key, fn){
this.get(key, function(err, value){
if (err) return fn(err);
if (!(name in value)) return done();

var prop = value[name];
sub.del(prop, done);

function done(err){
if (err) return fn(err);
del.call(self, key, fn);
}
});
};

return this;
}

/**
* Gets a value from `index` by `key`.
*
* @param {String} index
* @param {Object|String} key
* @param {Object} [options]
* @param {Function} fn
* @api public
*/

function by(index, key, options, fn){
var self = this;
var sub = this.sublevel(index, { valueEncoding: 'utf8' });
fn = fn || options;

if ('object' == typeof key) {
if (!(index in key)) return fn(error({
message: 'Key not found in the index.',
type: 'NotIndexedError'
}));
key = key[index];
}

sub.get(key, function(err, value){
if (err) {
if ('NotFoundError' == err.type) return fn(error({
message: 'Key not found in the index.',
type: 'NotIndexedError'
}));
return fn(err);
}
self.get(value, options, fn);
});
}

/**
* Finds `key` in all indexes.
*
* @param {Object|String} key
* @param {Object} options
* @param {Function} fn
* @api public
*/

function find(key, options, fn){
var self = this;
if ('function' == typeof options) {
fn = options;
options = {};
}

// search for actual key first
if (!('object' == typeof key)) {
this.get(key, options, function(err, value){
if (err && err.type == 'NotFoundError') return next(0);
fn(err, value);
});
}
else next(0);

function next(i, err){
var index = self.indexes[i];

if (err && err.type != 'NotIndexedError') return fn(err);

if (!index) return fn(error({
message: 'Key not found in any of the indexes.',
type: 'NotIndexedError'
}));

self.by(index, key, function(err, value){
if (err) return next(i + 1, err);
fn(null, value);
});
}
}

/**
* Error instance helper.
*
* @param {Object} props
* @return {Error}
* @api private
*/

function error(props){
var err = new Error();
for (var key in props) err[key] = props[key];
return err;
}
17 changes: 17 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "level-indexing",
"version": "0.0.1",
"repository": "https://github.com/stagas/level-indexing",
"description": "level indexing and finding",
"keywords": ["level", "levelup", "leveldb", "index", "indexes", "indexing", "find", "finding"],
"author": "stagas <gstagas@gmail.com>",
"license": "MIT",
"main": "index.js",
"dependencies": {},
"devDependencies": {
"should": "~2.1.0",
"level": "~0.18.0",
"sublevel": "~0.3.1"
},
"engines": { "node": "*" }
}
Loading

0 comments on commit 74f4df7

Please sign in to comment.