writing:function(){
   data.fields=[{name:'id', type:'hidden', reguired:true}];
   data.formFields={published:1, language:1};
   data.componentName='com_'+data.projectName;
   data.modelItemName=data.modelListName=data.name;
   data.names={
     item:{
       controller:s.capitalize(data.projectName)+'Controller'+s.capitalize(data.name),
       model:s.capitalize(data.projectName)+'Model'+s.capitalize(data.name),
       table:s.capitalize(data.projectName)+'Table'+s.capitalize(data.name)
     },
     list:{
       controller:s.capitalize(data.projectName)+'Controller'+s.capitalize(data.name),
       model:s.capitalize(data.projectName)+'Model'+s.capitalize(data.name)
     }
   };
   if(data.list){
     data.modelItemName=pluralize.singular(data.name);
     if(type=='controller'){
       data.names.item.model=pluralize.singular(data.names.item.model);
     }else if(type=='model'){
       data.names.item.table=pluralize.singular(data.names.item.table);
     }
   }
   this.data=data;
   this.fs.copyTpl(
     this.templatePath('../../crud/templates/'+pluralize(this.generatorType)+'/'+this.generatorType+data.list+'.php'),
     data.name+'.php',
     this
   );
 }
示例#2
0
    return async (obj, options, { context }) => {
      // Hack to be able to handle permissions for each query.
      const ctx = Object.assign(_.clone(context), {
        request: Object.assign(_.clone(context.request), {
          graphql: null,
        }),
      });

      // Execute policies stack.
      const policy = await strapi.koaMiddlewares.compose(policiesFn)(ctx);

      // Policy doesn't always return errors but they update the current context.
      if (
        _.isError(ctx.request.graphql) ||
        _.get(ctx.request.graphql, 'isBoom')
      ) {
        return ctx.request.graphql;
      }

      // Something went wrong in the policy.
      if (policy) {
        return policy;
      }

      // Resolver can be a function. Be also a native resolver or a controller's action.
      if (_.isFunction(resolver)) {
        context.params = Query.convertToParams(options.input.where || {});
        context.request.body = options.input.data || {};

        if (isController) {
          const values = await resolver.call(null, context);

          if (ctx.body) {
            return {
              [pluralize.singular(name)]: ctx.body,
            };
          }

          const body = values && values.toJSON ? values.toJSON() : values;

          return {
            [pluralize.singular(name)]: body,
          };
        }

        return resolver.call(null, obj, options, context);
      }

      // Resolver can be a promise.
      return resolver;
    };
示例#3
0
function resource (item, included, responseModel) {
  let model = this.modelFor(pluralize.singular(item.type))
  if (!model) {
    throw new Error('The JSON API response had a type of "' + item.type + '" but Devour expected the type to be "' + responseModel + '".')
  }

  if (model.options.deserializer) {
    return model.options.deserializer.call(this, item)
  }

  let deserializedModel = {}
  if (item.id) {
    deserializedModel.id = item.id
  }

  _.forOwn(model.attributes, (value, key) => {
    if (isRelationship(value)) {
      deserializedModel[key] = attachRelationsFor.call(this, model, value, item, included, key)
    } else if (item.attributes) {
      deserializedModel[key] = item.attributes[key]
    }
  })

  var params = ['meta', 'links']
  params.forEach(function (param) {
    if (item[param]) {
      deserializedModel[param] = item[param]
    }
  })

  return deserializedModel
}
示例#4
0
 .forEach(function (externalResource) {
   if (db.get(externalResource).value) {
     var query = {}
     var singularResource = pluralize.singular(name)
     query[singularResource + 'Id'] = resource.id
     resource[externalResource] = db.get(externalResource).filter(query).value()
   }
 })
示例#5
0
 .forEach(function (externalResource) {
   if (db.object[externalResource]) {
     var query = {}
     var singularResource = pluralize.singular(name)
     query[singularResource + 'Id'] = resource.id
     resource[externalResource] = db(externalResource).where(query)
   }
 })
示例#6
0
文件: table-utils.js 项目: aychoi/api
Table.pluralizeTerms = function(terms) {
	var pluralTerms = [];
	for(index in terms) {
		pluralTerms.push(pluralize.plural(terms[index]));
		pluralTerms.push(pluralize.singular(terms[index]));
	}
	return pluralTerms;
}
示例#7
0
 .forEach((externalResource) => {
   if (db.get(externalResource).value) {
     const query = {}
     const singularResource = pluralize.singular(name)
     query[`${singularResource}Id`] = resource.id
     resource[externalResource] = db.get(externalResource).filter(query).value()
   }
 })
示例#8
0
exports.singularize = function (str) {
  var words = str.split(' ')

  for (var x in words) {
    words[x] = pluralize.singular(words[x])
  }

  return words.join(' ')
}
示例#9
0
 [].concat(e).forEach(externalResource => {
   if (db.get(externalResource).value) {
     const query = {}
     const singularResource = pluralize.singular(name)
     query[`${singularResource}${opts.foreignKeySuffix}`] = resource.id
     resource[externalResource] = db
       .get(externalResource)
       .filter(query)
       .value()
   }
 })
示例#10
0
 fields.forEach((field) => {
   if (field.isObject) {
     sections = [
       ...sections,
       ...extraSchemaDesc(modelName + capitalize(field.isArray ? singular(field.name) : field.name), field.fields),
       {
         name: modelName + capitalize(field.isArray ? singular(field.name) : field.name),
         fields: field.fields
       }
     ];
   }
   if (field.modifiers && field.modifiers.enum) {
     sections = [
       ...sections,
       {
         enum: field.graphQLType,
         values: field.modifiers.enum
       }
     ];
   }
 });
示例#11
0
      _embed.forEach(function (otherResource) {

        if (otherResource
          && otherResource.trim().length > 0
          && db.object[otherResource]) {
          var query = {}
          var prop = pluralize.singular(req.params.resource) + 'Id'
          query[prop] = id
          resource[otherResource] = db(otherResource).where(query)

        }
      })
示例#12
0
  /**
   * HELPERS
   * - getName
  */
  getName() {
    const { tab, id, data } = this.state;

    if (id === 'new') {
      return `New ${singular(tab)}`;
    }

    if (data.title) {
      return data.title;
    }

    return '-';
  }
示例#13
0
function resource (item, included, responseModel, useCache = false) {
  if (useCache) {
    const cachedItem = cache.get(item.type, item.id)
    if (cachedItem) return cachedItem;
  }

  let model = this.modelFor(pluralize.singular(item.type))
  if (!model) throw new Error('The JSON API response had a type of "' + item.type + '" but Devour expected the type to be "' + responseModel + '".');

  if (model.options.deserializer) return model.options.deserializer.call(this, item);

  let deserializedModel = {id: item.id};

  _.forOwn(item.attributes, (value, attr) => {
    const attrConfig = model.attributes[attr];

    if (_.isUndefined(attrConfig) && attr !== "id")  {
      console.warn(`Resource response contains attribute "${attr}", but it is not present on model config and therefore not deserialized.`);
    } else {
      deserializedModel[attr] = value;
    }
  });

  // Important: cache before parsing relationships to avoid infinite loop
  cache.set(item.type, item.id, deserializedModel);

  _.forOwn(item.relationships, (value, rel) => {
    const relConfig = model.attributes[rel];

    if (_.isUndefined(relConfig))
      console.warn(`Resource response contains relationship "${rel}", but it is not present on model config and therefore not deserialized.`)
    else if (!isRelationship(relConfig))
      console.warn(`Resource response contains relationship "${rel}", but it is present on model config as a plain attribute.`)
    else
      deserializedModel[rel] =
        attachRelationsFor.call(this, model, relConfig, item, included, rel);
  });


  var params = ['meta', 'links']
  params.forEach(function (param) {
    if (item[param]) {
      deserializedModel[param] = item[param]
    }
  })

  cache.set(item.type, item.id, deserializedModel);

  return deserializedModel
}
示例#14
0
 fields.forEach((f, i) => {
   if (i > 0) {
     final = final + '\n';
   }
   final += ' '.repeat(indentSpace);
   final += f.name + ': ';
   if (f.isArray) final += '[';
   if (f.isObject) {
     if (!input) {
       if (f.isArray) {
         final += modelName + capitalize(singular(f.name));
       } else {
         final += modelName + capitalize(f.name);
       }
     } else {
       if (f.isArray) {
         final += modelName + capitalize(singular(f.name)) + 'Input';
       } else {
         final += modelName + capitalize(f.name) + 'Input';
       }
     }
   } else if (primitiveGraphQLTypes.includes(f.graphQLType)) {
     if (input && f.graphQLType === 'File') {
       final += 'Upload';
     } else {
       final += f.graphQLType;
     }
   } else if (f.isSchema) {
     final += f.graphQLType + (input ? 'Input' : '');
   } else if (f.modifiers && f.modifiers.enum) {
     final += f.graphQLType;
   } else {
     final += input ? 'ID' : f.graphQLType;
   }
   if (f.isArray) final += ']';
 });
示例#15
0
 desc.fields.forEach((f) => {
   t += `${' '.repeat(indentSpace)}${f.name}: `;
   if (f.isArray) t += '[';
   if (f.isObject) {
     if (f.isArray) {
       t += `${desc.name}${capitalize(singular(f.name))}`;
     } else {
       t += `${desc.name}${capitalize(f.name)}`;
     }
   } else {
     t += f.graphQLType;
   }
   if (f.isArray) t += ']';
   t += '\n';
 });
示例#16
0
      Object.keys(queries).forEach(type => {
        // The query cannot be built.
        if (_.isError(queries[type])) {
          console.error(queries[type]);
          strapi.stop();
        }

        // Only create query if the function is available.
        if (_.isFunction(queries[type])) {
          if (type === 'singular') {
            Object.assign(acc.query, {
              [`${pluralize.singular(name)}(id: String!)`]: model.globalId
            });
          } else {
            Object.assign(acc.query, {
              [`${pluralize.plural(name)}(sort: String, limit: Int, start: Int, where: JSON)`]: `[${model.globalId}]`
            });
          }

          _.merge(acc.resolver.Query, {
            [type === 'singular' ? pluralize.singular(name) : pluralize.plural(name)]: queries[type]
          });
        }
      });
 children.forEach(x => {
     let singular = pluralize.singular(x.name);
     parent[x.name] = function () {
         if (arguments.length > 0)
             throw new Error(`The access method ${x.name}() does not accept parameters. Did you mean to invoke ${singular}(id) instead?`);
         let proxy = new resource_proxy(client, x.name, parent, x._actions, x.methods);
         add_child_accessors(client, proxy, x._children);
         return proxy;
     };
     parent[singular] = id => {
         if (!id)
             throw new Error("The 'id' parameter is required.");
         let proxy = new resource_proxy(client, x.name, parent, x._actions, x.methods, id);
         add_child_accessors(client, proxy, x._children);
         return proxy;
     };
 });
