verymodel-level

Leveldb extensions for verymodel

#VeryModel-Level

VeryModel-Level is an ORM for an embedded keystore in your Node.js app.

Features Include:

  • Ordered Objects
  • Lookup by Index
  • Retrieving Models sorted by Index
  • Foreign Keys and Foreign Collections
  • Children
  • Pagination
  • Counts
  • Buckets
  • onSave & onDelete Model Events

The models in this ORM use VeryModel so Verymodel-level extends the definitions and methods.

var VeryLevelModel = requrie('verymodel-level');
var levelup = require('levelup');
var db = levelup('./test.db');
 
var PersonFactory = new VeryLevelModel({
    firstName: {},
    lastName: {},
    fullName: {derivefunction () {
        return this.firstName + ' ' + this.lastName;
    }},
}, {db: db, name: 'person'});
 
var nathan = PersonFactory.create({
    firstName: 'Nathan',
    lastName: 'Fritz',
});
nathan.save(function (err) {
    PersonFactory.all(function (errpersons) {
        persons.forEach(function (person) {
            console.dir(person.toJSON());
        });
    });
});

npm install verymodel-level

Model Factories define the platonic model, and can create model instances. These models are extensions on VeryModel. Creating a new model factory involves passing two arguments: an object describing each field, and an options object defining the configuration of the model (leveldb path, model name, etc).

Every root property of a model definition is a field name with an object value defining types, restrictions, and processing for a model field. In it's simplest form, a field definition can just be an empty object, and then you can assign anything to that field. If a field isn't mentioned in the defition, it won't be saved or loaded.

type

validate

processIn

processOut

onSet

derive

foreignKey

foreignCollection

  • name: String name of model
  • db: levelup or levelup compatible instance database
  • dbdir: automatically create leveldb files in this directory
  • bucket: name of bucket
  • onSave: -- function
  • onDelete --

Requirements:

  • Models must have a name option.
  • Models may have a db or a dbdir.
  • Models may have a bucket. You may also define buckets elsewhere if dynamic.

Note: Multiple models and can should use the same bucket. Multile models SHOULD NOT use the same name.

Examples:

{
    name: 'person',
    db: levelup(__dirname + '/thisapp.db'),
}
{
    name: 'person',
    dbdir: __dirname + '/database/',
    bucket: 'hampeople',
}

Buckets are useful for seperating groups of data by access groups or other things.

Most Model Factory and Model Instance methods require a callback. Any method that does require a callback has an optional options object as the argument before the callback.

Most methods will take db, and bucket as options properties, which override the defaults set in factory.options. Some methods will take pagination methods: offset and limit. save, update, and delete methods can take a ctx object in options to pass on to the factory.options.onSave and factory.options.onDelete callbacks.

Callbacks are always required on functions that include them, and lead with an error-first approach.

create(value_object)

Returns a factory instance model.

Create makes a new instance of the model with specific data. Any fields in the value_object that were not defined get thrown out. Validations are not done on creation, but some values may be processed based on the field defintion type and processIn functions.

Create does not save the value; you'll have to run .save(function (err) { ... }) on the returned model instance.

The model instance's private .key field will not be set until it has been saved either.

Logging the model out to console will produce a confusing result. If you want the model's data, run .toJSON() and use the result.

Example:

//assuming Person is a defined Model Factory 
var person = Person.create({
    firstName: 'Nathan',
    lastName: 'Fritz',
});
person.save(function (err) {
    console.log("Person saved as:", person.key);
});

get(key, options, callback)

Get a specific model instance by key.

Arguments:

  • key
  • options
  • callback -- function (err, model)

Options:

  • db: levelup instance
  • bucket: bucket name
  • depth: integer depth to recursively resolve foreign objects (default 5)

Example:

Person.get(someperson_key, {depth: 0}, function (errperson) {
    if (!err) {
        console.dir(person.toJSON());
    }
});

all(options, callback)

Get many/all of the model instances saved of this model factory Results are in order of insertion unless ordered by an indexed field.

