UNPKG

restify-model

Version:

'A surprisingly useful model/collection adapter that builds routes and handles CRUD operations (Create, Read, Update and Delete). Works with any custom database adapter (Postgres, MySQL, MongoDB, etc.).'

148 lines (127 loc) 3.89 kB
"use strict"; var _merge = require('./util').merge; module.exports = exports = { attr: function(name, value) { if (arguments.length === 0) { // Combined attributes/changes object. return _merge({}, this.attributes, this.changes); } else if (arguments.length === 2) { // Don't write to attributes yet, store in changes for now. if (this.attributes[name] === value) { // Clean up any stale changes. delete this.changes[name]; } else { this.changes[name] = value; } this.emit('change:' + name, [this]); return this; } else if (typeof name === 'object') { // Mass-assign attributes. for (var key in name) { this.attr(key, name[key]); } this.emit('change', [this]); return this; } else { // Changes take precedent over attributes. return (name in this.changes) ? this.changes[name] : this.attributes[name]; } }, callPersistMethod: function(method, callback) { var self = this; // Automatically manage adding and removing from the model's Collection. var manageCollection = function() { if (method === 'destroy') { self.constructor.remove(self); } else { self.constructor.add(self); } }; /**** * Wrap the existing callback in this function so we always manage the * collection and emit events from here rather than relying on the * persist adapter to do it for us. The persist adapter is * only required to execute the callback with a single argument - a * boolean to indicate whether the call was a success - though any * other arguments will also be forwarded to the original callback. */ function wrappedCallback(success) { if (success) { // Merge any changes into attributes and clear changes. self.merge(self.changes).reset(); // Add/remove from collection if persist was successful. manageCollection(); // Trigger the event before executing the callback. self.emit(method); } // Store the return value of the callback. var value; // Run the supplied callback. if (callback) value = callback.apply(self, arguments); return value; }; if (this.constructor._persist && 'function' === typeof this.constructor._persist[method]) { this.constructor._persist[method](this, wrappedCallback); } else { wrappedCallback.call(this, true); } }, destroy: function(callback) { this.callPersistMethod('destroy', callback); return this; }, extend: function() { var args = [{}, this.constructor.prototype].concat(Array.prototype.slice.call(arguments)); return _merge.apply({}, args); }, id: function() { return this.attributes[this.constructor.unique_key]; }, merge: function(attributes) { _merge(this.attributes, attributes); return this; }, get: function(prop) { return this.attr.call(this, prop); }, set: function(prop, value) { return this.attr.call(this, prop, value); }, isNew: function() { return this.id() === undefined; }, pick: function(keys) { var result = {}; var attrs = this.attr(); for (var prop in keys) { var key = keys[prop]; result[key] = attrs[key]; } return result; }, reset: function() { this.errors.clear(); this.changes = {}; return this; }, save: function(callback) { if (this.valid()) { var method = (this.isNew()) ? 'create' : 'update'; this.callPersistMethod(method, callback); } else if (callback) { callback(false); } return this; }, toJSON: function() { return this.attr(); }, valid: function() { this.errors.clear(); this.validate(); return this.errors.size() === 0; }, validate: function() { return this; } }