persist
persist is an ORM framework for node.js.
The following databases are currently supported:
Quick Examples
var persist = require("persist");
var type = persist.type;
Phone = persist.define("Phone", {
"number": type.STRING
});
Person = persist.define("Person", {
"name": type.STRING
}).hasMany(this.Phone);
persist.connect({
driver: 'sqlite3',
filename: 'test.db',
trace: true
}, function(err, connection) {
Person.using(connection).all(function(err, people) {
});
});
Download
You can install using Node Package Manager (npm):
npm install persist
Index
persist
Connection
Model
Query
Transaction
Results Set
Connection Pooling
# database.json
If the current working directory contains a file called database.json this file will be loaded upon requiring persist.
The file should follow a format like this:
{
"default": "dev",
"dev": {
"driver": "sqlite3",
"filename": ":memory:"
},
"test": {
"driver": "sqlite3",
"filename": ":memory:"
},
"prod": {
"driver": "sqlite3",
"filename": "prod.db",
"sqlDir": "./prodSql",
"pooling": {
"name": "testPool",
"max": 2,
"min": 1,
"idleTimeoutMillis": 30000
}
}
}
"default" specifies which environment to load.
API Documentation
## persist
### persist.env
The environment to read from the database.json file. If not set will use the value of default from the database.json.
Example
persist.env = 'prod';
### persist.connect([options], callback)
Connects to a database.
Arguments
Example
persist.connect({
driver: 'sqlite3',
filename: 'test.db',
trace: true
}, function(err, connection) {
});
### persist.define(modelName, properties, [opts]): Model
Defines a model object for use in persist.
The primary key column does not need to be specified and will default to the name 'id' with the attributes dbColumnName='id',
type='integer'. You can override the database name using dbColumnName or setting the primaryKey attribute on any column.
Arguments
- modelName - The name of the model. This name will map to the database name.
- properties - Hash of properties (or columns). The value of each property can simply be the type name (ie type.STRING)
or it can be a hash of more options.
- type - type of the property (ie type.STRING)
- defaultValue - this can be a value or a function that will be called each time this model object is created
- dbColumnName - the name of the database column. (default: name of the property, all lower case, seperated by '_')
- primaryKey - Marks this column as being the primary key column. You can have only one primary key column.
- opts - Options for this column.
- tableName - The name of the table (default: modelName pluralized).
Returns
A model class.
Events can also be registered with model instances - see Model Events
Example
Person = persist.define("Person", {
"name": type.STRING,
"createdDate": { type: type.DATETIME, defaultValue: function() { return self.testDate1 }, dbColumnName: 'new_date' },
"lastUpdated": { type: type.DATETIME }
})
### persist.defineAuto(modelName, dbConfig, callback): Model
Defines a model object for use in persist. Columns are defined by the program in this method. Uses an existing database connection to retrieve column data.
Arguments
- modelName - The name of the model. This name will map to the table name.
- dbConfig - Hash of dbConfig. Should contain the driver, as well as the database name.
- database - The database connection to use.
- driver - The name of the database driver to use.
Returns
A model class.
Events can also be registered with model instances - see Model Events
Example
persist.defineAuto("Person",{driver:dbDriver, db:self.connection.db},function(err,model){
Person = model.hasMany(Phone)
.on('beforeSave', function (obj) {
obj.lastUpdated = testDate;
})
.on('afterSave', function (obj) {
if (!obj.updateCount) obj.updateCount = 0;
obj.updateCount++;
});
});
### persist.setDefaultConnectOptions(options)
Sets the default connection options to be used on future connect calls. see database.json
Arguments
- options - See connect for the description of options
Example
persist.setDefaultConnectOptions({
driver: 'sqlite3',
filename: 'test.db',
trace: true});
### persist.shutdown([callback])
Shutdown persist. This is currently only required if you are using connection pooling. see generic-pool.
Arguments
- [callback] - Optional callback on successful shutdown.
Example
persist.shutdown(function() {
console.log('persist shutdown');
});
## Connection
### connection.chain(chainables, callback)
Chains multiple statements together in order and gets the results.
Arguments
- chainables - An array of chainable queries. These can be save, updates, selects, or deletes. Each item in the array will be
executed, wait for the results, and then execute the next. This can also be a hash of queries in which case the results
will contain a hash of results where each key corresponds to a key in the results.
- callback(err, results) - Callback called when all the items have been executed.
Example
connection.chain([
person3.save,
Person.min('age'),
Person.max('age'),
phone3.delete,
person2.delete,
Person.orderBy('name').all,
Phone.orderBy('number').first,
Phone.count,
Phone.deleteAll,
Phone.all,
Person.getById(1),
persist.runSql('SELECT * FROM Person')
], function(err, results) {
});
connection.chain({
minAge: Person.min('age'),
maxAge: Person.max('age')
}, function(err, results) {
});
### connection.tx(callback)
Begins a transaction on the connection.
Arguments
Example
connection.tx(function(err, tx) {
person1.save(connection, function(err) {
tx.commit(function(err) {
});
});
});
### connection.runSql(sql, values, callback)
Runs a sql statement that does not return results (INSERT, UPDATE, etc).
Arguments
- sql - The SQL statement to run.
- values - The values to substitute in the SQL statement. This is DB specific but typically you would use "?".
- callback(err, results) - Callback called when SQL statement completes. results will contain the number of affected
rows or last insert id.
Example
connection.runSql("UPDATE people SET age = ?", [32], function(err, results) {
});
### connection.runSqlAll(sql, values, callback)
Runs a sql statement that returns results (ie SELECT).
Arguments
- sql - The SQL statement to run.
- values - The values to substitute in the SQL statement. This is DB specific but typically you would use "?".
- callback(err, results) - Callback called when SQL statement completes. results will contain the row data.
Example
connection.runSqlAll("SELECT * FROM people WHERE age = ?", [32], function(err, people) {
});
### connection.runSqlEach(sql, values, callback, doneCallback)
Runs a sql statement that returns results (ie SELECT). This is different from runSqlAll in that it returns each row
in a seperate callback.
Arguments
- sql - The SQL statement to run.
- values - The values to substitute in the SQL statement. This is DB specific but typically you would use "?".
- callback(err, row) - Callback called for each row returned.
- doneCallback(err) - Callback called after all the rows have returned.
Example
connection.runSqlEach("SELECT * FROM people WHERE age = ?", [32], function(err, person) {
}, function(err) {
});
### connection.runSqlFromFile(filename, values, callback)
### connection.runSqlAllFromFile(filename, values, callback)
### connection.runSqlEachFromFile(filename, values, callback, doneCallback)
Same as runSql, runSqlAll, runSqlEach except the first parameter is a filename of where to load the SQL from.
Example
connection.runSqlFromFile('report.sql', [32], function(err, person) {
}, function(err) {
});
## Model
### Model.hasMany(AssociatedModel, [options]): Model
Adds a has many relationship to a model. This will automatically add a property to the associated model which links to this
model. It will also define a property on instances of this model to get the releated objects - see Associated Object Properties
Arguments
- AssociatedModel - The name of the model to associate to.
- options - (optional) An hash of options.
- through - creates a many to many relationship using the value of through as the join table.
- name - the name of the property to expose.
Returns
The model class object suitable for chaining.
Example
Phone = persist.define("Phone", {
"number": persist.String
});
Person = persist.define("Person", {
"name": persist.String
}).hasMany(Phone);
### Model.hasOne(AssociatedModel, [options]): Model
Adds a has one relationship to a model. This will automatically add a property to the associated model which links to this
model. It will also define a property on instances of this model to get the releated objects - see Associated Object Properties
Arguments
- AssociatedModel - The name of the model to associate to.
- options - (optional) An hash of options.
- foreignKey - The foreign key to use for the relationship
- name - the name of the property to expose.
- createHasMany - true/false to create the other side of the relationship.
- hasManyName - The name of the property on the other side of the relationship.
Returns
The model class object suitable for chaining.
Example
Phone = persist.define("Phone", {
"number": persist.String
}).hasOne(Person);
Person = persist.define("Person", {
"name": persist.String
});
### Model.using(connection): query
Gets a query object bound to a connection object.
Arguments
- connection - The connection to bind the query object to.
Returns
A new Query object.
Example
Person.using(connection).first(...);
### Model.save(connection, callback)
Saves the model object to the database
Arguments
- connection - The connection to use to save the object with.
- callback(err) - The callback to be called when the save is complete
Example
person1.save(connection, function() {
});
### modelInstance.update(connection, params, callback)
Updates the model object to the database
Arguments
- connection - The connection to use to update the object with.
- params - Object containing properties to update.
- callback(err) - The callback to be called when the update is complete
Example
person1.update(connection, { name: 'Tom' }, function() {
});
### Model.update(connection, id, params, callback)
Updates the model object specified with id to the database. This will only update the values
specified and will not retreive the item from the database first.
Arguments
- connection - The connection to use to update the object with.
- id - The id of the row you would like to update.
- params - Object containing properties to update.
- callback(err) - The callback to be called when the update is complete
Example
Person.update(connection, 5, { name: 'Tom' }, function() {
});
connection.chain([
Person.update(5, { name: 'Tom' })
], function(err, results) {
});
### Model.delete(connection, callback)
Deletes the model object from the database
Arguments
- connection - The connection to use to delete the object with.
- callback(err) - The callback to be called when the delete is complete
Example
person1.delete(connection, function() {
});
### Model.getById(connection, id, callback)
Gets an object from the database by id.
Arguments
- connection - The connection to use to delete the object with.
- id - The if of the item to get.
- callback(err, obj) - The callback to be called when the delete is complete
Example
Person.getById(connection, 1, function(err, person) {
});
### Model.defineClause(clauseName, clauses)
Creates a custom method that is a composition of clauses. this
is set to refer to the query.
you're constructing.
Arguments
- clauseName - The name of the clause to be attached to the model
- clauses - The function that describes the clause composition using a query.
Example
Person.defineClause('clauseName', function(arg1, arg2, ...) {
return this.where('id < ?', arg1).orderBy('id').limit(5);
});
Person.clauseName(5).all(connection, function(err, people) {
});
Person.defineClause('clauseName2', function(connection, callback) {
return this
.where('id < 5')
.orderBy('id')
.limit(5)
.all(connection, callback);
});
Person.clauseName2(connection, function(err, people) {
});
### Model.onSave(obj, connection, callback)
If preset this function will be called when an update or save occures. You would typically create this method
in your model file.
Arguments
Example
Person.onSave = function(obj, connection, callback) {
obj.lastUpdated = new Date();
callback();
};
### Model.onLoad(obj)
If preset this function will be called after an object is loaded from the database. You would typically
create this method in your model file.
Arguments
- obj - The object that was just loaded from the database.
- connection - The connection persist is currently using to do the save
- callback() - The callback to be called when the onLoad is complete
Example
Person.onLoad = function(obj, connection, callback) {
obj.fullName = obj.firstName + ' ' + obj.lastName;
callback();
};
### Model.validate(obj, callback, connection)
Model validation is loosely implemented. Instead, it's left to the developers to integrate any valiation library that fits their needs.
If present this function will be called during a save or update operation.
Arguments
- obj - The model object
- connection - The connection persist is currently using to do the save or update
- callback(success, message) - The callback to be called when the validate is complete.
- success - False if validation failed, True otherwise
- message - A string containing an error message, or a custom-defined object containing vaidation information
Example
Person = persist.define("Person", {
"name": type.STRING,
"age": type.INTEGER
};
Person.validate = function (obj, connection, callback) {
if (obj.name === 'bad name') {
return callback(false, 'You had a bad name');
}
return callback(true);
};
Person.validate = function (obj, connection, callback) {
var errors = [];
if (obj.name === 'bad name') {
errors.push({name:'You had a bad name'});
}
if (obj.age < 0) {
errors.push({age:'Age must be greater than 0'});
}
if(errors.length > 0) {
return callback(false, errors);
}
return callback(true);
};
### Associated Object Properties
If you have setup an associated property using hasMany instances of your model will have an additional property
which allows you to get the associated data. This property returns a Query object which you can further chain to limit
the results.
Example
Phone = persist.define("Phone", {
"number": persist.String
});
Person = persist.define("Person", {
"name": persist.String
}).hasMany(Phone);
Person.using(connection).first(function(err, person) {
person.phones.orderBy('number').all(function(err, phones) {
});
});
### Model Events
The following events can be registered when defining a new model:
beforeCreate
and afterCreate
: fired before/after a new object is being added to the DBbeforeUpdate
and afterUpdate
: fired before/after an existing object is being updated in the DBbeforeSave
and afterSave
: fired before/after an object is either created or updated.beforeDelete
and afterDelete
: fired before/after an object is removed from the DB
Each event function has the signature: function(obj) where 'obj' is the model instance that fired the event.
Limitation
Events are currently fired ONLY when invoking save/update/delete functions on model instances. So for instance, Model.update(connection,id,data) will not fire the save & update events.
Example
Phone = persist.define("Phone", {
"number": persist.String,
"created_at": persist.DATETIME,
"updated_at": persist.DATETIME
})
.on("beforeCreate", function(obj){
obj.created_at = new Date();
})
.on("beforeSave", function(obj){
obj.updated_at = new Date();
});
## Query
### query.all([connection], callback)
Gets all items from a query as a single array of items. The array returned will have additional
methods see here for documentation.
Arguments
- connection - (Optional) The connection to use. If this is not specified a using statement must be specified earlier.
- callback(err, items) - Callback to be called after the rows have been fetched. items is an array of model instances.
Example
Person.all(connection, function(err, people) {
});
### query.each([connection], callback, doneCallback)
Gets items from a query calling the callback for each item returned.
Arguments
Example
Person.each(connection, function(err, person) {
}, function() {
});
### query.first([connection], callback)
Gets the first item from a query.
Arguments
Example
Person.first(connection, function(err, person) {
});
### query.last([connection], callback)
Gets the last item from a query.
Arguments
Example
Person.last(connection, function(err, person) {
});
### query.orderBy(propertyName, direction): query
Orders the results of a query.
Arguments
- propertyName - Name of the property to order by.
- direction - The direction to orderBy. Can be persist.Ascending or persist.Descending.
Returns
The query object suitable for chaining.
Example
Person.orderBy('name').all(connection, function(err, people) {
});
### query.limit(count, [offset]): query
Limits the number of results of a query.
Arguments
- count - Number of items to return.
- offset - (Optional) The number of items to skip.
Returns
The query object suitable for chaining.
Example
Person.orderBy('name').limit(5, 5).all(connection, function(err, people) {
});
### query.where(clause, [values...]): query
### query.where(hash): query
Filters the results by a where clause.
Arguments
- clause - A clause to filter the results by.
- values - (Optional) A single value or array of values to substitute in for '?'s in the clause.
- hash - A hash of columns and values to match on (see example)
Returns
The query object suitable for chaining.
Example
Person.where('name = ?', 'bob').all(connection, function(err, people) {
});
Person.where('name = ? or age = ?', ['bob', 23]).all(connection, function(err, people) {
});
Person.where({'name': 'bob', 'age': 23}).all(connection, function(err, people) {
});
### query.whereIn(property, [values...]): query
Filters the results by a where clause using an IN clause.
Arguments
- property - The property to invoke the IN clause on.
- values - An array of values to include in the IN clause.
Returns
The query object suitable for chaining.
Example
Person.whereIn('name', ['bob', 'alice', 'cindy']).all(connection, function(err,people) {
});
Person.include("phones").whereIn('phones.number', ['111-2222','333-4444']).all(connection, function(err,people){
});
### query.count([connection], callback)
Counts the number of items that would be returned by the query.
Arguments
Example
Person.where('name = ?', 'bob').count(connection, function(err, count) {
});
### query.min([connection], fieldName, callback)
Gets the minimum value in the query of the given field.
Arguments
Example
Person.where('name = ?', 'bob').min(connection, 'age', function(err, min) {
});
### query.max([connection], fieldName, callback)
Gets the maximum value in the query of the given field.
Arguments
Example
Person.where('name = ?', 'bob').max(connection, 'age', function(err, min) {
});
### query.sum([connection], fieldName, callback)
Gets the sum of all values in the query of the given field.
Arguments
Example
Person.where('name = ?', 'bob').sum(connection, 'age', function(err, sum) {
});
### query.deleteAll([connection], callback)
Deletes all the items specified by the query.
Arguments
Example
Person.where('name = ?', 'bob').deleteAll(connection, function(err) {
});
### query.updateAll([connection], data, callback)
Updates all the items specified by the query.
Arguments
Example
Person.where('name = ?', 'bob').updateAll(connection, { age: 25 }, function(err) {
});
### query.include(propertyName): query
Includes the associated data linked by (hasMany or hasMany(through)) the propertyName when retrieving data from the database.
This will replace obj.propertyName with an array of results as opposed to the default before which is a query.
Internally this will do a join to the associated table in the case of a one to many. And will do a join to the associated through table
and the associated table in the case of a many to many.
Arguments
- propertyName - This can be a single property name or an array of property names to include.
Example
Person.include("phones").where('name = ?', 'bob').all(connection, function(err, people) {
});
## Transaction
### tx.commit(callback)
Commits a transaction.
Arguments
- callback(err) - Callback called when the transaction has committed.
Example
connection.tx(function(err, tx) {
person1.save(connection, function(err) {
tx.commit(function(err) {
});
});
});
### tx.rollback(callback)
Rollsback a transaction.
Arguments
- callback(err) - Callback called when the transaction has rolledback.
Example
connection.tx(function(err, tx) {
person1.save(connection, function(err) {
tx.rollback(function(err) {
});
});
});
## Result Set
### rs.getById(id)
Gets an item from the result set by id.
Arguments
- id - The id of the item to get.
Example
Person.all(connection, function(err, people) {
var person2 = people.getById(2);
});
## Connection Pooling
### Using
Persist uses generic-pool to manage the connection pool. If you specify
"pooling" in your configuration you must specify a pool name. See generic-pool
for other options. To cleanly shutdown the connection pool you must also call persist.shutdown.
Example database.json to enable pooling:
{
"default": "dev",
"dev": {
"driver": "sqlite3",
"filename": ":memory:",
"pooling": {
"name": "myDatabasePool"
}
}
}