11var _ = require ( 'lodash' ) ;
2+ var RelUtils = require ( './utilities/relationship-utils' ) ;
23var utils = require ( './utils' ) ;
34
45module . exports = function serializer ( type , data , relations , options ) {
@@ -25,6 +26,13 @@ module.exports = function serializer (type, data, relations, options) {
2526 resultData . links = makeLinks ( options . topLevelLinks ) ;
2627 }
2728
29+ /**
30+ * If we're requesting to sideload relationships...
31+ */
32+ if ( options . requestedIncludes ) {
33+ handleIncludes ( resultData , options . requestedIncludes , relations ) ;
34+ }
35+
2836 return resultData ;
2937} ;
3038
@@ -231,3 +239,101 @@ function makeLinks (links, item) {
231239
232240 return retLinks ;
233241}
242+
243+ /**
244+ * Handles serializing the requested includes to a seperate included property
245+ * per JSON API spec.
246+ * @private
247+ * @memberOf {Serializer}
248+ * @param {Object } resp
249+ * @param {Array<String>|String }
250+ * @throws {Error }
251+ * @return {undefined }
252+ */
253+ function handleIncludes ( resp , includes , relations ) {
254+ var resources = _ . isArray ( resp . data ) ? resp . data : [ resp . data ] ;
255+
256+ if ( typeof includes === 'string' ) {
257+ includes = [ includes ] ;
258+ }
259+
260+ if ( ! _ . isArray ( includes ) ) {
261+ throw RelUtils . getInvalidIncludesError ( 'JSON API unable to detect valid includes' ) ;
262+ }
263+
264+ var embedded = resources . map ( function subsituteEmbeddedForIds ( resource ) {
265+ return includes . map ( function ( include ) {
266+ var relation = relations [ include ] ;
267+ var propertyKey = relation . keyFrom ;
268+ var plural = utils . pluralForModel ( relation . modelTo ) ;
269+ var embeds = [ ] ;
270+
271+ // If relation is belongsTo then pk and fk are the other way around
272+ if ( relation . type === 'belongsTo' || relation . type === 'referencesMany' ) {
273+ propertyKey = relation . keyTo ;
274+ }
275+
276+ if ( ! relation ) {
277+ throw RelUtils . getInvalidIncludesError ( 'Can\'t locate relationship "' + include + '" to include' ) ;
278+ }
279+
280+ resource . relationships [ include ] = resource . relationships [ include ] || { } ;
281+
282+ if ( resource . relationships [ include ] && resource . attributes [ include ] ) {
283+ if ( _ . isArray ( resource . attributes [ include ] ) ) {
284+ embeds = resource . attributes [ include ] . map ( function ( rel ) {
285+ rel = utils . clone ( rel ) ;
286+ return createCompoundIncludes ( rel , propertyKey , relation . keyTo , plural ) ;
287+ } ) ;
288+ embeds = _ . compact ( embeds ) ;
289+
290+ resource . relationships [ include ] . data = resource . attributes [ include ] . map ( function ( relData ) {
291+ return {
292+ id : String ( relData [ propertyKey ] ) ,
293+ type : plural
294+ } ;
295+ } ) ;
296+ } else {
297+ var rel = utils . clone ( resource . attributes [ include ] ) ;
298+ var compoundIncludes = createCompoundIncludes ( rel , propertyKey , relation . keyFrom , plural ) ;
299+
300+ resource . relationships [ include ] . data = {
301+ id : String ( resource . attributes [ include ] [ propertyKey ] ) ,
302+ type : plural
303+ } ;
304+ embeds . push ( compoundIncludes ) ;
305+ }
306+ delete resource . attributes [ relation . keyFrom ] ;
307+ delete resource . attributes [ relation . keyTo ] ;
308+ delete resource . attributes [ include ] ;
309+ }
310+ return embeds ;
311+ } ) ;
312+ } ) ;
313+
314+ if ( embedded . length ) {
315+ resp . included = _ . flattenDeep ( embedded ) ;
316+ }
317+ }
318+
319+ /**
320+ * Creates a compound include object.
321+ * @private
322+ * @memberOf {Serializer}
323+ * @param {Object } relationship
324+ * @param {String } key
325+ * @param {String } type
326+ * @return {Object }
327+ */
328+ function createCompoundIncludes ( relationship , key , fk , type ) {
329+ var compoundInclude = makeRelation ( type , String ( relationship [ key ] ) ) ;
330+
331+ // remove the id key since its part of the base compound document, not part of attributes
332+ delete relationship [ key ] ;
333+ delete relationship [ fk ] ;
334+
335+ // The rest of the data goes in the attributes
336+ compoundInclude . attributes = relationship ;
337+
338+ return compoundInclude ;
339+ }
0 commit comments