Exemplo n.º 1
0
    self[assnKey] = function (name, options) {
      var opts = options || {}
        , assn = reg[self.name].associations[assnKey] || {}
        , assnName = name
        , modelName = opts.model || name;

      // Normalize inflection; we don't care which they use
      assnName = utils.inflection.singularize(assnName);
      modelName = utils.inflection.singularize(modelName);

      assn[assnName] = {
        model: modelName
      };

      reg[self.name].associations[assnKey] = assn;

      // Set up foreign keys
      // FIXME: Hack, let other models get defined first
      // Should probably listen for an event that signals
      // base models are set up
      var createForeignKey = function (assnName) {
        return function () {
          var ownerModelName
            , ownedModelName
            , idKey
            , datatype
            , def;

          if (assnKey == 'belongsTo') {
            ownerModelName = modelName;
            ownedModelName = self.name;
            idKey = modelName;
          }
          else {
            ownerModelName = self.name;
            ownedModelName = modelName;
            idKey = self.name;
          }

          if (assnName == modelName) {
            idKey = utils.string.decapitalize(idKey) + 'Id'
          }
          else {
            idKey = utils.string.decapitalize(assnName) + idKey  + 'Id'
          }

          if (!reg[ownedModelName].properties[idKey]) {
            def = model[ownerModelName];
            datatype = def.autoIncrementId ? 'int' : 'string';

            reg[ownedModelName].properties[idKey] =
              new model.PropertyDescription(idKey, datatype);
          }
        }
      };

      setTimeout(createForeignKey(assnName), 0);
    };
Exemplo n.º 2
0
      this._createAssociation = function () {
        var args = Array.prototype.slice.call(arguments)
          , assnName = args.shift()
          , assnType = args.shift()
          , data = args.shift()
          , otherKeyName
          , selfKeyName
          , reg = model.descriptionRegistry
          , assn = reg[this.type].associations[assnType]
          , modelName
          , unsaved;

        // Bail out if the association doesn't exist
        if (!assn) {
          throw new Error('Model ' + this.type + ' does not have ' + assnType +
              ' association.');
        }

        modelName = assn[assnName].model;

        // Normalize inflection
        modelName = utils.inflection.singularize(modelName);
        assnName = utils.inflection.singularize(assnName);

        if (assnType == 'belongsTo') {
          if (!(data._saved && data.id)) {
            throw new Error('Item cannot have a belongTo association ' +
                'if the item it belongs to is not yet saved.');
          }
          otherKeyName = modelName;
          if (modelName != assnName) {
            otherKeyName = assnName + otherKeyName;
          }
          otherKeyName = utils.string.decapitalize(otherKeyName + 'Id');
          this[otherKeyName] = data.id;
          unsaved = data._unsavedAssociations || [];
          unsaved.push(this);
          data._unsavedAssociations = unsaved;
        }
        else {
          if (!(this._saved && this.id)) {
            throw new Error('Item cannot have a hasOne/hasMany association ' +
                'if it is not yet saved.');
          }
          selfKeyName = this.type;
          if (modelName != assnName) {
            selfKeyName = assnName + selfKeyName;
          }
          selfKeyName = utils.string.decapitalize(selfKeyName + 'Id');
          data[selfKeyName] = this.id;
          unsaved = this._unsavedAssociations || [];
          unsaved.push(data);
          this._unsavedAssociations = unsaved;
        }
      };
Exemplo n.º 3
0
Arquivo: index.js Projeto: nlf/model
 ['hasMany', 'hasOne', 'belongsTo'].forEach(function (k) {
   var assnKeys
     , assnKey
     , modelName
     , keyForCreate = k == 'hasMany' ? 'add' : 'set'
     , createMethod = function (type, keyName, assnType) {
         return function () {
           var args = Array.prototype.slice.call(arguments);
           args.unshift(assnType);
           args.unshift(keyName);
           self[type + 'Association'].apply(self, args);
         };
       };
   if ((assnKeys = associations[k])) {
     for (assnKey in assnKeys) {
       modelName = k == 'hasMany' ?
           utils.inflection.singularize(assnKey) : assnKey;
       // this.getBooks({}, {}, function () {}); =>
       // this.getAssociation('Book', 'hasMany', {}, {}, function () {});
       self['get' + assnKey] = createMethod('get', modelName, k);
       // this.addBook(book); =>
       // this.createAssociation('Book', 'hasMany', book);
       self[keyForCreate + modelName] = createMethod('create', modelName, k);
     }
   }
 });