示例#18
0
 desc.fields.forEach((f) => {
   t += `${' '.repeat(indentSpace)}${f.name}: `;
   if (f.isArray) t += '[';
   if (f.isObject) {
     if (f.isArray) {
       t += `${desc.name}${capitalize(singular(f.name))}Input`;
     } else {
       t += `${desc.name}${capitalize(f.name)}Input`;
     }
   } else if (f.primitive) {
     t += f.graphQLType === 'File' ? 'Upload' : f.graphQLType;
   } else {
     t += 'ID';
   }
   if (f.isArray) t += ']';
   t += '\n';
 });
示例#19
0
  // Rewrite URL (/:resource/:id/:nested -> /:nested) and request query
  function get (req, res, next) {
    // TODO throw error
    var resource = db.get(req.params.resource).getById(utils.toNative(req.params.id), req.params.resource).value()
    var resourceIdName = db.id(req.params.resource).value()

    var nested = db.get(req.params.nested).getById(utils.toNative(req.params.id), req.params.nested).value()
    var nestedIdName = db.id(req.params.nested).value()

    if (nestedIdName === 'id') {
        var prop = pluralize.singular(req.params.nested)
        nestedIdName = prop + 'Id'
    }

    if (resource[nestedIdName].length) {
        req.url = '/' + req.params.nested
        req.query[nestedIdName] = resource[nestedIdName]
    } else {
        req.url = '/' + req.params.nested + '/' + resource[nestedIdName]
    }
    next()
  }
    constructor(client, name, parent, actions, methods, parent_id) {
        this._name = name;
        this._children = [];
        this._actions = actions || {
            find: true,
            create: true,
            update: true,
            patch: true,
            delete: true,
            find_by_id: true,
            delete_by_id: true,
            find_by_named_query: true
        };
        this._client = client;
        this._follow_names = [];
        this._template_params = {};
        this._parent = parent || null;
        this._parent_id = parent_id || null;
        this._singular_name = pluralize.singular(name);
        this._id_name = `${this._singular_name}_id`;

        let current = this;
        while (true) {
            this._follow_names.unshift(current.name);
            if (current.parent_id)
                this._template_params[current.id_name] = current.parent_id;
            current = current._parent;
            if (!current || !current.name)
                break;
        }

        if (methods) {
            methods.forEach(x => {
                if (x.func)
                    this[x.name] = x.func.bind(this);
            });
        }
    }
示例#21
0
 getTypename() {
   return capitalizeFirstLetter(pluralize.singular(this.relationTo()));
 }
