Skip to content

Commit

Permalink
Added blueprint controller back into core (apps may still customize b…
Browse files Browse the repository at this point in the history
…lueprints by creating api/blueprints/[find|create|update|destroy].js overrides)
  • Loading branch information
mikermcneil committed Jan 17, 2014
1 parent 85b8b82 commit d03b2eb
Show file tree
Hide file tree
Showing 6 changed files with 377 additions and 9 deletions.
5 changes: 4 additions & 1 deletion .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
// Suppress warnings about "weird constructions"
// i.e. allow code like:
// (new (function OneTimeUsePrototype () { } ))
"supernew": true
"supernew": true,

// Allow backwards, node-dependency-style commas
"laxcomma": true

// "bitwise": true,
// "camelcase": true,
Expand Down
61 changes: 61 additions & 0 deletions lib/hooks/blueprints/actions/create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Create
* (blueprint action)
*
*/
module.exports = function genericCreate (req, res) {

// Get access to `sails` (globals might be disabled) and look up the model.
var sails = req._sails;
var Model = sails.models[req.options.model];

// If no model exists for this controller, it's a 404.
if ( !Model ) return res.notFound();



// The name of the parameter to use for JSONP callbacks
var JSONP_CALLBACK_PARAM = 'callback';

// if req.transport is falsy or doesn't contain the phrase "socket"
// and JSONP is enabled for this action, we'll say we're "isJSONPCompatible"
var isJSONPCompatible = req.options.jsonp && ! ( req.transport && req.transport.match(/socket/i) );


// Create data object (monolithic combination of all parameters)
// Omit the JSONP callback parameter (if this is isJSONPCompatible)
// and params whose values are `undefined`
var data = req.params.all();
if (isJSONPCompatible) { data = sails.util.omit(data, JSONP_CALLBACK_PARAM); }




// Create new instance of model using data from params
Model.create(data).exec(function created (err, newInstance) {

// 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);

// // If 'silent' is set, don't use the built-in pubsub
// if (!req.options.silent) {
// // TODO: enable pubsub in blueprints again when new syntax if fully fleshed out
// sails.publish(newInstance, { method: 'create', data: newInstance.toJSON });
// }

// Set status code (HTTP 201: Created)
res.status(201);

// Send JSONP-friendly response if it's supported
if ( req.options.jsonp ) {
return res.jsonp(newInstance.toJSON());
}

// Otherwise, strictly JSON.
else {
return res.json(newInstance.toJSON());
}
});
};
59 changes: 59 additions & 0 deletions lib/hooks/blueprints/actions/destroy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
*
*/
module.exports = function destroy (req, res) {
// Locate and validate id parameter
var id = req.param('id');
if (!id) {
return res.badRequest('No id provided.');
}

// Get access to `sails` (globals might be disabled) and look up the model.
var sails = req._sails;
var Model = sails.models[req.options.model];

// If no model exists for this controller, it's a 404.
if ( !Model ) return res.notFound();

// The name of the parameter to use for JSONP callbacks
var JSONP_CALLBACK_PARAM = 'callback';

// if req.transport is falsy or doesn't contain the phrase "socket"
// and JSONP is enabled for this action, we'll say we're "isJSONPCompatible"
var isJSONPCompatible = req.options.jsonp && ! ( req.transport && req.transport.match(/socket/i) );




// Otherwise, find and destroy the model in question
Model.findOne(id).exec(function found(err, result) {

// 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);

if (!result) return res.notFound();

Model.destroy(id).exec(function destroyed(err) {
// 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);

// If 'silent' is set, don't use the built-in pubsub
// if (!req.options.silent) {
// TODO: enable pubsub in blueprints again when new syntax if fully fleshed out
// sails.publish(newInstance, { method: 'destroy', data: newInstance.toJSON });
// }

// Respond with JSON or JSONP
if ( isJSONPCompatible ) {
return res.jsonp(result);
}
else {
return res.json(result);
}
});
});
};
157 changes: 157 additions & 0 deletions lib/hooks/blueprints/actions/find.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/**
* 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`
*/

