/*jshint laxcomma: true, smarttabs: true, node:true, esnext:true */
'use strict';
/**
* Mixin class providing functionality for listing endpoints
* @module tastypie/lib/resource/list
* @author Eric Satterwhite
* @since 1.0.1
* @requires debug
* @requires class
* @requires class/options
* @requires boom
* @requires async
* @requires mout/collection/forEach
* @requires tastypie/lib/http
* @requires tastypie/lib/class
**/
var Boom = require('boom')
, EventEmitter = require('events').EventEmitter
, async = require('async')
, isString = require('mout/lang/isString')
, each = require('mout/collection/forEach')
, debug = require('debug')("tastypie:resources:list")
, Class = require('../class')
, http = require('../http')
, {annotate} = require('../utility')
, List
;
/**
* @mixin
* @alias module:tastypie/lib/resource/list
* @extends EventEmitter
*/
List = new Class({
inherits: EventEmitter
/**
* Internal method used during the `post_list` method
* @protected
* @method module:tastypie/lib/resource/list#create_object
* @param {Bundle} bundle A bundle representing the current request
* @param {module:tastypie/lib/resource~Nodeback} callback a callback function to call when the operation is complete
**/
, create_object: function create_object( bundle, callback ){
var e = Boom.notImplemented( "create_object is not implemented" );
e.req = bundle.req;
e.res = bundle.res;
callback( e );
}
/**
* disaptches a list request operating on a collection of objects.
* If any additional check / balances or processing needs to occur before a request is actually
* dispatched to the handler, this would be a good place to do that.
* @method module:tastypie/lib/resource/list#dispatch_list
* @param {Request} request A hapijs request object
* @param {Function} reply A hapis reply function
**/
, dispatch_list: function list( req, reply ){
return this.dispatch( 'list', this.bundle( req, reply ) );
}
/**
* Top level function used to handle get requests for listing endpoints. It handles paging and serialization
* @method module:tastypie/lib/resource/list#get_list
* @param {Bundle} bundle A bundle representing the current request
**/
, get_list: function get_list( bundle ){
this.get_objects( bundle, ( e, objects ) => {
var _obs = objects
, query = bundle.req.query
, uri = bundle.req.path
, page = this.options.paginator
, offset = query.offset
, limit = query.limit
, prop = this.options.collection
, max = this.options.max
, to_serialize
;
if( e ) return this.emit('error', annotate(e, bundle) );
_obs = objects || '[]';
if( isString( _obs ) || Buffer.isBuffer( _obs ) ){
_obs = JSON.parse(_obs)
}
_obs = this.sort( _obs );
to_serialize = page(uri, limit, query.offset, _obs, _obs.length, max, prop);
async.map( to_serialize[ prop ],( item, done ) => {
this.full_dehydrate( item, bundle, done );
}, ( err, results ) => {
if( err ) return this.emit('error', annotate(err, bundle) );
to_serialize[ prop ] = results;
bundle.data = to_serialize;
page = to_serialize = null;
this.respond( bundle );
});
});
}
/**
* Internal method used to retrieve a full list of objects for a resource
* @method module:tastypie/lib/resource/list#get_objects
* @param {module:tastypie/lib/resource~Bundle} bundle
* @param {module:tastypie/lib/resource~Nodeback} callback callback function to call when data retrieval is
**/
, get_objects: function get_objects( bundle, callback ){
var e = Boom.notImplemented( "get_objects is not implemented" );
e.req = bundle.req;
e.res = bundle.res;
callback( e );
}
/**
* High level function called in response to an OPTIONS request. Returns with an Allow header and empty body
* @method module:tastypie/lib/resource/detail#options_detail
* @param {module:tastypie/lib/resource~Bundle} bundle An object represneting the current `OPTIONS` request
**/
, options_list: function options_list( bundle ){
bundle.data = null;
this.respond( bundle, null, null, ( err, reply ) => {
let methods = [];
each( this.options.allowed.list,function( value, key ){
if( value ){
methods.push( key.toUpperCase() );
}
});
reply.header('Allow',methods.join(','));
});
}
/**
* Top level method used to handle post request to listing endpoints. Used to create new instances
* of the associated resource
* @method module:tastypie/lib/resource/list#post_list
* @param {Bundle} bundle An object represneting the current `POST` request
**/
, post_list: function post_list( bundle ){
var response = http.created
, format = this.format( bundle, this.options.serializer.types )
, that = this
;
this.deserialize( bundle.req.payload, format, function( err, data ){
bundle = that.bundle(bundle.req, bundle.res, data );
// create_object must save the object
that.create_object( bundle, function( err, bndl ){
if( err ){
err.res = bundle.res;
err.req = bundle.req;
return that.emit( 'error', err );
}
if( !that.options.returnData ){
bundle.data = null;
return that.respond( bndl, http.noContent );
}
that.full_dehydrate( bndl.object, bndl, function( err, data ){
bndl.data = data;
return that.respond( bndl, response );
});
});
});
}
});
module.exports = List;