Skip to content

Instantly share code, notes, and snippets.

@robwormald
Created February 1, 2014 01:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robwormald/8746479 to your computer and use it in GitHub Desktop.
Save robwormald/8746479 to your computer and use it in GitHub Desktop.
/**
* Module dependencies
*/
var util = require('util');
/**
* Find Records
*
* An API call to find and return model instances from the data adapter
* using the specified criteria. If an id was specified, just the instance
* with that unique id will be returned.
*
* @param {Integer|String} id - the unique id of the particular instance you'd like to look up
* @param {Object} where - the find criteria (passed directly to the ORM)
* @param {Integer} limit - the maximum number of records to send back (useful for pagination)
* @param {Integer} skip - the number of records to skip (useful for pagination)
* @param {String} sort - the order of returned records, e.g. `name ASC` or `age DESC`
*
* @param {String} _jsonpCallbackParam - optional override for JSONP callback param (can be overridden in req.options.requestTimeOverrideForJsonpCallbackParam)
* @param {String} callback - default jsonp callback param
*/
module.exports = function find (req, res) {
// Ensure a model can be deduced from the request options.
var model = req.options.model || req.options.controller;
//this array contains all possible populations for a model
var associations = req.options.associations;
var jsonp = req.options.jsonp;
if (!model) return res.badRequest(util.format('No "model" specified in route options.'));
// Get access to `sails` (globals might be disabled) and look up the model.
var sails = req._sails;
var Model = sails.models[model];
if ( !Model ) return res.notFound(util.format('Invalid route option, "model".\nI don\'t know about any models named: `%s`',model));
// if `req.isSocket` and JSONP is enabled for this action, we'll say of this request:
// "isJSONPCompatibleAndEnabled"
var isJSONPCompatibleAndEnabled = req.options.jsonp && !req.isSocket;
if (isJSONPCompatibleAndEnabled){
// Whether request-time overrides are allowed for the jsonp callback name
// (defaults to '_jsonpCallbackParam')
var requestTimeOverrideForJsonpCallbackParam =
typeof req.options.requestTimeOverrideForJsonpCallbackParam === 'undefined' ?
'_jsonpCallbackParam' :
req.options.requestTimeOverrideForJsonpCallbackParam;
// Enforce/apply request-time jsonp callback override setting
if (!requestTimeOverrideForJsonpCallbackParam &&
req.param(requestTimeOverrideForJsonpCallbackParam) &&
!allowRuntimeJsonpCallbackOverride) {
return res.forbidden('JSONP callback configuration not allowed.');
}
// The name of the parameter to use for JSONP callbacks
// Callback param can come from the params (if allowed above), `req.options`, or defaults to `callback`
var jsonpCallbackParam = req.param(requestTimeOverrideForJsonpCallbackParam) || req.options.jsonpCallbackParam || 'callback';
var originalJsonpCallbackParam = req.app.get('jsonp callback name');
req.app.set('jsonp callback name', jsonpCallbackParam);
}
var Q;
/**
* If a valid id was specified, find the particular instance with that id.
*/
if (req.param('id')) {
//populators is the *requested* populations
var populators = parsePopulateParam(req.params.all())
Q = Model.findOne(req.param('id'));
Q = _(populators).reduce(function (Q, populator) {
//todo rewrite to handle new populatate where
return Q.populate(populator.path /*, { limit: 30 } */);
}, Q);
Q.exec(function found(err, matchingRecord) {
// TODO: differentiate between waterline-originated validation errors
// and serious underlying issues
// TODO: Respond with badRequest if an error is encountered, w/ validation info
if (err) return res.serverError(err);
// No model instance found with the specified id
if(!matchingRecord) return res.notFound();
// If we have the pubsub hook, use the model class's subscribe method
// to subscribe to all blueprint notifications about this instance
if (sails.hooks.pubsub) {
Model.subscribe(req, matchingRecord);
}
// Otherwise serve a JSON(P) API
if ( isJSONPCompatibleAndEnabled ) {
return res.jsonp(matchingRecord);
}
else {
return res.json(matchingRecord);
}
});
}
/**
* If no id was specified, find instances matching the specified criteria.
*/
else {
// TODO: customize this logic
// (i.e. if req.options.limit is set, it's likely a ceiling, and while overridable,
// the `?limit=...` param probably shouldn't be allowed to exceed the configured limit in route options / policies)
var where = _.merge({}, req.options.where || {}, parseWhereParam(req.params.all())) || undefined;
var limit = req.param('limit') || (typeof req.options.limit !== 'undefined' ? req.options.limit : undefined);
if (limit) { limit = +limit; }
var skip = req.param('skip') || (typeof req.options.skip !== 'undefined' ? req.options.skip : undefined);
if (skip) { skip = +skip; }
// Lookup for records that match the specified criteria
Q = Model.find({
limit: limit,
skip: skip,
sort: req.param('sort') || req.options.sort || undefined,
where: where
});
var populators = parsePopulateParam(req.params.all())
Q = _(populators).reduce(function (Q, populate) {
console.log(populate)
return Q.populate(populate.path /*, { limit: 30 } */);
}, Q);
Q.exec(function found(err, matchingRecords) {
// TODO: differentiate between waterline-originated validation errors
// and serious underlying issues
// TODO: Respond with badRequest if an error is encountered, w/ validation info
if (err) return res.serverError(err);
// No instances found
if(!matchingRecords) return res.notFound();
// If we have the pubsub hook, use the model class's subscribe method
// to subscribe to all blueprint notifications about these instances
if (sails.hooks.pubsub) {
Model.subscribe(req, matchingRecords);
}
Model.subscribe(req);
// toJSON() all of the model instances
// matchingRecords = sails.util.invoke(matchingRecords, 'toJSON');
// Otherwise serve a JSON(P) API
if ( isJSONPCompatibleAndEnabled ) {
return res.jsonp(matchingRecords);
}
else {
return res.json(matchingRecords);
}
});
}
// TODO:
//
// Replace the following helper with the version in sails.util:
// Attempt to parse JSON
// If the parse fails, return the error object
// If JSON is falsey, return null
// (this is so that it will be ignored if not specified)
function tryToParseJSON (json) {
if (!sails.util.isString(json)) return null;
try {
return JSON.parse(json);
}
catch (e) {
return e;
}
}
/**
* parseWhereParam
*
* @param {Object} allParams [result of calling req.params.all()]
* @return {Object} the WHERE criteria object
*/
function parseWhereParam( allParams ) {
var where = req.param('where');
// If `where` parameter is a string, try to interpret it as JSON
if (sails.util.isString(where)) {
where = tryToParseJSON(where);
}
// If `where` has not been specified, but other unbound parameter variables
// **ARE** specified, build the `where` option using them.
if (!where) {
// Prune params which aren't fit to be used as `where` criteria
// to build a proper where query
where = allParams;
where = sails.util.omit(where, ['limit', 'skip', 'sort', 'populate']);
where = sails.util.omit(where, function (p){ if (sails.util.isUndefined(p)) return true; });
if (isJSONPCompatibleAndEnabled) {
where = sails.util.omit(where, [jsonpCallbackParam]);
if (requestTimeOverrideForJsonpCallbackParam) {
where = sails.util.omit(where, [requestTimeOverrideForJsonpCallbackParam]);
}
}
// console.log(requestTimeOverrideForJsonpCallbackParam);
// console.log(isJSONPCompatibleAndEnabled, jsonpCallbackParam, 'hi');
// console.log(req.params.all(), '***\n', where);
}
return where;
}
/**
* parsePopulateParam
*
* //TODO support where - talk to WL team?
*
* @param {Object} allParams [result of calling req.params.all()]
* @return {Array} [an array of populate objects to be used with Model.populate]
*/
function parsePopulateParam( allParams ) {
//each object in here will be passed into Model.populate()
var populators = []
//grab the populate param from the request
var populateParam = req.param('populate')
// If `where` parameter is a string, try to interpret it as JSON
if (sails.util.isString(populateParam)) {
populators.push({path : populateParam})
}
console.log(populateParam)
//if no populate params, just return an empty array.
if(!populateParam){
return populators;
}
return populators
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment