Source: lib/fields/related.js

/*jshint laxcomma: true, smarttabs: true, node: true, unused: true*/
'use strict';
/**
 * A field for dealing with related resources
 * @module tastypie/fields/related
 * @author Eric Satterwhite
 * @since 0.5.0
 * @requires async
 * @requires debug
 * @requires tastypie/lib/class
 * @requires tastypie/lib/utility
 * @requires tastypie/lib/fields/api
 */

var debug    = require('debug')('tastypie:field:related')
  , async    = require('async')
  , ApiField = require( './api' )
  , Class    = require( '../class' )
  , toModule = require('../utility').toModule
  , RelatedField
  ;

/**
 * @constructor
 * @alias module:tastypie/fields/related
 * @extends module:tastypie/fields/api
 * @param {Object} options
 * @param {String} [options.root=os.tempDir()]
 * @param {String} [options.dir]
 */
RelatedField = new Class({
  inherits:ApiField
  ,options:{
    to:null,
    minimal: false,
    full: false
  }
  ,is_related: true
  ,constructor: function(to, options){
    if( arguments.length === 1){
      options = to;
      to = options.to;
    }

    this.parent('constructor', options);
    this.options.to = to;
    this.instance = new this.cls();
  }
  ,dehydrate: function( obj,cb ){
    var that = this;
    if( !this.instance.options.apiname ){
      debug('setting field %s related apiname - %s', this.options.name, this.resource.options.apiname );
      this.instance.setOptions({
        apiname: this.resource.options.apiname
      });
    }

    this.parent('dehydrate', obj, function( err, value ){
      if( err ){
        return cb && cb( err, null );
      }

      if( that.options.full ){
        return cb( err, value );
      } else if( that.options.minimal ){
        async.map(
          value,
          that.to_minimal.bind( that ),
          cb
        );
      } else{
        return cb( err, value && value.map(that.instance.to_uri.bind( that.instance ) ) );
      }
    });
  }
  /**
   * converts a full object in to a minimal representation
   * @method module:tastypie/lib/field/related#to_minimal
   * @param {Object} obj A template object instance to introspect
   * @param {Function} callback a callback function to execute when the related field dehydration is completed
   **/
  ,to_minimal: function( obj, cb ){
    var label = this.instance.options.labelField || 'display'
      , that  = this
      , related_field
      ;
    related_field = this.instance.fields[label];
    related_field.dehydrate( obj, function( err, value ){
      var out = {};
      out.uri =  that.instance.to_uri( obj );
      out[  label ] = value;
      that = label = related_field = null;
      cb( null, out );
    });
  }
});


Object.defineProperties(RelatedField.prototype,{
  cls:{
    enumerable:false
    ,writeable: false
    ,get: function(){
            if( typeof this.options.to === 'string' ){
                this.options.to = toModule( this.options.to );
            }
            return this.options.to;
    }
  }
});

module.exports = RelatedField;