Exemplo n.º 4
0
  var _createTable = function (name, props, opts) {
        var sql = ''
          , tableName
          , prop
          , propArr = []
          , datatype;

        tableName = utils.inflection.pluralize(name);
        tableName = utils.string.snakeize(tableName);

        sql += 'DROP TABLE IF EXISTS ' + tableName + ';\n';
        sql += 'CREATE TABLE ' + tableName + ' (\n';

        // Use DB auto-increment
        if (opts.autoIncrementId) {
          propArr.push('  id SERIAL PRIMARY KEY');
        }
        // Use string UUIDs
        else {
          propArr.push('  id varchar(256) PRIMARY KEY');
        }

        for (var p in props) {
          prop = props[p];
          datatype = datatypeMap[prop.datatype];
          // Only create cols for known datatypes
          if (datatype) {
            propArr.push('  ' + utils.string.snakeize(prop.name) + ' ' +
                datatypeMap[prop.datatype]);
            }
        }
        sql += propArr.join(',\n') + '\n';
        sql += ');\n';
        return sql;
      };
Exemplo n.º 5
0
function pullLatest (model) {
  var type = model.type;
  var id   = model.id;

  if (!store[ type ]) {
    store[ type ] = {};
  }

  var latest;

  if (store[ type ][ id ]){
    latest = store [ type ][ id ];
  } else {

    // Initialize a model and return it:
    latest = model.toJSON();
    for( var associationName in reg[ type ].associations.hasMany ) {
      var assocKey = utils.inflection.pluralize( associationName );
      assocKey = utils.string.camelize( assocKey );
      latest[ assocKey ] = [];
    }

  }
  return latest;
}
Exemplo n.º 6
0
 , cleanup = function (modelName, next) {
     var removes = []
       , chain
       , Model
       , plural = utils.inflection.pluralize(modelName)
       , singular = utils.inflection.singularize(modelName);
     
     Model = geddy.model[modelName];
     
     //Wipe out all existing posts
     Model.all(function (err, models) {
       assert.strictEqual(err, null, 'Setup: Could not fetch '+plural);
       
       if(models.length) {
         removes = _.map(models, function (item) {
           return {
             func: Model.remove
           , args: [item.id]
           , callback: null
           };
         });
         
         chain = new utils.async.AsyncChain(removes);
         
         chain.last = function () {
           Model.all(function (err, models) {
             assert.strictEqual(err, null, 'Setup: Could not check if '+plural+' were removed');
             
             assert.strictEqual(0, models.length, 'Setup: '+plural+' weren\'t removed');
             
             next();
           });
         }
         
         chain.run();
       }
       else {
         next();
       }
     });
   }
Exemplo n.º 7
0
Arquivo: index.js Projeto: Duvel/model
 , create = function () {
     var c
       , tableName;
     if ((c = collections.shift())) {
       tableName = utils.inflection.pluralize(c);
       tableName = utils.string.snakeize(tableName);
       self.client._db.createCollection(c, {}, create);
     }
     else {
       callback();
     }
   };
Exemplo n.º 8
0
Arquivo: index.js Projeto: Duvel/model
 , drop = function () {
     var c
       , tableName
       , collection;
     if ((c = collections.shift())) {
       tableName = utils.inflection.pluralize(c);
       tableName = utils.string.snakeize(tableName);
       collection = self.client._db.collection(tableName);
       collection.drop(drop);
     }
     else {
       callback();
     }
   };