示例#22
0
            _.forEach(definition.attributes, (details, name) => {
              const verbose = _.get(
                utilsModels.getNature(details, name, undefined, model.toLowerCase()),
                'verbose'
              ) || '';

              // Build associations key
              utilsModels.defineAssociations(
                model.toLowerCase(),
                definition,
                details,
                name
              );

              let globalId;
              const globalName = details.model || details.collection || '';

              // Exclude polymorphic association.
              if (globalName !== '*') {
                globalId = details.plugin ?
                  _.get(strapi.plugins,`${details.plugin}.models.${globalName.toLowerCase()}.globalId`):
                  _.get(strapi.models, `${globalName.toLowerCase()}.globalId`);
              }

              switch (verbose) {
                case 'hasOne': {
                  const FK = details.plugin ?
                    _.findKey(
                      strapi.plugins[details.plugin].models[details.model].attributes,
                      details => {
                        if (
                          details.hasOwnProperty('model') &&
                          details.model === model &&
                          details.hasOwnProperty('via') &&
                          details.via === name
                        ) {
                          return details;
                        }
                      }
                    ):
                    _.findKey(
                      strapi.models[details.model].attributes,
                      details => {
                        if (
                          details.hasOwnProperty('model') &&
                          details.model === model &&
                          details.hasOwnProperty('via') &&
                          details.via === name
                        ) {
                          return details;
                        }
                      }
                    );

                  const columnName = details.plugin ?
                    _.get(strapi.plugins, `${details.plugin}.models.${details.model}.attributes.${FK}.columnName`, FK):
                    _.get(strapi.models, `${details.model}.attributes.${FK}.columnName`, FK);

                  loadedModel[name] = function() {
                    return this.hasOne(
                      GLOBALS[globalId],
                      columnName
                    );
                  };
                  break;
                }
                case 'hasMany': {
                  const columnName = details.plugin ?
                    _.get(strapi.plugins, `${details.plugin}.models.${globalId.toLowerCase()}.attributes.${details.via}.columnName`, details.via):
                    _.get(strapi.models[globalId.toLowerCase()].attributes, `${details.via}.columnName`, details.via);

                  // Set this info to be able to see if this field is a real database's field.
                  details.isVirtual = true;

                  loadedModel[name] = function() {
                    return this.hasMany(GLOBALS[globalId], columnName);
                  };
                  break;
                }
                case 'belongsTo': {
                  loadedModel[name] = function() {
                    return this.belongsTo(
                      GLOBALS[globalId],
                      _.get(details, 'columnName', name)
                    );
                  };
                  break;
                }
                case 'belongsToMany': {
                  const collection = details.plugin ?
                    strapi.plugins[details.plugin].models[details.collection]:
                    strapi.models[details.collection];

                  const collectionName = _.get(details, 'collectionName') ||
                    _.map(
                      _.sortBy(
                        [
                          collection.attributes[
                            details.via
                          ],
                          details
                        ],
                        'collection'
                      ),
                      table => {
                        return _.snakeCase(
                          pluralize.plural(table.collection) +
                            ' ' +
                            pluralize.plural(table.via)
                        );
                      }
                    ).join('__');

                  const relationship = _.clone(
                    collection.attributes[details.via]
                  );

                  // Force singular foreign key
                  relationship.attribute = pluralize.singular(
                    relationship.collection
                  );
                  details.attribute = pluralize.singular(details.collection);

                  // Define PK column
                  details.column = utils.getPK(model, strapi.models);
                  relationship.column = utils.getPK(
                    details.collection,
                    strapi.models
                  );

                  // Sometimes the many-to-many relationships
                  // is on the same keys on the same models (ex: `friends` key in model `User`)
                  if (
                    details.attribute + '_' + details.column ===
                    relationship.attribute + '_' + relationship.column
                  ) {
                    relationship.attribute = pluralize.singular(details.via);
                  }

                  // Set this info to be able to see if this field is a real database's field.
                  details.isVirtual = true;

                  loadedModel[name] = function() {
                    if (
                      _.isArray(_.get(details, 'withPivot')) &&
                      !_.isEmpty(details.withPivot)
                    ) {
                      return this.belongsToMany(
                        GLOBALS[globalId],
                        collectionName,
                        relationship.attribute + '_' + relationship.column,
                        details.attribute + '_' + details.column
                      ).withPivot(details.withPivot);
                    }

                    return this.belongsToMany(
                      GLOBALS[globalId],
                      collectionName,
                      relationship.attribute + '_' + relationship.column,
                      details.attribute + '_' + details.column
                    );
                  };
                  break;
                }
                case 'morphOne': {
                  const model = details.plugin ?
                    strapi.plugins[details.plugin].models[details.model]:
                    strapi.models[details.model];

                  const globalId = `${model.collectionName}_morph`;

                  loadedModel[name] =  function() {
                    return this
                      .morphOne(GLOBALS[globalId], details.via, `${definition.collectionName}`)
                      .query(qb => {
                        qb.where(_.get(model, `attributes.${details.via}.filter`, 'field'), name);
                      });
                  }
                  break;
                }
                case 'morphMany': {
                  const collection = details.plugin ?
                    strapi.plugins[details.plugin].models[details.collection]:
                    strapi.models[details.collection];

                  const globalId = `${collection.collectionName}_morph`;

                  loadedModel[name] =  function() {
                    return this
                      .morphMany(GLOBALS[globalId], details.via, `${definition.collectionName}`)
                      .query(qb => {
                        qb.where(_.get(collection, `attributes.${details.via}.filter`, 'field'), name);
                      });
                  }
                  break;
                }
                case 'belongsToMorph':
                case 'belongsToManyMorph': {
                  const association = definition.associations
                    .find(association => association.alias === name);

                  const morphValues = association.related.map(id => {
                    let models = Object.values(strapi.models).filter(model => model.globalId === id);

                    if (models.length === 0) {
                      models = Object.keys(strapi.plugins).reduce((acc, current) => {
                        const models = Object.values(strapi.plugins[current].models).filter(model => model.globalId === id);

                        if (acc.length === 0 && models.length > 0) {
                          acc = models;
                        }

                        return acc;
                      }, []);
                    }

                    if (models.length === 0) {
                      strapi.log.error('Impossible to register the `' + model + '` model.');
                      strapi.log.error('The collection name cannot be found for the morphTo method.');
                      strapi.stop();
                    }

                    return models[0].collectionName;
                  });

                  // Define new model.
                  const options = {
                    tableName: `${definition.collectionName}_morph`,
                    [definition.collectionName]: function () {
                      return this
                        .belongsTo(
                          GLOBALS[definition.globalId],
                          `${definition.collectionName}_id`
                        );
                    },
                    related: function () {
                      return this
                        .morphTo(name, ...association.related.map((id, index) => [GLOBALS[id], morphValues[index]]));
                    }
                  };

                  GLOBALS[options.tableName] = ORM.Model.extend(options);

                  // Set polymorphic table name to the main model.
                  target[model].morph = GLOBALS[options.tableName];

                  // Hack Bookshelf to create a many-to-many polymorphic association.
                  // Upload has many Upload_morph that morph to different model.
                  loadedModel[name] = function () {
                    if (verbose === 'belongsToMorph') {
                      return this.hasOne(
                        GLOBALS[options.tableName],
                        `${definition.collectionName}_id`
                      );
                    }

                    return this.hasMany(
                      GLOBALS[options.tableName],
                      `${definition.collectionName}_id`
                    );
                  };
                  break;
                }
                default: {
                  break;
                }
              }

              done();
            });
