Permalink
Browse files

added buffers and currying to models

  • Loading branch information...
nw committed Apr 15, 2010
1 parent 6fcde18 commit 3c71ba225b1875321f96cbbb6ff9e3f4bfb21483
Showing with 276 additions and 86 deletions.
  1. +77 −0 README.md
  2. +50 −0 examples/sugar.js
  3. +149 −86 lib/model.js
View
@@ -1,6 +1,77 @@
Mongoose: MongoDB utility library with ORM-like functionality
===============================================================
+The goal of Mongoose is to provide a extremely simple interface for MongoDB.
+
+Goals
+-----
+- Reduce the burden of dealing with nested callback from async operations.
+- Provide a simple yet rich set of APIs.
+- Still have easy access to the database/collection.
+
+
+Quick Start
+------------
+
+ User = require('mongoose').Storage
+ .connect({host: 'localhost', port : 34324})
+ .bindModel(__dirname+'/models/User');
+
+ User.find(query).each(function(user){
+ // do something to matching user
+ });
+
+ User
+ .find
+ .update
+ .upsert
+ .insert
+ .count
+ .distinct
+ .mapReduce
+ .remove
+ .flush
+
+ each : [find,update,upsert,insert,distinct,remove]
+ get/one [find,count,mapReduce]
+
+ User.collection = native collection instance
+ User.database = native database instance.
+
+
+
+ User.update(query)
+
+ User.insert(object);
+
+ var user = new User(object);
+
+
+
+
+
+
+
+ /*
+ loadModels takes either an array of specifc model paths.
+ Or it can take a require path that ends in a backslash (/)
+ it will load all .js files within the directory.
+
+ The return is an object whose keys are the basename and the
+ values is the Model instance
+
+ ex:
+
+ var storage = Mogoose.connect({...}),
+ m = Models = storage.loadModels('./models/');
+
+ m.user.find({}).each()
+
+ m.user.find().one(function(){})
+
+ */
+
+
Example
-------
@@ -21,3 +92,9 @@ Requirements
- [node-mongodb-native](http://github.com/christkv/node-mongodb-native)
+Future
+------
+- implement a generic BSON module for Node.js using: [Mongo BSON C++ Libray](http://www.mongodb.org/pages/viewpage.action?pageId=133415)
+
+Revisions
+---------
View
@@ -0,0 +1,50 @@
+
+ require.paths.unshift(__dirname + '/models');
+ var sys = require('sys'),
+
+ mongoose = require('../../mongoose/').configure({
+ dev : { master : { host : 'localhost', port : 27017, name : 'test', options : {auto_reconnect : true}} }
+ }),
+ devStore = mongoose.connect('dev'),
+ models = require('../lib/model').Model,
+
+ User = models.load('User',devStore);
+
+
+ User.find({'age':{'$gt':1}}).each(function(err,item){
+ if(item !== null){
+ sys.puts('------ age greater then 1 -------\n');
+ sys.puts(sys.inspect(item));
+ sys.puts('\n---------------------------------\n');
+ }
+ })
+
+// User = require('mongoose').Storage
+// .connect({host: 'localhost', port : 34324})
+// .loadModel('./models/User');
+
+ /*
+ loadModels takes either an array of specifc model paths.
+ Or it can take a require path that ends in a backslash (/)
+ it will load all .js files within the directory.
+
+ The return is an object whose keys are the basename and the
+ values is the Model instance
+
+ ex:
+
+ var storage = Mogoose.connect({...}),
+ m = Models = storage.loadModels('./models/');
+
+ m.user.find({}).each()
+
+ m.user.find().one(function(){})
+
+
+ */
+
+// Models = require('mongoose').Storage
+// .connect({host: 'localhost', port : 34324})
+// .loadModels('./models/');
+
+
View
@@ -1,95 +1,158 @@
var Class = require('./support/class/lib/class').Class,
- Collection = require('./support/mongodb/lib/mongodb/collection').Collection
sys = require('sys'),
- path = '',
- models = {},
-
-this.Doc = Doc = new Class({
- constructor : function(obj){
- var schema = this.schema;
- for(key in schema){
- if(!obj[key]){
- if(schema[key].if_missing) schema[key].value = schema[key].if_missing;
- else sys.puts('error: missing required data field');
- } else {
- schema[key].value = obj[key];
- }
- this.schema[key].state = 'dirty',
-
- this.__defineGetter__(key,function(key){
- return this.schema[key].value;
- }.bind(this,[key]));
- this.__defineSetter__(key,function(val,key){
- this.schema[key].value = val; // need to add validation and make dirty
- }.bind(this,[key]));
- }
- return this;
- },
-
- save : function(){
- var obj = {};
- for(i in this.schema) obj[i] = this.schema[i].value;
-
- this.store.insert(obj,function(err,resp){
- for(key in resp){
- if(key == '_id' && !this.schema[key]) this.schema[key] = { value : resp[key], state : 'clean' };
- }
- });
- }
-
-});
+ Manager = new Class({
-var Manager = new Class({
-
- models : [],
- path : '',
-
- constructor : function(){
- },
-
-
- configure : function(options){
- if(options.path) this.path = options.path;
- return this;
- },
-
- load : function(name,store,callback){
- var id = name + ':' + store.id;
- if(!this.models[id]) this.compile(id,require(this.path+name)[name],store,callback);
- if(this.models[id].loaded) callback(this.models[id]);
- else this.models[id].addListener('onLoad',callback);
- },
-
- compile : function(id,doc,store,callback){
- var schema = doc.prototype.schema,
- collectionName = doc.prototype.name;
-
- doc.loaded = false;
-
- for(i in process.EventEmitter.prototype) doc[i] = process.EventEmitter.prototype[i].bind(doc);
- process.EventEmitter.call(doc);
-
- if(store.collections[collectionName]) doc.prototype.store = store.collections[collectionName];
- else {
- store.openCollection(collectionName,function(collection){
- doc.prototype.store = collection;
-
- collection.createIndex(doc.prototype.indexes,function(err,resp){}); // ensures indexes
-
- for(cmd in collection) if(cmd != 'db' && cmd != 'collectionName' && cmd != 'hint') doc[cmd] = collection[cmd].bind(collection);
+ path : '',
+ models : [],
+
+ configure : function(options){
+ if(options.path) this.path = options.path;
+ return this;
+ },
+
+ load : function(name,store){
+ var id = name + ':' + store.id;
+ if(!this.models[id]) this.compile(id,require(this.path+name)[name],store);
+ return this.models[id];
+ },
+
+ compile : function(id,doc,store){
+
+ var schema = doc.prototype.schema,
+ collectionName = doc.prototype.name,
+ static = {
+
+ name : collectionName,
+ // database : store.db,
+ loaded : false,
+
+ buffer : [],
+
+ find : function(){ return this._cmd('find',Array.prototype.slice.call(arguments,0)); },
+ update : function(){ return this._cmd('update',Array.prototype.slice.call(arguments,0)); },
+ // upsert is the most complicated (its an update with an option flag)
+ insert : function(){ return this._cmd('insert',Array.prototype.slice.call(arguments,0)); },
+ count : function(){ return this._cmd('count', Array.prototype.slice.call(arguments,0)); },
+ distinct: function(){ return this._cmd('distinct', Array.prototype.slice.call(arguments,0)); },
+ mapReduce: function(){ return this._cmd('mapReduce', Array.prototype.slice.call(arguments,0)); },
+ remove: function(){ return this._cmd('remove', Array.prototype.slice.call(arguments,0)); },
+
+ _cmd : function(cmd,args){
+ var operation = {
+ name : cmd,
+ callback : (args[args.length-1] instanceof Function) ? args.pop() : null,
+ args : args
+ };
+
+ this.buffer.push(operation);
+
+ if(!operation.callback){
+ operation.callback = function(){};
+ return new Sugar(operation,this.dequeue);
+ }
+
+ this.dequeue();
+ },
+
+ dequeue : function(){
+ if(!this.buffer.length || !this.loaded) return;
+ var op = this.buffer.shift();
+ op.args.push(op.callback)
+ sys.puts(sys.inspect(op.args));
+ this.collection[op.name].apply(this.collection,op.args);
+ this.dequeue();
+ },
+
+ onLoad : function(collection){
+ this.collection = collection;
+ this.loaded = true;
+ this.dequeue();
+ }
+
+ };
+
+ // create static interface
+ for(i in static) doc[i] = (static[i] instanceof Function) ? static[i].bind(doc) : static[i];
- doc.loaded = true;
- doc.emit('onLoad',doc);
- });
- }
- this.models[id] = doc;
- return doc;
- }
-
-});
+ // add events
+ for(i in process.EventEmitter.prototype) doc[i] = process.EventEmitter.prototype[i].bind(doc);
+ process.EventEmitter.call(doc);
+
+ doc.addListener('onLoad', doc.onLoad);
+
+ if(store.collections[collectionName]) doc.collection = store.collection[collectionName];
+ else{
+ store.openCollection(collectionName,function(collection){
+ doc.collection = collection;
+ collection.createIndex(doc.prototype.indexes,function(err,resp){}); // ensures indexes
+ doc.emit('onLoad',collection);
+ })
+ }
+
+ this.models[id] = doc;
+ },
+
+ }),
+
+ Doc = new Class({
+
+ constructor : function(obj){
+ var schema = this.schema;
+ for(key in schema){
+ if(!obj[key]){
+ if(schema[key].if_missing) schema[key].value = schema[key].if_missing;
+ else sys.puts('error: missing required data field');
+ } else {
+ schema[key].value = obj[key];
+ }
+ this.schema[key].state = 'dirty',
+ this.__defineGetter__(key,function(key){
+ return this.schema[key].value;
+ }.bind(this,[key]));
+ this.__defineSetter__(key,function(val,key){
+ this.schema[key].value = val; // need to add validation and make dirty
+ }.bind(this,[key]));
+ }
+ return this;
+ },
+
+ save : function(){
+ var obj = {};
+ for(i in this.schema) obj[i] = this.schema[i].value;
+
+ this.store.insert(obj,function(err,resp){
+ for(key in resp){
+ if(key == '_id' && !this.schema[key]) this.schema[key] = { value : resp[key], state : 'clean' };
+ }
+ });
+ }
+
+ }),
+
+ Sugar = new Class({
+
+ constructor : function(operation,dequeue){
+ this.op = operation;
+ this.get = this.one;
+ this.dequeue = dequeue;
+ },
+
+ each : function(func){
+ this.op.callback = function(err,cursor){ if(!err) cursor.each(func); };
+ this.dequeue();
+ },
+
+ one : function(func){
+ this.op.callback = function(err,cursor){ if(!err) cursor.nextObject(func); };
+ this.dequeue();
+ }
+
+ });
+
-this.Model = new Manager();
+this.Model = new Manager();
+this.Doc = Doc;

0 comments on commit 3c71ba2

Please sign in to comment.