API Docs for:
Show:

File: index.js

var Factory, strgMethods;
strgMethods = require('strg_methods');

/**
@class Factory
@example
  new Factory(mongoose.model('name'), function() { return obj; });
@constructor
@param [model] {Object} The mongoose.model('name') or nothing if you want a plain factory Object
@param factory {Function} The factory Object
  @param factory.object {Object} The return Object of function, if you want you can include another factory in the obj/child. please look at the test/index.js ile in the repo how it is included
    @param [factory.object.key] {String|Number|Array} value 
    @param [factory.object.$child] {Object} you can nest children in other children as you wish. you can use empty children, too
    @param [factory.object.$child.child_name] {Object|Function}
@property model
@type Function|Object
@default factory
@property factory
@type Function
@property sequence
@type Number
@default 0
*/
function Factory(model, factory){
  this.model = model;
  this.factory = factory || model;
  this.sequenc = 0;
}

/**

builds a mongoose Object or a plain Object

@method build
@async
@param [options={}] {Object} options field, if nothing specified then return one default doc
  @param [options.$factory="default"] {String} write the child factories down seperated by space which you want to build. $child{first: {$child: second{}}} would be options.$factory = "first second"
  @param [options.$seq=this.sequenc] {Number} when provided resets sequence with given num
  @param [options.$doc={}] {Object} Set the value of the doc to create
    @param [options.$doc.$factory=options.$factory] {String} same as options.$factory
    @param [options.$doc.$num=1] {Number} set number of docs which should be created
    @param [options.$doc.key] {String|Number|Array} value which should be merged with parent factory and this factory
  @param [options.$docs=[{}]] {Array} if you want to build multiple different docs, basically the same as options.$doc in an Array -> [ options.$doc, options.$doc ]
@param callback {Function} callback
*/
Factory.prototype.build = function (options, callback){
  if (typeof options == "function"){
    callback = options;
    options = {};
  }
  this.sequenc = (typeof options.$seq === 'undefined') ? this.sequenc : options.$seq;
  this._getNewDocs(options, function (err, docs) {
    if (err) { return callback(err, null); }
    docs = (docs.length === 1 ) ? docs[0] : docs;
    return callback(err, docs);
  });
};

/**

checks if new mongoose.model(object) got a wrong field value

@method _compareObjSync
@private
@param mObj {Object} mongoose Object
@param obj {Object} plain Object
@return {Object} if no error then false else new Error
*/
Factory.prototype._compareObjSync = function (mObj, obj) {
  if(this.model === this.factory){ return false; }
  obj._id = "";
  mObj = Object.keys(mObj.toObject()).sort();
  obj = Object.keys(obj).sort();
  for (var i = 0; i < mObj.length; i++) {
    if (mObj[i] != obj[i]) {
      return new Error(obj[i]+' isnt the right Schema var type');
    }
  }
  return false;
};

/**

merges obj2 into obj1

@method _mergeObjsSync
@private
@param obj1 {Object} Object
@param obj2 {Object} Object
@return {Object} merged object
*/
Factory.prototype._mergeObjsSync = function (obj1, obj2) {
  var attrname, obj3;
  obj3 = {};
  for (attrname in obj1) {
    obj3[attrname] = obj1[attrname];
  }
  for (attrname in obj2) {
    obj3[attrname] = obj2[attrname];
  }
  return obj3;
};

/**

handles the options field from build

@method _getNewDocs
@private
@async
@param options {Object} options field
@param callback {Function} callback
@returns {Function} callback(err, docs) 
*/
Factory.prototype._getNewDocs = function (options, callback) {
  var $doc, docs, $docsOpt, factory, $num, _i, _len;
  docs = [];
  options.$docs = (options.$doc) ? [options.$doc] : options.$docs;
  $docsOpt = options.$docs || [{}];
  for (_i = 0, _len = $docsOpt.length; _i < _len; _i++) {
    $doc = $docsOpt[_i];
    $num = $doc.$num || 1;
    factory = (typeof $doc.$factory === "undefined") ? options.$factory : $doc.$factory;
    this._getFactory(factory, function(err, $fctry) {
      if (err) {return callback(err, null);}
      $factory = $fctry;
    });
    delete $doc.$factory;
    delete $doc.$num;
    for (__i = 0, __len = $num; __i < __len; __i++) {
      this.sequenc++;
      docs.push(this._newDoc($factory, $doc));
      err = this._compareObjSync(docs[_i], this._mergeObjsSync($factory, $doc));
    }
  }
  return callback(err, docs);
}; 

