kyoto-client v0.4.0

API

DB

Cursor

Related Projects

Changelog

kyoto-client – Kyoto Tycoon client for node.js

Introduction

kyoto-client is a node.js module that acts as a client to a Kyoto Tycoon server. Kyoto Tycoon is the server component of Kyoto Cabinet, a fast, efficient key-value store developed by FAL labs. Records can be stored on disk or in memory using a hash table or B+ tree.

Installation

Installation via npm is recommended:

npm install kyoto-client

Development

kyoto-client is implemented in CoffeeScript and uses nodeunit for testing. Both are available via npm as coffee-script and nodeunit respectfully. It is developed against the current stable node.js version.

The primary documentation for the project is its website, the source of which is also included here. The website is built with nanoc. To get setup for making documentation changes you’ll need to install nanoc and some other RubyGems:

Contributions are welcome and should maintain the existing coding style and be accompanied by tests and documentation. Bugs and desired features are tracked in the issue tracker. The tests can be run via cake test.

Licence

kyoto-client is licenced under the BSD licence. Refer to the LICENCE in the repository for the full details.

API

DB

The DB class is the primary interface to a Kyoto Tycoon database.

◆ constructor new(defaultDatabase)

Constructs and returns a new DB object.

Example
var kt = require('kyoto-client');
var db = new kt.Db();

// With default database
var db = new kt.Db('default.kct');

◆ open open(hostname='localhost', port=1978)

Open a connection to the database. Returns the Db object.

Examples
db.open();

// on a different host
db.open('kyoto.example.com');
var kyoto = require('kyoto-client');

// Chained with new
var db = new kyoto.Db().open('example.com', 1978);

◆ close close(callback)

Close the connection to the database.

Internally kyoto-client uses a persistent connection to the database to make requests faster. However to prevent your node application from hanging you must call db.close when you are done so that this persistent connection is closed.

Example
db.close(function(error) {
  // Connection is now closed. The db can't be used anymore.
});

◆ defaultDatabase defaultDatabase([database])

Set or get the default database.

A Tokyo Tycoon server can host multiple databases. Requests can be directed at a particular database by name or number. E.g. 'users.kct' or 1.

For procedures that accept a database option the value of defaultDatabase will be used if the option isn’t specified.

Example
// Set the default database
db.defaultDatabase('example.kct');

// Retrieve the current default database value
db.defaultDatabase();

◆ echo echo(input, callback)

Echo back the input data as the output data

Example
db.echo({test: "Value"}, function(error, output) {
  // output -> {test: "Value"}
});

◆ report report(callback)

Get a report on the server.

Example
db.report(function(error, output) {
/* output ->
 { conf_kc_features: '(atomic)(zlib)'
 , conf_kc_version: '1.2.30 (7.1)'
 , conf_kt_features: '(kqueue)(lua)'
 , conf_kt_version: '0.9.19 (1.25)'
 , conf_os_name: 'Mac OS X'
 , db_0: 'count=2 size=400128 path=tests.kct'
 , db_total_count: '2'
 , db_total_size: '400128'
 , serv_conn: '1'
 , serv_task: '0'
 , sys_mem_peak: '2777088'
 , sys_mem_rss: '2777088'
 , sys_mem_size: '2777088'
 , sys_proc_id: '70687'
 , sys_ru_stime: '73.651796'
 , sys_ru_utime: '90.519024'
 , sys_time: '351491.752587'
 }
*/
});

◆ playScript

Call a procedure of the script language (Lua) extension.

Not yet implemented.

◆ tuneReplication

Configure the replication configuration.

Not yet implemented.

◆ status status([options], callback)

Get miscellaneous status information about a database.

Example
db.status(function(error, output) {
/* output ->
 { apow: '8'
 , bnum: '65536'
 , chksum: '188'
 , count: '2'
 , cusage: '66'
 , dfunit: '0'
 , first: '1'
 , flags: '1'
 , fmtver: '5'
 , fpow: '10'
 , frgcnt: '0'
 , icnt: '0'
 , ktcapcnt: '-1'
 , ktcapsiz: '-1'
 , ktopts: '0'
 , last: '1'
 , lcnt: '1'
 , librev: '1'
 , libver: '7'
 , msiz: '67108864'
 , opts: '0'
 , path: 'tests.kct'
 , pccap: '67108864'
 , pnum: '2'
 , psiz: '8192'
 , rcomp: 'lexical'
 , realsize: '400128'
 , realtype: '49'
 , recovered: '0'
 , reorganized: '0'
 , root: '1'
 , size: '400128'
 , trimmed: '0'
 , type: '49'
 }
*/
});

