afterInit: function(callback) { // color = blue is inherited from our implicit subclass of the base module assert(apos.assets && apos.assets.color === 'blue'); // make sure that our modules match what is specifed in defaults.js assert(_.difference(_.keys(defaultModules), _.keys(apos.modules)).length === 0); return t.destroy(apos, done); }
it('should expose at least the expected core hooks', function() { var intersection = _.intersection(_.keys(sails.hooks), _.keys(constants.EXPECTED_DEFAULT_HOOKS)); // If i18n is missing, that might be ok-- but just check to be sure sails.config.i18n.locales is `[]`. // (i.e. it must have turned itself off) if (!_.contains(intersection, 'i18n')) { assert(_.isEqual(sails.config.i18n.locales, []), 'i18n.locales config must be [] in this situation'); } assert.deepEqual(intersection, _.without(_.keys(constants.EXPECTED_DEFAULT_HOOKS), 'i18n'), 'Missing expected default hooks'); });
orm.teardown = function teardown(done) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // FUTURE: In WL 0.14, deprecate support for this method in favor of the simplified // `Waterline.start()` (see bottom of this file). In WL 1.0, remove it altogether. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - async.each(_.keys(datastoreMap), function(datastoreName, next) { var datastore = datastoreMap[datastoreName]; // Check if the adapter has a teardown method implemented. // If not, then just skip this datastore. if (!_.has(datastore.adapter, 'teardown')) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // FUTURE: get rid of this `setImmediate` (or if it's serving a purpose, document what that is) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - setImmediate(function() { next(); });//_∏_ return; }//-• // But otherwise, call its teardown method. try { datastore.adapter.teardown(datastoreName, next); } catch (err) { return next(err); } }, done); };
function removeListeners(cb) { // Manually remove all event listeners _.each(_.keys(sails._events)||[], function (eventName){ sails.removeAllListeners(eventName); }); var listeners = sails._processListeners; if (listeners) { process.removeListener('SIGUSR2', listeners.sigusr2); process.removeListener('SIGINT', listeners.sigint); process.removeListener('SIGTERM', listeners.sigterm); process.removeListener('exit', listeners.exit); } sails._processListeners = null; // If `sails.config.process.removeAllListeners` is set, do that. // This is no longer necessary due to https://github.com/balderdashy/sails/pull/2693 // Deprecating for v0.12. if (sails.config && sails.config.process && sails.config.process.removeAllListeners) { sails.log.debug('sails.config.process.removeAllListeners is deprecated; please remove listeners indivually!'); process.removeAllListeners(); } cb(); },
Support.Teardown = function teardown(tableName, cb) { var manager = adapter.datastores[_.first(_.keys(adapter.datastores))].manager; MySQL.getConnection({ manager: manager, meta: Support.Config }).exec(function getConnectionCb(err, report) { if (err) { return cb(err); } var query = 'DROP TABLE IF EXISTS `' + tableName + '`;'; MySQL.sendNativeQuery({ connection: report.connection, nativeQuery: query }).exec(function dropTableCb(err) { if (err) { return cb(err); } MySQL.releaseConnection({ connection: report.connection }).exec(function releaseConnectionCb(err) { if (err) { return cb(err); } delete adapter.datastores[_.first(_.keys(adapter.datastores))]; return cb(); }); }); }); };
Support.Seed = function seed(tableName, cb) { var manager = adapter.datastores[_.first(_.keys(adapter.datastores))].manager; MySQL.getConnection({ manager: manager, meta: Support.Config }).exec(function getConnectionCb(err, report) { if (err) { return cb(err); } var query = [ 'INSERT INTO `' + tableName + '` (`fieldA`, `fieldB`) ', 'values (\'foo\', \'bar\'), (\'foo_2\', \'bAr_2\');' ].join(''); MySQL.sendNativeQuery({ connection: report.connection, nativeQuery: query }).exec(function seedCb(err) { if (err) { return cb(err); } MySQL.releaseConnection({ connection: report.connection }).exec(cb); }); }); };
prepare: function(cb) { async.each(_.without(_.keys(hooks), 'userconfig', 'moduleloader', 'userhooks'), function (id, cb) { prepareHook(id); // Defer to next tick to allow other stuff to happen process.nextTick(cb); }, cb); },
defaults: function(cb) { async.each(_.without(_.keys(hooks), 'userconfig', 'moduleloader', 'userhooks'), function (id, cb) { var hook = hooks[id]; applyDefaults(hook); // Defer to next tick to allow other stuff to happen process.nextTick(cb); }, cb); },
}).exec(function releaseConnectionCb(err) { if (err) { return cb(err); } delete adapter.datastores[_.first(_.keys(adapter.datastores))]; return cb(); });
_.each(archiversInfoByArchiveIdentity, function(archiversInfo, archiveIdentity) { var archiveWmd = _.find(wmds, function(wmd){ return wmd.prototype.identity === archiveIdentity; }); if (!archiveWmd) { throw new Error('Invalid `archiveModelIdentity` setting. A model declares `archiveModelIdentity: \''+archiveIdentity+'\'`, but there\'s no other model actually registered with that identity to use as an archive!'); } // Validate that this archive model can be used for the purpose of Waterline's .archive() // > (note that the error messages here should be considerate of the case where someone is // > upgrading their app from an older version of Sails/Waterline and might happen to have // > a model named "Archive".) var EXPECTED_ATTR_NAMES = ['id', 'createdAt', 'fromModel', 'originalRecord', 'originalRecordId']; var actualAttrNames = _.keys(archiveWmd.prototype.attributes); var namesOfMissingAttrs = _.difference(EXPECTED_ATTR_NAMES, actualAttrNames); try { if (namesOfMissingAttrs.length > 0) { throw flaverr({ code: 'E_INVALID_ARCHIVE_MODEL', because: 'it is missing '+ namesOfMissingAttrs.length+' mandatory attribute'+(namesOfMissingAttrs.length===1?'':'s')+': '+namesOfMissingAttrs+'.' }); }//• if (archiveWmd.prototype.primaryKey !== 'id') { throw flaverr({ code: 'E_INVALID_ARCHIVE_MODEL', because: 'it is using an attribute other than `id` as its logical primary key attribute.' }); }//• if (_.any(EXPECTED_ATTR_NAMES, { encrypt: true })) { throw flaverr({ code: 'E_INVALID_ARCHIVE_MODEL', because: 'it is using at-rest encryption on one of its mandatory attributes, when it shouldn\'t be.' }); }//• // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // FUTURE: do more checks (there's a lot of things we should probably check-- e.g. the `type` of each // mandatory attribute, that no crazy defaultsTo is provided, that the auto-timestamp is correct, etc.) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - } catch (err) { switch (err.code) { case 'E_INVALID_ARCHIVE_MODEL': throw new Error( 'The `'+archiveIdentity+'` model cannot be used as a custom archive, because '+err.because+'\n'+ 'Please adjust this custom archive model accordingly, or otherwise switch to a different '+ 'model as your custom archive. (For reference, this `'+archiveIdentity+'` model this is currently '+ 'configured as the custom archive model for '+archiversInfo.archivers.length+' other '+ 'model'+(archiversInfo.archivers.length===1?'':'s')+': '+_.pluck(archiversInfo.archivers, 'identity')+'.' ); default: throw err; } } });//∞
Adapter.describe('test', 'test_drop', function describeCb(err, result) { if (err) { return done(err); } assert.equal(_.keys(result), 0); return done(); });
}, bindToSails(function(err, supplements) { if (err) { return cb(err); } if (_.keys(supplements).length > 0) { sails.log.debug('The use of `.attributes.json` files is deprecated, and support will be removed in a future release of Sails.'); } return cb(undefined, _.merge(models, supplements)); }));
Collection.prototype._getPK = function _getPK () { var self = this; var pk; _.keys(this.schema).forEach(function(key) { if(self.schema[key].primaryKey) pk = key; }); if(!pk) pk = 'id'; return pk; };
self.sanitizeCrop = function(crop) { crop = _.pick(crop, 'top', 'left', 'width', 'height'); crop.top = self.apos.launder.integer(crop.top, 0, 0, 10000); crop.left = self.apos.launder.integer(crop.left, 0, 0, 10000); crop.width = self.apos.launder.integer(crop.width, 1, 1, 10000); crop.height = self.apos.launder.integer(crop.height, 1, 1, 10000); if (_.keys(crop).length < 4) { return undefined; } return crop; };
var Update = module.exports = function(collection, proto, mutatedModels, cb) { var values = typeof proto.toObject === 'function' ? proto.toObject() : proto; var attributes = collection.waterline.schema[collection.identity].attributes; var primaryKey = this.findPrimaryKey(attributes, values); if (!primaryKey) { return cb(new Error('No Primary Key set to update the record with! ' + 'Try setting an attribute as a primary key or include an ID property.')); } if (!values[primaryKey]) { return cb(new Error('No Primary Key set to update the record with! ' + 'Primary Key must have a value, it can\'t be an optional value.')); } // Build Search Criteria var criteria = {}; criteria[primaryKey] = values[primaryKey]; // Clone values so they can be mutated var _values = _.cloneDeep(values); // For any nested model associations (objects not collection arrays) that were not changed, // lets set the value to just the foreign key so that an update query is not performed on the // associatied model. var keys = _.keys(_values); keys.forEach(function(key) { // Nix any collection attributes so that they do not get sync'd during the update process. // One reason for this is that the result set is not guaranteed to be complete, // so the sync could exclude items. if (attributes[key] && hop(attributes[key], 'collection') && attributes[key].collection) { delete _values[key]; return; } // If the key was changed, keep it expanded if (mutatedModels.indexOf(key) !== -1) return; // Reduce it down to a foreign key value var vals = {}; vals[key] = _values[key]; // Delete and replace the value with a reduced version delete _values[key]; var reduced = nestedOperations.reduceAssociations.call(collection, collection.identity, collection.waterline.schema, vals); _values = _.merge(_values, reduced); }); // Update the collection with the new values collection.update(criteria, _values, cb); };
configure: function(cb) { async.each(_.without(_.keys(hooks), 'userconfig', 'moduleloader', 'userhooks'), function (id, cb) { var hook = hooks[id]; try { hook.configure(); } catch (err) { return process.nextTick(function(){ cb(err); }); } // Defer to next tick to allow other stuff to happen process.nextTick(cb); }, cb); },
_.each(sortClause, function (comparatorDirective){ var sortByKey = _.keys(comparatorDirective)[0]; if (_.contains(referencedComparatorTargets, sortByKey)) { throw flaverr('E_SORT_CLAUSE_UNUSABLE', new Error( 'Cannot sort by the same thing (`'+sortByKey+'`) twice!' )); }//-• referencedComparatorTargets.push(sortByKey); });//</_.each>
var mongoSort = _.map(s3q.criteria.sort, function mapSort(s3qSortDirective) { var mongoSortDirective = []; var sortByKey = _.first(_.keys(s3qSortDirective)); mongoSortDirective.push(sortByKey); var sortDirection = s3qSortDirective[sortByKey]; assert(sortDirection === 'ASC' || sortDirection === 'DESC', 'At this point, the sort direction should always be ASC or DESC (capitalized). If you are seeing this message, there is probably a bug somewhere in your version of Waterline core.'); mongoSortDirective.push(sortDirection === 'ASC' ? 1 : -1); return mongoSortDirective; });
.exec(function(err, driver) { if (err) { return done(err); } assert(driver); assert(_.isArray(driver.taxis)); assert.equal(driver.taxis.length, 1); assert.equal(_.keys(driver.taxis[0]).length, 6); assert(driver.taxis[0].id); assert(_.isUndefined(driver.taxis[0].model)); return done(); });
registerActions: function(cb) { // Loop through all of the loaded models and add actions for each. _.each(_.keys(sails.models), function(modelIdentity) { sails.registerAction(BlueprintController.create, modelIdentity + '/create'); sails.registerAction(BlueprintController.find, modelIdentity + '/find'); sails.registerAction(BlueprintController.findone, modelIdentity + '/findOne'); sails.registerAction(BlueprintController.update, modelIdentity + '/update'); sails.registerAction(BlueprintController.destroy, modelIdentity + '/destroy'); sails.registerAction(BlueprintController.populate, modelIdentity + '/populate'); sails.registerAction(BlueprintController.add, modelIdentity + '/add'); sails.registerAction(BlueprintController.remove, modelIdentity + '/remove'); }); return cb(); }
.exec(function(err, customer) { if (err) { return done(err); } assert(customer); assert(_.isArray(customer.payments)); assert.equal(customer.payments.length, 1); assert.equal(_.keys(customer.payments[0]).length, 7); assert(customer.payments[0].id); assert.equal(customer.payments[0].a_customer, customer.id); assert(_.isUndefined(customer.payments[0].amount)); return done(); });
ORM.teardown = function teardown(cb) { async.each(_.keys(datastoreMap), function(item, next) { var datastore = datastoreMap[item]; // Check if the adapter has a teardown method implemented if (!_.has(datastore.adapter, 'teardown')) { return setImmediate(function() { next(); }); } // Call the teardown method datastore.adapter.teardown(item, next); }, cb); };
module.exports = function hashCustomUsageOpts(customUsageOpts){ return _.reduce(_.keys(customUsageOpts).sort(), function(hashSoFar, optKey){ var optValue = customUsageOpts[optKey]; // If custom usage opts contain a non-string, then don't try to cache. if (!_.isString(optValue)) { throw flaverr('E_UNHASHABLE'); } hashSoFar += optKey+':'+JSON.stringify(optValue)+'|'; return hashSoFar; }, ''); };
self.loadDeferredWidgets = function(req, callback) { if (!(req && req.res)) { return callback(new Error('You forgot to pass req as the first argument to loadDeferredWidgets, which expects (req, callback). This method is normally called for you just before the page is rendered. You should not need to call it yourself.')); } if (!req.deferWidgetLoading) { return callback(null); } req.loadingDeferredWidgets = true; return async.eachSeries(_.keys(req.deferredWidgets), function(type, callback) { var manager = self.getWidgetManager(type); if (!manager) { self.warnMissingWidgetType(type); return setImmediate(callback); } return manager.load(req, req.deferredWidgets[type], callback); }, callback); };
registerActions: function(cb) { // Loop through all of the loaded models and add actions for each. // Even though we're adding the same exact actions for each model, // (e.g. user/find and pet/find are the same), it's important that // each model gets its own set so that they can have different // action middleware (e.g. policies) applied to them. _.each(_.keys(sails.models), function(modelIdentity) { sails.registerAction(BlueprintController.create, modelIdentity + '/create'); sails.registerAction(BlueprintController.find, modelIdentity + '/find'); sails.registerAction(BlueprintController.findone, modelIdentity + '/findOne'); sails.registerAction(BlueprintController.update, modelIdentity + '/update'); sails.registerAction(BlueprintController.destroy, modelIdentity + '/destroy'); sails.registerAction(BlueprintController.populate, modelIdentity + '/populate'); sails.registerAction(BlueprintController.add, modelIdentity + '/add'); sails.registerAction(BlueprintController.remove, modelIdentity + '/remove'); sails.registerAction(BlueprintController.replace, modelIdentity + '/replace'); }); return cb(); }
after(function(done) { function dropCollection(item, next) { if (!_.has(Adapter, 'drop')) { return next(); } // Grab the adapter to perform the query on var collection = ORM.collections[item]; var datastoreName = collection.datastore; var tableName = collection.tableName || collection.identity; Adapter.drop(datastoreName, tableName, [], next); } async.each(_.keys(ORM.collections), dropCollection, function(err) { if (err) { return done(err); } waterline.teardown(done); }); });
it('should load all of the valid controller actions', function() { var expectedActions = [ 'toplevellegacy/fnaction', 'toplevellegacy/machineaction', 'toplevellegacy/underscore_action', 'toplevellegacy/action-with-dashes', 'top-level-standalone-fn', 'top-level-standalone-machine', 'somefolder/someotherfolder/nestedlegacy/fnaction', 'somefolder/someotherfolder/nestedlegacy/machineaction', 'some/folder/some/other/folder/nestedlegacy/fnaction', 'some/folder/some/other/folder/nestedlegacy/machineaction', 'somefolder/someotherfolder/nested-standalone-machine' ]; var unexpectedActions = _.difference(_.keys(sailsApp._actions), expectedActions); assert(!unexpectedActions.length, 'Loaded unexpected actions:\n' + util.inspect(unexpectedActions)); _.each(expectedActions, function(expectedAction) { assert(sailsApp._actions[expectedAction], 'Did not load expected action `' + expectedAction + '`'); assert(_.isFunction(sailsApp._actions[expectedAction]), 'Expected action `' + expectedAction + '` loaded, but instead of a function it\'s a ' + typeof(sailsApp._actions[expectedAction])); }); });
sortClause = _.reduce(_.keys(sortClause), function (memo, sortByKey) { var sortDirection = sortClause[sortByKey]; // It this appears to be a well-formed comparator directive that was simply mistakenly // provided at the top level instead of being wrapped in an array, then throw an error // specifically mentioning that. if (_.isString(sortDirection) && _.keys(sortClause).length === 1) { throw flaverr('E_SORT_CLAUSE_UNUSABLE', new Error( 'The `sort` clause in the provided criteria is invalid. If specified, it should be either '+ 'a string like `\'fullName DESC\'`, or an array like `[ { fullName: \'DESC\' } ]`. '+ 'But it looks like you might need to wrap this in an array, because instead, got: '+ util.inspect(sortClause, {depth:5})+'' )); }//-• // Otherwise, continue attempting to normalize this dictionary into array // format under the assumption that it was provided as a Mongo-style comparator // dictionary. (and freaking out if we see anything that makes us uncomfortable) var newComparatorDirective = {}; if (sortDirection === 1) { newComparatorDirective[sortByKey] = 'ASC'; } else if (sortDirection === -1) { newComparatorDirective[sortByKey] = 'DESC'; } else { throw flaverr('E_SORT_CLAUSE_UNUSABLE', new Error( 'The `sort` clause in the provided criteria is invalid. If specified as a '+ 'dictionary, it should use Mongo-esque semantics, using -1 and 1 for the sort '+ 'direction (something like `{ fullName: -1, rank: 1 }`). But instead, got: '+ util.inspect(sortClause, {depth:5})+'' )); } memo.push(newComparatorDirective); return memo; }, []);//</_.reduce()>
module.exports = function sortData(data, sortCriteria) { function dynamicSort(property) { var sortOrder = 1; if (property[0] === '-') { sortOrder = -1; property = property.substr(1); } return function(a, b) { var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0; return result * sortOrder; }; } function dynamicSortMultiple() { var props = arguments; return function(obj1, obj2) { var i = 0; var result = 0; var numberOfProperties = props.length; while (result === 0 && i < numberOfProperties) { result = dynamicSort(props[i])(obj1, obj2); i++; } return result; }; } // build sort criteria in the format ['firstName', '-lastName'] var sortArray = []; _.each(_.keys(sortCriteria), function(key) { if (sortCriteria[key] === -1) sortArray.push('-' + key); else sortArray.push(key); }); data.sort(dynamicSortMultiple.apply(null, sortArray)); return data; };
findQuery.exec(function(err, records) { if (err) {return cb(err);} // Does this model contain any attributes with type `ref`? if (datastore.refCols[query.using].length > 0) { // If so, loop through the records and transform refs to Buffers where possible. _.each(records, function(record) { _.each(datastore.refCols[query.using], function(colName) { // If this looks like NeDB's idea of a serialized Buffer, turn it into a real buffer. if (record[colName] && record[colName].type === 'Buffer' && _.isArray(record[colName].data)) { record[colName] = new Buffer(record[colName].data); } }); }); } // If the primary key column is `_id`, and we had a projection with just `_id`, transform the records // to only contain that column. This is a workaround for an issue in NeDB where doing a projection // with just _id returns all the columns. if (primaryKeyCol === '_id' && _.keys(projection).length === 1 && projection._id === 1) { records = _.map(records, function(record) {return _.pick(record, '_id');}); } return cb(undefined, records); });