Exemplo n.º 9
0
function arrayize (store) {
  var response = {};

  for(var ModelName in store){
    var plural = utils.inflection.pluralize( ModelName );
    var camelized = utils.string.camelize( plural );
    response[ camelized ] = [];

    for( var id in store[ ModelName ] ){
      response[ camelized ].push( store[ ModelName ][id] );
    }
  }
  return response;
}
Exemplo n.º 10
0
Arquivo: index.js Projeto: efdi/model
            (function (assnName) {
              var methodName = k == 'hasMany' ?
                      utils.inflection.pluralize(assnName) : assnName
                , keyForCreate = k == 'hasMany' ? 'add' : 'set';

              // get can be singular or plural, depending on hasMany/hasOne
              // this.getBooks({}, {}, function () {}); =>
              // this.getAssociation('Book', 'hasMany', {}, {}, function () {});
              self['get' + methodName] = createMethod('_get', assnName, k);

              // add/set is always singular, just use assnName for method
              // this.addBook(book); =>
              // this.createAssociation('Book', 'hasMany', book);
              self[keyForCreate + assnName] = createMethod('_create', assnName, k);
            })(assnName);
Exemplo n.º 11
0
  this.renderTemplate = function (data, callback) {
    var self = this
      , templater = new Templater()
      , content = '';

    if (!this.template || !this.layout) {
      // Format directory names
      var dirName = utils.inflection.pluralize(this.name);
      dirName = utils.string.snakeize(dirName);
    }

    // Get template if not set
    this.template = this.template || 'app/views/' + dirName + '/' + this.params.action;

    // Get layout if not set or set empty layout if `false`
    if (typeof this.layout === 'boolean' && !this.layout) {
      // Use custom Geddy empty template in `lib/template/templates`
      this.layout = 'geddy/empty';
    }
    else {
      this.layout = this.layout || 'app/views/layouts/' + dirName;
    }

    templater.addListener('data', function (data) {
      // Buffer for now, but we could stream
      content += data;
    });
    templater.addListener('end', function () {
      callback(content);
    });

    // Mix in controller instance-vars -- don't overwrite data properties
    for (var p in this) {
      if (!data[p]) {
        data[p] = this[p];
      }
    };

    templater.render(data, {
        layout: this.layout
      , template: this.template
      , controller: this.name
      , action: this.params.action
    });
  };
Exemplo n.º 12
0
  before: function (scope, cb) {

    // scope.args are the raw command line arguments.
    //
    // e.g. if someone runs:
    // $ sails generate mvc user find create update
    // then `scope.args` would be `['user', 'find', 'create', 'update']`
    if (!scope.args[0]) {
      return cb( new Error('Please provide a name for this mvc.') );
    }

    // scope.rootPath is the base path for this generator
    //
    // e.g. if this generator specified the target:
    // './Foobar.md': { copy: 'Foobar.md' }
    //
    // And someone ran this generator from `/Users/dbowie/sailsStuff`,
    // then `/Users/dbowie/sailsStuff/Foobar.md` would be created.
    if (!scope.rootPath) {
      return cb( INVALID_SCOPE_VARIABLE('rootPath') );
    }


    // Attach defaults
    _.defaults(scope, {
      createdAt: new Date()
    });

    //Names used on MVC
    scope.name = utils.string.decapitalize(scope.args[0]);
    scope.nameLower = scope.name.toLowerCase();
    scope.nameC = utils.string.capitalize(scope.name);
    scope.namePlural = utils.inflection.pluralize(scope.name);
    scope.namePluralC = utils.string.capitalize(scope.namePlural);
    
    // Decide the output filename for use in targets below:
    scope.controllerFilename = scope.nameC +"Controller"
    scope.localFilename = scope.nameC +"Local"

    //Process attributes
    var attributes = scope.args.slice(1);
    scope.hasI18N = hasI18N(attributes);
    scope.languages = [];

    if(scope.hasI18N){
      scope.languages = attributes[attributes.length-1].split(':').slice(1);
      attributes = scope.args.slice(1,scope.args.length-1);      
    }

    scope.attributes = _.map(attributes, processAttr(scope.hasI18N));    
    scope.attributesNOI18N = _.map(attributes, processAttr(scope.hasI18N));
    scope.hasImage = hasImage(scope.attributes);

    if(scope.hasI18N){
      scope.attributesI18N = _.remove(scope.attributesNOI18N, function(attr) { return attr.i18n; });
    }

    //print attributes
    _.forEach(scope.attributes, function(attr) {console.log(clc.green(attr.name)+" type "+ clc.red(attr.type) +" and i18n on "+ attr.i18n);});

    //Escape chars for EJS
    scope.S = "<%"
    scope.SE = "<%="
    scope.SP = "<%-"
    scope.E = "%>"

    //modify package.json
    updatePackage (scope.rootPath, scope.hasImage, scope.hasI18N);

    //adapt targets
    if(scope.hasImage){
      addImageFiles(this.targets)
    }
    if(scope.hasI18N){
      addI18NFiles(this.targets, scope.languages)
    }

    // When finished, we trigger a callback with no error
    // to begin generating files/folders as specified by
    // the `targets` below.
    cb();
  },
