Update & delete polymorphic

This commit is contained in:
Alexandre Bodin 2021-07-26 19:40:30 +02:00
parent 6cc1c05bf9
commit e4199664c9
4 changed files with 244 additions and 179 deletions

View File

@ -19,131 +19,21 @@ async function main(connection) {
await orm.schema.reset();
let res, articleA, articleB, c1, c2, f1, f2;
let res;
f1 = await orm.query('folder').create({ data: {} });
f2 = await orm.query('folder').create({ data: {} });
articleA = await orm.query('article').create({
data: {
reportables: [
{
__type: 'folder',
id: f1.id,
},
{
__type: 'folder',
id: f2.id,
},
],
},
});
articleB = await orm.query('article').create({
data: {
reportables: {
__type: 'folder',
id: f2.id,
},
},
});
res = await orm.query('folder').findMany({
populate: {
articles: {
populate: {
reportables: true,
},
},
},
});
log(res);
// morph one
await orm.query('comment').create({
data: {
article: articleA.id,
},
});
res = await orm.query('comment').findMany({
populate: {
article: true,
},
});
log(res);
res = await orm.query('article').findMany({
populate: {
commentable: true,
},
});
log(res);
// morph many
await orm.query('video-comment').create({
data: {
articles: [articleA.id, articleB.id],
},
});
res = await orm.query('video-comment').findMany({
populate: {
articles: true,
},
});
log(res);
res = await orm.query('article').findMany({
populate: {
commentable: true,
},
});
log(res);
//----------
c1 = await orm.query('comment').create({
data: {
title: 'test',
},
});
c2 = await orm.query('video-comment').create({
const c1 = await orm.query('comment').create({
data: {
title: 'coucou',
articles: [articleA.id, articleB.id],
},
});
// morph to one
await orm.query('article').create({
const c2 = await orm.query('video-comment').create({
data: {
commentable: {
__type: 'comment',
id: c1.id,
},
title: 'coucou',
},
});
res = await orm.query('article').findMany({
populate: {
commentable: true,
},
});
log(res);
// morph to many
await orm.query('article').create({
res = await orm.query('article').create({
data: {
dz: [
{
@ -156,8 +46,13 @@ async function main(connection) {
},
],
},
populate: {
dz: true,
},
});
log(res);
res = await orm.query('article').findMany({
populate: {
dz: true,

View File

@ -261,65 +261,34 @@ const createEntityManager = db => {
for (const attributeName in attributes) {
const attribute = attributes[attributeName];
if (!_.has(attributeName, data)) {
if (attribute.type !== 'relation' || !_.has(attributeName, data)) {
continue;
}
// TODO: handle cleaning before creating the assocaitions
switch (attribute.relation) {
case 'morphOne':
case 'morphMany': {
const { target, morphBy } = attribute;
if (attribute.relation === 'morphOne' || attribute.relation === 'morphMany') {
const { target, morphBy } = attribute;
const targetAttribute = db.metadata.get(target).attributes[morphBy];
const targetAttribute = db.metadata.get(target).attributes[morphBy];
if (targetAttribute.relation === 'morphToOne') {
// set columns
const { idColumn, typeColumn } = targetAttribute.morphColumn;
if (targetAttribute.relation === 'morphToOne') {
// set columns
const { idColumn, typeColumn } = targetAttribute.morphColumn;
await this.createQueryBuilder(target)
.update({ [idColumn.name]: id, [typeColumn.name]: uid })
.where({ id: data[attributeName] })
.execute();
} else if (targetAttribute.type === 'morphToMany') {
const { joinTable } = targetAttribute;
const { name, joinColumn, morphColumn } = joinTable;
const { idColumn, typeColumn } = morphColumn;
const rows = _.castArray(data[attributeName]).map((dataID, idx) => ({
[joinColumn.name]: dataID,
[idColumn.name]: id,
[typeColumn.name]: uid,
...(joinTable.on || {}),
order: idx,
}));
if (_.isEmpty(rows)) {
continue;
}
await this.createQueryBuilder(name)
.insert(rows)
.execute();
}
continue;
}
case 'morphToOne': {
// handled on the entry itself
continue;
}
case 'morphToMany': {
const { joinTable } = attribute;
const { name, joinColumn, morphColumn } = joinTable;
await this.createQueryBuilder(target)
.update({ [idColumn.name]: id, [typeColumn.name]: uid })
.where({ id: data[attributeName] })
.execute();
} else if (targetAttribute.type === 'morphToMany') {
const { joinTable } = targetAttribute;
const { joinColumn, morphColumn } = joinTable;
const { idColumn, typeColumn } = morphColumn;
const rows = _.castArray(data[attributeName]).map((data, idx) => ({
[joinColumn.name]: id,
[idColumn.name]: data.id,
[typeColumn.name]: data.__type,
const rows = _.castArray(data[attributeName]).map((dataID, idx) => ({
[joinColumn.name]: dataID,
[idColumn.name]: id,
[typeColumn.name]: uid,
...(joinTable.on || {}),
order: idx,
}));
@ -328,12 +297,38 @@ const createEntityManager = db => {
continue;
}
await this.createQueryBuilder(name)
await this.createQueryBuilder(joinTable.name)
.insert(rows)
.execute();
}
continue;
} else if (attribute.relation === 'morphToOne') {
// handled on the entry itself
continue;
} else if (attribute.relation === 'morphToMany') {
const { joinTable } = attribute;
const { joinColumn, morphColumn } = joinTable;
const { idColumn, typeColumn } = morphColumn;
const rows = _.castArray(data[attributeName]).map((data, idx) => ({
[joinColumn.name]: id,
[idColumn.name]: data.id,
[typeColumn.name]: data.__type,
...(joinTable.on || {}),
order: idx,
}));
if (_.isEmpty(rows)) {
continue;
}
await this.createQueryBuilder(joinTable.name)
.insert(rows)
.execute();
continue;
}
if (attribute.joinColumn && attribute.owner) {
@ -428,7 +423,122 @@ const createEntityManager = db => {
for (const attributeName in attributes) {
const attribute = attributes[attributeName];
if (attribute.type !== 'relation' || !_.has(attributeName, data)) {
continue;
}
// TODO: implement polymorphic
/*
if morphOne | morphMany
clear previous:
if morphBy is morphToOne
set null
set new
if morphBy is morphToMany
delete links
add links
*/
if (attribute.relation === 'morphOne' || attribute.relation === 'morphMany') {
const { target, morphBy } = attribute;
const targetAttribute = db.metadata.get(target).attributes[morphBy];
if (targetAttribute.relation === 'morphToOne') {
// set columns
const { idColumn, typeColumn } = targetAttribute.morphColumn;
await this.createQueryBuilder(target)
.update({ [idColumn.name]: null, [typeColumn.name]: null })
.where({ [idColumn.name]: id, [typeColumn.name]: uid })
.execute();
await this.createQueryBuilder(target)
.update({ [idColumn.name]: id, [typeColumn.name]: uid })
.where({ id: data[attributeName] })
.execute();
} else if (targetAttribute.type === 'morphToMany') {
const { joinTable } = targetAttribute;
const { joinColumn, morphColumn } = joinTable;
const { idColumn, typeColumn } = morphColumn;
await this.createQueryBuilder(joinTable.name)
.delete()
.where({
[idColumn.name]: id,
[typeColumn.name]: uid,
...(joinTable.on || {}),
})
.execute();
const rows = _.castArray(data[attributeName]).map((dataID, idx) => ({
[joinColumn.name]: dataID,
[idColumn.name]: id,
[typeColumn.name]: uid,
...(joinTable.on || {}),
order: idx,
}));
if (_.isEmpty(rows)) {
continue;
}
await this.createQueryBuilder(joinTable.name)
.insert(rows)
.execute();
}
continue;
}
/*
if morphToOne
set new values in morph columns
*/
if (attribute.relation === 'morphToOne') {
// do nothing
}
/*
if morphToMany
delete old links
create new links
*/
if (attribute.relation === 'morphToMany') {
const { joinTable } = attribute;
const { joinColumn, morphColumn } = joinTable;
const { idColumn, typeColumn } = morphColumn;
await this.createQueryBuilder(joinTable.name)
.delete()
.where({
[joinColumn.name]: id,
...(joinTable.on || {}),
})
.execute();
const rows = _.castArray(data[attributeName]).map((data, idx) => ({
[joinColumn.name]: id,
[idColumn.name]: data.id,
[typeColumn.name]: data.__type,
...(joinTable.on || {}),
order: idx,
}));
if (_.isEmpty(rows)) {
continue;
}
await this.createQueryBuilder(joinTable.name)
.insert(rows)
.execute();
continue;
}
if (attribute.joinColumn && attribute.owner) {
// TODO: check edgecase
@ -518,17 +628,84 @@ const createEntityManager = db => {
*/
// TODO: wrap Transaction
async deleteRelations(uid, id) {
// TODO: Implement correctly
if (db.dialect.usesForeignKeys()) {
return;
}
const { attributes } = db.metadata.get(uid);
for (const attributeName in attributes) {
const attribute = attributes[attributeName];
// TODO: implement polymorphic
if (attribute.type !== 'relation') {
continue;
}
/*
if morphOne | morphMany
if morphBy is morphToOne
set null
if morphBy is morphToOne
delete links
*/
if (attribute.relation === 'morphOne' || attribute.relation === 'morphMany') {
const { target, morphBy } = attribute;
const targetAttribute = db.metadata.get(target).attributes[morphBy];
if (targetAttribute.relation === 'morphToOne') {
// set columns
const { idColumn, typeColumn } = targetAttribute.morphColumn;
await this.createQueryBuilder(target)
.update({ [idColumn.name]: null, [typeColumn.name]: null })
.where({ [idColumn.name]: id, [typeColumn.name]: uid })
.execute();
} else if (targetAttribute.type === 'morphToMany') {
const { joinTable } = targetAttribute;
const { morphColumn } = joinTable;
const { idColumn, typeColumn } = morphColumn;
await this.createQueryBuilder(joinTable.name)
.delete()
.where({
[idColumn.name]: id,
[typeColumn.name]: uid,
...(joinTable.on || {}),
})
.execute();
}
continue;
}
/*
if morphToOne
nothing to do
*/
if (attribute.relation === 'morphToOne') {
// do nothing
}
/*
if morphToMany
delete links
*/
if (attribute.relation === 'morphToMany') {
const { joinTable } = attribute;
const { joinColumn } = joinTable;
await this.createQueryBuilder(joinTable.name)
.delete()
.where({
[joinColumn.name]: id,
...(joinTable.on || {}),
})
.execute();
continue;
}
if (db.dialect.usesForeignKeys()) {
return;
}
// NOTE: we do not remove existing associations with the target as it should handled by unique FKs instead
if (attribute.joinColumn && attribute.owner) {

View File

@ -140,10 +140,7 @@ const createMetadata = (models = []) => {
}
if (types.isRelation(attribute.type)) {
// NOTE: also validate
createRelation(attributeName, attribute, meta, metadata);
continue;
}
} catch (error) {

View File

@ -424,11 +424,7 @@ const createComponents = async (uid, data) => {
componentBody[attributeName] = await Promise.all(
dynamiczoneValues.map(async value => {
const { id } = await createComponent(value.__component, value);
return {
__type: value.__component,
id,
};
return { id, __type: value.__component };
})
);