@jsreport/jsreport-core 3.6.1 → 3.7.0
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.
- package/README.md +14 -0
- package/index.js +1 -1
- package/lib/main/createDefaultLoggerFormat.js +6 -1
- package/lib/main/createNormalizeMetaLoggerFormat.js +19 -0
- package/lib/main/folders/moveBetweenFolders.js +244 -215
- package/lib/main/logger.js +25 -17
- package/lib/main/profiler.js +230 -86
- package/lib/main/reporter.js +8 -1
- package/lib/worker/render/executeEngine.js +12 -2
- package/lib/worker/render/profiler.js +8 -2
- package/lib/worker/render/render.js +1 -1
- package/lib/worker/sandbox/runInSandbox.js +3 -1
- package/package.json +13 -11
- package/test/extensions/validExtensions/listeners/jsreport.dontdiscover.config.js +9 -0
- package/test/extensions/validExtensions/listeners/main.js +51 -0
- package/test/extensions/validExtensions/listeners/worker.js +68 -0
- package/test/store/common.js +1 -1
package/README.md
CHANGED
|
@@ -282,6 +282,20 @@ jsreport.documentStore.collection('templates')
|
|
|
282
282
|
|
|
283
283
|
## Changelog
|
|
284
284
|
|
|
285
|
+
### 3.7.0
|
|
286
|
+
|
|
287
|
+
- add support for multiple source entities when copying and moving
|
|
288
|
+
- fix some issues with blobs and profiles
|
|
289
|
+
- format user logs differently on stdout
|
|
290
|
+
- fix logging of req as http.IncomingRequest
|
|
291
|
+
- fix profile compatibility with jsreport container based execution
|
|
292
|
+
- fix memory leak in profiling
|
|
293
|
+
- add support for logs of main reporter to show in profile
|
|
294
|
+
|
|
295
|
+
### 3.6.1
|
|
296
|
+
|
|
297
|
+
- update @jsreport/advanced-workers to fix bug with cloning req.data when `trustUserCode` is true
|
|
298
|
+
|
|
285
299
|
### 3.6.0
|
|
286
300
|
|
|
287
301
|
- improve handling of worker exit
|
package/index.js
CHANGED
|
@@ -25,5 +25,5 @@ module.exports.createDefaultLoggerFormat = createDefaultLoggerFormat
|
|
|
25
25
|
module.exports.tests = {
|
|
26
26
|
documentStore: () => require('./test/store/common.js'),
|
|
27
27
|
blobStorage: () => require('./test/blobStorage/common.js'),
|
|
28
|
-
listeners: () => require('./test/extensions/validExtensions/listeners/jsreport.config')
|
|
28
|
+
listeners: () => require('./test/extensions/validExtensions/listeners/jsreport.dontdiscover.config')
|
|
29
29
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const { MESSAGE } = require('triple-beam')
|
|
2
|
+
const colors = require('@colors/colors/safe')
|
|
2
3
|
const winston = require('winston')
|
|
3
4
|
|
|
4
5
|
module.exports = (options = {}) => {
|
|
5
6
|
return winston.format((info) => {
|
|
6
7
|
const { level, message, ...meta } = info
|
|
7
|
-
info[MESSAGE] = `${options.timestamp === true ? `${new Date().toISOString()} - ` : ''}${level}: ${message}`
|
|
8
|
+
info[MESSAGE] = `${options.timestamp === true ? `${new Date().toISOString()} - ` : ''}${level}: ${info.userLevel === true ? colors.cyan(message) : message}`
|
|
8
9
|
|
|
9
10
|
const metaKeys = Object.keys(meta)
|
|
10
11
|
|
|
@@ -12,6 +13,10 @@ module.exports = (options = {}) => {
|
|
|
12
13
|
info[MESSAGE] += ` ${metaKeys.map((k) => `${k}=${meta[k]}`).join(', ')}`
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
if (info.userLevel === true) {
|
|
17
|
+
info.level = colors.cyan(info.level)
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
return info
|
|
16
21
|
})
|
|
17
22
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const winston = require('winston')
|
|
2
|
+
const normalizeMetaFromLogs = require('../shared/normalizeMetaFromLogs')
|
|
3
|
+
|
|
4
|
+
module.exports = () => {
|
|
5
|
+
return winston.format((info) => {
|
|
6
|
+
const { level, message, ...meta } = info
|
|
7
|
+
const newMeta = normalizeMetaFromLogs(level, message, meta)
|
|
8
|
+
|
|
9
|
+
if (newMeta != null) {
|
|
10
|
+
return {
|
|
11
|
+
level,
|
|
12
|
+
message,
|
|
13
|
+
...newMeta
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return info
|
|
18
|
+
})
|
|
19
|
+
}
|
|
@@ -31,27 +31,8 @@ async function throwIfEntityIsNotFolder (reporter, targetShortid, req) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
module.exports = (reporter) => async ({ source, target, shouldCopy, shouldReplace }, req) => {
|
|
34
|
-
const
|
|
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
|
-
}
|
|
34
|
+
const isSingleSource = Array.isArray(source) ? source.length === 1 : true
|
|
35
|
+
const sourceList = isSingleSource ? [source] : source
|
|
55
36
|
|
|
56
37
|
if (target.shortid === undefined) {
|
|
57
38
|
throw reporter.createError('target should specify ".shortid"', {
|
|
@@ -65,259 +46,307 @@ module.exports = (reporter) => async ({ source, target, shouldCopy, shouldReplac
|
|
|
65
46
|
|
|
66
47
|
const targetUpdateReferences = target.updateReferences === true && target.shortid != null
|
|
67
48
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
await collectEntitiesInHierarchy(
|
|
71
|
-
reporter,
|
|
72
|
-
entitiesInHierarchy,
|
|
73
|
-
Object.assign(sourceEntity, { __entitySet: source.entitySet }),
|
|
74
|
-
onlyChildren,
|
|
75
|
-
req
|
|
76
|
-
)
|
|
49
|
+
const allEntitiesInvolved = []
|
|
77
50
|
|
|
78
|
-
|
|
51
|
+
for (const sourceInfo of sourceList) {
|
|
52
|
+
const sourceCol = reporter.documentStore.collection(sourceInfo.entitySet)
|
|
79
53
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
54
|
+
if (!sourceCol) {
|
|
55
|
+
throw reporter.createError(`Invalid entity set "${sourceInfo.entitySet}" for source`, {
|
|
56
|
+
statusCode: 400
|
|
57
|
+
})
|
|
58
|
+
}
|
|
85
59
|
|
|
86
|
-
|
|
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
|
-
}
|
|
60
|
+
const sourceEntity = await sourceCol.findOne({ _id: sourceInfo.id }, req)
|
|
95
61
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return []
|
|
62
|
+
if (!sourceEntity) {
|
|
63
|
+
throw reporter.createError('Source entity with specified id does not exists', {
|
|
64
|
+
statusCode: 400
|
|
65
|
+
})
|
|
101
66
|
}
|
|
102
67
|
|
|
103
|
-
|
|
68
|
+
const onlyChildren = sourceInfo.onlyChildren === true
|
|
104
69
|
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
$set: {
|
|
108
|
-
folder: null
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
} else {
|
|
112
|
-
updateQ = {
|
|
113
|
-
$set: {
|
|
114
|
-
folder: {
|
|
115
|
-
shortid: target.shortid
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
70
|
+
if (onlyChildren && sourceInfo.entitySet !== 'folders') {
|
|
71
|
+
throw reporter.createError('onlyChildren option can only be enabled when source is a folder')
|
|
119
72
|
}
|
|
120
73
|
|
|
121
|
-
let
|
|
74
|
+
let entitiesInHierarchy = []
|
|
122
75
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
76
|
+
await collectEntitiesInHierarchy(
|
|
77
|
+
reporter,
|
|
78
|
+
entitiesInHierarchy,
|
|
79
|
+
Object.assign(sourceEntity, { __entitySet: sourceInfo.entitySet }),
|
|
80
|
+
onlyChildren,
|
|
81
|
+
req
|
|
82
|
+
)
|
|
128
83
|
|
|
129
|
-
|
|
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
|
-
}
|
|
84
|
+
let rootChildren
|
|
140
85
|
|
|
141
|
-
|
|
86
|
+
if (onlyChildren) {
|
|
87
|
+
rootChildren = entitiesInHierarchy.filter((e) => {
|
|
88
|
+
return e.folder.shortid === sourceEntity.shortid
|
|
89
|
+
})
|
|
90
|
+
}
|
|
142
91
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
92
|
+
// ignore if we are doing a copy/move at the same level of hierarchy between source and target
|
|
93
|
+
if (
|
|
94
|
+
(sourceEntity.folder == null && target.shortid === null) ||
|
|
95
|
+
(sourceEntity.folder != null &&
|
|
96
|
+
target.shortid != null &&
|
|
97
|
+
sourceEntity.folder.shortid === target.shortid)
|
|
98
|
+
) {
|
|
99
|
+
continue
|
|
100
|
+
}
|
|
147
101
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
102
|
+
if (!shouldCopy) {
|
|
103
|
+
// validates that we can't move entities from higher level
|
|
104
|
+
// into lower level of the same hierarchy
|
|
105
|
+
if (entitiesInHierarchy.some((e) => e.shortid === target.shortid)) {
|
|
106
|
+
continue
|
|
154
107
|
}
|
|
155
|
-
}
|
|
156
108
|
|
|
157
|
-
|
|
158
|
-
return sourceEntities.find((childE) => childE._id === e._id) != null
|
|
159
|
-
})
|
|
109
|
+
let updateQ
|
|
160
110
|
|
|
161
|
-
for (const sourceEntityItem of sourceEntityItems) {
|
|
162
111
|
if (target.shortid === null) {
|
|
163
|
-
|
|
112
|
+
updateQ = {
|
|
113
|
+
$set: {
|
|
114
|
+
folder: null
|
|
115
|
+
}
|
|
116
|
+
}
|
|
164
117
|
} else {
|
|
165
|
-
|
|
166
|
-
|
|
118
|
+
updateQ = {
|
|
119
|
+
$set: {
|
|
120
|
+
folder: {
|
|
121
|
+
shortid: target.shortid
|
|
122
|
+
}
|
|
123
|
+
}
|
|
167
124
|
}
|
|
168
125
|
}
|
|
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
126
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
127
|
+
let sourceEntities
|
|
128
|
+
|
|
129
|
+
if (!onlyChildren) {
|
|
130
|
+
sourceEntities = [sourceEntity]
|
|
131
|
+
} else {
|
|
132
|
+
sourceEntities = rootChildren
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
for (const entity of sourceEntities) {
|
|
136
|
+
try {
|
|
137
|
+
await reporter.documentStore.collection(entity.__entitySet).update({
|
|
138
|
+
_id: entity._id
|
|
139
|
+
}, updateQ, req)
|
|
140
|
+
} catch (e) {
|
|
141
|
+
if (e.code === 'DUPLICATED_ENTITY' && shouldReplace) {
|
|
142
|
+
// replacing is not supported when it generates a conflict with folder
|
|
143
|
+
if (e.existingEntityEntitySet === 'folders') {
|
|
144
|
+
throw e
|
|
207
145
|
}
|
|
208
146
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
147
|
+
const removeFolderQ = target.shortid === null ? { folder: null } : { folder: { shortid: target.shortid } }
|
|
148
|
+
|
|
149
|
+
await reporter.documentStore.collection(e.existingEntityEntitySet).remove({
|
|
150
|
+
_id: e.existingEntity._id,
|
|
151
|
+
...removeFolderQ
|
|
152
|
+
}, req)
|
|
153
|
+
|
|
154
|
+
await reporter.documentStore.collection(entity.__entitySet).update({
|
|
155
|
+
_id: entity._id
|
|
156
|
+
}, updateQ, req)
|
|
212
157
|
} else {
|
|
213
|
-
|
|
214
|
-
reporter.documentStore.updateReference(originalLinkedEntity.__entitySet, currentNewLinkedEntity, entitySet, { referenceValue: originalEntity.shortid }, newEntity.shortid)
|
|
158
|
+
throw e
|
|
215
159
|
}
|
|
216
160
|
}
|
|
217
161
|
}
|
|
218
|
-
}
|
|
219
162
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}, req)
|
|
163
|
+
const sourceEntityItems = entitiesInHierarchy.filter((e) => {
|
|
164
|
+
return sourceEntities.find((childE) => childE._id === e._id) != null
|
|
165
|
+
})
|
|
224
166
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
167
|
+
for (const sourceEntityItem of sourceEntityItems) {
|
|
168
|
+
if (target.shortid === null) {
|
|
169
|
+
sourceEntityItem.folder = null
|
|
170
|
+
} else {
|
|
171
|
+
sourceEntityItem.folder = {
|
|
172
|
+
shortid: target.shortid
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
const entitiesInHierarchyByCollection = entitiesInHierarchy.reduce((acu, entity) => {
|
|
178
|
+
acu[entity.__entitySet] = acu[entity.__entitySet] || []
|
|
179
|
+
acu[entity.__entitySet].push(entity)
|
|
180
|
+
return acu
|
|
181
|
+
}, {})
|
|
182
|
+
|
|
183
|
+
const entityReferencesMap = new WeakMap()
|
|
184
|
+
const originalEntitiesNewMap = new WeakMap()
|
|
185
|
+
const entityRecordNewValueMap = new WeakMap()
|
|
186
|
+
const records = []
|
|
187
|
+
|
|
188
|
+
// eslint-disable-next-line
|
|
189
|
+
function createUpdateReferences (record) {
|
|
190
|
+
return async (newEntity) => {
|
|
191
|
+
const { entitySet, entity, originalEntity } = record
|
|
192
|
+
const linkedEntities = entityReferencesMap.get(entity)
|
|
193
|
+
|
|
194
|
+
if (linkedEntities.length === 0) {
|
|
195
|
+
return
|
|
196
|
+
}
|
|
231
197
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
198
|
+
for (const { properties: linkedProperties, entity: originalLinkedEntity } of linkedEntities) {
|
|
199
|
+
const currentNewLinkedEntity = originalEntitiesNewMap.get(originalLinkedEntity)
|
|
200
|
+
|
|
201
|
+
if (entityRecordNewValueMap.has(currentNewLinkedEntity)) {
|
|
202
|
+
const currentEntityProcessedNew = entityRecordNewValueMap.get(currentNewLinkedEntity)
|
|
203
|
+
const currentEntityUpdate = {}
|
|
204
|
+
|
|
205
|
+
// if we get here it means that the entity was already processed, so we need to
|
|
206
|
+
// execute an update directly to the store
|
|
207
|
+
for (const prop of linkedProperties) {
|
|
208
|
+
// here we care to use the new object result because we want to preserve other values
|
|
209
|
+
// in case the property is array with objects
|
|
210
|
+
reporter.documentStore.updateReference(originalLinkedEntity.__entitySet, currentEntityProcessedNew, entitySet, { referenceProp: prop, referenceValue: originalEntity.shortid }, newEntity.shortid)
|
|
211
|
+
const rootProp = prop.split('.')[0]
|
|
212
|
+
currentEntityUpdate[rootProp] = currentEntityProcessedNew[rootProp]
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
await reporter.documentStore.collection(originalLinkedEntity.__entitySet).update({
|
|
216
|
+
_id: currentEntityProcessedNew._id
|
|
217
|
+
}, { $set: currentEntityUpdate }, req)
|
|
218
|
+
} else {
|
|
219
|
+
// here we care to update all properties to point to old reference value
|
|
220
|
+
reporter.documentStore.updateReference(originalLinkedEntity.__entitySet, currentNewLinkedEntity, entitySet, { referenceValue: originalEntity.shortid }, newEntity.shortid)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
235
224
|
}
|
|
236
225
|
|
|
237
|
-
|
|
226
|
+
if (targetUpdateReferences) {
|
|
227
|
+
const targetEntity = await reporter.documentStore.collection('folders').findOne({
|
|
228
|
+
shortid: target.shortid
|
|
229
|
+
}, req)
|
|
238
230
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
231
|
+
targetEntity.__entitySet = 'folders'
|
|
232
|
+
entitiesInHierarchyByCollection.folders = entitiesInHierarchyByCollection.folders || []
|
|
233
|
+
entitiesInHierarchyByCollection.folders.push(targetEntity)
|
|
234
|
+
originalEntitiesNewMap.set(targetEntity, targetEntity)
|
|
235
|
+
entityRecordNewValueMap.set(targetEntity, targetEntity)
|
|
243
236
|
}
|
|
244
237
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
238
|
+
for (const entity of entitiesInHierarchy) {
|
|
239
|
+
const newEntity = {
|
|
240
|
+
...omit(entity, ['_id', 'shortid', '__entitySet'])
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
let isSourceEntityItem
|
|
244
|
+
|
|
245
|
+
if (!onlyChildren) {
|
|
246
|
+
isSourceEntityItem = sourceInfo.id === entity._id
|
|
248
247
|
} else {
|
|
249
|
-
|
|
250
|
-
|
|
248
|
+
isSourceEntityItem = rootChildren.find((e) => e._id === entity._id) != null
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (isSourceEntityItem) {
|
|
252
|
+
if (target.shortid === null) {
|
|
253
|
+
newEntity.folder = null
|
|
254
|
+
} else {
|
|
255
|
+
newEntity.folder = {
|
|
256
|
+
shortid: target.shortid
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// when we are copying with multi selection we want to normalize names
|
|
261
|
+
// so in case of duplicates we just add "(copy)" suffix, for single source
|
|
262
|
+
// we want the replace dialog
|
|
263
|
+
if (!isSingleSource) {
|
|
264
|
+
let copyAttempt = 0
|
|
265
|
+
let existsAtTarget
|
|
266
|
+
|
|
267
|
+
do {
|
|
268
|
+
existsAtTarget = await reporter.documentStore.collection(entity.__entitySet).findOne({
|
|
269
|
+
name: newEntity.name,
|
|
270
|
+
folder: newEntity.folder
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
if (existsAtTarget != null) {
|
|
274
|
+
copyAttempt++
|
|
275
|
+
newEntity.name = `${entity.name}(copy${copyAttempt > 1 ? copyAttempt : ''})`
|
|
276
|
+
}
|
|
277
|
+
} while (existsAtTarget != null)
|
|
251
278
|
}
|
|
252
279
|
}
|
|
253
|
-
}
|
|
254
280
|
|
|
255
|
-
|
|
256
|
-
|
|
281
|
+
const entitySet = entity.__entitySet
|
|
282
|
+
newEntity.__entitySet = entitySet
|
|
257
283
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
284
|
+
const linkedEntities = reporter.documentStore.findLinkedEntitiesForReference(
|
|
285
|
+
entitiesInHierarchyByCollection,
|
|
286
|
+
entitySet,
|
|
287
|
+
entity.shortid
|
|
288
|
+
)
|
|
263
289
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
290
|
+
const record = {
|
|
291
|
+
entitySet,
|
|
292
|
+
originalEntity: entity,
|
|
293
|
+
entity: newEntity
|
|
294
|
+
}
|
|
269
295
|
|
|
270
|
-
|
|
296
|
+
record.updateReferences = createUpdateReferences(record)
|
|
271
297
|
|
|
272
|
-
|
|
273
|
-
|
|
298
|
+
originalEntitiesNewMap.set(entity, newEntity)
|
|
299
|
+
entityReferencesMap.set(newEntity, linkedEntities)
|
|
274
300
|
|
|
275
|
-
|
|
276
|
-
|
|
301
|
+
records.push(record)
|
|
302
|
+
}
|
|
277
303
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
304
|
+
const processNewEntity = async (entitySet, entity) => {
|
|
305
|
+
const newEntityFromStore = await reporter.documentStore.collection(entitySet).insert({
|
|
306
|
+
...omit(entity, ['__entitySet'])
|
|
307
|
+
}, req)
|
|
282
308
|
|
|
283
|
-
|
|
284
|
-
|
|
309
|
+
entityRecordNewValueMap.set(entity, newEntityFromStore)
|
|
310
|
+
}
|
|
285
311
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
312
|
+
for (const record of records) {
|
|
313
|
+
try {
|
|
314
|
+
await processNewEntity(record.entitySet, record.entity)
|
|
315
|
+
} catch (e) {
|
|
316
|
+
if (e.code === 'DUPLICATED_ENTITY' && shouldReplace) {
|
|
317
|
+
// replacing is not supported when it generates a conflict with folder
|
|
318
|
+
if (e.existingEntityEntitySet === 'folders') {
|
|
319
|
+
throw e
|
|
320
|
+
}
|
|
295
321
|
|
|
296
|
-
|
|
322
|
+
const removeFolderQ = target.shortid === null ? { folder: null } : { folder: { shortid: target.shortid } }
|
|
297
323
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
324
|
+
await reporter.documentStore.collection(e.existingEntityEntitySet).remove({
|
|
325
|
+
_id: e.existingEntity._id,
|
|
326
|
+
...removeFolderQ
|
|
327
|
+
}, req)
|
|
302
328
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
329
|
+
await processNewEntity(record.entitySet, record.entity)
|
|
330
|
+
} else {
|
|
331
|
+
throw e
|
|
332
|
+
}
|
|
306
333
|
}
|
|
334
|
+
|
|
335
|
+
await record.updateReferences(entityRecordNewValueMap.get(record.entity))
|
|
307
336
|
}
|
|
308
337
|
|
|
309
|
-
|
|
338
|
+
entitiesInHierarchy = records.map((record) => ({
|
|
339
|
+
...omit(entityRecordNewValueMap.get(record.entity), ['$entitySet', '__entitySet']),
|
|
340
|
+
__entitySet: record.entitySet
|
|
341
|
+
}))
|
|
310
342
|
}
|
|
311
343
|
|
|
312
|
-
|
|
313
|
-
...omit(entityRecordNewValueMap.get(record.entity), ['$entitySet', '__entitySet']),
|
|
314
|
-
__entitySet: record.entitySet
|
|
315
|
-
}))
|
|
344
|
+
allEntitiesInvolved.push(...entitiesInHierarchy)
|
|
316
345
|
}
|
|
317
346
|
|
|
318
347
|
// return fresh version of creationDate, modificationDate in the records.
|
|
319
348
|
// this helps with concurrent validation on studio
|
|
320
|
-
await Promise.all(
|
|
349
|
+
await Promise.all(allEntitiesInvolved.map(async (entity) => {
|
|
321
350
|
const entitySet = reporter.documentStore.model.entitySets[entity.__entitySet]
|
|
322
351
|
const entityType = entitySet.entityTypeDef
|
|
323
352
|
const projection = {}
|
|
@@ -350,5 +379,5 @@ module.exports = (reporter) => async ({ source, target, shouldCopy, shouldReplac
|
|
|
350
379
|
}
|
|
351
380
|
}))
|
|
352
381
|
|
|
353
|
-
return
|
|
382
|
+
return allEntitiesInvolved
|
|
354
383
|
}
|