@jsreport/jsreport-core 3.1.2-test.2 → 3.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/LICENSE +166 -166
  2. package/README.md +310 -298
  3. package/index.js +29 -29
  4. package/lib/main/blobStorage/blobStorage.js +53 -52
  5. package/lib/main/blobStorage/inMemoryProvider.js +27 -27
  6. package/lib/main/blobStorage/mainActions.js +24 -24
  7. package/lib/main/createDefaultLoggerFormat.js +17 -17
  8. package/lib/main/defaults.js +14 -14
  9. package/lib/main/extensions/discover.js +20 -20
  10. package/lib/main/extensions/extensionsManager.js +264 -264
  11. package/lib/main/extensions/fileUtils.js +56 -56
  12. package/lib/main/extensions/findVersion.js +49 -49
  13. package/lib/main/extensions/locationCache.js +103 -103
  14. package/lib/main/extensions/sorter.js +10 -10
  15. package/lib/main/extensions/validateMinimalVersion.js +50 -50
  16. package/lib/main/folders/cascadeFolderRemove.js +25 -25
  17. package/lib/main/folders/getEntitiesInFolder.js +53 -53
  18. package/lib/main/folders/index.js +42 -42
  19. package/lib/main/folders/moveBetweenFolders.js +354 -354
  20. package/lib/main/folders/validateDuplicatedName.js +107 -107
  21. package/lib/main/folders/validateReservedName.js +53 -53
  22. package/lib/main/logger.js +254 -244
  23. package/lib/main/migration/resourcesToAssets.js +230 -230
  24. package/lib/main/migration/xlsxTemplatesToAssets.js +128 -128
  25. package/lib/main/monitoring.js +92 -91
  26. package/lib/main/optionsLoad.js +231 -237
  27. package/lib/main/optionsSchema.js +237 -237
  28. package/lib/main/profiler.js +13 -1
  29. package/lib/main/reporter.js +589 -579
  30. package/lib/main/request.js +21 -0
  31. package/lib/main/schemaValidator.js +252 -252
  32. package/lib/main/settings.js +154 -154
  33. package/lib/main/store/checkDuplicatedId.js +27 -27
  34. package/lib/main/store/collection.js +329 -329
  35. package/lib/main/store/documentStore.js +469 -469
  36. package/lib/main/store/mainActions.js +28 -28
  37. package/lib/main/store/memoryStoreProvider.js +99 -99
  38. package/lib/main/store/queue.js +48 -48
  39. package/lib/main/store/referenceUtils.js +251 -251
  40. package/lib/main/store/setupValidateId.js +43 -43
  41. package/lib/main/store/setupValidateShortid.js +71 -71
  42. package/lib/main/store/transaction.js +69 -69
  43. package/lib/main/store/typeUtils.js +180 -180
  44. package/lib/main/templates.js +34 -34
  45. package/lib/main/validateEntityName.js +62 -62
  46. package/lib/shared/createError.js +36 -36
  47. package/lib/shared/encryption.js +114 -114
  48. package/lib/shared/folders/index.js +11 -11
  49. package/lib/shared/folders/normalizeEntityPath.js +15 -15
  50. package/lib/shared/folders/resolveEntityFromPath.js +88 -88
  51. package/lib/shared/folders/resolveEntityPath.js +46 -46
  52. package/lib/shared/folders/resolveFolderFromPath.js +38 -38
  53. package/lib/shared/generateRequestId.js +4 -4
  54. package/lib/shared/listenerCollection.js +169 -169
  55. package/lib/shared/normalizeMetaFromLogs.js +30 -30
  56. package/lib/shared/reporter.js +128 -123
  57. package/lib/shared/request.js +64 -64
  58. package/lib/shared/tempFilesHandler.js +81 -81
  59. package/lib/shared/templates.js +82 -82
  60. package/lib/static/helpers.js +33 -33
  61. package/lib/worker/blobStorage.js +34 -34
  62. package/lib/worker/defaultProxyExtend.js +46 -46
  63. package/lib/worker/documentStore.js +49 -49
  64. package/lib/worker/extensionsManager.js +17 -17
  65. package/lib/worker/logger.js +48 -48
  66. package/lib/worker/render/diff.js +138 -138
  67. package/lib/worker/render/executeEngine.js +232 -207
  68. package/lib/worker/render/htmlRecipe.js +10 -10
  69. package/lib/worker/render/moduleHelper.js +45 -43
  70. package/lib/worker/render/noneEngine.js +12 -12
  71. package/lib/worker/render/profiler.js +162 -158
  72. package/lib/worker/render/render.js +202 -205
  73. package/lib/worker/render/resolveReferences.js +60 -60
  74. package/lib/worker/reporter.js +197 -191
  75. package/lib/worker/sandbox/runInSandbox.js +64 -12
  76. package/lib/worker/sandbox/safeSandbox.js +829 -828
  77. package/lib/worker/templates.js +80 -78
  78. package/lib/worker/workerHandler.js +55 -54
  79. package/package.json +91 -92
  80. package/test/blobStorage/common.js +25 -21
  81. package/test/store/common.js +1449 -1449
@@ -1,354 +1,354 @@
1
- const omit = require('lodash.omit')
2
-
3
- async function collectEntitiesInHierarchy (reporter, entities, sourceEntity, onlyChildren, req) {
4
- if (sourceEntity.__entitySet === 'folders') {
5
- if (!onlyChildren) {
6
- entities.push(sourceEntity)
7
- }
8
-
9
- const childEntities = await reporter.folders.getEntitiesInFolder(sourceEntity.shortid, true, req)
10
-
11
- for (const { entitySet, entity } of childEntities) {
12
- entities.push(Object.assign(entity, {
13
- __entitySet: entitySet
14
- }))
15
- }
16
- } else {
17
- entities.push(sourceEntity)
18
- }
19
- }
20
-
21
- async function throwIfEntityIsNotFolder (reporter, targetShortid, req) {
22
- const folder = await reporter.documentStore.collection('folders').findOne({
23
- shortid: targetShortid
24
- }, req)
25
-
26
- if (!folder) {
27
- throw reporter.createError(`Target entity "${targetShortid}" is not a folder, please review that the copy/move is against a valid folder entity`, {
28
- statusCode: 400
29
- })
30
- }
31
- }
32
-
33
- module.exports = (reporter) => async ({ source, target, shouldCopy, shouldReplace }, req) => {
34
- const sourceCol = reporter.documentStore.collection(source.entitySet)
35
-
36
- if (!sourceCol) {
37
- throw reporter.createError(`Invalid entity set "${source.entitySet}" for source`, {
38
- statusCode: 400
39
- })
40
- }
41
-
42
- const sourceEntity = await sourceCol.findOne({ _id: source.id }, req)
43
-
44
- if (!sourceEntity) {
45
- throw reporter.createError('Source entity with specified id does not exists', {
46
- statusCode: 400
47
- })
48
- }
49
-
50
- const onlyChildren = source.onlyChildren === true
51
-
52
- if (onlyChildren && source.entitySet !== 'folders') {
53
- throw reporter.createError('onlyChildren option can only be enabled when source is a folder')
54
- }
55
-
56
- if (target.shortid === undefined) {
57
- throw reporter.createError('target should specify ".shortid"', {
58
- statusCode: 400
59
- })
60
- }
61
-
62
- if (target.shortid != null) {
63
- await throwIfEntityIsNotFolder(reporter, target.shortid, req)
64
- }
65
-
66
- const targetUpdateReferences = target.updateReferences === true && target.shortid != null
67
-
68
- let entitiesInHierarchy = []
69
-
70
- await collectEntitiesInHierarchy(
71
- reporter,
72
- entitiesInHierarchy,
73
- Object.assign(sourceEntity, { __entitySet: source.entitySet }),
74
- onlyChildren,
75
- req
76
- )
77
-
78
- let rootChildren
79
-
80
- if (onlyChildren) {
81
- rootChildren = entitiesInHierarchy.filter((e) => {
82
- return e.folder.shortid === sourceEntity.shortid
83
- })
84
- }
85
-
86
- // ignore if we are doing a move at the same level of hierarchy between source and target
87
- if (
88
- (sourceEntity.folder == null && target.shortid === null) ||
89
- (sourceEntity.folder != null &&
90
- target.shortid != null &&
91
- sourceEntity.folder.shortid === target.shortid)
92
- ) {
93
- return []
94
- }
95
-
96
- if (!shouldCopy) {
97
- // validates that we can't move entities from higher level
98
- // into lower level of the same hierarchy
99
- if (entitiesInHierarchy.some((e) => e.shortid === target.shortid)) {
100
- return []
101
- }
102
-
103
- let updateQ
104
-
105
- if (target.shortid === null) {
106
- updateQ = {
107
- $set: {
108
- folder: null
109
- }
110
- }
111
- } else {
112
- updateQ = {
113
- $set: {
114
- folder: {
115
- shortid: target.shortid
116
- }
117
- }
118
- }
119
- }
120
-
121
- let sourceEntities
122
-
123
- if (!onlyChildren) {
124
- sourceEntities = [sourceEntity]
125
- } else {
126
- sourceEntities = rootChildren
127
- }
128
-
129
- for (const entity of sourceEntities) {
130
- try {
131
- await reporter.documentStore.collection(entity.__entitySet).update({
132
- _id: entity._id
133
- }, updateQ, req)
134
- } catch (e) {
135
- if (e.code === 'DUPLICATED_ENTITY' && shouldReplace) {
136
- // replacing is not supported when it generates a conflict with folder
137
- if (e.existingEntityEntitySet === 'folders') {
138
- throw e
139
- }
140
-
141
- const removeFolderQ = target.shortid === null ? { folder: null } : { folder: { shortid: target.shortid } }
142
-
143
- await reporter.documentStore.collection(e.existingEntityEntitySet).remove({
144
- _id: e.existingEntity._id,
145
- ...removeFolderQ
146
- }, req)
147
-
148
- await reporter.documentStore.collection(entity.__entitySet).update({
149
- _id: entity._id
150
- }, updateQ, req)
151
- } else {
152
- throw e
153
- }
154
- }
155
- }
156
-
157
- const sourceEntityItems = entitiesInHierarchy.filter((e) => {
158
- return sourceEntities.find((childE) => childE._id === e._id) != null
159
- })
160
-
161
- for (const sourceEntityItem of sourceEntityItems) {
162
- if (target.shortid === null) {
163
- sourceEntityItem.folder = null
164
- } else {
165
- sourceEntityItem.folder = {
166
- shortid: target.shortid
167
- }
168
- }
169
- }
170
- } else {
171
- const entitiesInHierarchyByCollection = entitiesInHierarchy.reduce((acu, entity) => {
172
- acu[entity.__entitySet] = acu[entity.__entitySet] || []
173
- acu[entity.__entitySet].push(entity)
174
- return acu
175
- }, {})
176
-
177
- const entityReferencesMap = new WeakMap()
178
- const originalEntitiesNewMap = new WeakMap()
179
- const entityRecordNewValueMap = new WeakMap()
180
- const records = []
181
-
182
- // eslint-disable-next-line
183
- function createUpdateReferences (record) {
184
- return async (newEntity) => {
185
- const { entitySet, entity, originalEntity } = record
186
- const linkedEntities = entityReferencesMap.get(entity)
187
-
188
- if (linkedEntities.length === 0) {
189
- return
190
- }
191
-
192
- for (const { properties: linkedProperties, entity: originalLinkedEntity } of linkedEntities) {
193
- const currentNewLinkedEntity = originalEntitiesNewMap.get(originalLinkedEntity)
194
-
195
- if (entityRecordNewValueMap.has(currentNewLinkedEntity)) {
196
- const currentEntityProcessedNew = entityRecordNewValueMap.get(currentNewLinkedEntity)
197
- const currentEntityUpdate = {}
198
-
199
- // if we get here it means that the entity was already processed, so we need to
200
- // execute an update directly to the store
201
- for (const prop of linkedProperties) {
202
- // here we care to use the new object result because we want to preserve other values
203
- // in case the property is array with objects
204
- reporter.documentStore.updateReference(originalLinkedEntity.__entitySet, currentEntityProcessedNew, entitySet, { referenceProp: prop, referenceValue: originalEntity.shortid }, newEntity.shortid)
205
- const rootProp = prop.split('.')[0]
206
- currentEntityUpdate[rootProp] = currentEntityProcessedNew[rootProp]
207
- }
208
-
209
- await reporter.documentStore.collection(originalLinkedEntity.__entitySet).update({
210
- _id: currentEntityProcessedNew._id
211
- }, { $set: currentEntityUpdate }, req)
212
- } else {
213
- // here we care to update all properties to point to old reference value
214
- reporter.documentStore.updateReference(originalLinkedEntity.__entitySet, currentNewLinkedEntity, entitySet, { referenceValue: originalEntity.shortid }, newEntity.shortid)
215
- }
216
- }
217
- }
218
- }
219
-
220
- if (targetUpdateReferences) {
221
- const targetEntity = await reporter.documentStore.collection('folders').findOne({
222
- shortid: target.shortid
223
- }, req)
224
-
225
- targetEntity.__entitySet = 'folders'
226
- entitiesInHierarchyByCollection.folders = entitiesInHierarchyByCollection.folders || []
227
- entitiesInHierarchyByCollection.folders.push(targetEntity)
228
- originalEntitiesNewMap.set(targetEntity, targetEntity)
229
- entityRecordNewValueMap.set(targetEntity, targetEntity)
230
- }
231
-
232
- for (const entity of entitiesInHierarchy) {
233
- const newEntity = {
234
- ...omit(entity, ['_id', 'shortid', '__entitySet'])
235
- }
236
-
237
- let isSourceEntityItem
238
-
239
- if (!onlyChildren) {
240
- isSourceEntityItem = source.id === entity._id
241
- } else {
242
- isSourceEntityItem = rootChildren.find((e) => e._id === entity._id) != null
243
- }
244
-
245
- if (isSourceEntityItem) {
246
- if (target.shortid === null) {
247
- newEntity.folder = null
248
- } else {
249
- newEntity.folder = {
250
- shortid: target.shortid
251
- }
252
- }
253
- }
254
-
255
- const entitySet = entity.__entitySet
256
- newEntity.__entitySet = entitySet
257
-
258
- const linkedEntities = reporter.documentStore.findLinkedEntitiesForReference(
259
- entitiesInHierarchyByCollection,
260
- entitySet,
261
- entity.shortid
262
- )
263
-
264
- const record = {
265
- entitySet,
266
- originalEntity: entity,
267
- entity: newEntity
268
- }
269
-
270
- record.updateReferences = createUpdateReferences(record)
271
-
272
- originalEntitiesNewMap.set(entity, newEntity)
273
- entityReferencesMap.set(newEntity, linkedEntities)
274
-
275
- records.push(record)
276
- }
277
-
278
- const processNewEntity = async (entitySet, entity) => {
279
- const newEntityFromStore = await reporter.documentStore.collection(entitySet).insert({
280
- ...omit(entity, ['__entitySet'])
281
- }, req)
282
-
283
- entityRecordNewValueMap.set(entity, newEntityFromStore)
284
- }
285
-
286
- for (const record of records) {
287
- try {
288
- await processNewEntity(record.entitySet, record.entity)
289
- } catch (e) {
290
- if (e.code === 'DUPLICATED_ENTITY' && shouldReplace) {
291
- // replacing is not supported when it generates a conflict with folder
292
- if (e.existingEntityEntitySet === 'folders') {
293
- throw e
294
- }
295
-
296
- const removeFolderQ = target.shortid === null ? { folder: null } : { folder: { shortid: target.shortid } }
297
-
298
- await reporter.documentStore.collection(e.existingEntityEntitySet).remove({
299
- _id: e.existingEntity._id,
300
- ...removeFolderQ
301
- }, req)
302
-
303
- await processNewEntity(record.entitySet, record.entity)
304
- } else {
305
- throw e
306
- }
307
- }
308
-
309
- await record.updateReferences(entityRecordNewValueMap.get(record.entity))
310
- }
311
-
312
- entitiesInHierarchy = records.map((record) => ({
313
- ...omit(entityRecordNewValueMap.get(record.entity), ['$entitySet', '__entitySet']),
314
- __entitySet: record.entitySet
315
- }))
316
- }
317
-
318
- // return fresh version of creationDate, modificationDate in the records.
319
- // this helps with concurrent validation on studio
320
- await Promise.all(entitiesInHierarchy.map(async (entity) => {
321
- const entitySet = reporter.documentStore.model.entitySets[entity.__entitySet]
322
- const entityType = entitySet.entityTypeDef
323
- const projection = {}
324
-
325
- if (entityType.creationDate != null && entityType.creationDate.type === 'Edm.DateTimeOffset') {
326
- projection.creationDate = 1
327
- }
328
-
329
- if (entityType.modificationDate != null && entityType.modificationDate.type === 'Edm.DateTimeOffset') {
330
- projection.modificationDate = 1
331
- }
332
-
333
- if (Object.keys(projection).length === 0) {
334
- return
335
- }
336
-
337
- const doc = await reporter.documentStore.collection(entity.__entitySet).findOne({
338
- _id: entity._id
339
- }, {
340
- creationDate: 1,
341
- modificationDate: 1
342
- }, req)
343
-
344
- if (projection.creationDate) {
345
- entity.creationDate = doc.creationDate
346
- }
347
-
348
- if (projection.modificationDate) {
349
- entity.modificationDate = doc.modificationDate
350
- }
351
- }))
352
-
353
- return entitiesInHierarchy
354
- }
1
+ const omit = require('lodash.omit')
2
+
3
+ async function collectEntitiesInHierarchy (reporter, entities, sourceEntity, onlyChildren, req) {
4
+ if (sourceEntity.__entitySet === 'folders') {
5
+ if (!onlyChildren) {
6
+ entities.push(sourceEntity)
7
+ }
8
+
9
+ const childEntities = await reporter.folders.getEntitiesInFolder(sourceEntity.shortid, true, req)
10
+
11
+ for (const { entitySet, entity } of childEntities) {
12
+ entities.push(Object.assign(entity, {
13
+ __entitySet: entitySet
14
+ }))
15
+ }
16
+ } else {
17
+ entities.push(sourceEntity)
18
+ }
19
+ }
20
+
21
+ async function throwIfEntityIsNotFolder (reporter, targetShortid, req) {
22
+ const folder = await reporter.documentStore.collection('folders').findOne({
23
+ shortid: targetShortid
24
+ }, req)
25
+
26
+ if (!folder) {
27
+ throw reporter.createError(`Target entity "${targetShortid}" is not a folder, please review that the copy/move is against a valid folder entity`, {
28
+ statusCode: 400
29
+ })
30
+ }
31
+ }
32
+
33
+ module.exports = (reporter) => async ({ source, target, shouldCopy, shouldReplace }, req) => {
34
+ const sourceCol = reporter.documentStore.collection(source.entitySet)
35
+
36
+ if (!sourceCol) {
37
+ throw reporter.createError(`Invalid entity set "${source.entitySet}" for source`, {
38
+ statusCode: 400
39
+ })
40
+ }
41
+
42
+ const sourceEntity = await sourceCol.findOne({ _id: source.id }, req)
43
+
44
+ if (!sourceEntity) {
45
+ throw reporter.createError('Source entity with specified id does not exists', {
46
+ statusCode: 400
47
+ })
48
+ }
49
+
50
+ const onlyChildren = source.onlyChildren === true
51
+
52
+ if (onlyChildren && source.entitySet !== 'folders') {
53
+ throw reporter.createError('onlyChildren option can only be enabled when source is a folder')
54
+ }
55
+
56
+ if (target.shortid === undefined) {
57
+ throw reporter.createError('target should specify ".shortid"', {
58
+ statusCode: 400
59
+ })
60
+ }
61
+
62
+ if (target.shortid != null) {
63
+ await throwIfEntityIsNotFolder(reporter, target.shortid, req)
64
+ }
65
+
66
+ const targetUpdateReferences = target.updateReferences === true && target.shortid != null
67
+
68
+ let entitiesInHierarchy = []
69
+
70
+ await collectEntitiesInHierarchy(
71
+ reporter,
72
+ entitiesInHierarchy,
73
+ Object.assign(sourceEntity, { __entitySet: source.entitySet }),
74
+ onlyChildren,
75
+ req
76
+ )
77
+
78
+ let rootChildren
79
+
80
+ if (onlyChildren) {
81
+ rootChildren = entitiesInHierarchy.filter((e) => {
82
+ return e.folder.shortid === sourceEntity.shortid
83
+ })
84
+ }
85
+
86
+ // ignore if we are doing a move at the same level of hierarchy between source and target
87
+ if (
88
+ (sourceEntity.folder == null && target.shortid === null) ||
89
+ (sourceEntity.folder != null &&
90
+ target.shortid != null &&
91
+ sourceEntity.folder.shortid === target.shortid)
92
+ ) {
93
+ return []
94
+ }
95
+
96
+ if (!shouldCopy) {
97
+ // validates that we can't move entities from higher level
98
+ // into lower level of the same hierarchy
99
+ if (entitiesInHierarchy.some((e) => e.shortid === target.shortid)) {
100
+ return []
101
+ }
102
+
103
+ let updateQ
104
+
105
+ if (target.shortid === null) {
106
+ updateQ = {
107
+ $set: {
108
+ folder: null
109
+ }
110
+ }
111
+ } else {
112
+ updateQ = {
113
+ $set: {
114
+ folder: {
115
+ shortid: target.shortid
116
+ }
117
+ }
118
+ }
119
+ }
120
+
121
+ let sourceEntities
122
+
123
+ if (!onlyChildren) {
124
+ sourceEntities = [sourceEntity]
125
+ } else {
126
+ sourceEntities = rootChildren
127
+ }
128
+
129
+ for (const entity of sourceEntities) {
130
+ try {
131
+ await reporter.documentStore.collection(entity.__entitySet).update({
132
+ _id: entity._id
133
+ }, updateQ, req)
134
+ } catch (e) {
135
+ if (e.code === 'DUPLICATED_ENTITY' && shouldReplace) {
136
+ // replacing is not supported when it generates a conflict with folder
137
+ if (e.existingEntityEntitySet === 'folders') {
138
+ throw e
139
+ }
140
+
141
+ const removeFolderQ = target.shortid === null ? { folder: null } : { folder: { shortid: target.shortid } }
142
+
143
+ await reporter.documentStore.collection(e.existingEntityEntitySet).remove({
144
+ _id: e.existingEntity._id,
145
+ ...removeFolderQ
146
+ }, req)
147
+
148
+ await reporter.documentStore.collection(entity.__entitySet).update({
149
+ _id: entity._id
150
+ }, updateQ, req)
151
+ } else {
152
+ throw e
153
+ }
154
+ }
155
+ }
156
+
157
+ const sourceEntityItems = entitiesInHierarchy.filter((e) => {
158
+ return sourceEntities.find((childE) => childE._id === e._id) != null
159
+ })
160
+
161
+ for (const sourceEntityItem of sourceEntityItems) {
162
+ if (target.shortid === null) {
163
+ sourceEntityItem.folder = null
164
+ } else {
165
+ sourceEntityItem.folder = {
166
+ shortid: target.shortid
167
+ }
168
+ }
169
+ }
170
+ } else {
171
+ const entitiesInHierarchyByCollection = entitiesInHierarchy.reduce((acu, entity) => {
172
+ acu[entity.__entitySet] = acu[entity.__entitySet] || []
173
+ acu[entity.__entitySet].push(entity)
174
+ return acu
175
+ }, {})
176
+
177
+ const entityReferencesMap = new WeakMap()
178
+ const originalEntitiesNewMap = new WeakMap()
179
+ const entityRecordNewValueMap = new WeakMap()
180
+ const records = []
181
+
182
+ // eslint-disable-next-line
183
+ function createUpdateReferences (record) {
184
+ return async (newEntity) => {
185
+ const { entitySet, entity, originalEntity } = record
186
+ const linkedEntities = entityReferencesMap.get(entity)
187
+
188
+ if (linkedEntities.length === 0) {
189
+ return
190
+ }
191
+
192
+ for (const { properties: linkedProperties, entity: originalLinkedEntity } of linkedEntities) {
193
+ const currentNewLinkedEntity = originalEntitiesNewMap.get(originalLinkedEntity)
194
+
195
+ if (entityRecordNewValueMap.has(currentNewLinkedEntity)) {
196
+ const currentEntityProcessedNew = entityRecordNewValueMap.get(currentNewLinkedEntity)
197
+ const currentEntityUpdate = {}
198
+
199
+ // if we get here it means that the entity was already processed, so we need to
200
+ // execute an update directly to the store
201
+ for (const prop of linkedProperties) {
202
+ // here we care to use the new object result because we want to preserve other values
203
+ // in case the property is array with objects
204
+ reporter.documentStore.updateReference(originalLinkedEntity.__entitySet, currentEntityProcessedNew, entitySet, { referenceProp: prop, referenceValue: originalEntity.shortid }, newEntity.shortid)
205
+ const rootProp = prop.split('.')[0]
206
+ currentEntityUpdate[rootProp] = currentEntityProcessedNew[rootProp]
207
+ }
208
+
209
+ await reporter.documentStore.collection(originalLinkedEntity.__entitySet).update({
210
+ _id: currentEntityProcessedNew._id
211
+ }, { $set: currentEntityUpdate }, req)
212
+ } else {
213
+ // here we care to update all properties to point to old reference value
214
+ reporter.documentStore.updateReference(originalLinkedEntity.__entitySet, currentNewLinkedEntity, entitySet, { referenceValue: originalEntity.shortid }, newEntity.shortid)
215
+ }
216
+ }
217
+ }
218
+ }
219
+
220
+ if (targetUpdateReferences) {
221
+ const targetEntity = await reporter.documentStore.collection('folders').findOne({
222
+ shortid: target.shortid
223
+ }, req)
224
+
225
+ targetEntity.__entitySet = 'folders'
226
+ entitiesInHierarchyByCollection.folders = entitiesInHierarchyByCollection.folders || []
227
+ entitiesInHierarchyByCollection.folders.push(targetEntity)
228
+ originalEntitiesNewMap.set(targetEntity, targetEntity)
229
+ entityRecordNewValueMap.set(targetEntity, targetEntity)
230
+ }
231
+
232
+ for (const entity of entitiesInHierarchy) {
233
+ const newEntity = {
234
+ ...omit(entity, ['_id', 'shortid', '__entitySet'])
235
+ }
236
+
237
+ let isSourceEntityItem
238
+
239
+ if (!onlyChildren) {
240
+ isSourceEntityItem = source.id === entity._id
241
+ } else {
242
+ isSourceEntityItem = rootChildren.find((e) => e._id === entity._id) != null
243
+ }
244
+
245
+ if (isSourceEntityItem) {
246
+ if (target.shortid === null) {
247
+ newEntity.folder = null
248
+ } else {
249
+ newEntity.folder = {
250
+ shortid: target.shortid
251
+ }
252
+ }
253
+ }
254
+
255
+ const entitySet = entity.__entitySet
256
+ newEntity.__entitySet = entitySet
257
+
258
+ const linkedEntities = reporter.documentStore.findLinkedEntitiesForReference(
259
+ entitiesInHierarchyByCollection,
260
+ entitySet,
261
+ entity.shortid
262
+ )
263
+
264
+ const record = {
265
+ entitySet,
266
+ originalEntity: entity,
267
+ entity: newEntity
268
+ }
269
+
270
+ record.updateReferences = createUpdateReferences(record)
271
+
272
+ originalEntitiesNewMap.set(entity, newEntity)
273
+ entityReferencesMap.set(newEntity, linkedEntities)
274
+
275
+ records.push(record)
276
+ }
277
+
278
+ const processNewEntity = async (entitySet, entity) => {
279
+ const newEntityFromStore = await reporter.documentStore.collection(entitySet).insert({
280
+ ...omit(entity, ['__entitySet'])
281
+ }, req)
282
+
283
+ entityRecordNewValueMap.set(entity, newEntityFromStore)
284
+ }
285
+
286
+ for (const record of records) {
287
+ try {
288
+ await processNewEntity(record.entitySet, record.entity)
289
+ } catch (e) {
290
+ if (e.code === 'DUPLICATED_ENTITY' && shouldReplace) {
291
+ // replacing is not supported when it generates a conflict with folder
292
+ if (e.existingEntityEntitySet === 'folders') {
293
+ throw e
294
+ }
295
+
296
+ const removeFolderQ = target.shortid === null ? { folder: null } : { folder: { shortid: target.shortid } }
297
+
298
+ await reporter.documentStore.collection(e.existingEntityEntitySet).remove({
299
+ _id: e.existingEntity._id,
300
+ ...removeFolderQ
301
+ }, req)
302
+
303
+ await processNewEntity(record.entitySet, record.entity)
304
+ } else {
305
+ throw e
306
+ }
307
+ }
308
+
309
+ await record.updateReferences(entityRecordNewValueMap.get(record.entity))
310
+ }
311
+
312
+ entitiesInHierarchy = records.map((record) => ({
313
+ ...omit(entityRecordNewValueMap.get(record.entity), ['$entitySet', '__entitySet']),
314
+ __entitySet: record.entitySet
315
+ }))
316
+ }
317
+
318
+ // return fresh version of creationDate, modificationDate in the records.
319
+ // this helps with concurrent validation on studio
320
+ await Promise.all(entitiesInHierarchy.map(async (entity) => {
321
+ const entitySet = reporter.documentStore.model.entitySets[entity.__entitySet]
322
+ const entityType = entitySet.entityTypeDef
323
+ const projection = {}
324
+
325
+ if (entityType.creationDate != null && entityType.creationDate.type === 'Edm.DateTimeOffset') {
326
+ projection.creationDate = 1
327
+ }
328
+
329
+ if (entityType.modificationDate != null && entityType.modificationDate.type === 'Edm.DateTimeOffset') {
330
+ projection.modificationDate = 1
331
+ }
332
+
333
+ if (Object.keys(projection).length === 0) {
334
+ return
335
+ }
336
+
337
+ const doc = await reporter.documentStore.collection(entity.__entitySet).findOne({
338
+ _id: entity._id
339
+ }, {
340
+ creationDate: 1,
341
+ modificationDate: 1
342
+ }, req)
343
+
344
+ if (projection.creationDate) {
345
+ entity.creationDate = doc.creationDate
346
+ }
347
+
348
+ if (projection.modificationDate) {
349
+ entity.modificationDate = doc.modificationDate
350
+ }
351
+ }))
352
+
353
+ return entitiesInHierarchy
354
+ }