From 1d09999586dd6293765e958eb97617cc7963b419 Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Fri, 26 Jul 2019 10:57:27 +0200 Subject: [PATCH 1/7] Fix search in content-manager --- packages/strapi-hook-bookshelf/lib/queries.js | 10 +++++++--- .../controllers/ContentManager.js | 4 ++-- .../services/ContentManager.js | 18 +++++------------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/packages/strapi-hook-bookshelf/lib/queries.js b/packages/strapi-hook-bookshelf/lib/queries.js index c05d5325da..17c3ac05b1 100644 --- a/packages/strapi-hook-bookshelf/lib/queries.js +++ b/packages/strapi-hook-bookshelf/lib/queries.js @@ -210,7 +210,11 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { } function countSearch(params) { - return model.query(qb => buildSearchQuery(qb, model, params)).count(); + return model + .query(qb => { + buildSearchQuery(qb, model, params); + }) + .count(); } async function createGroups(entry, values, { transacting }) { @@ -497,13 +501,13 @@ const buildSearchQuery = (qb, model, params) => { if (!_.isNaN(_.toNumber(query))) { searchInt.forEach(attribute => { - qb.orWhereRaw(attribute, _.toNumber(query)); + qb.orWhere(attribute, _.toNumber(query)); }); } if (query === 'true' || query === 'false') { searchBool.forEach(attribute => { - qb.orWhereRaw(attribute, _.toNumber(query === 'true')); + qb.orWhere(attribute, _.toNumber(query === 'true')); }); } diff --git a/packages/strapi-plugin-content-manager/controllers/ContentManager.js b/packages/strapi-plugin-content-manager/controllers/ContentManager.js index cbb50cd566..a3eec8f0ad 100644 --- a/packages/strapi-plugin-content-manager/controllers/ContentManager.js +++ b/packages/strapi-plugin-content-manager/controllers/ContentManager.js @@ -11,7 +11,7 @@ module.exports = { strapi.plugins['content-manager'].services['contentmanager']; let entities = []; - if (!_.isEmpty(ctx.request.query._q)) { + if (_.has(ctx.request.query, '_q')) { entities = await contentManagerService.search( ctx.params, ctx.request.query @@ -51,7 +51,7 @@ module.exports = { strapi.plugins['content-manager'].services['contentmanager']; let count; - if (!_.isEmpty(ctx.request.query._q)) { + if (_.has(ctx.request.query, '_q')) { count = await contentManagerService.countSearch( ctx.params, ctx.request.query diff --git a/packages/strapi-plugin-content-manager/services/ContentManager.js b/packages/strapi-plugin-content-manager/services/ContentManager.js index 10c20621cc..1060360aea 100644 --- a/packages/strapi-plugin-content-manager/services/ContentManager.js +++ b/packages/strapi-plugin-content-manager/services/ContentManager.js @@ -127,23 +127,15 @@ module.exports = { }, search(params, query) { - const { limit, skip, sort, source, _q, populate = [] } = query; // eslint-disable-line no-unused-vars - const filters = strapi.utils.models.convertParams(params.model, query); + const { model } = params; + const { source } = query; - // Find entries using `queries` system - return strapi.query(params.model, source).search( - { - limit: limit || filters.limit, - skip: skip || filters.start || 0, - sort: sort || filters.sort, - search: _q, - }, - populate - ); + return strapi.query(model, source).search(query); }, countSearch(params, query) { + const { model } = params; const { source, _q } = query; - return strapi.query(params.model, source).countSearch({ search: _q }); + return strapi.query(model, source).countSearch({ _q }); }, }; From 59523d47e7cec8bf97a670ee3c95959d72b36287 Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Fri, 26 Jul 2019 17:53:03 +0200 Subject: [PATCH 2/7] Rename content manager configuration key an model uid changes --- .../api/article/models/Article.settings.json | 4 +- .../services/ContentTypes.js | 11 ++++++ .../services/Groups.js | 12 ++++++ .../services/utils/store.js | 11 ++++++ .../controllers/ContentTypeBuilder.js | 18 ++++++++- .../services/Groups.js | 39 +++++++++++++++---- 6 files changed, 83 insertions(+), 12 deletions(-) diff --git a/examples/getstarted/api/article/models/Article.settings.json b/examples/getstarted/api/article/models/Article.settings.json index 08a78bc4a4..73ced91285 100644 --- a/examples/getstarted/api/article/models/Article.settings.json +++ b/examples/getstarted/api/article/models/Article.settings.json @@ -56,8 +56,8 @@ "collection": "tag" }, "manyTags": { - "dominant": true, "collection": "tag", + "dominant": true, "via": "linkedArticles" }, "fb_cta": { @@ -79,4 +79,4 @@ "max": 10 } } -} \ No newline at end of file +} diff --git a/packages/strapi-plugin-content-manager/services/ContentTypes.js b/packages/strapi-plugin-content-manager/services/ContentTypes.js index fae8678b9e..562c8e6c1c 100644 --- a/packages/strapi-plugin-content-manager/services/ContentTypes.js +++ b/packages/strapi-plugin-content-manager/services/ContentTypes.js @@ -105,4 +105,15 @@ module.exports = { ); return getModel(uid); }, + + async updateUID({ oldUID, newUID, source }) { + const oldKey = uidToStoreKey({ uid: oldUID, source }); + const newKey = uidToStoreKey({ uid: newUID, source }); + + await storeUtils.setModelConfiguration(oldKey, { + uid: oldUID, + }); + + return storeUtils.moveKey(oldKey, newKey); + }, }; diff --git a/packages/strapi-plugin-content-manager/services/Groups.js b/packages/strapi-plugin-content-manager/services/Groups.js index 4355e7a99e..78e5fe4a63 100644 --- a/packages/strapi-plugin-content-manager/services/Groups.js +++ b/packages/strapi-plugin-content-manager/services/Groups.js @@ -29,4 +29,16 @@ module.exports = { const storeKey = uidToStoreKey(uid); return storeUtils.deleteKey(storeKey); }, + + async updateUID(oldUID, newUID) { + const oldKey = uidToStoreKey(oldUID); + const newKey = uidToStoreKey(newUID); + + await storeUtils.setModelConfiguration(oldKey, { + uid: oldUID, + isGroup: true, + }); + + return storeUtils.moveKey(oldKey, newKey); + }, }; diff --git a/packages/strapi-plugin-content-manager/services/utils/store.js b/packages/strapi-plugin-content-manager/services/utils/store.js index 50106a63eb..27b2092392 100644 --- a/packages/strapi-plugin-content-manager/services/utils/store.js +++ b/packages/strapi-plugin-content-manager/services/utils/store.js @@ -89,6 +89,16 @@ function findByKeyQuery({ model }, key) { } const findByKey = key => strapi.query('core_store').custom(findByKeyQuery)(key); +const moveKey = (oldKey, newKey) => { + return strapi.query('core_store').update( + { + key: `plugin_content_manager_configuration_${oldKey}`, + }, + { + key: `plugin_content_manager_configuration_${newKey}`, + } + ); +}; const getAllConfigurations = () => findByKey('plugin_content_manager_configuration'); @@ -103,5 +113,6 @@ module.exports = { setModelConfiguration, deleteKey, + moveKey, keys, }; diff --git a/packages/strapi-plugin-content-type-builder/controllers/ContentTypeBuilder.js b/packages/strapi-plugin-content-type-builder/controllers/ContentTypeBuilder.js index 113f23be78..fc79fcbb79 100644 --- a/packages/strapi-plugin-content-type-builder/controllers/ContentTypeBuilder.js +++ b/packages/strapi-plugin-content-type-builder/controllers/ContentTypeBuilder.js @@ -220,8 +220,8 @@ module.exports = { ]) ); - modelJSON.connection = connection; - modelJSON.collectionName = collectionName; + modelJSON.connection = connection || modelJSON.connection; + modelJSON.collectionName = collectionName || modelJSON.collectionName; modelJSON.info = { name, description: _description, @@ -256,6 +256,20 @@ module.exports = { if (!_.isEmpty(removeModelErrors)) { return ctx.badRequest(null, [{ messages: removeModelErrors }]); } + + if ( + _.has(strapi.plugins, ['content-manager', 'services', 'contenttypes']) + ) { + await _.get(strapi.plugins, [ + 'content-manager', + 'services', + 'contenttypes', + ]).updateUID({ + oldUID: model, + newUID: name.toLowerCase(), + source: plugin, + }); + } } try { diff --git a/packages/strapi-plugin-content-type-builder/services/Groups.js b/packages/strapi-plugin-content-type-builder/services/Groups.js index 569c92a80c..998961bd21 100644 --- a/packages/strapi-plugin-content-type-builder/services/Groups.js +++ b/packages/strapi-plugin-content-type-builder/services/Groups.js @@ -116,15 +116,34 @@ async function createGroup(uid, infos) { * @param {Object} infos */ async function updateGroup(group, infos) { - const { uid } = group; + const { uid, schema: oldSchema } = group; - const newUid = createGroupUID(infos.name); - if (uid !== newUid) { + // don't update collectionName if not provided + const updatedSchema = { + info: { + name: infos.name || oldSchema.name, + description: infos.description || oldSchema.description, + }, + connection: infos.connection || oldSchema.connection, + collectionName: infos.collectionName || oldSchema.collectionName, + attributes: convertAttributes(infos.attributes), + }; + + const newUID = createGroupUID(infos.name); + if (uid !== newUID) { await deleteSchema(uid); - return createGroup(newUid, infos); - } - const updatedSchema = { ...group.schema, ...createSchema(uid, infos) }; + if (_.has(strapi.plugins, ['content-manager', 'services', 'groups'])) { + await _.get(strapi.plugins, [ + 'content-manager', + 'services', + 'groups', + ]).updateUID(uid, newUID); + } + + await writeSchema(newUID, updatedSchema); + return { uid: newUID }; + } await writeSchema(uid, updatedSchema); return { uid }; @@ -137,7 +156,11 @@ async function updateGroup(group, infos) { const createSchema = (uid, infos) => { const { name, - connection = 'default', + connection = _.get( + strapi, + ['config', 'currentEnvironment', 'database', 'defaultConnection'], + 'default' + ), description = '', collectionName, attributes, @@ -149,7 +172,7 @@ const createSchema = (uid, infos) => { description, }, connection, - collectionName: collectionName || `groups_${pluralize(uid)}`, + collectionName: collectionName || `groups_${pluralize(uid).toLowerCase()}`, attributes: convertAttributes(attributes), }; }; From 855a923ca02cd7ad72601f630c4e116dc6dc4b75 Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Sun, 28 Jul 2019 19:27:53 +0200 Subject: [PATCH 3/7] Fix tests --- .../services/__tests__/groups.test.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/strapi-plugin-content-type-builder/services/__tests__/groups.test.js b/packages/strapi-plugin-content-type-builder/services/__tests__/groups.test.js index 9e0c123aae..1c451793de 100644 --- a/packages/strapi-plugin-content-type-builder/services/__tests__/groups.test.js +++ b/packages/strapi-plugin-content-type-builder/services/__tests__/groups.test.js @@ -8,6 +8,16 @@ describe('Group Service', () => { attributes: {}, }; + global.strapi = { + config: { + defaultEnvironment: { + database: { + defaultConnection: 'default', + }, + }, + }, + }; + const expected = { info: { name: 'Some name', From 9245c32c70f4d9be6474ee16b907c3d0aa481e7b Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Wed, 24 Jul 2019 17:16:50 +0200 Subject: [PATCH 4/7] Create relations in groups bookshelf --- examples/getstarted/groups/ingredients.json | 3 + .../strapi-hook-bookshelf/lib/mount-models.js | 3 +- packages/strapi-hook-bookshelf/lib/queries.js | 102 +++++++----- .../strapi-hook-bookshelf/lib/relations.js | 145 ++++++++++++------ packages/strapi/lib/core/bootstrap.js | 1 + 5 files changed, 167 insertions(+), 87 deletions(-) diff --git a/examples/getstarted/groups/ingredients.json b/examples/getstarted/groups/ingredients.json index 87bb9a8829..c7389329cf 100644 --- a/examples/getstarted/groups/ingredients.json +++ b/examples/getstarted/groups/ingredients.json @@ -24,6 +24,9 @@ }, "article": { "model": "article" + }, + "articles": { + "collection": "article" } } } \ No newline at end of file diff --git a/packages/strapi-hook-bookshelf/lib/mount-models.js b/packages/strapi-hook-bookshelf/lib/mount-models.js index 005af2d7eb..2cce0a026b 100644 --- a/packages/strapi-hook-bookshelf/lib/mount-models.js +++ b/packages/strapi-hook-bookshelf/lib/mount-models.js @@ -623,7 +623,8 @@ module.exports = ({ models, target, plugin = false }, ctx) => { } else { options.withRelated = groupAttributes .map(key => `${key}.slice`) - .map(addPolymorphicRelated); + .map(addPolymorphicRelated) + .reduce((acc, paths) => acc.concat(paths), []); } return _.isFunction(target[model.toLowerCase()]['beforeFetchAll']) diff --git a/packages/strapi-hook-bookshelf/lib/queries.js b/packages/strapi-hook-bookshelf/lib/queries.js index 17c3ac05b1..83aecfeaba 100644 --- a/packages/strapi-hook-bookshelf/lib/queries.js +++ b/packages/strapi-hook-bookshelf/lib/queries.js @@ -38,6 +38,13 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { }); }; + const wrapTransaction = (fn, { transacting } = {}) => { + const db = strapi.connections[model.connection]; + + if (transacting) return fn(transacting); + return db.transaction(trx => fn(trx)); + }; + /** * Find one entry based on params */ @@ -60,12 +67,12 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { /** * Find multiple entries based on params */ - function find(params, populate) { + function find(params, populate, { transacting } = {}) { const filters = convertRestQueryParams(params); return model .query(buildQuery({ model, filters })) - .fetchAll({ withRelated: populate || defaultPopulate }) + .fetchAll({ withRelated: populate || defaultPopulate, transacting }) .then(results => results.toJSON()); } @@ -78,7 +85,7 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { return model.query(buildQuery({ model, filters: { where } })).count(); } - async function create(values) { + async function create(values, { transacting } = {}) { const relations = pickRelations(values); const data = selectAttributes(values); @@ -89,16 +96,19 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { return entry; }; - const db = strapi.connections[model.connection]; - const entry = await db.transaction(trx => runCreate(trx)); + const entry = await wrapTransaction(runCreate, { transacting }); - return model.updateRelations({ id: entry.id, values: relations }); + return model.updateRelations( + { id: entry.id, values: relations }, + { transacting } + ); } - async function update(params, values) { - const entry = await model.forge(params).fetch(); + async function update(params, values, { transacting } = {}) { + const entry = await model.forge(params).fetch({ transacting }); if (!entry) { + console.log('not found', model.globalId, params); const err = new Error('entry.notFound'); err.status = 404; throw err; @@ -121,20 +131,20 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { return updatedEntry; }; - const db = strapi.connections[model.connection]; - await db.transaction(trx => runUpdate(trx)); + await wrapTransaction(runUpdate, { transacting }); if (Object.keys(relations).length > 0) { return model.updateRelations( - Object.assign(params, { values: relations }) + Object.assign(params, { values: relations }), + { transacting } ); } - return await model.forge(params).fetch(); + return await model.forge(params).fetch({ transacting }); } - async function deleteOne(params) { - const entry = await model.forge(params).fetch(); + async function deleteOne(params, { transacting } = {}) { + const entry = await model.forge(params).fetch({ transacting }); if (!entry) { const err = new Error('entry.notFound'); @@ -151,6 +161,7 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { case 'oneToManyMorph': values[association.alias] = null; break; + case 'manyWay': case 'oneToMany': case 'manyToMany': case 'manyToManyMorph': @@ -160,25 +171,26 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { } }); - await model.updateRelations({ ...params, values }); + await model.updateRelations({ ...params, values }, { transacting }); const runDelete = async trx => { await deleteGroups(entry, { transacting: trx }); - await model.forge(params).destroy({ transacting: trx }); + await model.forge(params).destroy({ transacting: trx, require: false }); return entry; }; - const db = strapi.connections[model.connection]; - return db.transaction(trx => runDelete(trx)); + return wrapTransaction(runDelete, { transacting }); } - async function deleteMany(params) { + async function deleteMany(params, { transacting } = {}) { const primaryKey = params[model.primaryKey] || params.id; - if (primaryKey) return deleteOne(params); + if (primaryKey) return deleteOne(params, { transacting }); - const entries = await find(params); - return await Promise.all(entries.map(entry => deleteOne({ id: entry.id }))); + const entries = await find(params, null, { transacting }); + return await Promise.all( + entries.map(entry => deleteOne({ id: entry.id }, { transacting })) + ); } function search(params, populate) { @@ -230,9 +242,9 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { const groupModel = strapi.groups[group]; const createGroupAndLink = async ({ value, order }) => { - return groupModel - .forge() - .save(value, { transacting }) + return strapi + .query(groupModel.uid) + .create(value, { transacting }) .then(group => { return joinModel.forge().save( { @@ -291,9 +303,15 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { const updateOrCreateGroupAndLink = async ({ value, order }) => { // check if value has an id then update else create if (_.has(value, groupModel.primaryKey)) { - return groupModel - .forge(value) - .save(value, { transacting, patch: true, require: false }) + return strapi + .query(groupModel.uid) + .update( + { + [groupModel.primaryKey]: value[groupModel.primaryKey], + }, + value, + { transacting } + ) .then(group => { return joinModel .forge() @@ -314,9 +332,9 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { }); } // create - return groupModel - .forge() - .save(value, { transacting }) + return strapi + .query(groupModel.uid) + .create(value, { transacting }) .then(group => { return joinModel.forge().save( { @@ -371,7 +389,7 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { const idsToKeep = groupArr .filter(el => _.has(el, groupModel.primaryKey)) - .map(el => el[groupModel.primaryKey]); + .map(el => el[groupModel.primaryKey].toString()); const allIds = await joinModel .forge() @@ -383,7 +401,7 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { // verify the provided ids are realted to this entity. idsToKeep.forEach(id => { - if (!allIds.includes(id.toString())) { + if (!allIds.includes(id)) { const err = new Error( `Some of the provided groups in ${key} are not related to the entity` ); @@ -399,10 +417,12 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { .query(qb => qb.whereIn('slice_id', idsToDelete)) .destroy({ transacting, require: false }); - await groupModel - .forge() - .query(qb => qb.whereIn(groupModel.primaryKey, idsToDelete)) - .destroy({ transacting, require: false }); + await strapi + .query(groupModel.uid) + .delete( + { [`${groupModel.primaryKey}_in`]: idsToDelete }, + { transacting } + ); } } @@ -430,10 +450,10 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { .fetchAll({ transacting }) .map(el => el.get('slice_id')); - await groupModel - .forge() - .query(qb => qb.whereIn(groupModel.primaryKey, ids)) - .destroy({ transacting, require: false }); + await strapi + .query(groupModel.uid) + .delete({ [`${groupModel.primaryKey}_in`]: ids }, { transacting }); + await joinModel .forge() .query({ diff --git a/packages/strapi-hook-bookshelf/lib/relations.js b/packages/strapi-hook-bookshelf/lib/relations.js index c05a680967..cc125ce666 100644 --- a/packages/strapi-hook-bookshelf/lib/relations.js +++ b/packages/strapi-hook-bookshelf/lib/relations.js @@ -46,10 +46,11 @@ const getModel = (model, plugin) => { const removeUndefinedKeys = obj => _.pickBy(obj, _.negate(_.isUndefined)); module.exports = { - findOne: async function(params, populate) { + async findOne(params, populate, { transacting } = {}) { const record = await this.forge({ [this.primaryKey]: getValuePrimaryKey(params, this.primaryKey), }).fetch({ + transacting, withRelated: populate || this.associations.map(x => x.alias), }); @@ -70,7 +71,9 @@ module.exports = { this.primaryKey ), }) - .fetchAll(); + .fetchAll({ + transacting, + }); }); const related = await Promise.all(arrayOfPromises); @@ -83,10 +86,12 @@ module.exports = { return data; }, - update: async function(params) { + async update(params, { transacting } = {}) { const relationUpdates = []; const primaryKeyValue = getValuePrimaryKey(params, this.primaryKey); - const response = await module.exports.findOne.call(this, params); + const response = await module.exports.findOne.call(this, params, null, { + transacting, + }); // Only update fields which are on this document. const values = @@ -129,7 +134,12 @@ module.exports = { }) .save( { [details.via]: null }, - { method: 'update', patch: true, require: false } + { + method: 'update', + patch: true, + require: false, + transacting, + } ); relationUpdates.push(updatePromise); @@ -140,14 +150,24 @@ module.exports = { const updateLink = this.where({ [current]: property }) .save( { [current]: null }, - { method: 'update', patch: true, require: false } + { + method: 'update', + patch: true, + require: false, + transacting, + } ) .then(() => { return assocModel .where({ [this.primaryKey]: property }) .save( { [details.via]: primaryKeyValue }, - { method: 'update', patch: true, require: false } + { + method: 'update', + patch: true, + require: false, + transacting, + } ); }); @@ -179,7 +199,12 @@ module.exports = { ) .save( { [details.via]: null }, - { method: 'update', patch: true, require: false } + { + method: 'update', + patch: true, + require: false, + transacting, + } ) .then(() => { return assocModel @@ -190,7 +215,12 @@ module.exports = { ) .save( { [details.via]: primaryKeyValue }, - { method: 'update', patch: true, require: false } + { + method: 'update', + patch: true, + require: false, + transacting, + } ); }); @@ -221,9 +251,10 @@ module.exports = { const collection = this.forge({ [this.primaryKey]: primaryKeyValue, })[association.alias](); + const updatePromise = collection - .detach(toRemove) - .then(() => collection.attach(toAdd)); + .detach(toRemove, { transacting }) + .then(() => collection.attach(toAdd, { transacting })); relationUpdates.push(updatePromise); return acc; @@ -242,31 +273,43 @@ module.exports = { if (association.nature === 'manyMorphToOne') { relationUpdates.push( module.exports.removeRelationMorph - .call(this, { - alias: association.alias, - ref: model.collectionName, - refId: obj.refId, - field: obj.field, - }) - .then(() => - module.exports.addRelationMorph.call(this, { - id: response[this.primaryKey], + .call( + this, + { alias: association.alias, ref: model.collectionName, refId: obj.refId, field: obj.field, - }) + }, + { transacting } + ) + .then(() => + module.exports.addRelationMorph.call( + this, + { + id: response[this.primaryKey], + alias: association.alias, + ref: model.collectionName, + refId: obj.refId, + field: obj.field, + }, + { transacting } + ) ) ); } else { relationUpdates.push( - module.exports.addRelationMorph.call(this, { - id: response[this.primaryKey], - alias: association.alias, - ref: model.collectionName, - refId: obj.refId, - field: obj.field, - }) + module.exports.addRelationMorph.call( + this, + { + id: response[this.primaryKey], + alias: association.alias, + ref: model.collectionName, + refId: obj.refId, + field: obj.field, + }, + { transacting } + ) ); } }); @@ -293,26 +336,34 @@ module.exports = { toAdd.forEach(id => { relationUpdates.push( - module.exports.addRelationMorph.call(model, { - id, - alias: association.via, - ref: this.collectionName, - refId: response.id, - field: association.alias, - }) + module.exports.addRelationMorph.call( + model, + { + id, + alias: association.via, + ref: this.collectionName, + refId: response.id, + field: association.alias, + }, + { transacting } + ) ); }); // Update the relational array. toRemove.forEach(id => { relationUpdates.push( - module.exports.removeRelationMorph.call(model, { - id, - alias: association.via, - ref: this.collectionName, - refId: response.id, - field: association.alias, - }) + module.exports.removeRelationMorph.call( + model, + { + id, + alias: association.via, + ref: this.collectionName, + refId: response.id, + field: association.alias, + }, + { transacting } + ) ); }); break; @@ -336,17 +387,19 @@ module.exports = { [this.primaryKey]: getValuePrimaryKey(params, this.primaryKey), }).save(values, { patch: true, + transacting, }); } return await this.forge({ [this.primaryKey]: getValuePrimaryKey(params, this.primaryKey), }).fetch({ + transacting, withRelated: this.associations.map(x => x.alias), }); }, - addRelationMorph: async function(params) { + async addRelationMorph(params, { transacting } = {}) { const record = await this.morph .forge() .where({ @@ -356,6 +409,7 @@ module.exports = { field: params.field, }) .fetch({ + transacting, withRelated: this.associations.map(x => x.alias), }); @@ -372,10 +426,10 @@ module.exports = { [`${params.alias}_type`]: params.ref, field: params.field, }) - .save(); + .save(null, { transacting }); }, - removeRelationMorph: async function(params) { + async removeRelationMorph(params, { transacting } = {}) { return await this.morph .forge() .where( @@ -391,6 +445,7 @@ module.exports = { ) .destroy({ require: false, + transacting, }); }, }; diff --git a/packages/strapi/lib/core/bootstrap.js b/packages/strapi/lib/core/bootstrap.js index e13489549f..29cf59c803 100644 --- a/packages/strapi/lib/core/bootstrap.js +++ b/packages/strapi/lib/core/bootstrap.js @@ -51,6 +51,7 @@ module.exports = function(strapi) { throw new Error(`Group ${key} is missing a collectionName attribute`); return Object.assign(group, { + uid: key, modelType: 'group', globalId: group.globalId || _.upperFirst(_.camelCase(`group_${key}`)), }); From f757d4d95264f6984cb7a0e323f76b59781d65e6 Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Thu, 25 Jul 2019 16:43:17 +0200 Subject: [PATCH 5/7] Support relations inside of group creation --- packages/strapi-hook-mongoose/lib/queries.js | 30 +++++++++++-------- .../strapi-hook-mongoose/lib/relations.js | 10 +------ .../services/UsersPermissions.js | 2 +- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/packages/strapi-hook-mongoose/lib/queries.js b/packages/strapi-hook-mongoose/lib/queries.js index 3e2a97f135..ae8f50a53f 100644 --- a/packages/strapi-hook-mongoose/lib/queries.js +++ b/packages/strapi-hook-mongoose/lib/queries.js @@ -55,23 +55,25 @@ module.exports = ({ model, modelKey, strapi }) => { if (repeatable === true) { validateRepeatableInput(groupValue, { key, ...attr }); const groups = await Promise.all( - groupValue.map(value => groupModel.create(value)) + groupValue.map(value => { + return strapi.query(group).create(value); + }) ); - const groupsArr = groups.map(group => ({ + const groupsArr = groups.map(groupEntry => ({ kind: groupModel.globalId, - ref: group, + ref: groupEntry, })); entry[key] = groupsArr; await entry.save(); } else { validateNonRepeatableInput(groupValue, { key, ...attr }); - const group = await groupModel.create(groupValue); + const groupEntry = await strapi.query(group).create(groupValue); entry[key] = [ { kind: groupModel.globalId, - ref: group, + ref: groupEntry, }, ]; await entry.save(); @@ -95,15 +97,14 @@ module.exports = ({ model, modelKey, strapi }) => { const updateOrCreateGroup = async value => { // check if value has an id then update else create if (hasPK(value)) { - return groupModel.findOneAndUpdate( + return strapi.query(group).update( { [model.primaryKey]: getPK(value), }, - value, - { new: true } + value ); } - return groupModel.create(value); + return strapi.query(group).create(value); }; if (repeatable === true) { @@ -162,7 +163,9 @@ module.exports = ({ model, modelKey, strapi }) => { }, []); if (idsToDelete.length > 0) { - await groupModel.deleteMany({ [model.primaryKey]: { $in: idsToDelete } }); + await strapi + .query(groupModel.uid) + .delete({ [`${model.primaryKey}_in`]: idsToDelete }); } } @@ -175,9 +178,10 @@ module.exports = ({ model, modelKey, strapi }) => { const groupModel = strapi.groups[group]; if (Array.isArray(entry[key]) && entry[key].length > 0) { - await groupModel.deleteMany({ - [model.primaryKey]: { $in: entry[key].map(el => el.ref) }, - }); + const idsToDelete = entry[key].map(el => el.ref); + await strapi + .query(groupModel.uid) + .delete({ [`${model.primaryKey}_in`]: idsToDelete }); } } } diff --git a/packages/strapi-hook-mongoose/lib/relations.js b/packages/strapi-hook-mongoose/lib/relations.js index 73f93e0a28..cc07363db1 100644 --- a/packages/strapi-hook-mongoose/lib/relations.js +++ b/packages/strapi-hook-mongoose/lib/relations.js @@ -208,17 +208,9 @@ module.exports = { case 'manyMorphToOne': // Update the relational array. acc[current] = property.map(obj => { - const globalId = - obj.source && obj.source !== 'content-manager' - ? strapi.plugins[obj.source].models[_.toLower(obj.ref)] - .globalId - : strapi.models[_.toLower(obj.ref)].globalId; - - // Define the object stored in database. - // The shape is this object is defined by the strapi-hook-mongoose connector. return { ref: obj.refId, - kind: globalId, + kind: obj.ref, [association.filter]: obj.field, }; }); diff --git a/packages/strapi-plugin-users-permissions/services/UsersPermissions.js b/packages/strapi-plugin-users-permissions/services/UsersPermissions.js index ea864358a8..c267830a01 100644 --- a/packages/strapi-plugin-users-permissions/services/UsersPermissions.js +++ b/packages/strapi-plugin-users-permissions/services/UsersPermissions.js @@ -188,7 +188,7 @@ module.exports = { .findOne({ id: roleID }, ['users', 'permissions']); if (!role) { - throw new Error('Cannot found this role'); + throw new Error('Cannot find this role'); } // Group by `type`. From f484b4d66edab46dacc381cb21ee905b787aac01 Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Thu, 25 Jul 2019 17:06:02 +0200 Subject: [PATCH 6/7] Make groups non repeatable by default --- packages/strapi-hook-bookshelf/lib/queries.js | 4 ++-- packages/strapi-hook-mongoose/lib/queries.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/strapi-hook-bookshelf/lib/queries.js b/packages/strapi-hook-bookshelf/lib/queries.js index 83aecfeaba..f2ffd9c2e5 100644 --- a/packages/strapi-hook-bookshelf/lib/queries.js +++ b/packages/strapi-hook-bookshelf/lib/queries.js @@ -237,7 +237,7 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { for (let key of groupKeys) { const attr = model.attributes[key]; - const { group, required = false, repeatable = true } = attr; + const { group, required = false, repeatable = false } = attr; const groupModel = strapi.groups[group]; @@ -294,7 +294,7 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { if (!_.has(values, key)) continue; const attr = model.attributes[key]; - const { group, repeatable = true } = attr; + const { group, repeatable = false } = attr; const groupModel = strapi.groups[group]; diff --git a/packages/strapi-hook-mongoose/lib/queries.js b/packages/strapi-hook-mongoose/lib/queries.js index ae8f50a53f..6764f4d680 100644 --- a/packages/strapi-hook-mongoose/lib/queries.js +++ b/packages/strapi-hook-mongoose/lib/queries.js @@ -38,7 +38,7 @@ module.exports = ({ model, modelKey, strapi }) => { for (let key of groupKeys) { const attr = model.attributes[key]; - const { group, required = false, repeatable = true } = attr; + const { group, required = false, repeatable = false } = attr; const groupModel = strapi.groups[group]; @@ -89,7 +89,7 @@ module.exports = ({ model, modelKey, strapi }) => { if (!_.has(values, key)) continue; const attr = model.attributes[key]; - const { group, repeatable = true } = attr; + const { group, repeatable = false } = attr; const groupModel = strapi.groups[group]; const groupValue = values[key]; From 8835beb67a705cbbc2fd3f26067dd76edb9c215a Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Mon, 29 Jul 2019 08:14:42 +0200 Subject: [PATCH 7/7] Cleanup unwanted log --- packages/strapi-hook-bookshelf/lib/queries.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/strapi-hook-bookshelf/lib/queries.js b/packages/strapi-hook-bookshelf/lib/queries.js index f2ffd9c2e5..e08e69959d 100644 --- a/packages/strapi-hook-bookshelf/lib/queries.js +++ b/packages/strapi-hook-bookshelf/lib/queries.js @@ -108,7 +108,6 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) { const entry = await model.forge(params).fetch({ transacting }); if (!entry) { - console.log('not found', model.globalId, params); const err = new Error('entry.notFound'); err.status = 404; throw err;