@jsreport/jsreport-core 3.0.0 → 3.1.2-test.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 (80) hide show
  1. package/LICENSE +166 -166
  2. package/README.md +298 -284
  3. package/index.js +29 -27
  4. package/lib/main/blobStorage/blobStorage.js +52 -47
  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 -265
  11. package/lib/main/extensions/fileUtils.js +56 -55
  12. package/lib/main/extensions/findVersion.js +49 -53
  13. package/lib/main/extensions/locationCache.js +103 -97
  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 +244 -244
  23. package/lib/main/migration/resourcesToAssets.js +230 -210
  24. package/lib/main/migration/xlsxTemplatesToAssets.js +128 -118
  25. package/lib/main/monitoring.js +91 -91
  26. package/lib/main/optionsLoad.js +237 -237
  27. package/lib/main/optionsSchema.js +237 -237
  28. package/lib/main/profiler.js +2 -1
  29. package/lib/main/reporter.js +575 -578
  30. package/lib/main/schemaValidator.js +252 -252
  31. package/lib/main/settings.js +154 -154
  32. package/lib/main/store/checkDuplicatedId.js +27 -27
  33. package/lib/main/store/collection.js +329 -329
  34. package/lib/main/store/documentStore.js +469 -469
  35. package/lib/main/store/mainActions.js +28 -28
  36. package/lib/main/store/memoryStoreProvider.js +99 -99
  37. package/lib/main/store/queue.js +48 -48
  38. package/lib/main/store/referenceUtils.js +251 -251
  39. package/lib/main/store/setupValidateId.js +43 -43
  40. package/lib/main/store/setupValidateShortid.js +71 -71
  41. package/lib/main/store/transaction.js +69 -69
  42. package/lib/main/store/typeUtils.js +180 -180
  43. package/lib/main/templates.js +34 -34
  44. package/lib/main/validateEntityName.js +62 -62
  45. package/lib/shared/createError.js +36 -36
  46. package/lib/shared/encryption.js +114 -114
  47. package/lib/shared/folders/index.js +11 -11
  48. package/lib/shared/folders/normalizeEntityPath.js +15 -15
  49. package/lib/shared/folders/resolveEntityFromPath.js +88 -88
  50. package/lib/shared/folders/resolveEntityPath.js +46 -46
  51. package/lib/shared/folders/resolveFolderFromPath.js +38 -38
  52. package/lib/shared/generateRequestId.js +4 -4
  53. package/lib/shared/listenerCollection.js +169 -0
  54. package/lib/shared/normalizeMetaFromLogs.js +30 -30
  55. package/lib/shared/reporter.js +128 -123
  56. package/lib/shared/request.js +64 -64
  57. package/lib/shared/tempFilesHandler.js +81 -81
  58. package/lib/shared/templates.js +82 -82
  59. package/lib/static/helpers.js +33 -33
  60. package/lib/worker/blobStorage.js +34 -34
  61. package/lib/worker/defaultProxyExtend.js +46 -46
  62. package/lib/worker/documentStore.js +49 -49
  63. package/lib/worker/extensionsManager.js +17 -17
  64. package/lib/worker/logger.js +48 -48
  65. package/lib/worker/render/diff.js +138 -138
  66. package/lib/worker/render/executeEngine.js +227 -190
  67. package/lib/worker/render/htmlRecipe.js +10 -10
  68. package/lib/worker/render/moduleHelper.js +45 -43
  69. package/lib/worker/render/noneEngine.js +12 -12
  70. package/lib/worker/render/profiler.js +158 -158
  71. package/lib/worker/render/render.js +213 -209
  72. package/lib/worker/render/resolveReferences.js +60 -60
  73. package/lib/worker/reporter.js +192 -187
  74. package/lib/worker/sandbox/runInSandbox.js +13 -4
  75. package/lib/worker/sandbox/safeSandbox.js +828 -822
  76. package/lib/worker/templates.js +78 -78
  77. package/lib/worker/workerHandler.js +54 -54
  78. package/package.json +92 -92
  79. package/test/blobStorage/common.js +21 -21
  80. 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
+ }