// For a specific database
db.status({database: "users.kct"}, function(error, output) {
  // output contains status info for the users database
});

◆ clear clear([options], callback)

Remove all records from the database.

Example
db.clear(function(error, output) {
  // output -> {}
});

// Clear a specific database
db.clear({database: "test.kct"}, function(error, output) {
  // output -> {}
});

◆ synchronize

Synchronize updated contents with the file and the device

Not yet implemented.

◆ set set(key, value, [options], callback)

Set value of a record.

Example
db.set('test', "Value", function(error) {
});

// Set a record in a specific database
db.set('test', "Value", {database: "test.kct"}, function(error) {
  // error -> undefined
});

// Set the record to expire in one minute
db.set('test', "Value", {expiry: 60}, function(error) {
});

// Set the record to expire on 1 Jan 2020
var expires = new Date("1 Jan 2020");
db.set('test', "Value", {expiry: expires}, function(error) {
});

◆ add add(key, value, [options], callback)

Set value of a record. Returns an error if the record already exists.

Example
db.add('test', "Value", function(error, output) {
  // error -> undefined
});

// when value already exists
db.add('test', "Value", function(error, output) {
  db.add('test', "Value", function(error, output) {
    // error  -> Error("Record exists")
    // output -> { ERROR: 'DB: 6: record duplication: record duplication' }
  });
});

◆ replace replace(key, value, [options], callback)

Replace the value of a record. Returns an error if the record does not exist.

Example
db.set('test', "Test", function(error, output) {
  db.replace('test', "Value", function(error, output) {
    // error  -> undefined
    // output -> {}
  });
});

// when the record doesn't exist
db.replace('test', "Value", function(error, output) {
  // error  -> Error("Record does not exist")
  // output -> { ERROR: 'DB: 7: no record: no record' }
});

◆ append append(key, value, [options], callback)

Append to the value of a record. Sets the record if it does not exist.

Example
db.set('test', "Test", function(error, output) {
  db.append('test', " Value", function(error, output) {
    // error  -> undefined
    // output -> {}
    db.get('test', function(error, value) {
      // value -> 'Test Value'
    })
  });
});

// when the record doesn't exist
db.append('test', "Value", function(error, output) {
  // error  -> Error("Record does not exist")
  // output -> {}
  db.get('test', function(error, value) {
    // value -> 'Value'
  })
});

◆ increment increment(key, num, [options], callback)

Increment the integer value of a compatible record. Sets the record if it does not exist.

Note: It appears that Kyoto Tycoon only allows records that were created with increment to be incremented. Attempts to use this procedure on records set by other means results in an error (Kyoto Tycoon 0.9.29 (2.1) on Mac OS X (Kyoto Cabinet 1.2.39)).

Example
db.increment('count', 1, function(error, output) {
  // error  -> undefined
  // output -> { num: '1' }
  db.increment('count', 1, function(error, output) {
    // error  -> undefined
    // output -> { num: '2' }
  });
});

// incrementing an incompatible record
db.set('incompatible', "1", function(error, output) {
  db.increment('incompatible', 1, function(error, output) {
    // error  -> Error("The existing record was not compatible")
    // output -> { ERROR: 'DB: 8: logical inconsistency: logical inconsistency' }
  });
});

◆ incrementDouble incrementDouble(key, num, [options], callback)

Increment the double (floating point) value of a compatible record. Sets the record if it does not exist.

See note about compatible values in increment.

Example
db.incrementDouble('count', 1.5, function(error, output) {
  // error  -> undefined
  // output -> { num: '1.500000' }
  db.incrementDouble('count', -0.25, function(error, output) {
    // error  -> undefined
    // output -> { num: '1.250000' }
  });
});