Exemplo n.º 13
0
Arquivo: index.js Projeto: Duvel/model
_collectionizeModelName = function (name) {
  var collectionName = utils.inflection.pluralize(name);
  collectionName = utils.string.snakeize(collectionName);
  return collectionName;
};
Exemplo n.º 14
0
_bucketizeModelName = function (name) {
  var bucketName = utils.inflection.pluralize(name);
  bucketName = utils.string.snakeize(bucketName);
  return bucketName;
};
Exemplo n.º 15
0
Arquivo: index.js Projeto: efdi/model
      this._createAssociation = function () {
        var args = Array.prototype.slice.call(arguments)
          , assnName = args.shift()
          , assnType = args.shift()
          , data = args.shift()
          , otherKeyName
          , selfKeyName
          , reg = model.descriptionRegistry
          , assn = reg[this.type].associations[assnType]
          , modelName
          , through
          , joinInstance
          , unsaved
          , params;

        // Bail out if the association doesn't exist
        if (!assn) {
          throw new Error('Model ' + this.type + ' does not have ' + assnType +
              ' association.');
        }

        modelName = assn[assnName].model
        through = assn[assnName].through;

        // Normalize inflection
        modelName = utils.inflection.singularize(modelName);
        assnName = utils.inflection.singularize(assnName);

        otherKeyName = modelName;
        selfKeyName = this.type;
        // Prefix named assns
        if (modelName != assnName) {
          otherKeyName = assnName + otherKeyName;
          selfKeyName = assnName + selfKeyName;
        }
        otherKeyName = utils.string.decapitalize(otherKeyName + 'Id');
        selfKeyName = utils.string.decapitalize(selfKeyName + 'Id');

        // belongsTo
        if (assnType == 'belongsTo') {
          if (!(data._saved && data.id)) {
            throw new Error('Item cannot have a belongTo association ' +
                'if the item it belongs to is not yet saved.');
          }
          this[otherKeyName] = data.id;
          unsaved = data._unsavedAssociations || [];
          unsaved.push(this);
          data._unsavedAssociations = unsaved;
        }
        // hasOne, hasMany (through)
        else {
          if (!(this._saved && this.id)) {
            throw new Error('Item cannot have a hasOne/hasMany association ' +
                'if it is not yet saved.');
          }

          // ---------------
          // FIXME: This chained saving happens automagically, so
          // validation errors in the instances just throw, with
          // no visible .errors property
          // ---------------
          // Through assn
          if (through) {
            through = utils.string.getInflection(through, 'constructor', 'singular');
            // Create join-instance
            params = {};
            params[selfKeyName] = this.id;
            joinInstance = model[through].create(params);
            unsaved = this._unsavedAssociations || [];
            // Mark actual assn for chained save
            unsaved.push(data);
            // When this item gets saved, update the join-instance
            // with the correct assn foreign key
            data.on('save', function () {
              joinInstance[otherKeyName] = data.id;
            });
            // Mark join-instance for chained save
            unsaved.push(joinInstance);
            this._unsavedAssociations = unsaved;
          }
          else {
            data[selfKeyName] = this.id;
            unsaved = this._unsavedAssociations || [];
            unsaved.push(data);
            this._unsavedAssociations = unsaved;
          }
        }
      };