示例#23
0
                databaseUpdate.push(new Promise(async (resolve) => {
                  // Equilize database tables
                  const handler = async (table, attributes) => {
                    const tableExist = await ORM.knex.schema.hasTable(table);

                    const getType = (attribute, name) => {
                      let type;

                      if (!attribute.type) {
                        // Add integer value if there is a relation
                        const relation = definition.associations.find((association) => {
                          return association.alias === name;
                        });

                        switch (relation.nature) {
                          case 'oneToOne':
                          case 'manyToOne':
                            type = definition.client === 'pg' ? 'integer' : 'int';
                            break;
                          default:
                            return null;
                        }
                      } else {
                        switch (attribute.type) {
                          case 'text':
                          case 'json':
                            type = 'text';
                            break;
                          case 'string':
                          case 'enumeration':
                          case 'password':
                          case 'email':
                            type = 'varchar(255)';
                            break;
                          case 'integer':
                          case 'biginteger':
                            type = definition.client === 'pg' ? 'integer' : 'int';
                            break;
                          case 'float':
                            type = definition.client === 'pg' ? 'double precision' : 'double';
                            break;
                          case 'decimal':
                            type = 'decimal';
                            break;
                          case 'date':
                          case 'time':
                          case 'datetime':
                          case 'timestamp':
                            type = definition.client === 'pg' ? 'timestamp with time zone' : 'timestamp DEFAULT CURRENT_TIMESTAMP';
                            break;
                          case 'timestampUpdate':
                            type = definition.client === 'pg' ? 'timestamp with time zone' : 'timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP';
                            break;
                          case 'boolean':
                            type = 'boolean';
                            break;
                          default:
                        }
                      }

                      return type;
                    };

                    // Apply field type of attributes definition
                    const generateColumns = (attrs, start) => {
                      return Object.keys(attrs).reduce((acc, attr) => {
                        const attribute = attributes[attr];

                        const type = getType(attribute, attr);

                        if (type) {
                          acc.push(`${quote}${attr}${quote} ${type}`);
                        }

                        return acc;
                      }, start);
                    };

                    if (!tableExist) {
                      const columns = generateColumns(attributes, [`id ${definition.client === 'pg' ? 'SERIAL' : 'INT AUTO_INCREMENT'} NOT NULL PRIMARY KEY`]).join(',\n\r');

                      // Create table
                      await ORM.knex.raw(`
                        CREATE TABLE ${quote}${table}${quote} (
                          ${columns}
                        )
                      `);
                    } else {
                      const columns = Object.keys(attributes);

                      // Fetch existing column
                      const columnsExist = await Promise.all(columns.map(attribute =>
                        ORM.knex.schema.hasColumn(table, attribute)
                      ));

                      const columnsToAdd = {};

                      // Get columns to add
                      columnsExist.forEach((columnExist, index) => {
                        const attribute = attributes[columns[index]];

                        if (!columnExist) {
                          columnsToAdd[columns[index]] = attribute;
                        }
                      });

                      // Generate and execute query to add missing column
                      if (Object.keys(columnsToAdd).length > 0) {
                        const columns = generateColumns(columnsToAdd, []);
                        const queries = columns.reduce((acc, attribute) => {
                          acc.push(`ALTER TABLE ${quote}${table}${quote} ADD ${attribute};`)
                          return acc;
                        }, []).join('\n\r');

                        await ORM.knex.raw(queries);
                      }

                      // Execute query to update column type
                      await Promise.all(columns.map(attribute =>
                        new Promise(async (resolve) => {
                          const type = getType(attributes[attribute], attribute);

                          if (type) {
                            const changeType = definition.client === 'pg'
                              ? `ALTER COLUMN ${quote}${attribute}${quote} TYPE ${type} USING ${quote}${attribute}${quote}::${type}`
                              : `CHANGE ${quote}${attribute}${quote} ${quote}${attribute}${quote} ${type} `;

                            const changeRequired = definition.client === 'pg'
                              ? `ALTER COLUMN ${quote}${attribute}${quote} ${attributes[attribute].required ? 'SET' : 'DROP'} NOT NULL`
                              : `CHANGE ${quote}${attribute}${quote} ${quote}${attribute}${quote} ${type} ${attributes[attribute].required ? 'NOT' : ''} NULL`;

                            await ORM.knex.raw(`ALTER TABLE ${quote}${table}${quote} ${changeType}`);
                            await ORM.knex.raw(`ALTER TABLE ${quote}${table}${quote} ${changeRequired}`);
                          }

                          resolve();
                        })
                      ));
                    }
                  };

                  const quote = definition.client === 'pg' ? '"' : '`';

                  // Add created_at and updated_at field if timestamp option is true
                  if (loadedModel.hasTimestamps) {
                    definition.attributes['created_at'] = {
                      type: 'timestamp'
                    };
                    definition.attributes['updated_at'] = {
                      type: 'timestampUpdate'
                    };
                  }

                  // Equilize tables
                  await handler(loadedModel.tableName, definition.attributes);

                  // Equilize polymorphic releations
                  const morphRelations = definition.associations.find((association) => {
                    return association.nature.toLowerCase().includes('morphto');
                  });

                  if (morphRelations) {
                    const attributes = {
                      [`${loadedModel.tableName}_id`]: {
                        type: 'integer'
                      },
                      [`${morphRelations.alias}_id`]: {
                        type: 'integer'
                      },
                      [`${morphRelations.alias}_type`]: {
                        type: 'text'
                      },
                      [definition.attributes[morphRelations.alias].filter]: {
                        type: 'text'
                      }
                    };

                    await handler(`${loadedModel.tableName}_morph`, attributes);
                  }

                  // Equilize many to many releations
                  const manyRelations = definition.associations.find((association) => {
                    return association.nature === 'manyToMany';
                  });

                  if (manyRelations && manyRelations.dominant) {
                    const collection = manyRelations.plugin ?
                      strapi.plugins[manyRelations.plugin].models[manyRelations.collection]:
                      strapi.models[manyRelations.collection];

                    const attributes = {
                      [`${pluralize.singular(manyRelations.collection)}_id`]: {
                        type: 'integer'
                      },
                      [`${pluralize.singular(definition.globalId.toLowerCase())}_id`]: {
                        type: 'integer'
                      }
                    };

                    const table = _.get(manyRelations, 'collectionName') ||
                      _.map(
                        _.sortBy(
                          [
                            collection.attributes[
                              manyRelations.via
                            ],
                            manyRelations
                          ],
                          'collection'
                        ),
                        table => {
                          return _.snakeCase(
                            pluralize.plural(table.collection) +
                              ' ' +
                              pluralize.plural(table.via)
                          );
                        }
                      ).join('__');

                    await handler(table, attributes);
                  }

                  // Remove from attributes (auto handled by bookshlef and not displayed on ctb)
                  if (loadedModel.hasTimestamps) {
                    delete definition.attributes['created_at'];
                    delete definition.attributes['updated_at'];
                  }

                  resolve();
                }));