module.exports = function find (req, res) {

// Get access to `sails` (globals might be disabled) and look up the model.
var sails = req._sails;
var Model = sails.models[req.options.model];

// If no model exists for this controller, it's a 404.
if ( !Model ) return res.notFound();

// The name of the parameter to use for JSONP callbacks
var JSONP_CALLBACK_PARAM = 'callback';

// if req.transport is falsy or doesn't contain the phrase "socket"
// and JSONP is enabled for this action, we'll say we're "isJSONPCompatible"
var isJSONPCompatible = req.options.jsonp && ! ( req.transport && req.transport.match(/socket/i) );






/**
* If a valid id was specified, find the particular instance with that id.
*/
if (req.param('id')) {
Model.findOne(req.param('id')).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();

// // TODO: enable pubsub in blueprints again when new syntax if fully fleshed out
// req.socket.subscribe(newInstance);

// toJSON() the instance.
matchingRecord = matchingRecord.toJSON();

// Otherwise serve a JSON(P) API
if ( isJSONPCompatible ) {
return res.jsonp(matchingRecord);
}
else {
return res.json(matchingRecord);
}
});
}


/**
* If no id was specified, find instances matching the specified criteria.
*/
else {

// Lookup for records that match the specified criteria
Model.find({
limit: req.param('limit') || undefined,
skip: req.param('skip') || req.param('offset') || undefined,
sort: req.param('sort') || req.param('order') || undefined,
where: parseWhereParam(req.params.all()) || undefined
}).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();

// // TODO: enable pubsub in blueprints again when new syntax if fully fleshed out
// req.socket.subscribe(matchingRecords);

// toJSON() all of the model instances
matchingRecords = sails.util.invoke(matchingRecords, 'toJSON');

// Otherwise serve a JSON(P) API
if ( isJSONPCompatible ) {
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 = sails.util.omit(allParams, ['limit', 'skip', 'sort']);
where = sails.util.omit(allParams, function (p){ if (sails.util.isUndefined(p)) return true; });
if (isJSONPCompatible) { where = sails.util.omit(where, JSONP_CALLBACK_PARAM); }
}

return where;
}

};

69 changes: 69 additions & 0 deletions lib/hooks/blueprints/actions/update.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* Update Record
*
* An API call to update a model instance with the specified `id`,
* treating the other unbound parameters as attributes.
*
* @param {Integer|String} id - the unique id of the particular record you'd like to update
* @param * - values to set on the record
*
*/
module.exports = function update (req, res) {

// Locate and validate id parameter
var id = req.param('id');
if (!id) {
return res.badRequest('No id provided.');
}

// Get access to `sails` (globals might be disabled) and look up the model.
var sails = req._sails;
var Model = sails.models[req.options.model];

// If no model exists for this controller, it's a 404.
if ( !Model ) return res.notFound();

// The name of the parameter to use for JSONP callbacks
var JSONP_CALLBACK_PARAM = 'callback';

// if req.transport is falsy or doesn't contain the phrase "socket"
// and JSONP is enabled for this action, we'll say we're "isJSONPCompatible"
var isJSONPCompatible = req.options.jsonp && ! ( req.transport && req.transport.match(/socket/i) );

// Create data object (monolithic combination of all parameters)
// Omit the JSONP callback parameter (if this is isJSONPCompatible)
var data = req.params.all();
if (isJSONPCompatible) { data = sails.util.omit(data, JSONP_CALLBACK_PARAM); }
// TODO: and params whose values are `undefined`





// Otherwise find and update the models in question
Model.update(id, data).exec(function updated(err, models) {
// 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);
if(!models) return res.serverError('No instances returned from update.');
if (models.length === 0) return res.notFound();

// Because this should only update a single record and update
// returns an array, just use the first item
var model = models[0];

// If 'silent' is set, don't use the built-in pubsub
// if (!req.options.silent) {
// TODO: enable pubsub in blueprints again when new syntax if fully fleshed out
// sails.publish(newInstance, { method: 'update', data: newInstance.toJSON });
// }

if ( isJSONPCompatible ) {
return res.jsonp(model.toJSON());
}
else {
return res.json(model.toJSON());
}
});
};
Loading

0 comments on commit d03b2eb

Please sign in to comment.