Exemplo n.º 16
0
Arquivo: index.js Projeto: efdi/model
      this._getAssociation = function () {
        var args = Array.prototype.slice.call(arguments)
          , assnName = args.shift()
          , assnType = args.shift()
          , callback = args.pop()
          , query
          , opts
          , otherKeyName
          , selfKeyName
          , keyName
          , queryName
          , reg = model.descriptionRegistry
          , assn = reg[this.type].associations[assnType]
          , modelName
          , through;

        // Bail out if the association doesn't exist
        if (!assn) {
          throw new Error('Model ' + this.type + ' does not have ' + assnType +
              ' association.');
        }

        modelName = assn[assnName].model;
        through = assn[assnName].through;

        // Normalize inflection
        modelName = utils.inflection.singularize(modelName);
        assnName = utils.inflection.singularize(assnName);

        // Has query object
        if (assnType == 'hasMany') {
          query = args.shift() || {};
        }
        // No query object, create one
        else {
          query = {};
        }
        // Lastly grab opts if any
        opts = args.shift() || {};

        // I belong to the other model; look for the item
        // whose id matches my foreign key for that model
        if (assnType == 'belongsTo') {
          otherKeyName = modelName;
          if (modelName != assnName) {
            otherKeyName = assnName + otherKeyName;
          }
          otherKeyName = utils.string.decapitalize(otherKeyName + 'Id');
          query.id = this[otherKeyName];
        }
        // The other model belongs to me; look for any
        // items whose foreign keys match my id
        // (hasOne is just a special case of hasMany)
        else {
          selfKeyName = this.type;
          if (modelName != assnName) {
            selfKeyName = assnName + selfKeyName;
          }
          selfKeyName = utils.string.decapitalize(selfKeyName + 'Id');
          query[selfKeyName] = this.id;
        }

        queryName = assnType == 'hasMany' ? 'all' : 'first';

        // -----------
        // FIXME: This is pretty terrible -- should really do these
        // async queries in some sort of composable Promisey API
        // -----------
        // Through's -- get the join-model instances, and re-fetch
        // actual assns
        if (through) {
          through = utils.string.getInflection(through, 'constructor', 'singular');
          model[through][queryName](query, opts, function (err, data) {
            var query = {}
              , idColName = utils.string.getInflection(modelName,
                    'property', 'singular') + 'Id'
              , idParam;
            if (err) {
              return callback(err, null);
            }
            if (assnType == 'hasMany') {
              idParam = [];
              data.forEach(function (item) {
                idParam.push(item[idColName]);
              });
            }
            else {
              idParam = item[idColName];
            }
            query.id = idParam;
            model[modelName][queryName](query, opts, callback);
          });
        }
        // Normal assns, just do the damn query
        else {
          model[modelName][queryName](query, opts, callback);
        }
      };