Arguments:

  • options
  • callback -- function (err, models, pagination) { }

models in callback is an array of model instances unless returnStream is true in options.

Options:

  • db: levelup instance
  • bucket: bucket name
  • depth: integer depth to recursively resolve foreign objects (default 5)
  • sortBy: indexed field to results in order of value
  • offset: integer to offset results by (pagination)
  • limit: integer limit of results (pagination)
  • returnStream: boolean (default false) returns stream of objects rather than using callback (callback is also called with stream instead of array)

update(key, merge_object, options, callback)

Updates an existing stored model with new data. It only overrides fields that you send.

Arguments:

  • key
  • merge_object
  • options
  • callback -- function (err, newmodel) {}

Options:

  • db: levelup instance
  • bucket: bucket name
  • ctx: context object to send to factory.options.onSave upon success

delete(key, options, callback)

Deletes a stored model.

Arguments:

  • key
  • options
  • callback -- function (err) {}

Options:

  • db: levelup instance
  • bucket: bucket name

wipe(options, callback)

Deletes all models and their children from the database.

Arguments:

  • options
  • callback -- function (err) {}

Options:

  • db: levelup instance
  • bucket: bucket name

getByIndex(field, value, options, callback)

Gets the models by an index.

Arguments:

  • field -- indexed field
  • value -- value to match
  • options
  • callback -- function (err, models, pagination) { }

models in callback is an array of model instances unless returnStream is true in options.

Options:

  • db: levelup instance
  • bucket: bucket name
  • depth: integer depth to recursively resolve foreign objects (default 5)
  • offset: integer to offset results by (pagination)
  • limit: integer limit of results (pagination)
  • returnStream: boolean (default false) returns stream of objects rather than using callback (callback is also called with stream instead of array)

This ends up calling all with some index options, so you get the same pagination features.


findByIndex(field, value, options, callback)

Just like getByIndex, except only return one value, rather than an array of models, or an error.

Arguments:

  • field -- indexed field
  • value -- value to match
  • options
  • callback -- function (err, models, pagination) { }

models in callback is an array of model instances unless returnStream is true in options.

Options:

  • db: levelup instance
  • bucket: bucket name
  • depth: integer depth to recursively resolve foreign objects (default 5)

bucket(name)

Returns a new Factory, set up for the bucket named. Factory.options.dbdir must be set.

Arguments:

  • name -- bucket name

save(options, callback)


delete(options, callback)


createChild(otherModelFactory, value_object)


getChildren(otherModelFactory, options, callback)


getChildrenByIndex(otherModelFactory, field, value, options, callback)


findChildByIndex(otherModelFactory, field, value, options, callback)


toJSON()


toString()


diff()


getChanges()


getOldModel()


loadData()


function (err, {model, changes, ctx}, cb) {
}

The changes is an object of fields with 'then', 'now', and 'changed', values.

{
    field1: {then: 'cheese', now: 'ham', changed: true},
    field2: {then: 'who', now: 'whom', changed: true}
}

If you require a full model instance of what used to be, do this:

var oldmodel = model.getOldModel();

The ctx argument is whatever you passed to save({ctx: 'ctx goes here'}, function ...

You must execute the callback as is the callback you passed save.

function (err, {ctx}, cb) {
}

The ctx argument is whatever you passed to delete({ctx: 'ctx goes here'}, function ...

You must execute the callback as is the callback you passed delete.

By default, fields marked private: true will not be saved, but you can override that with factory.options.savePrivate = true You can seperately mark fields as not saved in the field definition with save: false.

These destinctions are useful for things like password fields that you wouldn't want to be exposed to an API with toJSON, but do want to save.

You can refer to foreign objects, and have them load automatically with an object by with foreignKey and foreignCollection field defintions. They should point to another VeryLevelModel Factory.

While recursive loading happens automatically, only the keys of the sub-objects are saved on save(). If you've changed fields in the foreign objects, you must save those directly.