Skip to content

Instantly share code, notes, and snippets.

@sourishkrout
Created November 20, 2012 21:12
Show Gist options
  • Save sourishkrout/4121169 to your computer and use it in GitHub Desktop.
Save sourishkrout/4121169 to your computer and use it in GitHub Desktop.
Barebones of a model based on couchdb + nano
/**
* Adopted from jquery's extend method. Under the terms of MIT License.
*
* http://code.jquery.com/jquery-1.4.2.js
*/
exports.extend = function() {
// copy reference to target object
var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy, cb = arguments[length-1];
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && typeof target !== 'function') {
target = {};
}
var isArray = function(obj) {
return toString.call(copy) === "[object Array]" ? true : false;
};
var isPlainObject = function( obj ) {
// Must be an Object.
// Because of IE, we also have to check the presence of the constructor property.
// Make sure that DOM nodes and window objects don't pass through, as well
if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {
return false;
}
var has_own_constructor = Object.hasOwnProperty.call(obj, "constructor");
var has_is_property_of_method = Object.hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf");
// Not own constructor property must be Object
if ( obj.constructor && !has_own_constructor && !has_is_property_of_method) {
return false;
}
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var last_key;
for (var key in obj) {
last_key = key;
}
return typeof last_key === "undefined" || Object.hasOwnProperty.call( obj, last_key );
};
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) !== null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging object literal values or arrays
if ( deep && copy && ( isPlainObject(copy) || isArray(copy) ) ) {
var clone = src && ( isPlainObject(src) || isArray(src) ) ? src : isArray(copy) ? [] : {};
// Never move original objects, clone them
target[ name ] = GLOBAL.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( typeof copy !== "undefined" ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
cb(target);
};
// Shallow strip only
exports.strip = function(obj, cb) {
for (var prop in obj) {
if (typeof obj[prop] === "function") {
delete obj[prop];
}
}
cb(obj);
};
var config = require('./config')
, helpers = require('./helpers')
, normalize = require('./normalize')
, couchdb = require('nano')(config().couchdb.url)
, users = couchdb.use(config().couchdb.users)
, emails = couchdb.use(config().couchdb.emails);
var Base = function() {
};
Base.prototype.save = function(callback) {
helpers.strip(this, function(target) {
users.insert(target, target._id, function(err, info) {
var self = this;
exports.User.load(info.id, function(err, temp) {
helpers.strip(temp, function(_temp) {
helpers.extend(self, _temp, function(obj) {
if (callback) {
callback(err, info);
}
});
});
});
});
});
};
Base.prototype.destroy = function(callback) {
users.destroy(this._id, this._rev, callback);
};
Base.prototype.normalize = function(callback) {
// We want to chain normalizers by priority here
var self = this;
normalize.github(this, function(profile) {
self.profile = profile;
self.profile.synced = new Date();
self.save(callback);
});
};
var base = Object.create(Base.prototype);
exports.Email = function() {
};
exports.Email.create = function(id, doc, callback) {
helpers.strip(doc, function(target) {
emails.insert(target, id, function(err, body) {
callback(err, body);
});
});
};
exports.User = function() {
};
exports.User.load = function(id, callback) {
users.get(id, { revs_info: false }, function(err, body) {
if (!err) {
helpers.extend(body, base, function(target) { callback(null, target); } );
} else {
callback(err);
}
});
};
exports.User.create = function(id, doc, callback) {
var retrieve = function(info, cb) {
exports.User.load(info.id, function(err, temp) {
helpers.extend(
doc
, temp
, function(stub) {
helpers.extend(doc, base, function(user) {
cb(null, user);
});
});
});
};
helpers.strip(doc, function(target) {
users.insert(target, id, function(err, body) {
if (err) {
users.insert(target, function(err, body) {
retrieve(body, callback);
});
} else {
retrieve(body, callback);
}
});
});
};
exports.User.provider = function(extid, provider, callback) {
var ufound = false;
users.view('lookup', 'by_external_id', { "keys": [ extid ] }, function(err, body) {
if (body.total_rows > 0) {
body.rows.forEach(function(record) {
if (record.key === extid && record.value.provider === provider) {
ufound = true;
return callback(null, record);
}
});
}
if (!ufound) {
return callback(null, null);
}
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment