Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit.

  • Loading branch information...
commit bc127e1efc75ff206f45ca9f04018bcb2e933311 0 parents
@dmcquay authored
21 LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2010 Dustin McQuay
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
25 README.markdown
@@ -0,0 +1,25 @@
+#node-data-provider
+
+This library helps you use MongoDB. Eventually it may support other document-oriented databases.
+
+#Design goals
+
+In many cases, especially with document oriented databases, an ORM is no longer needed. The documents
+are easy to work with and map naturally to objects. In some cases, the user many not even want to
+map the documents to anything, but would prefer to work with the documents directly. Based on that
+theory, here are the design goals.
+
+ - Allow users to pass in raw documents and provide a means for them to get raw documents in response.
+ - In the case that a user does want to use a model, provide a simple means of integrating their model
+ with this library (e.g. so they can call model.save() or get a list of models in response to a query).
+ - Don't couple this code with the user's model code. Let the user make their models however they want.
+ - Provide a means to configure connections in one place.
+ - Provide simple connection pooling.
+
+#Status
+
+This is a very new project. I've only used it so far for save and find methods (it doesn't currently
+support any other methods). Not all of the design goals are achieved yet. In particular, the following
+is lacking:
+
+ - Allow users to pass in raw documents and provide a means for them to get raw documents in response.
2  index.js
@@ -0,0 +1,2 @@
+module.exports.DataProvider = require('./lib/DataProvider').DataProvider;
+module.exports.DataProvider = require('./lib/Persistable').Persistable;
76 lib/DataProvider.js
@@ -0,0 +1,76 @@
+var mongodb = require('mongodb'),
+ sys = require('sys');
+
+var DataProvider = function(cfg) {
+ cfg = cfg || {};
+
+ if (!cfg.host) { throw new Error('Missing host config.'); }
+ cfg.port = cfg.port || 27017;
+ if (!cfg.dbname) { throw new Error('Missing dbname config.'); }
+
+ this.cfg = cfg;
+};
+
+DataProvider.initCfg = function(cfg) {
+ DataProvider._cfg = cfg;
+};
+
+DataProvider.getInstance = function(connName) {
+ connName = connName || 'default';
+ DataProvider._instances = DataProvider._instances || {};
+ if (!DataProvider._instances[connName]) {
+ if (!DataProvider._cfg[connName]) {
+ throw new Error('Unknown connection: ' + connName);
+ }
+ DataProvider._instances[connName] = new DataProvider(DataProvider._cfg[connName]);
+ }
+ return DataProvider._instances[connName];
+};
+
+DataProvider.prototype.save = function(persistable, callback) {
+ var db = new mongodb.Db(
+ this.cfg.dbname,
+ new mongodb.Server(this.cfg.host, this.cfg.port, {auto_reconnect:true}),
+ {strict:false}
+ );
+ db.addListener('error', callback);
+ db.open(function(err, db) {
+ if (err) { return callback(err) }
+ db.createCollection(persistable.getCollectionName(), function(err, collection) {
+ if (err) { return callback(err) }
+ collection.save(persistable.toObject(), function(err, docs) {
+ db.close();
+ callback(null, persistable);
+ });
+ });
+ });
+};
+
+DataProvider.prototype.find = function(klass, queryObj, callback) {
+ var db = new mongodb.Db(
+ this.cfg.dbname,
+ new mongodb.Server(this.cfg.host, this.cfg.port, {auto_reconnect:true}),
+ {strict:false}
+ );
+ db.addListener('error', callback);
+ db.open(function(err, db) {
+ if (err) return callback(err);
+ db.createCollection(klass.prototype.getCollectionName(), function(err, collection) {
+ if (err) return callback(err);
+ collection.find(queryObj, function(err, cursor) {
+ if (err) return callback(err);
+ cursor.toArray(function(err, docs) {
+ if (err) return callback(err);
+ var objs = [];
+ for (var i = 0; i < docs.length; i++) {
+ objs.push(new klass(docs[i]));
+ }
+ db.close();
+ callback(null, objs);
+ });
+ });
+ });
+ });
+};
+
+exports.DataProvider = DataProvider;
9 lib/Persistable.js
@@ -0,0 +1,9 @@
+var Persistable = function(){};
+
+Persistable.prototype.getCollectionName = function() { throw new Error('not implemented') };
+
+Persistable.prototype.toObject = function() { throw new Error('not implemented') };
+
+Persistable.prototype.initFromObject = function() { throw new Error('not implemented') };
+
+exports.Persistable = Persistable;
56 test/DataProvider.js
@@ -0,0 +1,56 @@
+var DataProvider = require('../lib/DataProvider').DataProvider,
+ vows = require('vows'),
+ assert = require('assert'),
+ sys = require('sys');
+
+var mongoConfig = {
+ driver: 'mongodb',
+ host: 'localhost',
+ dbname: 'test'
+};
+
+vows.describe('DataProvider').addBatch({
+ 'DataProvider': {
+ 'should have an initCfg method': function() {
+ assert.equal(typeof(DataProvider.initCfg), 'function');
+ },
+
+ 'getInstance should err on bad name': function() {
+ assert.throws(function() {
+ DataProvider.initCfg({}); //ensure blank config
+ DataProvider.getInstance('fake');
+ });
+ },
+
+ 'getInstance should return default conn if none specified': function() {
+ DataProvider.initCfg({default:{host:'localhost',dbname:'test'}});
+ var dp = DataProvider.getInstance();
+ assert.ok(dp instanceof DataProvider);
+ },
+
+ 'getInstance should return named connection when specified': function() {
+ DataProvider.initCfg({testname:{host:'localhost',dbname:'test'}});
+ var dp = DataProvider.getInstance('testname');
+ assert.ok(dp instanceof DataProvider);
+ },
+
+ 'getInstance should only create one of each connection name': function() {
+ DataProvider.initCfg({'default':{host:'localhost',dbname:'test'}});
+ var dp1 = DataProvider.getInstance();
+ var dp2 = DataProvider.getInstance();
+ assert.strictEqual(dp1, dp2);
+ }
+ },
+
+ 'A DataProvider instance': {
+ topic: new DataProvider(mongoConfig),
+
+ 'should not be null': function(dp) {
+ assert.strictEqual(typeof(dp), 'object');
+ },
+
+ 'must be an instance of DataProvider': function(dp) {
+ assert.ok(dp instanceof DataProvider);
+ }
+ }
+}).export(module);
35 test/Persistable.js
@@ -0,0 +1,35 @@
+var Persistable = require('../lib/Persistable').Persistable,
+ vows = require('vows'),
+ assert = require('assert'),
+ sys = require('sys');
+
+vows.describe('Persistable').addBatch({
+ 'A Persistable': {
+ topic: new Persistable(),
+
+ 'must not be null': function(per) {
+ assert.strictEqual(typeof(per), 'object');
+ },
+
+ 'must be an instance of Persistable': function(per) {
+ assert.ok(per instanceof Persistable);
+ },
+
+ 'must define the following interface methods': {
+ 'getCollectionName': function(per) {
+ assert.strictEqual(typeof(per.getCollectionName), 'function');
+ assert.throws(function(){per.getCollectionName()});
+ },
+
+ 'toObject': function(per) {
+ assert.strictEqual(typeof(per.toObject), 'function');
+ assert.throws(function(){per.toObject()});
+ },
+
+ 'initFromObject': function(per) {
+ assert.strictEqual(typeof(per.initFromObject), 'function');
+ assert.throws(function(){per.initFromObject()});
+ }
+ }
+ }
+}).export(module);
Please sign in to comment.
Something went wrong with that request. Please try again.