rest-mongo
A JS ORM for nodejs / mongo-db and/or the browser.
Intro
RestMongo works by letting you describe your data using a JSON schema and then provides you high level objects which can be created / updated / deleted / retrieved using an easy-to-use API. The core functionalities work on both node and the browser. There are different backends, wether you want to plug to a mongodb, a REST API, etc.
Examples
A Schema describing a person
var schema = {
"Person": {
resource: '/people',
schema: {
id: "Person",
description: "someone, blablabla",
type: "object",
properties: {
firstname: {type: "string"},
friends: {type: "array", items: {"$ref": "Person"}},
mother: {"$ref": "Person"}
}
},
methods: {
sayHello: function() {
console.log("Hello, "+ this.firstname);
}
}
}
};
The schema describes a document. It can have references or list of references to other documents. You can also associate methods to objects in the schema. Here, we will have the sayHello method available on Person objects.
Get a unit of work (we call it 'R'):
var rest_mongo = require("rest-mongo");
var mongo_backend = require('rest-mongo/mongo_backend');
var backend = mongo_backend.get_backend({db_name: 'db_name', username: "username", password:"password"});
var RFactory = rest_mongo.getRFactory(schema, backend);
var R = RFactory();
Get a new R every time you need to get a new context to work in (at every client request for example).
Additional schema
When creating a RFactory, you can specify an additional schema that will extend the base one. This is done so you can have properties or methods specific to server/browser side.
var server_schema = {
"Person": {
schema: {
properties: {
secret: {type: "string"}
}
},
methods: {
get_same_secrets: function(callback, fallback) {
// Returns Persons with the same secret as me.
this.R.Person.index({query: {secret: this.secret}},
callback, fallback);
}
}
}
}
var RFactory = rest_mongo.getRFactory(schema, backend, {
additional_schema: server_schema
});
Create and save an object into the DB
var lilly = new R.Person({firstname: "Lilly"});
lilly.sayHello();
lilly.save(function() {
sys.puts("Lilly saved in DB with id " + lilly.id());
});
Get one or more objects from DB
R.Person.get({
ids: lilly.id()
}, function(lilly2){
// lilly and lilly2 are the same
});
Search in DB
R.Person.index({
query: {firstname: "Lilly"}
}, function(data){
var lilly = data[0];
});
Delete an object
lilly.delete_(function(){
sys.puts('Lilly deleted from DB!');
}, function() {
sys.puts('You can not delete Lily!');
});
Usage of references:
var harry = new R.Person({firstname: "Harry", mother: lilly});
harry.save(function() {
sys.puts('Only the id of Lilly has been saved in harry.mother in DB.');
});
Update more than one object in once:
R.Person.update({
ids: [lilly.id(), harry.id()],
data: {firstname: 'anonymous'}
}, function() {
sys.puts("Voldemort cannot find them anymore...");
});
Save more than one object in once:
var p1 = new R.Person({firstname: 'Hermione'});
var p2 = new R.Person({firstname: 'Ron'});
R.save([p1, p2], function() {
console.log('Now Harry has friends.')
}, function(error) {
console.log('Harry has no friends, because of ', error);
});
Delete more than one object in once:
R.Person.remove({
firstname: 'anonymous'
}, function() {
console.log('There is no more anonymous person in DB.');
});
R.Person.remove({}, function() {
console.log('No more person object in DB.');
}, function(error) {
console.error('Could not remove all persons from DB.');
});
Connect middleware
rest-mongo also provides you with a connect middleware which can serve your data over a REST API using the provided schema.
Starting a REST server on the port 8888
var connector = rest_server.connector(RFactory, schema);
server = http.createServer(function(req, resp) {
connector(req, resp, function() {
res.writeHead(404, {}); res.end();
});
});
server.listen(8888);
If is now possible to get the list of Person objects doing a GET HTTP request on localhost:8888/people
Authorization
It is possible to specify a third argument auth_check when calling the connector function. This argument should be a function. If provided, it will be called to check if rest-mongo can reply to the request or not. The function signature is:
auth_check(req, res, next, info)
- req: nodejs req obj.
- res: nodejs res obj.
- next: to be called if ok to continue serving the request.
- info: hash containing 'pathname', 'method', and 'data' attrs.
Installation
This version has been tested on:
- node (v0.3.0)
- node-mongodb-native
- mongodb (1.6.1 and 1.4.2)
- nodetk
node-mongodb-native and nodetk are vendorized through git submodules:
$ git submodule update --init
To run the tests: nodetests
Please have a look at the nodetk README file to install nodetk.
License
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero 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 Affero General Public License along with this program. If not, see http://www.fsf.org/licensing/licenses/agpl-3.0.html