function arrayize (store) { var response = {}; for(var ModelName in store){ var plural = utils.inflection.pluralize( ModelName ); var camelized = utils.string.camelize( plural ); response[ camelized ] = []; for( var id in store[ ModelName ] ){ response[ camelized ].push( store[ ModelName ][id] ); } } return response; }
function (err, stdout, stderr) { if (err) { fail(err); } if (stderr) { fail(new Error(stderr)); } if (!stdout) { fail(new Error('No current Git branch found')); } _currentBranch = utils.string.trim(stdout); console.log('On branch ' + _currentBranch); complete(); });
, drop = function () { var c , tableName , collection; if ((c = collections.shift())) { tableName = utils.inflection.pluralize(c); tableName = utils.string.snakeize(tableName); collection = self.client._db.collection(tableName); collection.drop(drop); } else { callback(); } };
this._getAction = function (err) { var action; if (err.statusText) { // e.g., Not Found => NotFound action = err.statusText.replace(/ /g, ''); // e.g., NotFound => notFound action = utils.string.getInflection(action, 'property', 'singular'); } else { action = 'internalServerError'; } return action; };
return function () { var ownerModelName , ownedModelName , idKey , datatype , def; if (assnKey == 'belongsTo') { ownerModelName = modelName; ownedModelName = self.name; idKey = modelName; } else { ownerModelName = self.name; ownedModelName = modelName; idKey = self.name; } if (assnName == modelName) { idKey = utils.string.decapitalize(idKey) + 'Id' } else { idKey = utils.string.decapitalize(assnName) + idKey + 'Id' } if (!reg[ownedModelName]) { throw new Error('Model ' + ownedModelName + ' does not exist.'); } if (!reg[ownedModelName].properties[idKey]) { def = model[ownerModelName]; datatype = model.config.autoIncrementId ? 'int' : 'string'; reg[ownedModelName].properties[idKey] = new model.PropertyDescription(idKey, datatype); } }
this.getAssociation = function () { var args = Array.prototype.slice.call(arguments) , modelName = args.shift() , assnType = args.shift() , callback = args.pop() , query , opts , otherKeyName = utils.string.decapitalize(modelName) , selfKeyName = utils.string.decapitalize(this.type) , queryName; // Has query object if (assnType == 'hasMany') { query = args.shift() || {}; } // No query object, create one else { query = {}; } // Lastly grab opts if any opts = args.shift() || {}; // I belong to the other model; look for the item // whose id matches my foreign key for that model if (assnType == 'belongsTo') { query.id = this[otherKeyName + 'Id']; } // The other model belongs to me; look for any // items whose foreign keys match my id // (hasOne is just a special case of hasMany) else { query[selfKeyName + 'Id'] = this.id; } queryName = assnType == 'hasMany' ? 'all' : 'load' model[modelName][queryName](query, opts, callback); };
model[resourceType].first(query, function(err, first) { if (err) { throw err; return; } var all = [first]; var pluralName = utils.string.getInflection(resourceType, 'property', 'plural'); res[pluralName] = all || []; res.count = (all) ? all.length : 0; cb(null, res); });
this.createStore = function (type, callback) { var key , constructor; if (type === 'mongo') { type = 'mongodb'; } if (type === 'couch') { type = 'couchdb'; } key = utils.string.capitalize(type); constructor = require('./stores/' + type)[key]; session.store = new constructor(callback); };
this.kill = function (pid) { var pidList = this.workerPidList , joined; try { process.kill(pid); } catch (e) {} delete this.workers[pid]; // Remove from the array of PIDs as well -- look for the actual PID // value, not just array-position joined = ',' + pidList.join(',') + ','; joined = joined.replace(',' + pid + ',', ','); joined = utils.string.trim(joined, ','); this.workerPidList = joined.length ? joined.split(',') : []; };
, _loadHelpers = function(next) { this.viewHelpers = {}; var self = this , i, helper; for(i in helpers) { helper = helpers[i]; // Create alternative helper name with opposite case style helper.altName = helper.altName || utils.string.snakeize(helper.name); // Assign to geddy.helpers self.viewHelpers[helper.altName] = helper.action; self.viewHelpers[helper.name] = helper.action; } next(); }
this.renderTemplate = function (data, callback) { var self = this , templater = new Templater() , content = ''; if (!this.template || !this.layout) { // Format directory names var dirName = utils.inflection.pluralize(this.name); dirName = utils.string.snakeize(dirName); } // Get template if not set this.template = this.template || 'app/views/' + dirName + '/' + this.params.action; // Get layout if not set or set empty layout if `false` if (typeof this.layout === 'boolean' && !this.layout) { // Use custom Geddy empty template in `lib/template/templates` this.layout = 'geddy/empty'; } else { this.layout = this.layout || 'app/views/layouts/' + dirName; } templater.addListener('data', function (data) { // Buffer for now, but we could stream content += data; }); templater.addListener('end', function () { callback(content); }); // Mix in controller instance-vars -- don't overwrite data properties for (var p in this) { if (!data[p]) { data[p] = this[p]; } }; templater.render(data, { layout: this.layout , template: this.template , controller: this.name , action: this.params.action }); };
model[resourceType].all(query || {}, opts || {}, function (err, all) { if (err) { throw err; return; } if (opts && opts.limit === 1) { all = [all]; } var pluralName = utils.string.getInflection(resourceType, 'property', 'plural'); res[pluralName] = all || []; res.query = query; res.count = (all) ? all.length : 0; cb(null, res); });
Partial = function (templatePath, data, parent) { var self = this; this.id = utils.string.uuid(); this.templatePath = templatePath this.data = data || {}; this.parent = parent; this.children = []; this.content = ''; // Hang a `partial` method on the execution-context for the // template rendering (e.g., will be the EJS global `partial` // function to add sub-templates this.data.partial = function (templatePath, data) { var child = new Partial(templatePath, data, self); self.addChild(child); return '###partial###' + child.id }; };
var _getAdapterPath = function (base, name) { var p = path.join(base, utils.string.snakeize(name)) , testPath; // F*****g CoffeeScript testPath = p + '.coffee'; if (utils.file.existsSync(testPath)) { useCoffee = useCoffee || utils.file.requireLocal('coffee-script'); return testPath; } // Normal JS testPath = p + '.js'; if (utils.file.existsSync(testPath)) { return testPath; } // Nothing found return null; }
// Pass a relation object and the kind model it is for // If it matches a belongsTo, // Get back the inverse model's key: function inverseSingularKeyForRelation (relation, type) { var desc = reg[ relation.model ]; var belongsTo = desc.associations.belongsTo; var result; for (var relationName in belongsTo) { var candidate = belongsTo[ relationName ]; // Only accepts belongsTo relations: if( candidate.model === type && candidate.type === 'belongsTo'){ result = utils.string.camelize( relationName ); } } return result; }
this.toJSON = function (options) { var self = this , opts = options || {} , whitelist = Object.keys(_systemProperties) , obj = {} , reg = model.descriptionRegistry[this.type] , properties = reg.properties , associations = reg.associations || {} , assns = { hasMany: 'plural' , hasOne: 'singular' , belongsTo: 'singular' } , assnList , assnName; whitelist = whitelist.concat(opts.whitelist || []) // First, simple defined properties for (var p in properties) { obj[p] = this[p]; } // Assocations for (var k in assns) { assnList = associations[k]; for (var p in assnList) { assnName = utils.string.getInflection(p, 'property', assns[k]); if (this[assnName]) { obj[assnName] = this[assnName]; } } } // Any non-defined, but whitelisted properties whitelist.forEach(function (p) { if (self[p]) { obj[p] = self[p]; } }); return obj; };
this.alterTableStatement = function (name, alterations, options) { var self = this , sql = '' , opts = options || {} , alter = Array.isArray(alterations) ? alterations : [alterations] , alterArr = [] , tableName; tableName = utils.string.getInflection(name, 'filename', 'plural'); sql += 'ALTER TABLE ' + tableName + ' '; // {operation: 'add', property: {name: 'foo', datatype: 'string'}} alter.forEach(function (item) { alterArr.push(self[item.operation + 'ColumnStatement'](item.property)); }); sql += alterArr.join(', '); sql += ';'; return sql; };
tagOptions: function (options) { if(!options) { return; } var self = this , attrs = [] , key , value , i, k; // Loop through each option for (i in options) { key = utils.string.dasherize(i); value = options[i]; // If it's a data key that has an object // loop through each of the values in the object // and create data attributes out of them if (key === 'data' && typeof value === 'object') { for (k in value) { attrs.push(self.dataAttribute(k, value[k])); } } // If the attribute is a boolean attribute // parse it as a bool attribute else if (utils.array.included(key, self.boolAttributes)) { if (value) { attrs.push(self.boolAttribute(key)); } } // Just a normal attribute, parse it normally else if (value || value === '') { attrs.push(self.tagAttribute(key, value)) } } if (attrs.length > 0) { return ' ' + attrs.sort().join(' '); } else { return ''; } },
this._createInsertStatement = function (item, props) { var sql = '' , modelName = item.type , def , prop , cols = [] , vals = []; // If using string UUID ids if (model.config.autoIncrementId) { cols.push(this._columnizePropertyName('id')); vals.push('DEFAULT'); } else { item.id = item.id || utils.string.uuid(); cols.push(this._columnizePropertyName('id')); vals.push(datatypes.string.serialize(item.id, { escape: 'sql' , useQuotes: true })); } for (var p in props) { def = props[p]; prop = item[p]; // Use the same definition of NULL as for updates prop = this.transformValue(prop, def.datatype); if (prop != 'NULL') { cols.push(this._columnizePropertyName(p, { useQuotes: true })); vals.push(prop); } } sql += 'INSERT INTO ' + this._tableizeModelName(modelName) + ' '; sql += '(' + cols.join(', ') + ')'; sql += ' VALUES '; sql += '(' + vals.join(', ') + ')'; sql += ';'; return sql; };
model[through][queryName](query, opts, function (err, data) { var query = {} , idColName = utils.string.getInflection(modelName, 'property', 'singular') + 'Id' , idParam; if (err) { return callback(err, null); } if (assnType == 'hasMany') { idParam = []; data.forEach(function (item) { idParam.push(item[idColName]); }); } else { idParam = item[idColName]; } query.id = idParam; model[modelName][queryName](query, opts, callback); });
this.createStore = function (config, callback) { var type = config.sessions.store , key , constructor; this.config = config; // Normalize if (type === 'mongo') { type = 'mongodb'; } if (type === 'couch') { type = 'couchdb'; } key = utils.string.capitalize(type); constructor = require('./stores/' + type)[key]; session.store = new constructor(callback); };
, _getThroughAssnKey = function (assn, assnType, modelType, opts) { var through = assn.through , assns , reg = model.descriptionRegistry , keyAssn , keyName , side = opts.side; if (side == 'other') { if (!assn.inverse) { // Look through other associations, find the inverse, and cache // for later lookup for (var p in reg) { assns = reg[p].associations[assnType]; for (var q in assns) { if (q != assn.name && assns[q].through == through) { assn.inverse = assns[q]; } } } } if (!assn.inverse) { throw new Error('No inverse found for this through-association.'); } keyAssn = assn.inverse; } else { keyAssn = assn; } if (keyAssn.name != keyAssn.model) { keyName = keyAssn.name + keyAssn.model; } else { keyName = keyAssn.name; } keyName = utils.string.decapitalize(keyName + 'Id'); return keyName; };
this.redirect = function (target, options) { var url , opts = options || {} , statusCode = opts.statusCode || 302; // Make sure it's a 3xx if (String(statusCode).indexOf('3') != 0) { throw new Error('Redirect status must be 3xx'); } if (typeof target == 'string') { url = target } else if (typeof this.app.router.url == 'function') { if (this.name && !target.controller) { target.controller = this.name; } if (this.params.format && !target.format) { target.format = this.params.format; } url = this.app.router.url(target); } if (!url) { var contr = target.controller || this.name , act = target.action , ext = target.format || this.params.format , id = target.id; contr = utils.string.decamelize(contr); url = '/' + contr; url += act ? '/' + act : ''; url += id ? '/' + id : ''; if (ext) { url += '.' + ext; } } this.output(statusCode, { 'Location': url }, ''); };
createAdapterCtor = function (p, extensions) { var ext , adapterName = utils.string.capitalize(p) + 'Adapter' , ctor = function (template, options) { this.engineName = p; this.fn = null; this.template = template; this.helpers = {}; this.options = options || {}; this.engine = new (require('./' + p))(); this.registerHelpers(adapter.helpers); }; util.inherits(ctor, Adapter); adapter[adapterName] = ctor; ext = Array.isArray(extensions) ? extensions : [extensions]; ext.forEach(function (e) { adapterExtMap[e] = ctor; }); };
this.createTableStatement = function (name, props, options) { var model = require('../index') , sql = '' , opts = options || {} , tableName , idCol , propArr = []; tableName = utils.string.getInflection(name, 'filename', 'plural'); sql += 'CREATE TABLE ' + tableName + ' ('; // Use DB auto-increment // FIXME: Is this syntax Postgres-specific? if (model.autoIncrementId) { idCol = this.addColumnStatement({ name: 'id' }, {append: 'SERIAL PRIMARY KEY'}); } // Use string UUIDs else { idCol = this.addColumnStatement({ name: 'id' , datatype: 'string' }, {append: 'PRIMARY KEY'}); } propArr.push(idCol); for (var p in props) { propArr.push(this.addColumnStatement(props[p])); } sql += propArr.join(', '); sql += ');'; // Strip out the ADD COLUMN commands, which are implicit // in a CREATE TABLE sql = sql.replace(/ADD COLUMN /g, ''); return sql; };
function getItemsFromData(modelName, data) { var items = []; var inflections = utils.string.getInflections(modelName); if (inflections.filename.plural === 'persons') { inflections.filename.plural = 'people'; } else if (data[inflections.filename.singular]) { items = [data[inflections.filename.singular]]; } else if (data[inflections.filename.plural]) { items = data[inflections.filename.plural]; } else if (data[inflections.property.singular]) { items = [data[inflections.property.singular]]; } else if (data[inflections.property.plural]) { items = data[inflections.property.plural]; } // in IE JSON parsed Arrays can become Objects if (typeof items.forEach !== 'function') { var _items = []; for(var i in items) { if (typeof items[i] === 'object') { _items.push(items[i]); } } items = _items; } return items; }
insert = function () { var item; if ((item = items.shift())) { var url , requestOpts; id = utils.string.uuid(); url = '/riak/' + bucket + '/' + id; item.id = id; item = item.toJSON(); item = JSON.stringify(item); requestOpts = { url: url , method: 'POST' , data: item }; self.request(requestOpts, function (err, res) { if (err) { callback(err, null); } else { insert(); } }); } else { if (data instanceof model.ModelBase) { data.id = id; // Single instance, can use last id generated above data._saved = true; callback(null, data); } else { callback(null, true); } } };
action: function (content, options, htmlOptions) { var opts = options || {} , htmlOpts = htmlOptions || {} , url; // This is for imageLink to avoid escaping // FIXME: Kinda stupid putting this in htmlOptions, but options is taken. if(htmlOpts._escapeContent !== false) { content = utils.string.escapeXML(content); delete htmlOpts._escapeContent; } // If options is a function, assume it was from a action helper if (typeof opts === 'function') { opts = String(opts()); } url = exports.urlFor.action(opts); htmlOpts.href = htmlOpts.href || url; return exports.contentTag.action('a', content, htmlOpts); }
function removeFirst(resourceType, id, params, cb) { // normalize resourceType resourceType = utils.string.getInflection(resourceType, 'constructor', 'singular'); if (model[resourceType]) { var res = {}; model[resourceType].remove(id, function(err, data) { if (err) { throw err; return; } cb(null, { success: true, data: data }); }); } else { var err = new Error('Resource "' + resourceType + '" does not exist.', 404); throw err; } }
insert = function () { var item; if ((item = items.shift())) { var id = utils.string.uuid() , url = '/riak/' + bucket + '/' + id , requestOpts; item.id = id; item = item.toData({whitelist: ['id', 'createdAt']}); item = JSON.stringify(item); requestOpts = { url: url , method: 'POST' , data: item }; self.request(requestOpts, function (err, res) { if (err) { callback(err, null); } else { item.id = id; item._saved = true; insert(); } }); } else { if (data instanceof model.ModelBase) { callback(null, data); } else { callback(null, true); } } };