Exemplo n.º 17
0
  , Strategy = function (content, options, cb) {

      // Where to redirect to on a success event
      var params = this.params
        , type = options.type
          // Check the content for an errors hash
        , isFailure = (content.errors && typeof content.errors === 'object')
        , response
        , redirect

          // Default status messages
        , successStatuses = {
            create: options.type + ' created'
          , update: options.type + ' updated'
          , remove: options.type + ' removed'
          }

          // Default routes to redirect to
        , successRedirects = {
            create: {id: content.id}
          , update: {id: content.id}
          , destroy: {}
          }
        , failureRedirects = {
            create: {action: 'add'}
          , update: {action:'edit', id: content.id}
          , update: {action:'edit', id: content.id}
          }

          /**
          * Select the appropriate redirect URL for the current situation
          * @return {Boolean|Object} - false if no redirect
          *   should occur, a route object if otherwise
          */
        , getRedirect = function () {
            var location = options.location
                // Select the appropriate defaults for the situation
              , redirects = isFailure ? failureRedirects : successRedirects;

            // Don't redirect if the user explicitly set location to false
            if(location === false) {
              return false;
            }
            else {
              // If the user defined a location, use that
              if(location) {
                return location;
              }
              else {
                // Otherwise look it up in the defaults
                return redirects[params.action] || false;
              }
            }
          }

          /**
          * Sets the appropriate flash message for the current situation
          */
        , doFlash = function () {
            var status;

            // User can suppress flashes with {silent: true}
            if(options.silent) {
              return;
            }

            // Find an appropriate flash message
            if(options.status) {
              // Use a user provided status if possible

              this.flash.set(isFailure ? 'error' : 'success', options.status);
            }
            else {

              if(isFailure) {
                this.flash.set('error', content.errors);
              }
              else {
                status = successStatuses[params.action.toLowerCase()];

                // Don't set a flash if no message was found
                if(status) {
                  this.flash.set('success', status);
                }
              }
            }
          };

      // Determine if `content` is a model object
      if (typeof content === 'object' && content.type && content.toObj) {

        // Set the flash message
        doFlash.apply(this);

        // Determine if we need to redirect
        redirect = getRedirect.apply(this);

        if(redirect) {
          this.redirect(redirect);
          if(cb) {
            cb();
          }
        }
        else {
          // Respond in the style
          // {model: {attr: val, attr2: val...}, params: {}}
          response = {params: params};
          response[type] = content.toObj();
          response[type].id = content.id;

          this.respond.call(this, response, options, cb);
        }
      }
      // Determine if `content` is a collection of models
      else if(content instanceof Array) {
        if(!type) {
          throw new Error(
            'Cannot determine model type from empty array, specify one in opts');
        }

        type = utils.inflection.pluralize(type);

        response = {params: params};
        response[type] = [];

        for(var i=0, ii=content.length; i<ii; i++) {
          response[type][i] = content[i].toObj();
          response[type][i].id = content[i].id;
        }

        this.respond(response, options, cb);
      }
      else if (content instanceof Error) {
        // Format error for template-rendering
        response = utils.mixin({}, content);
        if (geddy.config.detailedErrors) {
          // 'message' and 'stack' are not enumerable
          response.message = content.message || '';
          response.stack = content.stack || '';
        }
        else {
          response.message = '';
          response.stack = '';
        }
        options.statusCode = content.statusCode || 500;
        this.respond(response, options);
      }
      else {
        console.dir(content);
        throw new Error(
          'respondWith expects either a model, a collection of models, or an Error object');
      }
    };
Exemplo n.º 18
0
function pluralize (relationName) {
  var plural = utils.inflection.pluralize( relationName );
  var camelized = utils.string.camelize( plural );
  return camelized;
}
Exemplo n.º 19
0
      this._getAssociation = function () {
        var args = Array.prototype.slice.call(arguments)
          , assnName = args.shift()
          , assnType = args.shift()
          , callback = args.pop()
          , query
          , opts
          , otherKeyName
          , selfKeyName
          , keyName
          , queryName
          , reg = model.descriptionRegistry
          , assn = reg[this.type].associations[assnType]
          , modelName;

        // Bail out if the association doesn't exist
        if (!assn) {
          throw new Error('Model ' + this.type + ' does not have ' + assnType +
              ' association.');
        }

        modelName = assn[assnName].model;

        // Normalize inflection
        modelName = utils.inflection.singularize(modelName);
        assnName = utils.inflection.singularize(assnName);

        // Has query object
        if (assnType == 'hasMany') {
          query = args.shift() || {};
        }
        // No query object, create one
        else {
          query = {};
        }
        // Lastly grab opts if any
        opts = args.shift() || {};

        // I belong to the other model; look for the item
        // whose id matches my foreign key for that model
        if (assnType == 'belongsTo') {
          otherKeyName = modelName;
          if (modelName != assnName) {
            otherKeyName = assnName + otherKeyName;
          }
          otherKeyName = utils.string.decapitalize(otherKeyName + 'Id');
          query.id = this[otherKeyName];
        }
        // The other model belongs to me; look for any
        // items whose foreign keys match my id
        // (hasOne is just a special case of hasMany)
        else {
          selfKeyName = this.type;
          if (modelName != assnName) {
            selfKeyName = assnName + selfKeyName;
          }
          selfKeyName = utils.string.decapitalize(selfKeyName + 'Id');
          query[selfKeyName] = this.id;
        }

        queryName = assnType == 'hasMany' ? 'all' : 'first';
        model[modelName][queryName](query, opts, callback);
      };