mirror of
https://github.com/strapi/strapi.git
synced 2025-12-26 14:44:31 +00:00
Add config id type
This commit is contained in:
parent
6b2e1f2bde
commit
4a3c25fbfe
@ -12,12 +12,11 @@ const _ = require('lodash');
|
||||
const bookshelf = require('bookshelf');
|
||||
const pluralize = require('pluralize');
|
||||
|
||||
// Strapi helpers for models.
|
||||
const utilsModels = require('strapi-utils').models;
|
||||
|
||||
// Local helpers.
|
||||
const utils = require('./utils/');
|
||||
const relations = require('./relations');
|
||||
|
||||
// Strapi helpers for models.
|
||||
const utilsModels = require('strapi-utils').models;
|
||||
|
||||
const PIVOT_PREFIX = '_pivot_';
|
||||
const GLOBALS = {};
|
||||
@ -26,11 +25,8 @@ const GLOBALS = {};
|
||||
* Bookshelf hook
|
||||
*/
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
/* eslint-disable prefer-template */
|
||||
/* eslint-disable no-case-declarations */
|
||||
module.exports = function(strapi) {
|
||||
const hook = _.merge({
|
||||
const hook = {
|
||||
/**
|
||||
* Default options
|
||||
*/
|
||||
@ -79,17 +75,16 @@ module.exports = function(strapi) {
|
||||
_.forEach(models, (definition, model) => {
|
||||
definition.globalName = _.upperFirst(_.camelCase(definition.globalId));
|
||||
|
||||
_.defaults(definition, {
|
||||
primaryKey: 'id'
|
||||
});
|
||||
|
||||
// Define local GLOBALS to expose every models in this file.
|
||||
GLOBALS[definition.globalId] = {};
|
||||
|
||||
// Add some informations about ORM & client connection & tableName
|
||||
definition.orm = 'bookshelf';
|
||||
definition.client = _.get(connection.settings, 'client');
|
||||
|
||||
_.defaults(definition, {
|
||||
primaryKey: 'id',
|
||||
primaryKeyType: _.get(definition, 'options.idAttributeType', definition.client === 'pg' ? 'SERIAL' : 'INT AUTO_INCREMENT')
|
||||
});
|
||||
// Register the final model for Bookshelf.
|
||||
const loadedModel = _.assign({
|
||||
tableName: definition.collectionName,
|
||||
@ -317,7 +312,6 @@ module.exports = function(strapi) {
|
||||
|
||||
// Push attributes to be aware of model schema.
|
||||
target[model]._attributes = definition.attributes;
|
||||
target[model].updateRelations = relations.update;
|
||||
|
||||
databaseUpdate.push(new Promise(async (resolve) => {
|
||||
// Equilize database tables
|
||||
@ -336,19 +330,23 @@ module.exports = function(strapi) {
|
||||
switch (relation.nature) {
|
||||
case 'oneToOne':
|
||||
case 'manyToOne':
|
||||
type = definition.client === 'pg' ? 'integer' : 'int';
|
||||
type = definition.primaryKeyType;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
switch (attribute.type) {
|
||||
case 'uuid':
|
||||
type = definition.client === 'pg' ? 'uuid' : 'varchar(255)';
|
||||
break;
|
||||
case 'text':
|
||||
case 'json':
|
||||
type = 'text';
|
||||
break;
|
||||
case 'json':
|
||||
type = definition.client === 'pg' ? 'jsonb' : 'text';
|
||||
break;
|
||||
case 'string':
|
||||
case 'enumeration':
|
||||
case 'password':
|
||||
case 'email':
|
||||
type = 'varchar(255)';
|
||||
@ -358,10 +356,8 @@ module.exports = function(strapi) {
|
||||
type = definition.client === 'pg' ? 'integer' : 'int';
|
||||
break;
|
||||
case 'float':
|
||||
type = definition.client === 'pg' ? 'double precision' : 'double';
|
||||
break;
|
||||
case 'decimal':
|
||||
type = 'decimal';
|
||||
type = attribute.type;
|
||||
break;
|
||||
case 'date':
|
||||
case 'time':
|
||||
@ -398,7 +394,11 @@ module.exports = function(strapi) {
|
||||
};
|
||||
|
||||
if (!tableExist) {
|
||||
const columns = generateColumns(attributes, [`id ${definition.client === 'pg' ? 'SERIAL' : 'INT AUTO_INCREMENT'} NOT NULL PRIMARY KEY`]).join(',\n\r');
|
||||
let idAttributeBuilder = [`id ${definition.primaryKeyType} NOT NULL PRIMARY KEY`];
|
||||
if (definition.primaryKeyType === 'uuid' && definition.client === 'pg') {
|
||||
idAttributeBuilder = ['id uuid NOT NULL DEFAULT uuid_generate_v4() NOT NULL PRIMARY KEY'];
|
||||
}
|
||||
const columns = generateColumns(attributes, idAttributeBuilder).join(',\n\r');
|
||||
|
||||
// Create table
|
||||
await ORM.knex.raw(`
|
||||
@ -483,10 +483,10 @@ module.exports = function(strapi) {
|
||||
if (morphRelations) {
|
||||
const attributes = {
|
||||
[`${loadedModel.tableName}_id`]: {
|
||||
type: 'integer'
|
||||
type: definition.primaryKeyType
|
||||
},
|
||||
[`${morphRelations.alias}_id`]: {
|
||||
type: 'integer'
|
||||
type: definition.primaryKeyType
|
||||
},
|
||||
[`${morphRelations.alias}_type`]: {
|
||||
type: 'text'
|
||||
@ -511,10 +511,10 @@ module.exports = function(strapi) {
|
||||
|
||||
const attributes = {
|
||||
[`${pluralize.singular(manyRelations.collection)}_id`]: {
|
||||
type: 'integer'
|
||||
type: definition.primaryKeyType
|
||||
},
|
||||
[`${pluralize.singular(definition.globalId.toLowerCase())}_id`]: {
|
||||
type: 'integer'
|
||||
type: definition.primaryKeyType
|
||||
}
|
||||
};
|
||||
|
||||
@ -849,7 +849,7 @@ module.exports = function(strapi) {
|
||||
cb();
|
||||
},
|
||||
|
||||
getQueryParams: (value, type, key) => {
|
||||
getQueryParams: (value, type, key) => {
|
||||
const result = {};
|
||||
|
||||
switch (type) {
|
||||
@ -896,18 +896,18 @@ module.exports = function(strapi) {
|
||||
};
|
||||
break;
|
||||
case '_sort':
|
||||
result.key = `sort`;
|
||||
result.key = 'sort';
|
||||
result.value = {
|
||||
key,
|
||||
order: value.toUpperCase()
|
||||
};
|
||||
break;
|
||||
case '_start':
|
||||
result.key = `start`;
|
||||
result.key = 'start';
|
||||
result.value = parseFloat(value);
|
||||
break;
|
||||
case '_limit':
|
||||
result.key = `limit`;
|
||||
result.key = 'limit';
|
||||
result.value = parseFloat(value);
|
||||
break;
|
||||
case '_contains':
|
||||
@ -923,8 +923,340 @@ module.exports = function(strapi) {
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
manageRelations: async function (model, params) {
|
||||
const models = _.assign(_.clone(strapi.models), Object.keys(strapi.plugins).reduce((acc, current) => {
|
||||
_.assign(acc, strapi.plugins[current].models);
|
||||
return acc;
|
||||
}, {}));
|
||||
|
||||
const Model = models[model];
|
||||
|
||||
const virtualFields = [];
|
||||
const record = await Model
|
||||
.forge({
|
||||
[Model.primaryKey]: params[Model.primaryKey]
|
||||
})
|
||||
.fetch({
|
||||
withRelated: Model.associations.map(x => x.alias)
|
||||
});
|
||||
|
||||
const response = record ? record.toJSON() : record;
|
||||
|
||||
// Only update fields which are on this document.
|
||||
const values = params.parseRelationships === false ? params.values : Object.keys(JSON.parse(JSON.stringify(params.values))).reduce((acc, current) => {
|
||||
const association = Model.associations.filter(x => x.alias === current)[0];
|
||||
const details = Model._attributes[current];
|
||||
|
||||
if (_.get(Model._attributes, `${current}.isVirtual`) !== true && _.isUndefined(association)) {
|
||||
acc[current] = params.values[current];
|
||||
} else {
|
||||
switch (association.nature) {
|
||||
case 'oneWay':
|
||||
acc[current] = _.get(params.values[current], this.primaryKey, params.values[current]) || null;
|
||||
|
||||
break;
|
||||
case 'oneToOne':
|
||||
if (response[current] !== params.values[current]) {
|
||||
const value = _.isNull(params.values[current]) ? response[current] : params.values;
|
||||
|
||||
const recordId = _.isNull(params.values[current]) ? value[Model.primaryKey] || value.id || value._id : typeof value[current] === 'object' ? value[current].id : value[current];
|
||||
|
||||
if (response[current] && _.isObject(response[current]) && response[current][Model.primaryKey] !== value[current]) {
|
||||
virtualFields.push(
|
||||
this.manageRelations(details.collection || details.model, {
|
||||
id: response[current][Model.primaryKey],
|
||||
values: {
|
||||
[details.via]: null
|
||||
},
|
||||
parseRelationships: false
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Remove previous relationship asynchronously if it exists.
|
||||
virtualFields.push(
|
||||
models[details.model || details.collection]
|
||||
.forge({ id : recordId })
|
||||
.fetch({
|
||||
withRelated: models[details.model || details.collection].associations.map(x => x.alias)
|
||||
})
|
||||
.then(response => {
|
||||
const record = response ? response.toJSON() : response;
|
||||
|
||||
if (record && _.isObject(record[details.via]) && record[details.via][current] !== value[current]) {
|
||||
return this.manageRelations(model, {
|
||||
id: record[details.via][models[details.model || details.collection].primaryKey] || record[details.via].id,
|
||||
values: {
|
||||
[current]: null
|
||||
},
|
||||
parseRelationships: false
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
})
|
||||
);
|
||||
|
||||
// Update the record on the other side.
|
||||
// When params.values[current] is null this means that we are removing the relation.
|
||||
virtualFields.push(this.manageRelations(details.model || details.collection, {
|
||||
id: recordId,
|
||||
values: {
|
||||
[details.via]: _.isNull(params.values[current]) ? null : value[Model.primaryKey] || params.id || params._id || value.id || value._id
|
||||
},
|
||||
parseRelationships: false
|
||||
}));
|
||||
|
||||
acc[current] = _.isNull(params.values[current]) ? null : typeof value[current] === 'object' ? value[current][Model.primaryKey] : value[current];
|
||||
}
|
||||
|
||||
break;
|
||||
case 'oneToMany':
|
||||
case 'manyToOne':
|
||||
case 'manyToMany':
|
||||
if (details.dominant === true) {
|
||||
acc[current] = params.values[current];
|
||||
} else if (response[current] && _.isArray(response[current]) && current !== 'id') {
|
||||
// Records to add in the relation.
|
||||
const toAdd = _.differenceWith(params.values[current], response[current], (a, b) =>
|
||||
((typeof a === 'number') ? a : a[Model.primaryKey].toString()) === b[Model.primaryKey].toString()
|
||||
);
|
||||
// Records to remove in the relation.
|
||||
const toRemove = _.differenceWith(response[current], params.values[current], (a, b) =>
|
||||
a[Model.primaryKey].toString() === ((typeof b === 'number') ? b : b[Model.primaryKey].toString())
|
||||
)
|
||||
.filter(x => toAdd.find(y => x.id === y.id) === undefined);
|
||||
|
||||
// Push the work into the flow process.
|
||||
toAdd.forEach(value => {
|
||||
value = (typeof value === 'number') ? { id: value } : value;
|
||||
|
||||
value[details.via] = parseFloat(params[Model.primaryKey]);
|
||||
params.values[Model.primaryKey] = parseFloat(params[Model.primaryKey]);
|
||||
|
||||
virtualFields.push(this.addRelation(details.model || details.collection, {
|
||||
id: value[Model.primaryKey] || value.id || value._id,
|
||||
values: association.nature === 'manyToMany' ? params.values : value,
|
||||
foreignKey: current
|
||||
}, details.plugin));
|
||||
});
|
||||
|
||||
toRemove.forEach(value => {
|
||||
value[details.via] = null;
|
||||
|
||||
virtualFields.push(this.removeRelation(details.model || details.collection, {
|
||||
id: value[Model.primaryKey] || value.id || value._id,
|
||||
values: association.nature === 'manyToMany' ? params.values : value,
|
||||
foreignKey: current
|
||||
}, details.plugin));
|
||||
});
|
||||
} else if (_.get(Model._attributes, `${current}.isVirtual`) !== true) {
|
||||
acc[current] = params.values[current];
|
||||
}
|
||||
|
||||
break;
|
||||
case 'manyMorphToMany':
|
||||
case 'manyMorphToOne':
|
||||
// Update the relational array.
|
||||
params.values[current].forEach(obj => {
|
||||
const model = obj.source && obj.source !== 'content-manager' ?
|
||||
strapi.plugins[obj.source].models[obj.ref]:
|
||||
strapi.models[obj.ref];
|
||||
|
||||
virtualFields.push(this.addRelationMorph(details.model || details.collection, {
|
||||
id: response[this.primaryKey],
|
||||
alias: association.alias,
|
||||
ref: model.collectionName,
|
||||
refId: obj.refId,
|
||||
field: obj.field
|
||||
}, obj.source));
|
||||
});
|
||||
break;
|
||||
case 'oneToManyMorph':
|
||||
case 'manyToManyMorph':
|
||||
const transformToArrayID = (array) => {
|
||||
if(_.isArray(array)) {
|
||||
return array.map(value => {
|
||||
if (_.isPlainObject(value)) {
|
||||
return value._id || value.id;
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
if (association.type === 'model') {
|
||||
return _.isEmpty(array) ? [] : transformToArrayID([array]);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
// Compare array of ID to find deleted files.
|
||||
const currentValue = transformToArrayID(response[current]).map(id => id.toString());
|
||||
const storedValue = transformToArrayID(params.values[current]).map(id => id.toString());
|
||||
|
||||
const toAdd = _.difference(storedValue, currentValue);
|
||||
const toRemove = _.difference(currentValue, storedValue);
|
||||
|
||||
toAdd.forEach(id => {
|
||||
virtualFields.push(this.addRelationMorph(details.model || details.collection, {
|
||||
id,
|
||||
alias: association.via,
|
||||
ref: Model.collectionName,
|
||||
refId: response.id,
|
||||
field: association.alias
|
||||
}, details.plugin));
|
||||
});
|
||||
|
||||
// Update the relational array.
|
||||
toRemove.forEach(id => {
|
||||
virtualFields.push(this.removeRelationMorph(details.model || details.collection, {
|
||||
id,
|
||||
alias: association.via,
|
||||
ref: Model.collectionName,
|
||||
refId: response.id,
|
||||
field: association.alias
|
||||
}, details.plugin));
|
||||
});
|
||||
break;
|
||||
case 'oneMorphToOne':
|
||||
case 'oneMorphToMany':
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
if (!_.isEmpty(values)) {
|
||||
virtualFields.push(Model
|
||||
.forge({
|
||||
[Model.primaryKey]: params[Model.primaryKey]
|
||||
})
|
||||
.save(values, {
|
||||
patch: true
|
||||
}));
|
||||
} else {
|
||||
virtualFields.push(Promise.resolve(_.assign(response, params.values)));
|
||||
}
|
||||
|
||||
// Update virtuals fields.
|
||||
await Promise.all(virtualFields);
|
||||
},
|
||||
|
||||
addRelation: async function (model, params, source) {
|
||||
const models = _.assign(_.clone(strapi.models), Object.keys(strapi.plugins).reduce((acc, current) => {
|
||||
_.assign(acc, strapi.plugins[current].models);
|
||||
return acc;
|
||||
}, {}));
|
||||
|
||||
const Model = models[model];
|
||||
const association = Model.associations.filter(x => x.via === params.foreignKey)[0];
|
||||
|
||||
if (!association) {
|
||||
// Resolve silently.
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
switch (association.nature) {
|
||||
case 'oneToOne':
|
||||
case 'oneToMany':
|
||||
return this.manageRelations(model, params);
|
||||
case 'manyToMany':
|
||||
return Model.forge({
|
||||
[Model.primaryKey]: parseFloat(params[Model.primaryKey])
|
||||
})[association.alias]().attach(params.values[Model.primaryKey]);
|
||||
default:
|
||||
// Resolve silently.
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
|
||||
removeRelation: async function (model, params, source) {
|
||||
const models = _.assign(_.clone(strapi.models), Object.keys(strapi.plugins).reduce((acc, current) => {
|
||||
_.assign(acc, strapi.plugins[current].models);
|
||||
return acc;
|
||||
}, {}));
|
||||
|
||||
const Model = models[model];
|
||||
|
||||
const association = Model.associations.filter(x => x.via === params.foreignKey)[0];
|
||||
|
||||
if (!association) {
|
||||
// Resolve silently.
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
switch (association.nature) {
|
||||
case 'oneToOne':
|
||||
case 'oneToMany':
|
||||
return this.manageRelations(model, params);
|
||||
case 'manyToMany':
|
||||
return Model.forge({
|
||||
[Model.primaryKey]: parseFloat(params[Model.primaryKey])
|
||||
})[association.alias]().detach(params.values[Model.primaryKey]);
|
||||
default:
|
||||
// Resolve silently.
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
|
||||
addRelationMorph: async function (model, params, source) {
|
||||
const models = _.assign(_.clone(strapi.models), Object.keys(strapi.plugins).reduce((acc, current) => {
|
||||
_.assign(acc, strapi.plugins[current].models);
|
||||
return acc;
|
||||
}, {}));
|
||||
|
||||
const Model = models[model];
|
||||
|
||||
const record = await Model.morph.forge()
|
||||
.where({
|
||||
[`${Model.collectionName}_id`]: params.id,
|
||||
[`${params.alias}_id`]: params.refId,
|
||||
[`${params.alias}_type`]: params.ref,
|
||||
field: params.field
|
||||
})
|
||||
.fetch({
|
||||
withRelated: Model.associations.map(x => x.alias)
|
||||
});
|
||||
|
||||
const entry = record ? record.toJSON() : record;
|
||||
|
||||
if (entry) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return await Model.morph.forge({
|
||||
[`${Model.collectionName}_id`]: params.id,
|
||||
[`${params.alias}_id`]: params.refId,
|
||||
[`${params.alias}_type`]: params.ref,
|
||||
field: params.field
|
||||
})
|
||||
.save();
|
||||
},
|
||||
|
||||
removeRelationMorph: async function (model, params, source) {
|
||||
const models = _.assign(_.clone(strapi.models), Object.keys(strapi.plugins).reduce((acc, current) => {
|
||||
_.assign(acc, strapi.plugins[current].models);
|
||||
return acc;
|
||||
}, {}));
|
||||
|
||||
const Model = models[model];
|
||||
|
||||
return await Model.morph.forge()
|
||||
.where({
|
||||
[`${Model.collectionName}_id`]: params.id,
|
||||
[`${params.alias}_id`]: params.refId,
|
||||
[`${params.alias}_type`]: params.ref,
|
||||
field: params.field
|
||||
})
|
||||
.destroy();
|
||||
}
|
||||
}, relations);
|
||||
};
|
||||
|
||||
return hook;
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user