// incrementing an incompatible record
db.set('incompatible', "1", function(error, output) {
  db.incrementDouble('incompatible', 1, function(error, output) {
    // error  -> Error("The existing record was not compatible")
    // output -> { ERROR: 'DB: 8: logical inconsistency: logical inconsistency' }
  });
});

◆ cas cas(key, oval, nval, [options], callback)

Performs a compare-and-swap operation. The value is only updated if the assumed existing value matches.

Example
// sets the new value when the old value matches
db.set('test', 'old', function() {
  db.cas('test', 'old', 'new', function(error, output) {
    db.get('test', function(error, value) {
      // value -> 'new'
    });
  });
});

// doesn't set the new value when the old value differs
db.set('test', 'old', function() {
  db.cas('test', 'not old', 'new', function(error, output) {
    db.get('test', function(error, value) {
      // value -> 'old'
    });
  });
});

// removes the record when the new value is null
db.set('test', 'old', function() {
  db.cas('test', 'old', null, function(error, output) {
    db.get('test', function(error, value) {
      // value -> null
    });
  });
});

◆ remove remove(key, [options], callback)

Removes a record.

Example
db.set('test', "Value", function() {
  db.remove('test', function(error) {
    // error -> undefined
  });
});

// Non-existent record
db.remove('non-existent', function(error) {
  // error -> Error("Record not found")
});

◆ get get(key, [options], callback)

Get the value of a record. Returns null if the record doesn’t exist.

Example
db.set('test', "Value", function(error, output) {
  db.get('test', function(error, value) {
    // error  -> undefined
    // value  -> Buffer("Value")
  });
});

// Non-existent record
db.get('not here', function(error, value) {
  // error  -> undefined
  // value  -> null
});

// Record with an expiry date
db.set('key', "Will Expire", {expiry: 60}, function(error) {
  db.get('key', function(error, value, expires) {
    // error   -> undefined
    // value   -> "Will Expire"
    // expires -> Date(now + 60 seconds)
  });
});

◆ exists exists(key, [options], callback)

Checks if a record with the specified key exists. Returns true if it does, false otherwise.

Example
db.set('test', "Value", function(error, output) {
  db.exists('test', function(error, result) {
    // error  -> undefined
    // result -> true
  });
});

// Non-existent record
db.exists('not here', function(error, result) {
  // error  -> undefined
  // result -> false
});

◆ setBulk setBulk(records, [options], callback)

Set multiple records at once.

Example
var records = {
  bulk1: "Bulk\tValue",
  bulk2: "Bulk Value 2"
};
db.setBulk(records, function(error, output) {
  // output -> {num: '2'}
});

◆ removeBulk removeBulk(keys, [options], callback)

Remove multiple records at once.

Example
var records = {
  bulk1: "Bulk\tValue",
  bulk2: "Bulk Value 2"
};
db.setBulk(records, function(error, output) {
  db.removeBulk(Object.keys(records), function(error, output) {
    // output -> {num: '2'}
  })
});

◆ getBulk getBulk(keys, [options], callback)

Retrieve multiple records at once.

Example
db.set('bulk1', "Bulk\tValue", function () {
  db.set('bulk2', "Bulk Value 2", function() {
    db.getBulk(['bulk1', 'bulk2', 'bulk3'], function(error, results) {
      // error   -> undefined
      // results -> { bulk1: 'Bulk\tValue', bulk2: 'Bulk Value 2' }
    });
  });
});

◆ vacuum vacuum()

Not yet implemented.

◆ matchPrefix matchPrefix(prefix, [max], [options], callback)

Returns keys matching the supplied prefix.

Note: if 3 arguments are supplied they are assumed to be prefix, max and callback.

Example
var records = {
  bulk1: "Bulk\tValue",
  bulk2: "Bulk Value 2",
  test: "Value",
  tulk: "Value"
};

db.setBulk(records, function(error, output) {
  db.matchprefix('bulk', function(error, output) {
    // output -> ['bulk1', 'bulk2']
  });
});

// with a limit
db.setBulk(this.records, function(error, output) {
  return db.matchPrefix('bulk', 1, function(error, output) {
    // output -> ['bulk1']
  });
});

◆ matchRegex matchRegex(regex, [max], [options], callback)

