mirror of
https://github.com/strapi/strapi.git
synced 2025-11-02 19:04:38 +00:00
implement simple partial update
This commit is contained in:
parent
e29c069e2a
commit
b7a1e312b4
@ -13,6 +13,7 @@ const {
|
|||||||
isArray,
|
isArray,
|
||||||
isNull,
|
isNull,
|
||||||
map,
|
map,
|
||||||
|
uniqBy,
|
||||||
} = require('lodash/fp');
|
} = require('lodash/fp');
|
||||||
const types = require('../types');
|
const types = require('../types');
|
||||||
const { createField } = require('../fields');
|
const { createField } = require('../fields');
|
||||||
@ -26,6 +27,13 @@ const toIds = (value) => castArray(value || []).map(toId);
|
|||||||
|
|
||||||
const isValidId = (value) => isString(value) || isInteger(value);
|
const isValidId = (value) => isString(value) || isInteger(value);
|
||||||
const toAssocs = (data) => {
|
const toAssocs = (data) => {
|
||||||
|
if (data?.connect || data?.disconnect) {
|
||||||
|
return {
|
||||||
|
connect: toAssocs(data.connect),
|
||||||
|
disconnect: toAssocs(data.disconnect),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return castArray(data)
|
return castArray(data)
|
||||||
.filter((datum) => !isNil(datum))
|
.filter((datum) => !isNil(datum))
|
||||||
.map((datum) => {
|
.map((datum) => {
|
||||||
@ -651,68 +659,82 @@ const createEntityManager = (db) => {
|
|||||||
const onlyDeleteRelation = isNull(data[attributeName]);
|
const onlyDeleteRelation = isNull(data[attributeName]);
|
||||||
let insert;
|
let insert;
|
||||||
|
|
||||||
if (!onlyDeleteRelation) {
|
if (onlyDeleteRelation) {
|
||||||
|
// clear previous associations in the joinTable
|
||||||
|
await this.createQueryBuilder(joinTable.name)
|
||||||
|
.delete()
|
||||||
|
.where({ [joinColumn.name]: id })
|
||||||
|
.where(joinTable.on || {})
|
||||||
|
.execute();
|
||||||
|
} else {
|
||||||
const cleanRelationData = toAssocs(data[attributeName]);
|
const cleanRelationData = toAssocs(data[attributeName]);
|
||||||
const isPartialUpdate = cleanRelationData.connect || cleanRelationData.disconnect;
|
const connect = cleanRelationData.connect || [];
|
||||||
|
const disconnect = cleanRelationData.disconnect || [];
|
||||||
|
const isPartialUpdate = connect.length || disconnect.length;
|
||||||
|
|
||||||
if (isPartialUpdate) {
|
if (isPartialUpdate) {
|
||||||
// partial update case
|
const idsToRemove = map('id', connect.concat(disconnect));
|
||||||
insert = await this.createQueryBuilder(joinTable.name).select().orderBy('order');
|
const existingRelsToDelete = await this.createQueryBuilder(joinTable.name)
|
||||||
|
.select([inverseJoinColumn.name, 'order'])
|
||||||
|
.where({
|
||||||
|
[joinColumn.name]: id,
|
||||||
|
[inverseJoinColumn.name]: { $in: idsToRemove },
|
||||||
|
})
|
||||||
|
.where(joinTable.on || {})
|
||||||
|
.execute();
|
||||||
|
|
||||||
if (isArray(cleanRelationData.connect)) {
|
await this.createQueryBuilder(joinTable.name)
|
||||||
for (const connectItem of cleanRelationData.connect) {
|
.delete()
|
||||||
const { start, end, after, before } = connectItem;
|
.where({
|
||||||
let wasInserted = false;
|
[joinColumn.name]: id,
|
||||||
const relationToInsert = {
|
[inverseJoinColumn.name]: { $in: idsToRemove },
|
||||||
|
})
|
||||||
|
.where(joinTable.on || {})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
for (const relToDelete of existingRelsToDelete) {
|
||||||
|
await this.createQueryBuilder(joinTable.name)
|
||||||
|
.update({ order: db.getConnection().raw('?? - 1', 'order') })
|
||||||
|
.where({
|
||||||
[joinColumn.name]: id,
|
[joinColumn.name]: id,
|
||||||
[inverseJoinColumn.name]: connectItem.id,
|
order: { $gt: relToDelete.order },
|
||||||
};
|
})
|
||||||
|
.where(joinTable.on || {})
|
||||||
insert = insert.reduce((acc, rel, i, arr) => {
|
.execute();
|
||||||
const currRelId = String(rel[inverseJoinColumn.name]);
|
|
||||||
const nextRelId = String(arr[i + 1]?.[inverseJoinColumn.name]);
|
|
||||||
if (currRelId === String(connectItem.id)) {
|
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wasInserted) {
|
|
||||||
return acc.push(rel);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i === 0 && start) {
|
|
||||||
wasInserted = true;
|
|
||||||
return acc.push(relationToInsert);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i === arr.length - 1 && (end || !wasInserted)) {
|
|
||||||
wasInserted = true;
|
|
||||||
return acc.push(relationToInsert);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (after && currRelId === String(after)) {
|
|
||||||
wasInserted = true;
|
|
||||||
return acc.push(relationToInsert);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (before && nextRelId === String(before)) {
|
|
||||||
wasInserted = true;
|
|
||||||
return acc.push(relationToInsert);
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc.push(rel);
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isArray(cleanRelationData.disconnect)) {
|
if (connect.length) {
|
||||||
const idsToRemove = map('id', cleanRelationData.disconnect);
|
const { max } = await this.createQueryBuilder(joinTable.name)
|
||||||
insert = insert.filter((rel) => !idsToRemove.includes(rel[inverseJoinColumn.name]));
|
.max('order')
|
||||||
|
.where({ [joinColumn.name]: id })
|
||||||
|
.where(joinTable.on || {})
|
||||||
|
.first()
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
insert = uniqBy('id', connect).map((rel, idx) => ({
|
||||||
|
[joinColumn.name]: id,
|
||||||
|
[inverseJoinColumn.name]: rel.id,
|
||||||
|
order: max + idx + 1,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
insert.forEach((rel, i) => {
|
if (
|
||||||
rel.order = i;
|
isBidirectional(attribute) &&
|
||||||
});
|
['oneToOne', 'oneToMany'].includes(attribute.relation)
|
||||||
|
) {
|
||||||
|
// TODO: reordering the relations when oneToMany
|
||||||
|
await this.createQueryBuilder(joinTable.name)
|
||||||
|
.delete()
|
||||||
|
.where({ [inverseJoinColumn.name]: toIds(data[attributeName]) })
|
||||||
|
.where(joinTable.on || {})
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isEmpty(insert)) {
|
||||||
|
await this.createQueryBuilder(joinTable.name).insert(insert).execute();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// overwrite
|
||||||
insert = toAssocs(data[attributeName]).map((data, idx) => {
|
insert = toAssocs(data[attributeName]).map((data, idx) => {
|
||||||
return {
|
return {
|
||||||
[joinColumn.name]: id,
|
[joinColumn.name]: id,
|
||||||
@ -722,30 +744,28 @@ const createEntityManager = (db) => {
|
|||||||
order: idx + 1,
|
order: idx + 1,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isBidirectional(attribute) &&
|
isBidirectional(attribute) &&
|
||||||
['oneToOne', 'oneToMany'].includes(attribute.relation)
|
['oneToOne', 'oneToMany'].includes(attribute.relation)
|
||||||
) {
|
) {
|
||||||
|
// TODO: reordering the relations when oneToMany
|
||||||
|
await this.createQueryBuilder(joinTable.name)
|
||||||
|
.delete()
|
||||||
|
.where({ [inverseJoinColumn.name]: toIds(data[attributeName]) })
|
||||||
|
.where(joinTable.on || {})
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
await this.createQueryBuilder(joinTable.name)
|
await this.createQueryBuilder(joinTable.name)
|
||||||
.delete()
|
.delete()
|
||||||
.where({ [inverseJoinColumn.name]: toIds(data[attributeName]) })
|
.where({ [joinColumn.name]: id })
|
||||||
.where(joinTable.on || {})
|
.where(joinTable.on || {})
|
||||||
.execute();
|
.execute();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear previous associations in the joinTable
|
if (!isEmpty(insert)) {
|
||||||
await this.createQueryBuilder(joinTable.name)
|
await this.createQueryBuilder(joinTable.name).insert(insert).execute();
|
||||||
.delete()
|
}
|
||||||
.where({ [joinColumn.name]: id })
|
|
||||||
.where(joinTable.on || {})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
if (!onlyDeleteRelation) {
|
|
||||||
if (!isEmpty(insert)) {
|
|
||||||
await this.createQueryBuilder(joinTable.name).insert(insert).execute();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user