示例#24
0
 // Rewrite URL (/:resource/:id/:nested -> /:nested) and request query
 function get(req, res, next) {
   const prop = pluralize.singular(req.params.resource)
   req.query[`${prop}${opts.foreignKeySuffix}`] = req.params.id
   req.url = `/${req.params.nested}`
   next()
 }
示例#25
0
 route.path.split('/').forEach(function (element) {
     if (element) {
         handleDbFile(pluralize.singular(element));
     }
 });
示例#26
0
  // GET /:resource
  // GET /:resource?q=
  // GET /:resource?attr=&attr=
  // GET /:parent/:parentId/:resource?attr=&attr=
  // GET /*?*&_end=
  // GET /*?*&_start=&_end=
  function list (req, res, next) {
    // Test if resource exists
    if (!db.object.hasOwnProperty(req.params.resource)) {
      return res.sendStatus(404)
    }

    // Filters list
    var filters = {}

    // Result array
    var array

    // Remove _start, _end and _limit from req.query to avoid filtering using those
    // parameters
    var _start = req.query._start
    var _end = req.query._end
    var _sort = req.query._sort
    var _order = req.query._order
    var _limit = req.query._limit
    delete req.query._start
    delete req.query._end
    delete req.query._sort
    delete req.query._order
    delete req.query._limit

    if (req.query.q) {

      // Full-text search
      var q = req.query.q.toLowerCase()

      array = db(req.params.resource).filter(function (obj) {
        for (var key in obj) {
          var value = obj[key]
          if (utils.deepQuery(value, q)) {
            return true
          }
        }
      })

    } else {

      // Add :parentId filter in case URL is like /:parent/:parentId/:resource
      if (req.params.parent) {
        var parent = pluralize.singular(req.params.parent)
        filters[parent + 'Id'] = +req.params.parentId
      }

      // Add query parameters filters
      // Convert query parameters to their native counterparts
      for (var key in req.query) {
        // don't take into account JSONP query parameters
        // jQuery adds a '_' query parameter too
        if (key !== 'callback' && key !== '_') {
          filters[key] = utils.toNative(req.query[key])
        }
      }

      // Filter
      if (_(filters).isEmpty()) {
        array = db(req.params.resource).value()
      } else {
        array = db(req.params.resource).filter(filters)
      }
    }

    // Sort
    if (_sort) {
      _order = _order || 'ASC'

      array = _.sortBy(array, function (element) {
        return element[_sort]
      })

      if (_order === 'DESC') {
        array.reverse()
      }
    }

    // Slice result
    if (_end || _limit) {
      res.setHeader('X-Total-Count', array.length)
      res.setHeader('Access-Control-Expose-Headers', 'X-Total-Count')
    }

    _start = parseInt(_start, 10) || 0

    if (_end) {
      _end = parseInt(_end, 10)
      array = array.slice(_start, _end)
    } else if (_limit) {
      _limit = parseInt(_limit, 10)
      array = array.slice(_start, _start + _limit)
    }

    res.jsonp(array)
  }
示例#27
0
 // Rewrite URL (/:resource/:id/:nested -> /:nested) and request body
 function post (req, res, next) {
   var prop = pluralize.singular(req.params.resource)
   req.body[prop + 'Id'] = utils.toNative(req.params.id)
   req.url = '/' + req.params.nested
   next()
 }
 s : function() {
   return pluralize.singular( this.name );
 }