Returns keys matching the supplied regular expression.

Note: if 3 arguments are supplied they are assumed to be prefix, max and callback.

Example
var records = {
  bulk1: "Bulk\tValue",
  bulk2: "Bulk Value 2",
  test: "Value",
  tulk: "Value"
};

db.setBulk(records, function(error, output) {
  db.matchRegex('[0-9]', function(error, output) {
    // output -> ['bulk1', 'bulk2']
  });
});

// with a limit
db.setBulk(this.records, function(error, output) {
  return db.matchRegex('[0-9]', 1, function(error, output) {
    // output -> ['bulk1']
  });
});

◆ getCursor getCursor([key], [options], callback)

Obtain a database cursor. A cursor allows you to scan through the records in the database.

Note: The number of arguments is interpreted as follows:

  1. callback
  2. key, callback
  3. key, options, callback
Example
db.getCursor('bulk1', function(error, cursor) {
  cursor.get(function(error, output) {
    // output -> {key: 'bulk1', value: 'Some value'}
  });
});

Cursor

A cursor allows the records of the database to be traversed. Depending on the type of database this will either be in order of insertion or order determined by a hashing function. A Cursor object is retrieved via the getCursor function.

◆ jump jump([key], [options], callback)

Jump the cursor to the specified record or the first record if no key is specified.

Note: The number of arguments is interpreted as follows:

  1. callback
  2. key, callback
  3. key, options, callback
Example
// Jump to first record
cursor.jump(function(error, output) {
});

// Jump to a specific record
cursor.jump('test', function(error, output) {
});

◆ jumpBack jumpBack([key], [options], callback)

Jump the cursor to the specified record or the last record if no key is specified.

Note: The number of arguments is interpreted as follows:

  1. callback
  2. key, callback
  3. key, options, callback
Example
// Jump to first record
cursor.jump(function(error, output) {
});

// Jump to a specific record
cursor.jump('test', function(error, output) {
});

◆ step step(callback)

Steps the cursor to the next record.

Example
// Jump to first record
cursor.jump(function(error, output) {
  cursor.step(function(error, output) {
    // cursor is now on the second record
  });
});

◆ stepBack stepBack(callback)

Steps the cursor to the previous record.

Example
// Jump to last record
cursor.jumpBack(function(error, output) {
  cursor.stepBack(function(error, output) {
    // cursor is now on the second last record
  });
});

◆ setValue setValue(value, [step], callback)

Sets the value of the current record and optionally steps to the next record.

Example
cursor.setValue("New Value", function(error, output) {
  // value updated
});

// set and step
cursor.setValue("New Value", true, function(error, output) {
  // value updated
});

◆ remove remove(callback)

Remove the current record.

Example
cursor.remove(function(error, output) {
});

◆ getKey getKey([step], callback)

Get the key of the current record.

Example
cursor.getKey(true, function(error, output) {
  // output -> {key: 'test'}
});

◆ getValue getValue([step], callback)

Get the value of the current record.

Example
cursor.getValue(true, function(error, output) {
  // output -> {value: "Value"}
});

◆ get get([step], callback)

Get the key and value of the current record.

Example
cursor.get(true, function(error, output) {
  // output -> {key: 'test', value: "Value"}
});

◆ delete delete(callback)

Close the cursor’s connection, invalidating it. It will not be valid for subsequent operations.

Note: delete is a reserved word so the syntax for calling this procedure is a little awkward. Refer to examples.

Example
cursor["delete"](true, function(error, output) {
  // deleted
});
CoffeeScript Example

cursor.delete true, (error, output) ->
  // deleted

◆ each each(callback)

Scan the cursor forward from its current record to the last record.

TODO: Add support for cancelling the traversal.

Example
var results = [];

cursor.each(function(error, output) {
  if (output.key != null) {
    results.push([output.key, output.value]);
  } else {
    console.log(require('util').inspect(results));
  }
});

Related Projects

connect-kyoto

connect-kyoto allows Kyoto Tycoon to be used as a session store for connect.

Changelog

0.4.0 –

0.3.0 –

0.2.0 –

0.1.1 –

Some last minute documentation additions.

0.1.0 –

Initial release.