Skip to content

nodeJS key-value-store with secondary indices (tags) based on upscaledb

License

Unknown, Unknown licenses found

Licenses found

Unknown
LICENSE
Unknown
LICENSE.md
Notifications You must be signed in to change notification settings

hakt0r/node-tagscale

Repository files navigation

tagscale

nodeJS extension utilizing upscaledb to store JSON-documents. Currently, you can define indices for the following types: string, bool, date and array of string. Of course this be used as a common key-value-store.

This is a synchronous API, no threading - nothing.

Also, consider this experimental, loosely tested, slow and sloppy, test it well before you use it. Share your patches!!!11elf

That being said; I use this in nuu and various experimental projects and I am pretty happy with it :)

Installing

# Will try prebuild, fallback to build
foo@bar:~app$ npm i --save git+https://github.com/hakt0r/node-tagscale

Installing from source

# Will remove sources after build
foo@bar:~app$ FROM_SOURCE=yes npm i --save git+https://github.com/hakt0r/node-tagscale

JavaScript Example

var ts = require('tagscale');

// Simple key-value store like leveldb, etc.
if ( table = new ts.XScale('somefile.db') ){
  table.set('test1',"Hello World!");    console.log(table.get('test1')); // "Hello World!"
  table.set('test1',"Hello Universe!"); console.log(table.get('test1')); // "Hello Universe!"
  table.del('test1');                   console.log(table.get('test1')); // false
  table.close(); }

// Tag-indexed database
if ( db = new ts.XScale('somefile.db') ){
  db.defineIndex('tag',ts.STRING_ARRAY);
  db.set('test1',{tag:["news","tagscale"],body:'Hello World!'});
  db.set('test2',{tag:["news","hashtags"],body:'Hello Universe!'});
  db.set('test3',{tag:["news","forall!!"],body:'Hello Code!'});
  console.log(db.get('test1')); // {{tag:"news","tagscale"},body:'Hello World!'}
  db.del('test3');
  console.log(db.get('test3')); // false
  if ( news = db.tag.find('news') ){
                 console.log(news.current); // {{tag:"news","tagscale"},body:'Hello World!'}
    news.next(); console.log(news.current); // {{tag:"news","hashtags"},body:'Hello Universe!'}
    news.prev(); console.log(news.current); // {{tag:"news","tagscale"},body:'Hello World!'}
  db.close(); }}

CoffeeScript Example

ts = require 'tagscale'

# Simple key-value store like leveldb, etc.
if table = new ts.XScale 'somefile.db'
  table.set 'test1', 'Hello World!';    console.log table.get 'test1' # "Hello World!"
  table.set 'test1', 'Hello Universe!'; console.log table.get 'test1' # "Hello Universe!"
  table.del 'test1';                    console.log table.get 'test1' # false
  table.close()

# Tag-indexed database
if db = new ts.XScale 'somefile.db'
  db.defineIndex 'tag', ts.STRING_ARRAY
  db.set 'test1', tag: ['news','tagscale'], body: 'Hello World!'
  db.set 'test2', tag: ['news','hashtags'], body: 'Hello Universe!'
  db.set 'test3', tag: ['news','forall!!'], body: 'Hello Code!'
  console.log db.get 'test1' # {{tag:"news","tagscale"},body:'Hello World!'}
  db.del 'test3'
  console.log db.get 'test3' # false
  if news = db.tag.find 'news'
    console.log              news.current # {{tag:"news","tagscale"},body:'Hello World!'}
    news.next(); console.log news.current # {{tag:"news","hashtags"},body:'Hello Universe!'}
    news.prev(); console.log news.current # {{tag:"news","tagscale"},body:'Hello World!'}
    db.close()

API

class XScale
  constructor:(path)->
    String path: "full or relative path to database file"
  close:-> "flush and close database and all it's indexes"
  set:(key,value)->
    String key: "primary key (as in unique)"
    Object value: "the associated object (must be an object)"
    return Number or false
  get:(key)->
    String key: "primary key (as in unique)"
    return Object or false
  del:(key)->
    String key: "primary key (as in unique)"
    return Boolean
  find:(key)->
    String key: "primary key (as in unique)"
    return XCursor or false
  defineIndex:(name,type)->
    String name: "Name of the index and -OFC- the field to be indexed."
    Number type: "Type of index you desire"
      ts.BOOL:         "Records with ( key && key != false )"
      ts.DATE:         "Attach a timestamp (automatic)"
      ts.STRING:       "A String whose value should be indexed"
      ts.STRING_ARRAY: "An Array of strings - like tags ;>"
    return XIndex or false

class XIndex
  find:(key)->
    String key: "the key to look up (not require fr ts.BOOL)"
    return XCursor or false

class XCursor
  length:  Number "the number of keys initially matched"
  current: Object "the current object"
  close:-> return Boolean
  next:->  return Boolean
  prev:->  return Boolean
  first:-> return Boolean
  last:->  return Boolean

Manual Building

First get node-tagscale

foo@bar:~app$ cd node_modules
foo@bar:~a/node_modules$ git clone https://github.com/hakt0r/node-tagscale --depth=1
foo@bar:~a/node_modules$ cd node-tagscale

Install from source, keep upscaledb and co.

foo@bar:~an/node-tagscale$ KEEP_FILES=yes npm i

All subsequent builds only need

foo@bar:~an/node-tagscale$ npm run build

Dependencies (for Debian)

# Don't forget
foo@bar:~$ sudo apt install build-essential nodejs npm node-gyp

# Required dependencies
foo@bar:~$ sudo apt install libgoogle-perftools-dev libboost-filesystem-dev libboost-thread-dev libboost-asio-dev libboost-dev

# Optionals
foo@bar:~$ sudo apt install ccache dietlibc libdb-dev protobuf-compiler libprotobuf-dev

Testing

A very basic test suite is included. Feel free to have a glance.

foo@bar:~an/node-tagscale$ npm run test
  building [...]
  ts.XScale
    ✓ open database
  [...]

License

tagscale

nodeJS key-value-store with secondary indices (tags) based on upscaledb

Copyright © 2016-2019 Sebastian Glaser

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.