示例#29
0
    return {
      name: this.getFileName(name),
      commandName: _.snakeCase(this.getFileName(name)).replace(/_/g, ':')
    }
  },

  /**
   * Returns file name for the command file
   *
   * @method getFileName
   * @param  {String}    name
   * @return {String}
   */
  getFileName (name) {
    name = name.replace(/task/ig, '')
    return pluralize.singular(_.upperFirst(_.camelCase(name)))
  },

  /**
   * Returns file path for the command file
   *
   * @method getFilePath
   * @param  {String}    name
   * @param  {Object}    options
   * @return {String}
   */
  getFilePath (name, options) {
    return path.join(options.appRoot, options.appDir, options.dirs.tasks, this.getFileName(name)) + '.js'
  }
}
示例#30
0
  function handleRelation(infos, models, modelName, details, attribute, toDrop, onlyDrop) {
    if (_.isEmpty(_.get(rootModels[modelName].attributes, attribute + '.create'))) {
      _.set(rootModels[modelName].attributes, attribute + '.create', {
        drop: '',
        others: ''
      });
    }

    if (_.isEmpty(_.get(rootModels[modelName].attributes, attribute + '.delete'))) {
      _.set(rootModels[modelName].attributes, attribute + '.delete', {
        drop: '',
        others: ''
      });
    }

    // If it's a "one-to-one" relationship.
    if (infos.verbose === 'hasOne') {
      // Force singular foreign key.
      details.attribute = pluralize.singular(details.model);

      // Define PK column.
      details.column = utilsBookShelf.getPK(modelName, undefined, models);

      if (!toDrop) {
        tplRelationUp = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'relations', 'hasOne.template'), 'utf8');
        models[modelName].attributes[attribute].create.others += _.unescape(_.template(tplRelationUp)({
          tableName: modelName,
          attribute,
          details
        }));

        tplRelationDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'columns', 'dropColumn-unique.template'), 'utf8');
        models[modelName].attributes[attribute].delete.others += _.unescape(_.template(tplRelationDown)({
          tableName: modelName,
          attribute,
          details
        }));
      } else {
        tplRelationDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'columns', 'dropColumn-unique.template'), 'utf8');
        models[modelName].attributes[attribute].create.drop += _.unescape(_.template(tplRelationDown)({
          tableName: modelName,
          attribute,
          details
        }));

        tplRelationUp = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'relations', 'hasOne.template'), 'utf8');
        models[modelName].attributes[attribute].delete.drop += _.unescape(_.template(tplRelationUp)({
          tableName: modelName,
          attribute,
          details
        }));
      }
    } else if (infos.verbose === 'belongsTo') {
      // Force singular foreign key.
      details.attribute = pluralize.singular(details.model);

      // Define PK column.
      details.column = utilsBookShelf.getPK(modelName, undefined, models);

      if (infos.nature === 'oneToMany' || infos.nature === 'oneWay') {
        if (!toDrop) {
          tplRelationUp = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'relations', 'belongsTo.template'), 'utf8');
          rootModels[modelName].attributes[attribute].create.others += _.unescape(_.template(tplRelationUp)({
            tableName: modelName,
            attribute,
            details,
            nature: infos.nature
          }));

          tplRelationDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'columns', 'dropColumn.template'), 'utf8');
          rootModels[modelName].attributes[attribute].delete.drop += _.unescape(_.template(tplRelationDown)({
            tableName: modelName,
            attribute,
            details
          }));
        } else {
          tplRelationDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'columns', 'dropForeign.template'), 'utf8');
          rootModels[modelName].attributes[attribute].create.drop += _.unescape(_.template(tplRelationDown)({
            tableName: modelName,
            attribute,
            details
          }));

          tplRelationUp = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'relations', 'belongsTo.template'), 'utf8');
          rootModels[modelName].attributes[attribute].delete.others += _.unescape(_.template(tplRelationUp)({
            tableName: modelName,
            attribute,
            details,
            nature: infos.nature
          }));
        }
      } else {
        if (!toDrop) {
          tplRelationUp = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'relations', 'belongsTo-unique.template'), 'utf8');
          rootModels[modelName].attributes[attribute].create.others += _.unescape(_.template(tplRelationUp)({
            tableName: modelName,
            attribute,
            details
          }));

          tplRelationDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'columns', 'dropColumn-unique.template'), 'utf8');
          rootModels[modelName].attributes[attribute].delete.drop += _.unescape(_.template(tplRelationDown)({
            tableName: modelName,
            attribute,
            details
          }));
        } else {
          tplRelationDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'columns', 'dropColumn.template'), 'utf8');
          rootModels[modelName].attributes[attribute].create.drop += _.unescape(_.template(tplRelationDown)({
            tableName: modelName,
            attribute,
            details
          }));

          tplRelationUp = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'relations', 'belongsTo.template'), 'utf8');
          rootModels[modelName].attributes[attribute].delete.others += _.unescape(_.template(tplRelationUp)({
            tableName: modelName,
            attribute,
            details,
            nature: infos.nature
          }));
        }
      }
    } else if (infos.verbose === 'hasMany') {
      if (toDrop) {
        tplRelationDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'columns', 'dropForeign.template'), 'utf8');
        rootModels[modelName].attributes[attribute].create.drop += _.unescape(_.template(tplRelationDown)({
          tableName: modelName,
          attribute,
          details
        }));

        tplRelationUp = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'relations', 'belongsTo.template'), 'utf8');
        rootModels[modelName].attributes[attribute].delete.others += _.unescape(_.template(tplRelationUp)({
          tableName: modelName,
          attribute,
          details,
          nature: infos.nature
        }));
      }
    } else if (infos.verbose === 'belongsToMany') {
      // Otherwise if it's a "many-to-many" relationship.

      // Save the relationship.
      const relationship = models[details.collection].attributes[details.via];

      // Construct relation table name.
      const relationTable = _.map(_.sortBy([relationship, details], 'collection'), table => {
        return _.snakeCase(pluralize.plural(table.collection) + ' ' + pluralize.plural(table.via));
      }).join('__');

      // Force singular foreign key.
      relationship.attribute = pluralize.singular(relationship.collection);
      details.attribute = pluralize.singular(details.collection);

      // Define PK column.
      details.column = utilsBookShelf.getPK(modelName, undefined, models);
      relationship.column = utilsBookShelf.getPK(details.collection, undefined, models);

      // Avoid to create table both times.
      if (!rootModels.hasOwnProperty(relationTable) || !_.isEmpty(_.get(rootModels, relationTable + '.up.drop'))) {
        // Set objects
        if (_.isUndefined(_.get(models, relationTable + '.up.others'))) {
          _.set(rootModels, relationTable + '.up.others', '');
        }

        if (_.isUndefined(_.get(rootModels, relationTable + '.up.drop'))) {
          _.set(rootModels, relationTable + '.up.drop', '');
        }

        if (_.isUndefined(_.get(rootModels, relationTable + '.down.others'))) {
          _.set(rootModels, relationTable + '.down.others', '');
        }

        if (_.isUndefined(_.get(rootModels, relationTable + '.down.drop'))) {
          _.set(rootModels, relationTable + '.down.drop', '');
        }

        if (_.isUndefined(_.get(rootModels, relationTable + '.attributes'))) {
          _.set(rootModels, relationTable + '.attributes', {});
        }

        if (!toDrop) {
          // Load templates.
          const tplTableUp = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'relations', 'belongsToMany.template'), 'utf8');
          const tplTableDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'tables', 'dropTable.template'), 'utf8');

          // Create relationships table for many-to-many.
          rootModels[relationTable].up.others += _.unescape(_.template(tplTableUp)({
            models,
            tableName: relationTable,
            details,
            relationship
          }));

          if (_.isUndefined(_.get(rootModels, relationTable + '.attributes.fk'))) {
            // Load templates.
            const tplFKDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'columns', 'dropForeign.template'), 'utf8');
            const tplSelectTableDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'tables', 'select', 'down.template'), 'utf8');

            // Drop current relationships table on migration rollback.
            rootModels[relationTable].down.others += _.unescape(_.template(tplTableDown)({
              tableName: relationTable
            }));

            // Remove foreign key current relationships table before drop the table on migration rollback.
            rootModels[relationTable].attributes.fk = {
              delete: {
                drop: _.unescape(_.template(tplFKDown)({
                  attribute: details.attribute + '_' + details.column
                })) + _.unescape(_.template(tplFKDown)({
                  attribute: relationship.attribute + '_' + relationship.column
                }))
              }
            };

            rootModels[relationTable].down.drop += _.unescape(_.template(tplSelectTableDown)({
              models,
              tableName: relationTable,
              attributes: models[relationTable].attributes,
              toDrop: true
            }));
          } else {
            const dropMigrationTable = _.unescape(_.template(tplTableDown)({
              tableName: relationTable
            }));

            // Eliminate duplicate
            if (rootModels[relationTable].down.drop.indexOf(dropMigrationTable) === -1) {
              // Drop current relationships table on migration rollback.
              rootModels[relationTable].down.drop += dropMigrationTable;
            }
          }
        } else if (onlyDrop) {
          // Load templates.
          const tplTableUp = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'relations', 'belongsToMany.template'), 'utf8');
          const tplTableDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'tables', 'dropTable.template'), 'utf8');
          const tplFKDown = fs.readFileSync(path.resolve(__dirname, '..', '..', 'templates', 'builder', 'columns', 'dropForeign.template'), 'utf8');

          const dropMigrationTable = _.unescape(_.template(tplTableDown)({
            tableName: relationTable
          }));

          if (_.isUndefined(_.get(rootModels[relationTable].attributes, 'fk.delete')) && _.get(rootModels[modelName].newAttributes[attribute], 'isRemoved') !== true) {
            // Eliminate duplicate
            if (rootModels[relationTable].up.drop.indexOf(dropMigrationTable) === -1) {
              // Drop current relationships table on migration run.
              rootModels[relationTable].up.drop += _.unescape(_.template(tplTableDown)({
                tableName: relationTable
              }));
            }

            // We have to this to be in the up template loop
            _.set(rootModels[relationTable], 'newAttributes.fk', {});
            _.set(rootModels[relationTable].attributes, 'fk', {
              delete: {
                drop: ''
              }
            });

            // Drop first FK on migration relation table.
            const dropMigrationFK1 = _.unescape(_.template(tplFKDown)({
              attribute: details.attribute + '_' + details.column
            }));

            // Eliminate duplicate
            if (rootModels[relationTable].attributes.fk.delete.drop.indexOf(dropMigrationFK1) === -1) {
              // Remove foreign key current relationships table before drop the table on migration rollback.
              rootModels[relationTable].attributes.fk.delete.drop += dropMigrationFK1;
            }

            // Drop first FK on migration relation table.
            const dropMigrationFK2 = _.unescape(_.template(tplFKDown)({
              attribute: relationship.attribute + '_' + relationship.column
            }));

            // Eliminate duplicate
            if (rootModels[relationTable].attributes.fk.delete.drop.indexOf(dropMigrationFK2) === -1) {
              rootModels[relationTable].attributes.fk.delete.drop += dropMigrationFK2;
            }

            // Builder: select the table.
            selectTable(rootModels, relationTable);
          } else if (_.get(rootModels[modelName].newAttributes[attribute], 'isRemoved') === true) {
            // Eliminate duplicate
            if (rootModels[relationTable].up.others.indexOf(dropMigrationTable) === -1) {
              // Drop current relationships table on migration run.
              rootModels[relationTable].up.others += _.unescape(_.template(tplTableDown)({
                tableName: relationTable
              }));
            }

            if (_.isUndefined(_.get(rootModels[relationTable].attributes, 'fk.create'))) {
              // We have to this to be in the up template loop
              _.set(rootModels[relationTable], 'newAttributes.fk.create', {});
              _.set(rootModels[relationTable].attributes, 'fk', {
                create: {
                  drop: ''
                }
              });

              // Drop first FK on migration relation table.
              const dropMigrationFK1 = _.unescape(_.template(tplFKDown)({
                attribute: details.attribute + '_' + details.column
              }));

              // Eliminate duplicate
              if (rootModels[relationTable].attributes.fk.create.drop.indexOf(dropMigrationFK1) === -1) {
                // Remove foreign key current relationships table before drop the table on migration rollback.
                rootModels[relationTable].attributes.fk.create.drop += dropMigrationFK1;
              }

              // Drop first FK on migration relation table.
              const dropMigrationFK2 = _.unescape(_.template(tplFKDown)({
                attribute: relationship.attribute + '_' + relationship.column
              }));

              // Eliminate duplicate
              if (rootModels[relationTable].attributes.fk.create.drop.indexOf(dropMigrationFK2) === -1) {
                rootModels[relationTable].attributes.fk.create.drop += dropMigrationFK2;
              }

              // Builder: select the table.
              selectTable(rootModels, relationTable);
            }
          }

          // Eliminate duplicate
          if (rootModels[relationTable].down.others.indexOf('createTableIfNotExists(\'' + relationTable + '\'') === -1) {
            // Create previous relationships table on migration rollback.
            rootModels[relationTable].down.others += _.unescape(_.template(tplTableUp)({
              models,
              tableName: relationTable || relationTable,
              details,
              relationship
            }));
          }
        }
      }
    }
  }