/**

get factory object

@method _getFactory
@private
@async
@param options {Object} options field
@param callback {Function} callback
@returns {Function} callback(err, factoryObject) 
*/
Factory.prototype._getFactory = function (options, callback){
  var factory, err, child, _len, _i, child_factory;
  if (typeof options == "function"){
    callback = options;
    options = "";
  }
  factory = this.factory();
  child = factory.$child;
  delete factory.$child;
  if(options && options != "default"){
    factories = options.split(' ');
    for (_i = 0, _len = factories.length; _i < _len; _i++) {
      child_factory = child[factories[_i]];
      if (typeof child_factory === "undefined") { return callback(new Error(factories[_i]+' isnt a child factory'), null); }
      child_factory = (typeof child_factory === 'function') ? child_factory() : child_factory;
      child = child_factory.$child;
      delete child_factory.$child;
      factory = this._mergeObjsSync(factory, child_factory);
    }
  }
  return callback(err, factory);
};

/**

set new doc

@method _newDoc
@private
@param [options={}] {Object} options field
@param callback {Function} callback
@return {Object} mongoose factory ? mongoose Object : plain Object 
*/
Factory.prototype._newDoc = function (factory, doc){
  if(this.model === this.factory){
    return this.stringMethods(this._mergeObjsSync(factory, doc));
  } else {
    return new this.model(this.stringMethods(this._mergeObjsSync(factory, doc)));
  }
};

/**

applies strMethods.all() to each value of object

@method stringMethods
@uses strgMethods
@private
@param doc {Object} takes a document
@return {Object} object with applied strgMethods
*/
Factory.prototype.stringMethods = function (doc){
  for (var key in doc) {
    if (doc.hasOwnProperty(key)) {
      Strg = new strgMethods(doc[key], this.sequenc);
      doc[key] = Strg.all();
    }
  }
  return doc;
};

/** 

accepts options as factory.build

@example
  //with mocha you can pass done() as a callback
  factory.create({$doc: {$num: 3}}, done());
  factory.create(function(err, docs){
    //insert here whatever you want
  });

@method create
@async
@param [options={}] {Object} options field
@param [callback] {Function} callback
@return {Function} with (err, docs)
*/
Factory.prototype.create = function (options, callback) {
  if(this.model === this.factory){ throw new Error("you cant use a mongoose method on a plain factory object"); }
  if (typeof options == "function"){
    callback = options;
    options = {};
  } else if (typeof options == "undefined"){
    options = {};
  }
  this.build(options, function (err, docs) {
    if (err && typeof callback == "function") { return callback(err, null); }
    this.model.create(docs, function (err, docs){
      if (typeof callback == "function"){
        return callback(err, docs);
      }
    });
  });
};

/**

instead of factory.model.find
see http://mongoosejs.com/docs/api.html#model_Model.find

@method find
@uses mongoose.model.find
*/
Factory.prototype.find =  function (args) {
  if(this.model === this.factory){ throw new Error("you cant use a mongoose method on a plain factory object"); }
  this.model.find.call(arguments);
};

/**

instead of factory.model.count
see http://mongoosejs.com/docs/api.html#model_Model.count

@method count
@uses mongoose.model.count
*/
Factory.prototype.count =  function (args) {
  if(this.model === this.factory){ throw new Error("you cant use a mongoose method on a plain factory object"); }
  this.model.count.call(arguments);
};

/** 

instead of factory.model.findOne
see http://mongoosejs.com/docs/api.html#model_Model.findOne

@method findOne
@uses mongoose.model.findOne
*/
Factory.prototype.findOne = function (args) {
  if(this.model === this.factory){ throw new Error("you cant use a mongoose method on a plain factory object"); }
  this.model.findOne.call(arguments);
};

/**

removes docs which matches options from factory.model

@method remove
@async
@uses mongoose.model.remove
@param [options={}] options field as in mongoose.model.remove
@param [callback] {Function} callback
@return {Function} returns the same callback as http://mongoosejs.com/docs/api.html#model_Model.remove
*/
Factory.prototype.remove = function (options, callback) {
  if(this.model === this.factory){ throw new Error("you cant use a mongoose method on a plain factory object"); }
  if (typeof options == "undefined") {
    options = {};
  }
  if (typeof options == "function") {
    callback = options;
    options = {};
  }
  this.model.remove(options, function (err, num){
    if (typeof callback != "undefined") {
      callback(err, num);
    }
  });
};

module.exports = Factory;