refactor with groupby

This commit is contained in:
Pierre Noël 2022-09-02 12:18:48 +02:00
parent a658c6cc0a
commit aa53790bd5
2 changed files with 62 additions and 25 deletions

View File

@ -1,6 +1,5 @@
'use strict';
const _ = require('lodash');
const {
isUndefined,
castArray,
@ -13,6 +12,10 @@ const {
isEmpty,
isArray,
isNull,
groupBy,
pipe,
mapValues,
map,
} = require('lodash/fp');
const types = require('./types');
const { createField } = require('./fields');
@ -416,25 +419,37 @@ const createEntityManager = (db) => {
}
// delete previous relations
const typeAndFieldIdsMap = {};
const morphOneRows = rows.filter((row) => {
const relatedType = row[typeColumn.name];
const field = row.field;
for (const { field, related_type: relatedType, related_id: relatedId } of rows) {
if (!relatedType) continue; // if !relatedType then it's a component. No need to handle that case
const targetAttribute = db.metadata.get(relatedType).attributes[field];
const isMorphOne =
db.metadata.get(relatedType).attributes[field].relation === 'morphOne';
if (isMorphOne) {
const key = `${relatedType}+${field}`;
typeAndFieldIdsMap[key] = typeAndFieldIdsMap[key] || [];
typeAndFieldIdsMap[key].push(relatedId);
// ensure targeted field is the right one + check if it is a morphOne
return (
targetAttribute?.target === uid &&
targetAttribute?.morphBy === attributeName &&
targetAttribute?.relation === 'morphOne'
);
});
const groupByType = groupBy(typeColumn.name);
const groupByField = groupBy('field');
const typeAndFieldIdsGrouped = pipe(groupByType, mapValues(groupByField))(morphOneRows);
const orWhere = [];
for (const [type, v] of Object.entries(typeAndFieldIdsGrouped)) {
for (const [field, arr] of Object.entries(v)) {
orWhere.push({
[typeColumn.name]: type,
field,
[idColumn.name]: { $in: map(idColumn.name, arr) },
});
}
}
const orWhere = _.map(typeAndFieldIdsMap, (ids, typeAndField) => {
const [type, field] = typeAndField.split('+');
return { related_type: type, field, related_id: { $in: ids } };
});
if (!isEmpty(orWhere)) {
await this.createQueryBuilder(joinTable.name)
.delete()
@ -624,20 +639,42 @@ const createEntityManager = (db) => {
}
// delete previous relations
const where = { $or: [] };
const morphOneRows = rows.filter((row) => {
const relatedType = row[typeColumn.name];
const field = row.field;
for (const { field, related_type: relatedType, related_id: relatedId } of rows) {
if (!relatedType) continue; // if !relatedType then it's a component. No need to handle that case
const targetAttribute = db.metadata.get(relatedType).attributes[field];
const isMorphOne =
db.metadata.get(relatedType).attributes[field].relation === 'morphOne';
if (isMorphOne) {
where.$or.push({ related_type: relatedType, field, related_id: relatedId });
// ensure targeted field is the right one + check if it is a morphOne
return (
targetAttribute?.target === uid &&
targetAttribute?.morphBy === attributeName &&
targetAttribute?.relation === 'morphOne'
);
});
const groupByType = groupBy(typeColumn.name);
const groupByField = groupBy('field');
const typeAndFieldIdsGrouped = pipe(groupByType, mapValues(groupByField))(morphOneRows);
const orWhere = [];
for (const [type, v] of Object.entries(typeAndFieldIdsGrouped)) {
for (const [field, arr] of Object.entries(v)) {
orWhere.push({
[typeColumn.name]: type,
field,
[idColumn.name]: { $in: map(idColumn.name, arr) },
});
}
}
if (!isEmpty(where.$or)) {
await this.createQueryBuilder(joinTable.name).delete().where(where).execute();
if (!isEmpty(orWhere)) {
await this.createQueryBuilder(joinTable.name)
.delete()
.where({ $or: orWhere })
.execute();
}
await this.createQueryBuilder(joinTable.name).insert(rows).execute();

View File

@ -119,7 +119,7 @@ const applyPopulate = async (results, populate, ctx) => {
return results;
}
for (const key in populate) {
for (const key of Object.keys(populate)) {
const attribute = meta.attributes[key];
const targetMeta = db.metadata.get(attribute.target);