| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  | const { | 
					
						
							|  |  |  |   isUndefined, | 
					
						
							|  |  |  |   castArray, | 
					
						
							| 
									
										
										
										
											2022-10-24 09:22:45 +02:00
										 |  |  |   compact, | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |   isNil, | 
					
						
							|  |  |  |   has, | 
					
						
							|  |  |  |   isString, | 
					
						
							|  |  |  |   isInteger, | 
					
						
							|  |  |  |   pick, | 
					
						
							|  |  |  |   isPlainObject, | 
					
						
							|  |  |  |   isEmpty, | 
					
						
							|  |  |  |   isArray, | 
					
						
							|  |  |  |   isNull, | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |   uniqWith, | 
					
						
							|  |  |  |   isEqual, | 
					
						
							|  |  |  |   differenceWith, | 
					
						
							| 
									
										
										
										
											2022-09-19 14:39:59 +02:00
										 |  |  |   isNumber, | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  |   map, | 
					
						
							|  |  |  |   difference, | 
					
						
							| 
									
										
										
										
											2022-11-25 16:19:04 +01:00
										 |  |  |   uniqBy, | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  | } = require('lodash/fp'); | 
					
						
							| 
									
										
										
										
											2022-09-05 16:18:00 +02:00
										 |  |  | const types = require('../types'); | 
					
						
							|  |  |  | const { createField } = require('../fields'); | 
					
						
							|  |  |  | const { createQueryBuilder } = require('../query'); | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | const { createRepository } = require('./entity-repository'); | 
					
						
							| 
									
										
										
										
											2022-09-05 16:18:00 +02:00
										 |  |  | const { deleteRelatedMorphOneRelationsAfterMorphToManyUpdate } = require('./morph-relations'); | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  | const { | 
					
						
							|  |  |  |   isBidirectional, | 
					
						
							|  |  |  |   isAnyToOne, | 
					
						
							| 
									
										
										
										
											2022-09-27 16:07:00 +02:00
										 |  |  |   isOneToAny, | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  |   hasOrderColumn, | 
					
						
							|  |  |  |   hasInverseOrderColumn, | 
					
						
							|  |  |  | } = require('../metadata/relations'); | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  | const { | 
					
						
							| 
									
										
										
										
											2022-09-16 18:38:46 +02:00
										 |  |  |   deletePreviousOneToAnyRelations, | 
					
						
							|  |  |  |   deletePreviousAnyToOneRelations, | 
					
						
							| 
									
										
										
										
											2022-09-20 11:18:32 +02:00
										 |  |  |   deleteRelations, | 
					
						
							| 
									
										
										
										
											2022-09-26 16:22:22 +02:00
										 |  |  |   cleanOrderColumns, | 
					
						
							| 
									
										
										
										
											2022-09-20 11:18:32 +02:00
										 |  |  | } = require('./regular-relations'); | 
					
						
							| 
									
										
										
										
											2022-12-01 14:13:24 +01:00
										 |  |  | const { relationsOrderer } = require('./relations-orderer'); | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-08 23:33:39 +02:00
										 |  |  | const toId = (value) => value.id || value; | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  | const toIds = (value) => castArray(value || []).map(toId); | 
					
						
							| 
									
										
										
										
											2021-07-30 21:15:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  | const isValidId = (value) => isString(value) || isInteger(value); | 
					
						
							| 
									
										
										
										
											2022-09-19 14:39:59 +02:00
										 |  |  | const toIdArray = (data) => { | 
					
						
							|  |  |  |   const array = castArray(data) | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |     .filter((datum) => !isNil(datum)) | 
					
						
							| 
									
										
										
										
											2022-08-08 23:33:39 +02:00
										 |  |  |     .map((datum) => { | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |       // if it is a string or an integer return an obj with id = to datum
 | 
					
						
							|  |  |  |       if (isValidId(datum)) { | 
					
						
							|  |  |  |         return { id: datum, __pivot: {} }; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // if it is an object check it has at least a valid id
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |       if (!has('id', datum) || !isValidId(datum.id)) { | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |         throw new Error(`Invalid id, expected a string or integer, got ${datum}`); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return datum; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |   return uniqWith(isEqual, array); | 
					
						
							| 
									
										
										
										
											2022-09-19 14:39:59 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const toAssocs = (data) => { | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |   if (isArray(data) || isString(data) || isNumber(data) || isNull(data) || data?.id) { | 
					
						
							| 
									
										
										
										
											2022-09-19 14:39:59 +02:00
										 |  |  |     return { | 
					
						
							|  |  |  |       set: isNull(data) ? data : toIdArray(data), | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (data?.set) { | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       set: isNull(data.set) ? data.set : toIdArray(data.set), | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							| 
									
										
										
										
											2022-12-12 18:16:37 +01:00
										 |  |  |     options: { | 
					
						
							| 
									
										
										
										
											2022-12-20 15:09:21 +01:00
										 |  |  |       strict: data?.options?.strict, | 
					
						
							| 
									
										
										
										
											2022-12-12 18:16:37 +01:00
										 |  |  |     }, | 
					
						
							| 
									
										
										
										
											2022-10-24 10:21:29 +02:00
										 |  |  |     connect: toIdArray(data?.connect).map((elm) => ({ | 
					
						
							|  |  |  |       id: elm.id, | 
					
						
							|  |  |  |       position: elm.position ? elm.position : { end: true }, | 
					
						
							|  |  |  |     })), | 
					
						
							| 
									
										
										
										
											2022-09-19 14:39:59 +02:00
										 |  |  |     disconnect: toIdArray(data?.disconnect), | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-22 10:49:43 +02:00
										 |  |  | const processData = (metadata, data = {}, { withDefaults = false } = {}) => { | 
					
						
							| 
									
										
										
										
											2021-06-22 17:13:11 +02:00
										 |  |  |   const { attributes } = metadata; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-23 15:37:20 +02:00
										 |  |  |   const obj = {}; | 
					
						
							| 
									
										
										
										
											2021-06-22 17:13:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-05 19:44:58 +02:00
										 |  |  |   for (const attributeName of Object.keys(attributes)) { | 
					
						
							| 
									
										
										
										
											2021-06-23 15:37:20 +02:00
										 |  |  |     const attribute = attributes[attributeName]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |     if (types.isScalar(attribute.type)) { | 
					
						
							|  |  |  |       const field = createField(attribute); | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |       if (isUndefined(data[attributeName])) { | 
					
						
							|  |  |  |         if (!isUndefined(attribute.default) && withDefaults) { | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |           if (typeof attribute.default === 'function') { | 
					
						
							|  |  |  |             obj[attributeName] = attribute.default(); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             obj[attributeName] = attribute.default; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |       if (typeof field.validate === 'function' && data[attributeName] !== null) { | 
					
						
							|  |  |  |         field.validate(data[attributeName]); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-06-30 20:00:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-28 21:37:44 +02:00
										 |  |  |       const val = data[attributeName] === null ? null : field.toDB(data[attributeName]); | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-28 21:37:44 +02:00
										 |  |  |       obj[attributeName] = val; | 
					
						
							| 
									
										
										
										
											2021-06-23 15:37:20 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (types.isRelation(attribute.type)) { | 
					
						
							|  |  |  |       // oneToOne & manyToOne
 | 
					
						
							|  |  |  |       if (attribute.joinColumn && attribute.owner) { | 
					
						
							|  |  |  |         const joinColumnName = attribute.joinColumn.name; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |         // allow setting to null
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |         const attrValue = !isUndefined(data[attributeName]) | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |           ? data[attributeName] | 
					
						
							|  |  |  |           : data[joinColumnName]; | 
					
						
							| 
									
										
										
										
											2021-06-23 15:37:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |         if (!isUndefined(attrValue)) { | 
					
						
							| 
									
										
										
										
											2021-06-23 15:37:20 +02:00
										 |  |  |           obj[joinColumnName] = attrValue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (attribute.morphColumn && attribute.owner) { | 
					
						
							| 
									
										
										
										
											2021-07-26 22:02:48 +02:00
										 |  |  |         const { idColumn, typeColumn, typeField = '__type' } = attribute.morphColumn; | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const value = data[attributeName]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-30 20:45:51 +02:00
										 |  |  |         if (value === null) { | 
					
						
							|  |  |  |           Object.assign(obj, { | 
					
						
							|  |  |  |             [idColumn.name]: null, | 
					
						
							|  |  |  |             [typeColumn.name]: null, | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |         if (!isUndefined(value)) { | 
					
						
							|  |  |  |           if (!has('id', value) || !has(typeField, value)) { | 
					
						
							| 
									
										
										
										
											2021-07-26 22:02:48 +02:00
										 |  |  |             throw new Error(`Expects properties ${typeField} an id to make a morph association`); | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-30 20:45:51 +02:00
										 |  |  |           Object.assign(obj, { | 
					
						
							|  |  |  |             [idColumn.name]: value.id, | 
					
						
							|  |  |  |             [typeColumn.name]: value[typeField], | 
					
						
							|  |  |  |           }); | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-06-23 15:37:20 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return obj; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-08 23:33:39 +02:00
										 |  |  | const createEntityManager = (db) => { | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |   const repoMap = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |     async findOne(uid, params) { | 
					
						
							| 
									
										
										
										
											2022-04-04 19:22:05 +02:00
										 |  |  |       const states = await db.lifecycles.run('beforeFindOne', uid, { params }); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-08 23:33:39 +02:00
										 |  |  |       const result = await this.createQueryBuilder(uid).init(params).first().execute(); | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 13:20:14 +01:00
										 |  |  |       await db.lifecycles.run('afterFindOne', uid, { params, result }, states); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return result; | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // should we name it findOne because people are used to it ?
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |     async findMany(uid, params) { | 
					
						
							| 
									
										
										
										
											2022-04-04 19:22:05 +02:00
										 |  |  |       const states = await db.lifecycles.run('beforeFindMany', uid, { params }); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-08 23:33:39 +02:00
										 |  |  |       const result = await this.createQueryBuilder(uid).init(params).execute(); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 13:20:14 +01:00
										 |  |  |       await db.lifecycles.run('afterFindMany', uid, { params, result }, states); | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |       return result; | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 13:20:14 +01:00
										 |  |  |     async count(uid, params) { | 
					
						
							| 
									
										
										
										
											2022-04-04 19:22:05 +02:00
										 |  |  |       const states = await db.lifecycles.run('beforeCount', uid, { params }); | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |       const res = await this.createQueryBuilder(uid) | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |         .init(pick(['_q', 'where', 'filters'], params)) | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |         .count() | 
					
						
							|  |  |  |         .first() | 
					
						
							|  |  |  |         .execute(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |       const result = Number(res.count); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 13:20:14 +01:00
										 |  |  |       await db.lifecycles.run('afterCount', uid, { params, result }, states); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return result; | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |     async create(uid, params = {}) { | 
					
						
							| 
									
										
										
										
											2022-04-04 19:22:05 +02:00
										 |  |  |       const states = await db.lifecycles.run('beforeCreate', uid, { params }); | 
					
						
							| 
									
										
										
										
											2021-06-23 15:37:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |       const metadata = db.metadata.get(uid); | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |       const { data } = params; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |       if (!isPlainObject(data)) { | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |         throw new Error('Create expects a data object'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-22 10:49:43 +02:00
										 |  |  |       const dataToInsert = processData(metadata, data, { withDefaults: true }); | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 16:11:08 +01:00
										 |  |  |       const res = await this.createQueryBuilder(uid).insert(dataToInsert).execute(); | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 16:11:08 +01:00
										 |  |  |       const id = res[0].id || res[0]; | 
					
						
							| 
									
										
										
										
											2022-03-22 19:41:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 16:11:08 +01:00
										 |  |  |       const trx = await strapi.db.transaction(); | 
					
						
							|  |  |  |       try { | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |         await this.attachRelations(uid, id, data, { transaction: trx }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await trx.commit(); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         await trx.rollback(); | 
					
						
							| 
									
										
										
										
											2022-12-02 18:09:30 +01:00
										 |  |  |         await this.createQueryBuilder(uid).where({ id }).delete().execute(); | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |         throw e; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-13 14:06:16 +02:00
										 |  |  |       // TODO: in case there is no select or populate specified return the inserted data ?
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |       // TODO: do not trigger the findOne lifecycles ?
 | 
					
						
							| 
									
										
										
										
											2021-08-04 17:47:38 +02:00
										 |  |  |       const result = await this.findOne(uid, { | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |         where: { id }, | 
					
						
							|  |  |  |         select: params.select, | 
					
						
							|  |  |  |         populate: params.populate, | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 13:20:14 +01:00
										 |  |  |       await db.lifecycles.run('afterCreate', uid, { params, result }, states); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return result; | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |     // TODO: where do we handle relation processing for many queries ?
 | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |     async createMany(uid, params = {}) { | 
					
						
							| 
									
										
										
										
											2022-04-04 19:22:05 +02:00
										 |  |  |       const states = await db.lifecycles.run('beforeCreateMany', uid, { params }); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const metadata = db.metadata.get(uid); | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |       const { data } = params; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |       if (!isArray(data)) { | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |         throw new Error('CreateMany expects data to be an array'); | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-08 23:33:39 +02:00
										 |  |  |       const dataToInsert = data.map((datum) => | 
					
						
							|  |  |  |         processData(metadata, datum, { withDefaults: true }) | 
					
						
							|  |  |  |       ); | 
					
						
							| 
									
										
										
										
											2021-06-22 17:13:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |       if (isEmpty(dataToInsert)) { | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |         throw new Error('Nothing to insert'); | 
					
						
							| 
									
										
										
										
											2021-06-24 18:28:36 +02:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-08 23:33:39 +02:00
										 |  |  |       await this.createQueryBuilder(uid).insert(dataToInsert).execute(); | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |       const result = { count: data.length }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 13:20:14 +01:00
										 |  |  |       await db.lifecycles.run('afterCreateMany', uid, { params, result }, states); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return result; | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |     async update(uid, params = {}) { | 
					
						
							| 
									
										
										
										
											2022-04-04 19:22:05 +02:00
										 |  |  |       const states = await db.lifecycles.run('beforeUpdate', uid, { params }); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-23 15:37:20 +02:00
										 |  |  |       const metadata = db.metadata.get(uid); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |       const { where, data } = params; | 
					
						
							| 
									
										
										
										
											2021-06-22 17:13:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |       if (!isPlainObject(data)) { | 
					
						
							| 
									
										
										
										
											2021-06-30 20:00:03 +02:00
										 |  |  |         throw new Error('Update requires a data object'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |       if (isEmpty(where)) { | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |         throw new Error('Update requires a where parameter'); | 
					
						
							| 
									
										
										
										
											2021-06-24 18:28:36 +02:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 18:09:30 +01:00
										 |  |  |       const entity = await this.createQueryBuilder(uid) | 
					
						
							|  |  |  |         .select('*') | 
					
						
							|  |  |  |         .where(where) | 
					
						
							|  |  |  |         .first() | 
					
						
							|  |  |  |         .execute({ mapResults: false }); | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |       if (!entity) { | 
					
						
							|  |  |  |         return null; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const { id } = entity; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 16:11:08 +01:00
										 |  |  |       const dataToUpdate = processData(metadata, data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (!isEmpty(dataToUpdate)) { | 
					
						
							|  |  |  |         await this.createQueryBuilder(uid).where({ id }).update(dataToUpdate).execute(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |       const trx = await strapi.db.transaction(); | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         await this.updateRelations(uid, id, data, { transaction: trx }); | 
					
						
							|  |  |  |         await trx.commit(); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         await trx.rollback(); | 
					
						
							| 
									
										
										
										
											2022-12-02 18:09:30 +01:00
										 |  |  |         await this.createQueryBuilder(uid).where({ id }).update(entity).execute(); | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |         throw e; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |       // TODO: do not trigger the findOne lifecycles ?
 | 
					
						
							| 
									
										
										
										
											2021-08-04 17:47:38 +02:00
										 |  |  |       const result = await this.findOne(uid, { | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |         where: { id }, | 
					
						
							|  |  |  |         select: params.select, | 
					
						
							|  |  |  |         populate: params.populate, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 13:20:14 +01:00
										 |  |  |       await db.lifecycles.run('afterUpdate', uid, { params, result }, states); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return result; | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |     // TODO: where do we handle relation processing for many queries ?
 | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |     async updateMany(uid, params = {}) { | 
					
						
							| 
									
										
										
										
											2022-04-04 19:22:05 +02:00
										 |  |  |       const states = await db.lifecycles.run('beforeUpdateMany', uid, { params }); | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-23 15:37:20 +02:00
										 |  |  |       const metadata = db.metadata.get(uid); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |       const { where, data } = params; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-22 10:49:43 +02:00
										 |  |  |       const dataToUpdate = processData(metadata, data); | 
					
						
							| 
									
										
										
										
											2021-06-22 17:13:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |       if (isEmpty(dataToUpdate)) { | 
					
						
							| 
									
										
										
										
											2021-06-24 18:28:36 +02:00
										 |  |  |         throw new Error('Update requires data'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |       const updatedRows = await this.createQueryBuilder(uid) | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |         .where(where) | 
					
						
							| 
									
										
										
										
											2021-06-22 17:13:11 +02:00
										 |  |  |         .update(dataToUpdate) | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |         .execute(); | 
					
						
							| 
									
										
										
										
											2021-06-24 18:28:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |       const result = { count: updatedRows }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 13:20:14 +01:00
										 |  |  |       await db.lifecycles.run('afterUpdateMany', uid, { params, result }, states); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return result; | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |     }, | 
					
						
							| 
									
										
										
										
											2021-06-24 18:28:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |     async delete(uid, params = {}) { | 
					
						
							| 
									
										
										
										
											2022-04-04 19:22:05 +02:00
										 |  |  |       const states = await db.lifecycles.run('beforeDelete', uid, { params }); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |       const { where, select, populate } = params; | 
					
						
							| 
									
										
										
										
											2021-06-24 18:28:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |       if (isEmpty(where)) { | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |         throw new Error('Delete requires a where parameter'); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-13 14:06:16 +02:00
										 |  |  |       // TODO: do not trigger the findOne lifecycles ?
 | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |       const entity = await this.findOne(uid, { | 
					
						
							|  |  |  |         select: select && ['id'].concat(select), | 
					
						
							| 
									
										
										
										
											2021-07-07 18:04:39 +02:00
										 |  |  |         where, | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |         populate, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (!entity) { | 
					
						
							|  |  |  |         return null; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const { id } = entity; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 16:11:08 +01:00
										 |  |  |       await this.createQueryBuilder(uid).where({ id }).delete().execute(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |       const trx = await strapi.db.transaction(); | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         await this.deleteRelations(uid, id, { transaction: trx }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await trx.commit(); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         await trx.rollback(); | 
					
						
							|  |  |  |         throw e; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-06-24 18:28:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 13:20:14 +01:00
										 |  |  |       await db.lifecycles.run('afterDelete', uid, { params, result: entity }, states); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |       return entity; | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 12:07:32 +02:00
										 |  |  |     // TODO: where do we handle relation processing for many queries ?
 | 
					
						
							|  |  |  |     async deleteMany(uid, params = {}) { | 
					
						
							| 
									
										
										
										
											2022-04-04 19:22:05 +02:00
										 |  |  |       const states = await db.lifecycles.run('beforeDeleteMany', uid, { params }); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |       const { where } = params; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-08 23:33:39 +02:00
										 |  |  |       const deletedRows = await this.createQueryBuilder(uid).where(where).delete().execute(); | 
					
						
							| 
									
										
										
										
											2021-06-24 18:28:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |       const result = { count: deletedRows }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-23 10:26:10 +02:00
										 |  |  |       await db.lifecycles.run('afterDeleteMany', uid, { params, result }, states); | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return result; | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Attach relations to a new entity | 
					
						
							| 
									
										
										
										
											2021-06-30 21:17:32 +02:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |      * @param {EntityManager} em - entity manager instance | 
					
						
							|  |  |  |      * @param {Metadata} metadata - model metadta | 
					
						
							|  |  |  |      * @param {ID} id - entity ID | 
					
						
							|  |  |  |      * @param {object} data - data received for creation | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |     async attachRelations(uid, id, data, { transaction: trx }) { | 
					
						
							| 
									
										
										
										
											2021-07-06 14:18:03 +02:00
										 |  |  |       const { attributes } = db.metadata.get(uid); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-26 17:35:11 +02:00
										 |  |  |       for (const attributeName of Object.keys(attributes)) { | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |         const attribute = attributes[attributeName]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |         const isValidLink = has(attributeName, data) && !isNil(data[attributeName]); | 
					
						
							| 
									
										
										
										
											2021-07-28 15:32:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (attribute.type !== 'relation' || !isValidLink) { | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |         const cleanRelationData = toAssocs(data[attributeName]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |         if (attribute.relation === 'morphOne' || attribute.relation === 'morphMany') { | 
					
						
							|  |  |  |           const { target, morphBy } = attribute; | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |           const targetAttribute = db.metadata.get(target).attributes[morphBy]; | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |           if (targetAttribute.relation === 'morphToOne') { | 
					
						
							|  |  |  |             // set columns
 | 
					
						
							|  |  |  |             const { idColumn, typeColumn } = targetAttribute.morphColumn; | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |             const relId = toId(cleanRelationData.set[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |             await this.createQueryBuilder(target) | 
					
						
							|  |  |  |               .update({ [idColumn.name]: id, [typeColumn.name]: uid }) | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |               .where({ id: relId }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |               .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |               .execute(); | 
					
						
							| 
									
										
										
										
											2021-07-30 20:45:51 +02:00
										 |  |  |           } else if (targetAttribute.relation === 'morphToMany') { | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |             const { joinTable } = targetAttribute; | 
					
						
							|  |  |  |             const { joinColumn, morphColumn } = joinTable; | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             const { idColumn, typeColumn } = morphColumn; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-30 10:47:32 +02:00
										 |  |  |             if (isEmpty(cleanRelationData.set)) { | 
					
						
							|  |  |  |               continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |             const rows = cleanRelationData.set.map((data, idx) => { | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |               return { | 
					
						
							|  |  |  |                 [joinColumn.name]: data.id, | 
					
						
							|  |  |  |                 [idColumn.name]: id, | 
					
						
							|  |  |  |                 [typeColumn.name]: uid, | 
					
						
							|  |  |  |                 ...(joinTable.on || {}), | 
					
						
							|  |  |  |                 ...(data.__pivot || {}), | 
					
						
							| 
									
										
										
										
											2021-08-17 18:08:42 +02:00
										 |  |  |                 order: idx + 1, | 
					
						
							|  |  |  |                 field: attributeName, | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |               }; | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |             await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute(); | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } else if (attribute.relation === 'morphToOne') { | 
					
						
							|  |  |  |           // handled on the entry itself
 | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } else if (attribute.relation === 'morphToMany') { | 
					
						
							|  |  |  |           const { joinTable } = attribute; | 
					
						
							|  |  |  |           const { joinColumn, morphColumn } = joinTable; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-26 22:02:48 +02:00
										 |  |  |           const { idColumn, typeColumn, typeField = '__type' } = morphColumn; | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-30 10:47:32 +02:00
										 |  |  |           if (isEmpty(cleanRelationData.set)) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-22 17:42:30 +02:00
										 |  |  |           const rows = cleanRelationData.set.map((data, idx) => ({ | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |             [joinColumn.name]: id, | 
					
						
							|  |  |  |             [idColumn.name]: data.id, | 
					
						
							| 
									
										
										
										
											2021-07-26 22:02:48 +02:00
										 |  |  |             [typeColumn.name]: data[typeField], | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |             ...(joinTable.on || {}), | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |             ...(data.__pivot || {}), | 
					
						
							| 
									
										
										
										
											2022-09-22 17:42:30 +02:00
										 |  |  |             order: idx + 1, | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |           })); | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 10:56:36 +02:00
										 |  |  |           // delete previous relations
 | 
					
						
							| 
									
										
										
										
											2022-09-05 16:18:00 +02:00
										 |  |  |           await deleteRelatedMorphOneRelationsAfterMorphToManyUpdate(rows, { | 
					
						
							|  |  |  |             uid, | 
					
						
							|  |  |  |             attributeName, | 
					
						
							|  |  |  |             joinTable, | 
					
						
							|  |  |  |             db, | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |             transaction: trx, | 
					
						
							| 
									
										
										
										
											2022-09-02 12:18:48 +02:00
										 |  |  |           }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |           await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute(); | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |           continue; | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |         if (attribute.joinColumn && attribute.owner) { | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |           const relIdsToAdd = toIds(cleanRelationData.set); | 
					
						
							| 
									
										
										
										
											2021-07-05 18:35:16 +02:00
										 |  |  |           if ( | 
					
						
							|  |  |  |             attribute.relation === 'oneToOne' && | 
					
						
							|  |  |  |             isBidirectional(attribute) && | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |             relIdsToAdd.length | 
					
						
							| 
									
										
										
										
											2021-07-05 18:35:16 +02:00
										 |  |  |           ) { | 
					
						
							| 
									
										
										
										
											2021-07-06 14:18:03 +02:00
										 |  |  |             await this.createQueryBuilder(uid) | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |               .where({ [attribute.joinColumn.name]: relIdsToAdd, id: { $ne: id } }) | 
					
						
							| 
									
										
										
										
											2021-07-02 02:26:14 +02:00
										 |  |  |               .update({ [attribute.joinColumn.name]: null }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |               .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-07-02 02:26:14 +02:00
										 |  |  |               .execute(); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // oneToOne oneToMany on the non owning side
 | 
					
						
							|  |  |  |         if (attribute.joinColumn && !attribute.owner) { | 
					
						
							|  |  |  |           // need to set the column on the target
 | 
					
						
							|  |  |  |           const { target } = attribute; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // TODO: check it is an id & the entity exists (will throw due to FKs otherwise so not a big pbl in SQL)
 | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |           const relIdsToAdd = toIds(cleanRelationData.set); | 
					
						
							| 
									
										
										
										
											2021-07-02 02:26:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-28 15:32:21 +02:00
										 |  |  |           await this.createQueryBuilder(target) | 
					
						
							|  |  |  |             .where({ [attribute.joinColumn.referencedColumn]: id }) | 
					
						
							|  |  |  |             .update({ [attribute.joinColumn.referencedColumn]: null }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |             .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-07-28 15:32:21 +02:00
										 |  |  |             .execute(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           await this.createQueryBuilder(target) | 
					
						
							|  |  |  |             .update({ [attribute.joinColumn.referencedColumn]: id }) | 
					
						
							|  |  |  |             // NOTE: works if it is an array or a single id
 | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |             .where({ id: relIdsToAdd }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |             .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-07-28 15:32:21 +02:00
										 |  |  |             .execute(); | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (attribute.joinTable) { | 
					
						
							|  |  |  |           // need to set the column on the target
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           const { joinTable } = attribute; | 
					
						
							| 
									
										
										
										
											2022-09-07 18:21:54 +02:00
										 |  |  |           const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = | 
					
						
							|  |  |  |             joinTable; | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-19 14:39:59 +02:00
										 |  |  |           const relsToAdd = cleanRelationData.set || cleanRelationData.connect; | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |           const relIdsToadd = toIds(relsToAdd); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 16:07:00 +02:00
										 |  |  |           if (isBidirectional(attribute) && isOneToAny(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |             await deletePreviousOneToAnyRelations({ | 
					
						
							|  |  |  |               id, | 
					
						
							|  |  |  |               attribute, | 
					
						
							|  |  |  |               relIdsToadd, | 
					
						
							|  |  |  |               db, | 
					
						
							|  |  |  |               transaction: trx, | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2022-09-27 16:07:00 +02:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2021-07-28 15:32:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |           // prepare new relations to insert
 | 
					
						
							| 
									
										
										
										
											2022-11-25 16:19:04 +01:00
										 |  |  |           const insert = uniqBy('id', relsToAdd).map((data) => { | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |             return { | 
					
						
							|  |  |  |               [joinColumn.name]: id, | 
					
						
							|  |  |  |               [inverseJoinColumn.name]: data.id, | 
					
						
							|  |  |  |               ...(joinTable.on || {}), | 
					
						
							|  |  |  |               ...(data.__pivot || {}), | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |           }); | 
					
						
							| 
									
										
										
										
											2022-09-07 18:21:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-21 11:17:12 +02:00
										 |  |  |           // add order value
 | 
					
						
							| 
									
										
										
										
											2022-11-20 10:49:24 +01:00
										 |  |  |           if (cleanRelationData.set && hasOrderColumn(attribute)) { | 
					
						
							|  |  |  |             insert.forEach((data, idx) => { | 
					
						
							|  |  |  |               data[orderColumnName] = idx + 1; | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           } else if (cleanRelationData.connect && hasOrderColumn(attribute)) { | 
					
						
							|  |  |  |             // use position attributes to calculate order
 | 
					
						
							| 
									
										
										
										
											2023-01-11 16:40:06 +01:00
										 |  |  |             const orderMap = relationsOrderer( | 
					
						
							|  |  |  |               [], | 
					
						
							|  |  |  |               inverseJoinColumn.name, | 
					
						
							|  |  |  |               joinTable.orderColumnName, | 
					
						
							|  |  |  |               true // Always make an strict connect when inserting
 | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2022-11-20 10:49:24 +01:00
										 |  |  |               .connect(relsToAdd) | 
					
						
							|  |  |  |               .get() | 
					
						
							|  |  |  |               // set the order based on the order of the ids
 | 
					
						
							| 
									
										
										
										
											2022-11-21 15:00:47 +01:00
										 |  |  |               .reduce((acc, rel, idx) => ({ ...acc, [rel.id]: idx }), {}); | 
					
						
							| 
									
										
										
										
											2022-11-20 10:49:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             insert.forEach((row) => { | 
					
						
							|  |  |  |               row[orderColumnName] = orderMap[row[inverseJoinColumn.name]]; | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |             }); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2022-11-20 10:49:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-21 11:17:12 +02:00
										 |  |  |           // add inv_order value
 | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  |           if (hasInverseOrderColumn(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-09-21 11:17:12 +02:00
										 |  |  |             const maxResults = await db | 
					
						
							|  |  |  |               .getConnection() | 
					
						
							|  |  |  |               .select(inverseJoinColumn.name) | 
					
						
							|  |  |  |               .max(inverseOrderColumnName, { as: 'max' }) | 
					
						
							|  |  |  |               .whereIn(inverseJoinColumn.name, relIdsToadd) | 
					
						
							|  |  |  |               .where(joinTable.on || {}) | 
					
						
							|  |  |  |               .groupBy(inverseJoinColumn.name) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |               .from(joinTable.name) | 
					
						
							|  |  |  |               .transacting(trx); | 
					
						
							| 
									
										
										
										
											2022-09-21 11:17:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             const maxMap = maxResults.reduce( | 
					
						
							|  |  |  |               (acc, res) => Object.assign(acc, { [res[inverseJoinColumn.name]]: res.max }), | 
					
						
							|  |  |  |               {} | 
					
						
							| 
									
										
										
										
											2022-09-07 18:21:54 +02:00
										 |  |  |             ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |             insert.forEach((rel) => { | 
					
						
							| 
									
										
										
										
											2022-09-21 11:17:12 +02:00
										 |  |  |               rel[inverseOrderColumnName] = (maxMap[rel[inverseJoinColumn.name]] || 0) + 1; | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |             }); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2021-07-28 15:32:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |           if (insert.length === 0) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |           // insert new relations
 | 
					
						
							| 
									
										
										
										
											2022-11-25 16:19:04 +01:00
										 |  |  |           await this.createQueryBuilder(joinTable.name).insert(insert).transacting(trx).execute(); | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Updates relations of an existing entity | 
					
						
							| 
									
										
										
										
											2021-06-30 21:17:32 +02:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |      * @param {EntityManager} em - entity manager instance | 
					
						
							|  |  |  |      * @param {Metadata} metadata - model metadta | 
					
						
							|  |  |  |      * @param {ID} id - entity ID | 
					
						
							|  |  |  |      * @param {object} data - data received for creation | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     // TODO: check relation exists (handled by FKs except for polymorphics)
 | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |     async updateRelations(uid, id, data, { transaction: trx }) { | 
					
						
							| 
									
										
										
										
											2021-07-06 14:18:03 +02:00
										 |  |  |       const { attributes } = db.metadata.get(uid); | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-26 17:35:11 +02:00
										 |  |  |       for (const attributeName of Object.keys(attributes)) { | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |         const attribute = attributes[attributeName]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-25 11:56:52 +02:00
										 |  |  |         if (attribute.type !== 'relation' || !has(attributeName, data)) { | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |         const cleanRelationData = toAssocs(data[attributeName]); | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 10:56:36 +02:00
										 |  |  |             // update instead of deleting because the relation is directly on the entity table
 | 
					
						
							|  |  |  |             // and not in a join table
 | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |             await this.createQueryBuilder(target) | 
					
						
							|  |  |  |               .update({ [idColumn.name]: null, [typeColumn.name]: null }) | 
					
						
							|  |  |  |               .where({ [idColumn.name]: id, [typeColumn.name]: uid }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |               .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |               .execute(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |             if (!isNull(cleanRelationData.set)) { | 
					
						
							|  |  |  |               const relId = toIds(cleanRelationData.set[0]); | 
					
						
							| 
									
										
										
										
											2021-07-30 20:45:51 +02:00
										 |  |  |               await this.createQueryBuilder(target) | 
					
						
							|  |  |  |                 .update({ [idColumn.name]: id, [typeColumn.name]: uid }) | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |                 .where({ id: relId }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |                 .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-07-30 20:45:51 +02:00
										 |  |  |                 .execute(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } else if (targetAttribute.relation === 'morphToMany') { | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |             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 || {}), | 
					
						
							| 
									
										
										
										
											2021-08-17 18:08:42 +02:00
										 |  |  |                 field: attributeName, | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |               }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |               .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |               .execute(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-30 10:47:32 +02:00
										 |  |  |             if (isEmpty(cleanRelationData.set)) { | 
					
						
							|  |  |  |               continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |             const rows = cleanRelationData.set.map((data, idx) => ({ | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |               [joinColumn.name]: data.id, | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |               [idColumn.name]: id, | 
					
						
							|  |  |  |               [typeColumn.name]: uid, | 
					
						
							|  |  |  |               ...(joinTable.on || {}), | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |               ...(data.__pivot || {}), | 
					
						
							| 
									
										
										
										
											2021-08-17 18:08:42 +02:00
										 |  |  |               order: idx + 1, | 
					
						
							|  |  |  |               field: attributeName, | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |             })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |             await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute(); | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (attribute.relation === 'morphToOne') { | 
					
						
							| 
									
										
										
										
											2021-07-30 20:45:51 +02:00
										 |  |  |           // handled on the entry itself
 | 
					
						
							|  |  |  |           continue; | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (attribute.relation === 'morphToMany') { | 
					
						
							|  |  |  |           const { joinTable } = attribute; | 
					
						
							|  |  |  |           const { joinColumn, morphColumn } = joinTable; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-26 22:02:48 +02:00
										 |  |  |           const { idColumn, typeColumn, typeField = '__type' } = morphColumn; | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |           await this.createQueryBuilder(joinTable.name) | 
					
						
							|  |  |  |             .delete() | 
					
						
							|  |  |  |             .where({ | 
					
						
							|  |  |  |               [joinColumn.name]: id, | 
					
						
							|  |  |  |               ...(joinTable.on || {}), | 
					
						
							|  |  |  |             }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |             .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |             .execute(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-30 10:47:32 +02:00
										 |  |  |           if (isEmpty(cleanRelationData.set)) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-22 17:42:30 +02:00
										 |  |  |           const rows = cleanRelationData.set.map((data, idx) => ({ | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |             [joinColumn.name]: id, | 
					
						
							|  |  |  |             [idColumn.name]: data.id, | 
					
						
							| 
									
										
										
										
											2021-07-26 22:02:48 +02:00
										 |  |  |             [typeColumn.name]: data[typeField], | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |             ...(joinTable.on || {}), | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |             ...(data.__pivot || {}), | 
					
						
							| 
									
										
										
										
											2022-09-22 17:42:30 +02:00
										 |  |  |             order: idx + 1, | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |           })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 10:56:36 +02:00
										 |  |  |           // delete previous relations
 | 
					
						
							| 
									
										
										
										
											2022-09-05 16:18:00 +02:00
										 |  |  |           await deleteRelatedMorphOneRelationsAfterMorphToManyUpdate(rows, { | 
					
						
							|  |  |  |             uid, | 
					
						
							|  |  |  |             attributeName, | 
					
						
							|  |  |  |             joinTable, | 
					
						
							|  |  |  |             db, | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |             transaction: trx, | 
					
						
							| 
									
										
										
										
											2022-09-02 12:18:48 +02:00
										 |  |  |           }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |           await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute(); | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |         if (attribute.joinColumn && attribute.owner) { | 
					
						
							| 
									
										
										
										
											2022-05-19 14:47:23 +02:00
										 |  |  |           // handled in the row itself
 | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // oneToOne oneToMany on the non owning side.
 | 
					
						
							|  |  |  |         // Since it is a join column no need to remove previous relations
 | 
					
						
							|  |  |  |         if (attribute.joinColumn && !attribute.owner) { | 
					
						
							|  |  |  |           // need to set the column on the target
 | 
					
						
							|  |  |  |           const { target } = attribute; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-28 15:32:21 +02:00
										 |  |  |           await this.createQueryBuilder(target) | 
					
						
							|  |  |  |             .where({ [attribute.joinColumn.referencedColumn]: id }) | 
					
						
							|  |  |  |             .update({ [attribute.joinColumn.referencedColumn]: null }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |             .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-07-28 15:32:21 +02:00
										 |  |  |             .execute(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |           if (!isNull(cleanRelationData.set)) { | 
					
						
							|  |  |  |             const relIdsToAdd = toIds(cleanRelationData.set); | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |             await this.createQueryBuilder(target) | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |               .where({ id: relIdsToAdd }) | 
					
						
							| 
									
										
										
										
											2021-07-28 15:32:21 +02:00
										 |  |  |               .update({ [attribute.joinColumn.referencedColumn]: id }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |               .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |               .execute(); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (attribute.joinTable) { | 
					
						
							|  |  |  |           const { joinTable } = attribute; | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |           const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = | 
					
						
							|  |  |  |             joinTable; | 
					
						
							|  |  |  |           const select = [joinColumn.name, inverseJoinColumn.name]; | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  |           if (hasOrderColumn(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |             select.push(orderColumnName); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  |           if (hasInverseOrderColumn(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |             select.push(inverseOrderColumnName); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |           // only delete relations
 | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |           if (isNull(cleanRelationData.set)) { | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |             await deleteRelations({ id, attribute, db, relIdsToDelete: 'all', transaction: trx }); | 
					
						
							| 
									
										
										
										
											2022-09-06 17:54:42 +02:00
										 |  |  |           } else { | 
					
						
							| 
									
										
										
										
											2022-09-19 14:39:59 +02:00
										 |  |  |             const isPartialUpdate = !has('set', cleanRelationData); | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |             let relIdsToaddOrMove; | 
					
						
							| 
									
										
										
										
											2022-09-06 15:16:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if (isPartialUpdate) { | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |               if (isAnyToOne(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-09-19 14:39:59 +02:00
										 |  |  |                 cleanRelationData.connect = cleanRelationData.connect.slice(-1); | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |               } | 
					
						
							| 
									
										
										
										
											2022-09-19 14:39:59 +02:00
										 |  |  |               relIdsToaddOrMove = toIds(cleanRelationData.connect); | 
					
						
							|  |  |  |               const relIdsToDelete = toIds( | 
					
						
							| 
									
										
										
										
											2022-09-19 17:38:24 +02:00
										 |  |  |                 differenceWith(isEqual, cleanRelationData.disconnect, cleanRelationData.connect) | 
					
						
							| 
									
										
										
										
											2022-09-19 14:39:59 +02:00
										 |  |  |               ); | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-28 13:28:02 +02:00
										 |  |  |               if (!isEmpty(relIdsToDelete)) { | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |                 await deleteRelations({ id, attribute, db, relIdsToDelete, transaction: trx }); | 
					
						
							| 
									
										
										
										
											2022-09-28 13:28:02 +02:00
										 |  |  |               } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-22 14:38:58 +02:00
										 |  |  |               if (isEmpty(cleanRelationData.connect)) { | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               // Fetch current relations to handle ordering
 | 
					
						
							|  |  |  |               let currentMovingRels; | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  |               if (hasOrderColumn(attribute) || hasInverseOrderColumn(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-09-22 14:38:58 +02:00
										 |  |  |                 currentMovingRels = await this.createQueryBuilder(joinTable.name) | 
					
						
							|  |  |  |                   .select(select) | 
					
						
							|  |  |  |                   .where({ | 
					
						
							|  |  |  |                     [joinColumn.name]: id, | 
					
						
							|  |  |  |                     [inverseJoinColumn.name]: { $in: relIdsToaddOrMove }, | 
					
						
							|  |  |  |                   }) | 
					
						
							|  |  |  |                   .where(joinTable.on || {}) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |                   .transacting(trx) | 
					
						
							| 
									
										
										
										
											2022-09-22 14:38:58 +02:00
										 |  |  |                   .execute(); | 
					
						
							|  |  |  |               } | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-22 14:38:58 +02:00
										 |  |  |               // prepare relations to insert
 | 
					
						
							| 
									
										
										
										
											2022-11-25 16:19:04 +01:00
										 |  |  |               const insert = uniqBy('id', cleanRelationData.connect).map((relToAdd) => ({ | 
					
						
							| 
									
										
										
										
											2022-09-22 14:38:58 +02:00
										 |  |  |                 [joinColumn.name]: id, | 
					
						
							|  |  |  |                 [inverseJoinColumn.name]: relToAdd.id, | 
					
						
							|  |  |  |                 ...(joinTable.on || {}), | 
					
						
							|  |  |  |                 ...(relToAdd.__pivot || {}), | 
					
						
							|  |  |  |               })); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  |               if (hasOrderColumn(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-11-11 17:08:52 +01:00
										 |  |  |                 // Get all adjacent relations and the one with the highest order
 | 
					
						
							| 
									
										
										
										
											2022-10-24 09:22:45 +02:00
										 |  |  |                 const adjacentRelations = await this.createQueryBuilder(joinTable.name) | 
					
						
							|  |  |  |                   .where({ | 
					
						
							| 
									
										
										
										
											2022-11-11 17:08:52 +01:00
										 |  |  |                     $or: [ | 
					
						
							|  |  |  |                       { | 
					
						
							|  |  |  |                         [joinColumn.name]: id, | 
					
						
							|  |  |  |                         [inverseJoinColumn.name]: { | 
					
						
							|  |  |  |                           $in: compact( | 
					
						
							|  |  |  |                             cleanRelationData.connect.map( | 
					
						
							|  |  |  |                               (r) => r.position?.after || r.position?.before | 
					
						
							|  |  |  |                             ) | 
					
						
							|  |  |  |                           ), | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                       }, | 
					
						
							|  |  |  |                       { | 
					
						
							| 
									
										
										
										
											2022-11-20 10:49:59 +01:00
										 |  |  |                         [joinColumn.name]: id, | 
					
						
							| 
									
										
										
										
											2022-11-11 17:08:52 +01:00
										 |  |  |                         [orderColumnName]: this.createQueryBuilder(joinTable.name) | 
					
						
							|  |  |  |                           .max(orderColumnName) | 
					
						
							|  |  |  |                           .where({ [joinColumn.name]: id }) | 
					
						
							|  |  |  |                           .where(joinTable.on || {}) | 
					
						
							|  |  |  |                           .transacting(trx) | 
					
						
							|  |  |  |                           .getKnexQuery(), | 
					
						
							|  |  |  |                       }, | 
					
						
							|  |  |  |                     ], | 
					
						
							| 
									
										
										
										
											2022-10-24 09:22:45 +02:00
										 |  |  |                   }) | 
					
						
							|  |  |  |                   .where(joinTable.on || {}) | 
					
						
							|  |  |  |                   .transacting(trx) | 
					
						
							|  |  |  |                   .execute(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-16 12:44:28 +01:00
										 |  |  |                 const orderMap = relationsOrderer( | 
					
						
							| 
									
										
										
										
											2022-10-24 09:22:45 +02:00
										 |  |  |                   adjacentRelations, | 
					
						
							|  |  |  |                   inverseJoinColumn.name, | 
					
						
							| 
									
										
										
										
											2022-12-12 18:16:37 +01:00
										 |  |  |                   joinTable.orderColumnName, | 
					
						
							| 
									
										
										
										
											2022-12-20 15:09:21 +01:00
										 |  |  |                   cleanRelationData.options.strict | 
					
						
							| 
									
										
										
										
											2022-10-24 09:22:45 +02:00
										 |  |  |                 ) | 
					
						
							|  |  |  |                   .connect(cleanRelationData.connect) | 
					
						
							|  |  |  |                   .getOrderMap(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 insert.forEach((row) => { | 
					
						
							|  |  |  |                   row[orderColumnName] = orderMap[row[inverseJoinColumn.name]]; | 
					
						
							| 
									
										
										
										
											2022-09-22 14:38:58 +02:00
										 |  |  |                 }); | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |               } | 
					
						
							| 
									
										
										
										
											2022-09-06 17:54:42 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-22 14:38:58 +02:00
										 |  |  |               // add inv order value
 | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  |               if (hasInverseOrderColumn(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-09-22 14:38:58 +02:00
										 |  |  |                 const nonExistingRelsIds = difference( | 
					
						
							|  |  |  |                   relIdsToaddOrMove, | 
					
						
							|  |  |  |                   map(inverseJoinColumn.name, currentMovingRels) | 
					
						
							|  |  |  |                 ); | 
					
						
							| 
									
										
										
										
											2022-09-21 11:35:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-22 14:38:58 +02:00
										 |  |  |                 const maxResults = await db | 
					
						
							|  |  |  |                   .getConnection() | 
					
						
							|  |  |  |                   .select(inverseJoinColumn.name) | 
					
						
							|  |  |  |                   .max(inverseOrderColumnName, { as: 'max' }) | 
					
						
							|  |  |  |                   .whereIn(inverseJoinColumn.name, nonExistingRelsIds) | 
					
						
							|  |  |  |                   .where(joinTable.on || {}) | 
					
						
							|  |  |  |                   .groupBy(inverseJoinColumn.name) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |                   .from(joinTable.name) | 
					
						
							|  |  |  |                   .transacting(trx); | 
					
						
							| 
									
										
										
										
											2022-09-22 14:38:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 const maxMap = maxResults.reduce( | 
					
						
							|  |  |  |                   (acc, res) => Object.assign(acc, { [res[inverseJoinColumn.name]]: res.max }), | 
					
						
							|  |  |  |                   {} | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 insert.forEach((row) => { | 
					
						
							|  |  |  |                   row[inverseOrderColumnName] = (maxMap[row[inverseJoinColumn.name]] || 0) + 1; | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               // insert rows
 | 
					
						
							|  |  |  |               const query = this.createQueryBuilder(joinTable.name) | 
					
						
							|  |  |  |                 .insert(insert) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |                 .onConflict(joinTable.pivotColumns) | 
					
						
							|  |  |  |                 .transacting(trx); | 
					
						
							| 
									
										
										
										
											2022-09-21 11:35:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  |               if (hasOrderColumn(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-09-22 14:38:58 +02:00
										 |  |  |                 query.merge([orderColumnName]); | 
					
						
							|  |  |  |               } else { | 
					
						
							|  |  |  |                 query.ignore(); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               await query.execute(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               // remove gap between orders
 | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |               await cleanOrderColumns({ attribute, db, id, transaction: trx }); | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2022-09-26 16:22:22 +02:00
										 |  |  |               if (isAnyToOne(attribute)) { | 
					
						
							|  |  |  |                 cleanRelationData.set = cleanRelationData.set.slice(-1); | 
					
						
							|  |  |  |               } | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |               // overwrite all relations
 | 
					
						
							| 
									
										
										
										
											2022-09-19 14:39:59 +02:00
										 |  |  |               relIdsToaddOrMove = toIds(cleanRelationData.set); | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  |               await deleteRelations({ | 
					
						
							|  |  |  |                 id, | 
					
						
							|  |  |  |                 attribute, | 
					
						
							|  |  |  |                 db, | 
					
						
							|  |  |  |                 relIdsToDelete: 'all', | 
					
						
							|  |  |  |                 relIdsToNotDelete: relIdsToaddOrMove, | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |                 transaction: trx, | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  |               }); | 
					
						
							| 
									
										
										
										
											2022-09-06 17:54:42 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  |               if (isEmpty(cleanRelationData.set)) { | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |               } | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-25 16:19:04 +01:00
										 |  |  |               const insert = uniqBy('id', cleanRelationData.set).map((relToAdd) => ({ | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  |                 [joinColumn.name]: id, | 
					
						
							|  |  |  |                 [inverseJoinColumn.name]: relToAdd.id, | 
					
						
							|  |  |  |                 ...(joinTable.on || {}), | 
					
						
							|  |  |  |                 ...(relToAdd.__pivot || {}), | 
					
						
							|  |  |  |               })); | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  |               // add order value
 | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  |               if (hasOrderColumn(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  |                 insert.forEach((row, idx) => { | 
					
						
							|  |  |  |                   row[orderColumnName] = idx + 1; | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               // add inv order value
 | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  |               if (hasInverseOrderColumn(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  |                 const existingRels = await this.createQueryBuilder(joinTable.name) | 
					
						
							| 
									
										
										
										
											2022-09-21 11:35:47 +02:00
										 |  |  |                   .select(inverseJoinColumn.name) | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  |                   .where({ | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |                     [joinColumn.name]: id, | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  |                     [inverseJoinColumn.name]: { $in: relIdsToaddOrMove }, | 
					
						
							|  |  |  |                   }) | 
					
						
							|  |  |  |                   .where(joinTable.on || {}) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |                   .transacting(trx) | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  |                   .execute(); | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-21 11:35:47 +02:00
										 |  |  |                 const nonExistingRelsIds = difference( | 
					
						
							|  |  |  |                   relIdsToaddOrMove, | 
					
						
							|  |  |  |                   map(inverseJoinColumn.name, existingRels) | 
					
						
							|  |  |  |                 ); | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  |                 const maxResults = await db | 
					
						
							|  |  |  |                   .getConnection() | 
					
						
							|  |  |  |                   .select(inverseJoinColumn.name) | 
					
						
							|  |  |  |                   .max(inverseOrderColumnName, { as: 'max' }) | 
					
						
							|  |  |  |                   .whereIn(inverseJoinColumn.name, nonExistingRelsIds) | 
					
						
							|  |  |  |                   .where(joinTable.on || {}) | 
					
						
							|  |  |  |                   .groupBy(inverseJoinColumn.name) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |                   .from(joinTable.name) | 
					
						
							|  |  |  |                   .transacting(trx); | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  |                 const maxMap = maxResults.reduce( | 
					
						
							|  |  |  |                   (acc, res) => Object.assign(acc, { [res[inverseJoinColumn.name]]: res.max }), | 
					
						
							|  |  |  |                   {} | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 insert.forEach((row) => { | 
					
						
							|  |  |  |                   row[inverseOrderColumnName] = (maxMap[row[inverseJoinColumn.name]] || 0) + 1; | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               // insert rows
 | 
					
						
							|  |  |  |               const query = this.createQueryBuilder(joinTable.name) | 
					
						
							|  |  |  |                 .insert(insert) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |                 .onConflict(joinTable.pivotColumns) | 
					
						
							|  |  |  |                 .transacting(trx); | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 11:56:46 +02:00
										 |  |  |               if (hasOrderColumn(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  |                 query.merge([orderColumnName]); | 
					
						
							|  |  |  |               } else { | 
					
						
							|  |  |  |                 query.ignore(); | 
					
						
							| 
									
										
										
										
											2022-09-06 15:16:58 +02:00
										 |  |  |               } | 
					
						
							| 
									
										
										
										
											2022-09-20 15:53:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |               await query.execute(); | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-09-06 15:16:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-14 11:30:00 +02:00
										 |  |  |             // Delete the previous relations for oneToAny relations
 | 
					
						
							| 
									
										
										
										
											2022-09-27 16:07:00 +02:00
										 |  |  |             if (isBidirectional(attribute) && isOneToAny(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-09-26 16:22:22 +02:00
										 |  |  |               await deletePreviousOneToAnyRelations({ | 
					
						
							|  |  |  |                 id, | 
					
						
							|  |  |  |                 attribute, | 
					
						
							|  |  |  |                 relIdsToadd: relIdsToaddOrMove, | 
					
						
							|  |  |  |                 db, | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |                 transaction: trx, | 
					
						
							| 
									
										
										
										
											2022-09-26 16:22:22 +02:00
										 |  |  |               }); | 
					
						
							| 
									
										
										
										
											2022-09-27 16:07:00 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-09-26 16:22:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 16:07:00 +02:00
										 |  |  |             // Delete the previous relations for anyToOne relations
 | 
					
						
							| 
									
										
										
										
											2022-10-17 18:16:57 +02:00
										 |  |  |             if (isAnyToOne(attribute)) { | 
					
						
							| 
									
										
										
										
											2022-09-26 16:22:22 +02:00
										 |  |  |               await deletePreviousAnyToOneRelations({ | 
					
						
							|  |  |  |                 id, | 
					
						
							|  |  |  |                 attribute, | 
					
						
							|  |  |  |                 relIdToadd: relIdsToaddOrMove[0], | 
					
						
							|  |  |  |                 db, | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |                 transaction: trx, | 
					
						
							| 
									
										
										
										
											2022-09-26 16:22:22 +02:00
										 |  |  |               }); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |      * Delete relational associations of an existing entity | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |      * This removes associations but doesn't do cascade deletions for components for example. This will be handled on the entity service layer instead | 
					
						
							| 
									
										
										
										
											2021-08-12 16:12:40 +02:00
										 |  |  |      * NOTE: Most of the deletion should be handled by ON DELETE CASCADE for dialects that have FKs | 
					
						
							| 
									
										
										
										
											2021-06-30 21:17:32 +02:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |      * @param {EntityManager} em - entity manager instance | 
					
						
							|  |  |  |      * @param {Metadata} metadata - model metadta | 
					
						
							|  |  |  |      * @param {ID} id - entity ID | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |     async deleteRelations(uid, id, { transaction: trx }) { | 
					
						
							| 
									
										
										
										
											2021-07-06 14:18:03 +02:00
										 |  |  |       const { attributes } = db.metadata.get(uid); | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-05 19:44:58 +02:00
										 |  |  |       for (const attributeName of Object.keys(attributes)) { | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |         const attribute = attributes[attributeName]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |         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 }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |               .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |               .execute(); | 
					
						
							| 
									
										
										
										
											2021-07-30 20:45:51 +02:00
										 |  |  |           } else if (targetAttribute.relation === 'morphToMany') { | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |             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 || {}), | 
					
						
							| 
									
										
										
										
											2021-08-17 18:08:42 +02:00
										 |  |  |                 field: attributeName, | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |               }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |               .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |               .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 || {}), | 
					
						
							|  |  |  |             }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |             .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |             .execute(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-15 12:25:09 +02:00
										 |  |  |         // do not need to delete links when using foreign keys
 | 
					
						
							| 
									
										
										
										
											2021-07-26 19:40:30 +02:00
										 |  |  |         if (db.dialect.usesForeignKeys()) { | 
					
						
							|  |  |  |           return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-07-26 17:52:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |         // NOTE: we do not remove existing associations with the target as it should handled by unique FKs instead
 | 
					
						
							|  |  |  |         if (attribute.joinColumn && attribute.owner) { | 
					
						
							|  |  |  |           // nothing to do => relation already added on the table
 | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // oneToOne oneToMany on the non owning side.
 | 
					
						
							|  |  |  |         if (attribute.joinColumn && !attribute.owner) { | 
					
						
							|  |  |  |           // need to set the column on the target
 | 
					
						
							|  |  |  |           const { target } = attribute; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           await this.createQueryBuilder(target) | 
					
						
							|  |  |  |             .where({ [attribute.joinColumn.referencedColumn]: id }) | 
					
						
							| 
									
										
										
										
											2021-07-02 02:26:14 +02:00
										 |  |  |             .update({ [attribute.joinColumn.referencedColumn]: null }) | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |             .transacting(trx) | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |             .execute(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (attribute.joinTable) { | 
					
						
							| 
									
										
										
										
											2022-10-06 18:03:10 +02:00
										 |  |  |           await deleteRelations({ id, attribute, db, relIdsToDelete: 'all', transaction: trx }); | 
					
						
							| 
									
										
										
										
											2021-06-28 12:34:29 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |     // TODO: add lifecycle events
 | 
					
						
							| 
									
										
										
										
											2021-07-08 18:15:32 +02:00
										 |  |  |     async populate(uid, entity, populate) { | 
					
						
							|  |  |  |       const entry = await this.findOne(uid, { | 
					
						
							|  |  |  |         select: ['id'], | 
					
						
							|  |  |  |         where: { id: entity.id }, | 
					
						
							| 
									
										
										
										
											2021-09-13 12:03:12 +02:00
										 |  |  |         populate, | 
					
						
							| 
									
										
										
										
											2021-07-08 18:15:32 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-08 15:50:34 +02:00
										 |  |  |       return { ...entity, ...entry }; | 
					
						
							| 
									
										
										
										
											2021-07-07 18:04:39 +02:00
										 |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:22:57 +02:00
										 |  |  |     // TODO: add lifecycle events
 | 
					
						
							| 
									
										
										
										
											2022-08-26 14:22:05 +02:00
										 |  |  |     async load(uid, entity, fields, params) { | 
					
						
							| 
									
										
										
										
											2021-07-07 18:04:39 +02:00
										 |  |  |       const { attributes } = db.metadata.get(uid); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-05 16:31:05 +02:00
										 |  |  |       const fieldsArr = castArray(fields); | 
					
						
							| 
									
										
										
										
											2022-08-26 14:22:05 +02:00
										 |  |  |       fieldsArr.forEach((field) => { | 
					
						
							|  |  |  |         const attribute = attributes[field]; | 
					
						
							| 
									
										
										
										
											2021-07-07 18:04:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-26 14:22:05 +02:00
										 |  |  |         if (!attribute || attribute.type !== 'relation') { | 
					
						
							|  |  |  |           throw new Error(`Invalid load. Expected ${field} to be a relational attribute`); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2021-07-07 18:04:39 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const entry = await this.findOne(uid, { | 
					
						
							|  |  |  |         select: ['id'], | 
					
						
							| 
									
										
										
										
											2021-07-08 18:15:32 +02:00
										 |  |  |         where: { id: entity.id }, | 
					
						
							| 
									
										
										
										
											2022-08-26 14:22:05 +02:00
										 |  |  |         populate: fieldsArr.reduce((acc, field) => { | 
					
						
							|  |  |  |           acc[field] = params || true; | 
					
						
							|  |  |  |           return acc; | 
					
						
							|  |  |  |         }, {}), | 
					
						
							| 
									
										
										
										
											2021-07-07 18:04:39 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-10 15:51:38 +02:00
										 |  |  |       if (!entry) { | 
					
						
							|  |  |  |         return null; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-26 14:22:05 +02:00
										 |  |  |       if (Array.isArray(fields)) { | 
					
						
							| 
									
										
										
										
											2022-09-05 16:31:05 +02:00
										 |  |  |         return pick(fields, entry); | 
					
						
							| 
									
										
										
										
											2022-08-26 14:22:05 +02:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return entry[fields]; | 
					
						
							| 
									
										
										
										
											2021-07-07 18:04:39 +02:00
										 |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     // cascading
 | 
					
						
							|  |  |  |     // aggregations
 | 
					
						
							|  |  |  |     // -> avg
 | 
					
						
							|  |  |  |     // -> min
 | 
					
						
							|  |  |  |     // -> max
 | 
					
						
							|  |  |  |     // -> grouping
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // formulas
 | 
					
						
							|  |  |  |     // custom queries
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // utilities
 | 
					
						
							|  |  |  |     // -> map result
 | 
					
						
							|  |  |  |     // -> map input
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // extra features
 | 
					
						
							|  |  |  |     // -> virtuals
 | 
					
						
							|  |  |  |     // -> private
 | 
					
						
							| 
									
										
										
										
											2021-06-30 21:17:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-17 16:17:15 +02:00
										 |  |  |     createQueryBuilder(uid) { | 
					
						
							|  |  |  |       return createQueryBuilder(uid, db); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     getRepository(uid) { | 
					
						
							|  |  |  |       if (!repoMap[uid]) { | 
					
						
							|  |  |  |         repoMap[uid] = createRepository(uid, db); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return repoMap[uid]; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     clearRepositories() { | 
					
						
							|  |  |  |       repoMap.clear(); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = { | 
					
						
							|  |  |  |   createEntityManager, | 
					
						
							|  |  |  | }; |