@jsreport/jsreport-core 3.1.2-test.2 → 3.2.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/LICENSE +166 -166
- package/README.md +298 -298
- package/index.js +29 -29
- package/lib/main/blobStorage/blobStorage.js +52 -52
- package/lib/main/blobStorage/inMemoryProvider.js +27 -27
- package/lib/main/blobStorage/mainActions.js +24 -24
- package/lib/main/createDefaultLoggerFormat.js +17 -17
- package/lib/main/defaults.js +14 -14
- package/lib/main/extensions/discover.js +20 -20
- package/lib/main/extensions/extensionsManager.js +264 -264
- package/lib/main/extensions/fileUtils.js +56 -56
- package/lib/main/extensions/findVersion.js +49 -49
- package/lib/main/extensions/locationCache.js +103 -103
- package/lib/main/extensions/sorter.js +10 -10
- package/lib/main/extensions/validateMinimalVersion.js +50 -50
- package/lib/main/folders/cascadeFolderRemove.js +25 -25
- package/lib/main/folders/getEntitiesInFolder.js +53 -53
- package/lib/main/folders/index.js +42 -42
- package/lib/main/folders/moveBetweenFolders.js +354 -354
- package/lib/main/folders/validateDuplicatedName.js +107 -107
- package/lib/main/folders/validateReservedName.js +53 -53
- package/lib/main/logger.js +244 -244
- package/lib/main/migration/resourcesToAssets.js +230 -230
- package/lib/main/migration/xlsxTemplatesToAssets.js +128 -128
- package/lib/main/monitoring.js +91 -91
- package/lib/main/optionsLoad.js +237 -237
- package/lib/main/optionsSchema.js +237 -237
- package/lib/main/reporter.js +574 -579
- package/lib/main/schemaValidator.js +252 -252
- package/lib/main/settings.js +154 -154
- package/lib/main/store/checkDuplicatedId.js +27 -27
- package/lib/main/store/collection.js +329 -329
- package/lib/main/store/documentStore.js +469 -469
- package/lib/main/store/mainActions.js +28 -28
- package/lib/main/store/memoryStoreProvider.js +99 -99
- package/lib/main/store/queue.js +48 -48
- package/lib/main/store/referenceUtils.js +251 -251
- package/lib/main/store/setupValidateId.js +43 -43
- package/lib/main/store/setupValidateShortid.js +71 -71
- package/lib/main/store/transaction.js +69 -69
- package/lib/main/store/typeUtils.js +180 -180
- package/lib/main/templates.js +34 -34
- package/lib/main/validateEntityName.js +62 -62
- package/lib/shared/createError.js +36 -36
- package/lib/shared/encryption.js +114 -114
- package/lib/shared/folders/index.js +11 -11
- package/lib/shared/folders/normalizeEntityPath.js +15 -15
- package/lib/shared/folders/resolveEntityFromPath.js +88 -88
- package/lib/shared/folders/resolveEntityPath.js +46 -46
- package/lib/shared/folders/resolveFolderFromPath.js +38 -38
- package/lib/shared/generateRequestId.js +4 -4
- package/lib/shared/listenerCollection.js +169 -169
- package/lib/shared/normalizeMetaFromLogs.js +30 -30
- package/lib/shared/reporter.js +128 -123
- package/lib/shared/request.js +64 -64
- package/lib/shared/tempFilesHandler.js +81 -81
- package/lib/shared/templates.js +82 -82
- package/lib/static/helpers.js +33 -33
- package/lib/worker/blobStorage.js +34 -34
- package/lib/worker/defaultProxyExtend.js +46 -46
- package/lib/worker/documentStore.js +49 -49
- package/lib/worker/extensionsManager.js +17 -17
- package/lib/worker/logger.js +48 -48
- package/lib/worker/render/diff.js +138 -138
- package/lib/worker/render/executeEngine.js +239 -207
- package/lib/worker/render/htmlRecipe.js +10 -10
- package/lib/worker/render/moduleHelper.js +45 -43
- package/lib/worker/render/noneEngine.js +12 -12
- package/lib/worker/render/profiler.js +158 -158
- package/lib/worker/render/render.js +202 -205
- package/lib/worker/render/resolveReferences.js +60 -60
- package/lib/worker/reporter.js +192 -191
- package/lib/worker/sandbox/runInSandbox.js +16 -9
- package/lib/worker/sandbox/safeSandbox.js +828 -828
- package/lib/worker/templates.js +80 -78
- package/lib/worker/workerHandler.js +54 -54
- package/package.json +92 -92
- package/test/blobStorage/common.js +21 -21
- package/test/store/common.js +1449 -1449
|
@@ -1,329 +1,329 @@
|
|
|
1
|
-
const createListenerCollection = require('../../shared/listenerCollection')
|
|
2
|
-
const { resolvePropDefinition } = require('./typeUtils')
|
|
3
|
-
const createError = require('../../shared/createError')
|
|
4
|
-
const validateEntityName = require('../validateEntityName')
|
|
5
|
-
|
|
6
|
-
module.exports = (entitySet, provider, model, validator, encryption, transactions) => ({
|
|
7
|
-
name: entitySet,
|
|
8
|
-
beforeFindListeners: createListenerCollection(`DocumentStoreCollection(${entitySet})@beforeFind`),
|
|
9
|
-
beforeUpdateListeners: createListenerCollection(`DocumentStoreCollection(${entitySet})@beforeUpdate`),
|
|
10
|
-
beforeInsertListeners: createListenerCollection(`DocumentStoreCollection(${entitySet})@beforeInsert`),
|
|
11
|
-
beforeRemoveListeners: createListenerCollection(`DocumentStoreCollection(${entitySet})@beforeRemove`),
|
|
12
|
-
beforeUpdateValidationListeners: createListenerCollection(`DocumentStoreCollection(${entitySet})@beforeUpdateValidation`),
|
|
13
|
-
beforeInsertValidationListeners: createListenerCollection(`DocumentStoreCollection(${entitySet})@beforeInsertValidation`),
|
|
14
|
-
entitySet,
|
|
15
|
-
|
|
16
|
-
load: (...args) => {
|
|
17
|
-
provider.load(entitySet, ...args)
|
|
18
|
-
},
|
|
19
|
-
|
|
20
|
-
find (q, p, req) {
|
|
21
|
-
if (p && p.__isJsreportRequest__ === true) {
|
|
22
|
-
req = p
|
|
23
|
-
p = {}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
p = p || {}
|
|
27
|
-
|
|
28
|
-
const listenerPromise = this.beforeFindListeners.fire(q, p, req)
|
|
29
|
-
|
|
30
|
-
// the jsreport back-compatible API for find returns promise with the result array
|
|
31
|
-
// the new API returns a cursor like mongo uses
|
|
32
|
-
// to make it working for both way of calling, we return
|
|
33
|
-
// an object which is a promise and in the same time a cursor
|
|
34
|
-
const cursorCalls = []
|
|
35
|
-
const functions = ['skip', 'limit', 'sort', 'toArray', 'count']
|
|
36
|
-
const fakeCursor = {}
|
|
37
|
-
functions.forEach((f) => {
|
|
38
|
-
fakeCursor[f] = (...args) => {
|
|
39
|
-
cursorCalls.push({ f: f, args: args })
|
|
40
|
-
return fakeCursor
|
|
41
|
-
}
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
const replay = (cursor) => {
|
|
45
|
-
cursorCalls.filter((c) => c.f !== 'toArray' && c.f !== 'count').forEach((c) => cursor[c.f].apply(cursor, c.args))
|
|
46
|
-
|
|
47
|
-
if (cursorCalls.find((c) => c.f === 'count')) {
|
|
48
|
-
return cursor.count()
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return cursor.toArray()
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return Object.assign(fakeCursor, {
|
|
55
|
-
then: (onFulfilled, onRejected) => {
|
|
56
|
-
// the node A compatible promise expects then to be called with two functions
|
|
57
|
-
let promise = listenerPromise.then(() => {
|
|
58
|
-
return replay(provider.find(entitySet, q, p, {
|
|
59
|
-
transaction: transactions.getActiveTransaction(req)
|
|
60
|
-
}))
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
// the node A compatible promise expects then to be called with two functions
|
|
64
|
-
if (typeof onFulfilled === 'function') {
|
|
65
|
-
promise = promise.then(onFulfilled)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (typeof onRejected === 'function') {
|
|
69
|
-
promise = promise.catch(onRejected)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return promise
|
|
73
|
-
}
|
|
74
|
-
})
|
|
75
|
-
},
|
|
76
|
-
|
|
77
|
-
count (...args) {
|
|
78
|
-
return this.find(...args).count()
|
|
79
|
-
},
|
|
80
|
-
|
|
81
|
-
async insert (data, req) {
|
|
82
|
-
await this.beforeInsertValidationListeners.fire(data, req)
|
|
83
|
-
|
|
84
|
-
// internal entities are not in the model
|
|
85
|
-
if (model.entitySets[entitySet] && model.entitySets[entitySet].entityTypeDef.name) {
|
|
86
|
-
validateEntityName(data.name)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const entityType = model.entitySets[entitySet] ? model.entitySets[entitySet].normalizedEntityTypeName : null
|
|
90
|
-
|
|
91
|
-
if (entityType != null && validator.getSchema(entityType) != null) {
|
|
92
|
-
const validationResult = validator.validate(entityType, data)
|
|
93
|
-
|
|
94
|
-
if (!validationResult.valid) {
|
|
95
|
-
throw createError(`Error when trying to insert into "${entitySet}" collection. input contain values that does not match the schema. ${validationResult.fullErrorMessage}`, {
|
|
96
|
-
weak: true,
|
|
97
|
-
statusCode: 400
|
|
98
|
-
})
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
await this.beforeInsertListeners.fire(data, req)
|
|
103
|
-
|
|
104
|
-
return provider.insert(entitySet, data, {
|
|
105
|
-
transaction: transactions.getActiveTransaction(req)
|
|
106
|
-
})
|
|
107
|
-
},
|
|
108
|
-
|
|
109
|
-
async update (q, u, o, req) {
|
|
110
|
-
if (o && o.__isJsreportRequest__) {
|
|
111
|
-
req = o
|
|
112
|
-
o = {}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
await this.beforeUpdateValidationListeners.fire(q, u, o, req)
|
|
116
|
-
|
|
117
|
-
// internal entities are not in the model
|
|
118
|
-
if (model.entitySets[entitySet] && model.entitySets[entitySet].entityTypeDef.name && u.$set.name !== undefined) {
|
|
119
|
-
validateEntityName(u.$set.name)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const entityType = model.entitySets[entitySet] ? model.entitySets[entitySet].normalizedEntityTypeName : null
|
|
123
|
-
|
|
124
|
-
if (entityType != null && validator.getSchema(entityType) != null) {
|
|
125
|
-
const validationResult = validator.validate(entityType, u.$set)
|
|
126
|
-
|
|
127
|
-
if (!validationResult.valid) {
|
|
128
|
-
throw createError(`Error when trying to update "${entitySet}" collection. input contain values that does not match the schema. ${validationResult.fullErrorMessage}`, {
|
|
129
|
-
weak: true,
|
|
130
|
-
statusCode: 400
|
|
131
|
-
})
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
await this.beforeUpdateListeners.fire(q, u, o, req)
|
|
136
|
-
|
|
137
|
-
const updateOpts = Object.assign({}, o)
|
|
138
|
-
const activeTran = transactions.getActiveTransaction(req)
|
|
139
|
-
|
|
140
|
-
if (activeTran) {
|
|
141
|
-
updateOpts.transaction = activeTran
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return provider.update(entitySet, q, u, updateOpts)
|
|
145
|
-
},
|
|
146
|
-
|
|
147
|
-
async remove (q, req) {
|
|
148
|
-
await this.beforeRemoveListeners.fire(q, req)
|
|
149
|
-
|
|
150
|
-
return provider.remove(entitySet, q, {
|
|
151
|
-
transaction: transactions.getActiveTransaction(req)
|
|
152
|
-
})
|
|
153
|
-
},
|
|
154
|
-
|
|
155
|
-
async findOne (...args) {
|
|
156
|
-
const res = await this.find(...args)
|
|
157
|
-
if (res.length > 0) {
|
|
158
|
-
return res[0]
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return null
|
|
162
|
-
},
|
|
163
|
-
|
|
164
|
-
async serializeProperties (docs, customTypeDef) {
|
|
165
|
-
let typeDef
|
|
166
|
-
|
|
167
|
-
if (customTypeDef == null) {
|
|
168
|
-
const entitySetInfo = model.entitySets[entitySet]
|
|
169
|
-
const entityType = entitySetInfo.entityTypeDef
|
|
170
|
-
typeDef = entityType
|
|
171
|
-
} else {
|
|
172
|
-
typeDef = customTypeDef
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (!typeDef) {
|
|
176
|
-
return
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return Promise.all(docs.map(async (doc) => {
|
|
180
|
-
if (doc == null) {
|
|
181
|
-
return doc
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const newDoc = Object.assign({}, doc)
|
|
185
|
-
|
|
186
|
-
for (const prop in newDoc) {
|
|
187
|
-
if (!prop) {
|
|
188
|
-
continue
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const propDef = typeDef[prop]
|
|
192
|
-
|
|
193
|
-
if (!propDef || propDef.type == null) {
|
|
194
|
-
continue
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const resolveResult = resolvePropDefinition(model, propDef)
|
|
198
|
-
|
|
199
|
-
if (!resolveResult) {
|
|
200
|
-
continue
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const isCollection = resolveResult.def.type.startsWith('Collection(')
|
|
204
|
-
|
|
205
|
-
if (propDef.encrypted === true) {
|
|
206
|
-
if (isCollection && resolveResult.subType == null) {
|
|
207
|
-
if (Array.isArray(newDoc[prop])) {
|
|
208
|
-
for (const [idx, value] of Object.entries(newDoc[prop])) {
|
|
209
|
-
newDoc[prop][idx] = await encryption.decrypt(value)
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
} else if (resolveResult.def.type.startsWith('Edm')) {
|
|
213
|
-
newDoc[prop] = await encryption.decrypt(newDoc[prop])
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (
|
|
218
|
-
isCollection ||
|
|
219
|
-
resolveResult.subType
|
|
220
|
-
) {
|
|
221
|
-
if (isCollection) {
|
|
222
|
-
if (!Array.isArray(newDoc[prop])) {
|
|
223
|
-
continue
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (resolveResult.subType) {
|
|
227
|
-
const result = await this.serializeProperties(newDoc[prop], resolveResult.subType)
|
|
228
|
-
newDoc[prop] = result
|
|
229
|
-
}
|
|
230
|
-
} else {
|
|
231
|
-
const result = await this.serializeProperties([newDoc[prop]], resolveResult.subType)
|
|
232
|
-
newDoc[prop] = result[0]
|
|
233
|
-
}
|
|
234
|
-
} else if (propDef.type === 'Edm.Binary') {
|
|
235
|
-
newDoc[prop] = Buffer.from(newDoc[prop]).toString('base64') // eslint-disable-line
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return newDoc
|
|
240
|
-
}))
|
|
241
|
-
},
|
|
242
|
-
|
|
243
|
-
async deserializeProperties (docs, customTypeDef) {
|
|
244
|
-
let typeDef
|
|
245
|
-
|
|
246
|
-
if (customTypeDef == null) {
|
|
247
|
-
const entitySetInfo = model.entitySets[entitySet]
|
|
248
|
-
|
|
249
|
-
if (!entitySetInfo) {
|
|
250
|
-
return []
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const entityType = entitySetInfo.entityTypeDef
|
|
254
|
-
|
|
255
|
-
if (!entityType) {
|
|
256
|
-
return []
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
typeDef = entityType
|
|
260
|
-
} else {
|
|
261
|
-
typeDef = customTypeDef
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
return Promise.all(docs.map(async (doc) => {
|
|
265
|
-
if (doc == null) {
|
|
266
|
-
return doc
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
const newDoc = Object.assign({}, doc)
|
|
270
|
-
|
|
271
|
-
for (const prop in newDoc) {
|
|
272
|
-
if (!prop) {
|
|
273
|
-
continue
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
const propDef = typeDef[prop]
|
|
277
|
-
|
|
278
|
-
if (!propDef || propDef.type == null) {
|
|
279
|
-
continue
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
const resolveResult = resolvePropDefinition(model, propDef)
|
|
283
|
-
|
|
284
|
-
if (!resolveResult) {
|
|
285
|
-
continue
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const isCollection = resolveResult.def.type.startsWith('Collection(')
|
|
289
|
-
|
|
290
|
-
if (
|
|
291
|
-
isCollection ||
|
|
292
|
-
resolveResult.subType
|
|
293
|
-
) {
|
|
294
|
-
if (isCollection) {
|
|
295
|
-
if (!Array.isArray(newDoc[prop])) {
|
|
296
|
-
continue
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (resolveResult.subType) {
|
|
300
|
-
const result = await this.deserializeProperties(newDoc[prop], resolveResult.subType)
|
|
301
|
-
newDoc[prop] = result
|
|
302
|
-
}
|
|
303
|
-
} else {
|
|
304
|
-
const result = await this.deserializeProperties([newDoc[prop]], resolveResult.subType)
|
|
305
|
-
newDoc[prop] = result[0]
|
|
306
|
-
}
|
|
307
|
-
} else if (propDef.type === 'Edm.Binary') {
|
|
308
|
-
newDoc[prop] = Buffer.from(newDoc[prop], 'base64') // eslint-disable-line
|
|
309
|
-
} else if (propDef.type === 'Edm.DateTimeOffset') {
|
|
310
|
-
newDoc[prop] = new Date(newDoc[prop])
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (propDef.encrypted === true) {
|
|
314
|
-
if (isCollection && resolveResult.subType == null) {
|
|
315
|
-
if (Array.isArray(newDoc[prop])) {
|
|
316
|
-
for (const [idx, value] of Object.entries(newDoc[prop])) {
|
|
317
|
-
newDoc[prop][idx] = await encryption.encrypt(value)
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
} else if (resolveResult.def.type.startsWith('Edm')) {
|
|
321
|
-
newDoc[prop] = await encryption.encrypt(newDoc[prop])
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
return newDoc
|
|
327
|
-
}))
|
|
328
|
-
}
|
|
329
|
-
})
|
|
1
|
+
const createListenerCollection = require('../../shared/listenerCollection')
|
|
2
|
+
const { resolvePropDefinition } = require('./typeUtils')
|
|
3
|
+
const createError = require('../../shared/createError')
|
|
4
|
+
const validateEntityName = require('../validateEntityName')
|
|
5
|
+
|
|
6
|
+
module.exports = (entitySet, provider, model, validator, encryption, transactions) => ({
|
|
7
|
+
name: entitySet,
|
|
8
|
+
beforeFindListeners: createListenerCollection(`DocumentStoreCollection(${entitySet})@beforeFind`),
|
|
9
|
+
beforeUpdateListeners: createListenerCollection(`DocumentStoreCollection(${entitySet})@beforeUpdate`),
|
|
10
|
+
beforeInsertListeners: createListenerCollection(`DocumentStoreCollection(${entitySet})@beforeInsert`),
|
|
11
|
+
beforeRemoveListeners: createListenerCollection(`DocumentStoreCollection(${entitySet})@beforeRemove`),
|
|
12
|
+
beforeUpdateValidationListeners: createListenerCollection(`DocumentStoreCollection(${entitySet})@beforeUpdateValidation`),
|
|
13
|
+
beforeInsertValidationListeners: createListenerCollection(`DocumentStoreCollection(${entitySet})@beforeInsertValidation`),
|
|
14
|
+
entitySet,
|
|
15
|
+
|
|
16
|
+
load: (...args) => {
|
|
17
|
+
provider.load(entitySet, ...args)
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
find (q, p, req) {
|
|
21
|
+
if (p && p.__isJsreportRequest__ === true) {
|
|
22
|
+
req = p
|
|
23
|
+
p = {}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
p = p || {}
|
|
27
|
+
|
|
28
|
+
const listenerPromise = this.beforeFindListeners.fire(q, p, req)
|
|
29
|
+
|
|
30
|
+
// the jsreport back-compatible API for find returns promise with the result array
|
|
31
|
+
// the new API returns a cursor like mongo uses
|
|
32
|
+
// to make it working for both way of calling, we return
|
|
33
|
+
// an object which is a promise and in the same time a cursor
|
|
34
|
+
const cursorCalls = []
|
|
35
|
+
const functions = ['skip', 'limit', 'sort', 'toArray', 'count']
|
|
36
|
+
const fakeCursor = {}
|
|
37
|
+
functions.forEach((f) => {
|
|
38
|
+
fakeCursor[f] = (...args) => {
|
|
39
|
+
cursorCalls.push({ f: f, args: args })
|
|
40
|
+
return fakeCursor
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const replay = (cursor) => {
|
|
45
|
+
cursorCalls.filter((c) => c.f !== 'toArray' && c.f !== 'count').forEach((c) => cursor[c.f].apply(cursor, c.args))
|
|
46
|
+
|
|
47
|
+
if (cursorCalls.find((c) => c.f === 'count')) {
|
|
48
|
+
return cursor.count()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return cursor.toArray()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return Object.assign(fakeCursor, {
|
|
55
|
+
then: (onFulfilled, onRejected) => {
|
|
56
|
+
// the node A compatible promise expects then to be called with two functions
|
|
57
|
+
let promise = listenerPromise.then(() => {
|
|
58
|
+
return replay(provider.find(entitySet, q, p, {
|
|
59
|
+
transaction: transactions.getActiveTransaction(req)
|
|
60
|
+
}))
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// the node A compatible promise expects then to be called with two functions
|
|
64
|
+
if (typeof onFulfilled === 'function') {
|
|
65
|
+
promise = promise.then(onFulfilled)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (typeof onRejected === 'function') {
|
|
69
|
+
promise = promise.catch(onRejected)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return promise
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
count (...args) {
|
|
78
|
+
return this.find(...args).count()
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
async insert (data, req) {
|
|
82
|
+
await this.beforeInsertValidationListeners.fire(data, req)
|
|
83
|
+
|
|
84
|
+
// internal entities are not in the model
|
|
85
|
+
if (model.entitySets[entitySet] && model.entitySets[entitySet].entityTypeDef.name) {
|
|
86
|
+
validateEntityName(data.name)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const entityType = model.entitySets[entitySet] ? model.entitySets[entitySet].normalizedEntityTypeName : null
|
|
90
|
+
|
|
91
|
+
if (entityType != null && validator.getSchema(entityType) != null) {
|
|
92
|
+
const validationResult = validator.validate(entityType, data)
|
|
93
|
+
|
|
94
|
+
if (!validationResult.valid) {
|
|
95
|
+
throw createError(`Error when trying to insert into "${entitySet}" collection. input contain values that does not match the schema. ${validationResult.fullErrorMessage}`, {
|
|
96
|
+
weak: true,
|
|
97
|
+
statusCode: 400
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
await this.beforeInsertListeners.fire(data, req)
|
|
103
|
+
|
|
104
|
+
return provider.insert(entitySet, data, {
|
|
105
|
+
transaction: transactions.getActiveTransaction(req)
|
|
106
|
+
})
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
async update (q, u, o, req) {
|
|
110
|
+
if (o && o.__isJsreportRequest__) {
|
|
111
|
+
req = o
|
|
112
|
+
o = {}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
await this.beforeUpdateValidationListeners.fire(q, u, o, req)
|
|
116
|
+
|
|
117
|
+
// internal entities are not in the model
|
|
118
|
+
if (model.entitySets[entitySet] && model.entitySets[entitySet].entityTypeDef.name && u.$set.name !== undefined) {
|
|
119
|
+
validateEntityName(u.$set.name)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const entityType = model.entitySets[entitySet] ? model.entitySets[entitySet].normalizedEntityTypeName : null
|
|
123
|
+
|
|
124
|
+
if (entityType != null && validator.getSchema(entityType) != null) {
|
|
125
|
+
const validationResult = validator.validate(entityType, u.$set)
|
|
126
|
+
|
|
127
|
+
if (!validationResult.valid) {
|
|
128
|
+
throw createError(`Error when trying to update "${entitySet}" collection. input contain values that does not match the schema. ${validationResult.fullErrorMessage}`, {
|
|
129
|
+
weak: true,
|
|
130
|
+
statusCode: 400
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
await this.beforeUpdateListeners.fire(q, u, o, req)
|
|
136
|
+
|
|
137
|
+
const updateOpts = Object.assign({}, o)
|
|
138
|
+
const activeTran = transactions.getActiveTransaction(req)
|
|
139
|
+
|
|
140
|
+
if (activeTran) {
|
|
141
|
+
updateOpts.transaction = activeTran
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return provider.update(entitySet, q, u, updateOpts)
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
async remove (q, req) {
|
|
148
|
+
await this.beforeRemoveListeners.fire(q, req)
|
|
149
|
+
|
|
150
|
+
return provider.remove(entitySet, q, {
|
|
151
|
+
transaction: transactions.getActiveTransaction(req)
|
|
152
|
+
})
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
async findOne (...args) {
|
|
156
|
+
const res = await this.find(...args)
|
|
157
|
+
if (res.length > 0) {
|
|
158
|
+
return res[0]
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return null
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
async serializeProperties (docs, customTypeDef) {
|
|
165
|
+
let typeDef
|
|
166
|
+
|
|
167
|
+
if (customTypeDef == null) {
|
|
168
|
+
const entitySetInfo = model.entitySets[entitySet]
|
|
169
|
+
const entityType = entitySetInfo.entityTypeDef
|
|
170
|
+
typeDef = entityType
|
|
171
|
+
} else {
|
|
172
|
+
typeDef = customTypeDef
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (!typeDef) {
|
|
176
|
+
return
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return Promise.all(docs.map(async (doc) => {
|
|
180
|
+
if (doc == null) {
|
|
181
|
+
return doc
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const newDoc = Object.assign({}, doc)
|
|
185
|
+
|
|
186
|
+
for (const prop in newDoc) {
|
|
187
|
+
if (!prop) {
|
|
188
|
+
continue
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const propDef = typeDef[prop]
|
|
192
|
+
|
|
193
|
+
if (!propDef || propDef.type == null) {
|
|
194
|
+
continue
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const resolveResult = resolvePropDefinition(model, propDef)
|
|
198
|
+
|
|
199
|
+
if (!resolveResult) {
|
|
200
|
+
continue
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const isCollection = resolveResult.def.type.startsWith('Collection(')
|
|
204
|
+
|
|
205
|
+
if (propDef.encrypted === true) {
|
|
206
|
+
if (isCollection && resolveResult.subType == null) {
|
|
207
|
+
if (Array.isArray(newDoc[prop])) {
|
|
208
|
+
for (const [idx, value] of Object.entries(newDoc[prop])) {
|
|
209
|
+
newDoc[prop][idx] = await encryption.decrypt(value)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} else if (resolveResult.def.type.startsWith('Edm')) {
|
|
213
|
+
newDoc[prop] = await encryption.decrypt(newDoc[prop])
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (
|
|
218
|
+
isCollection ||
|
|
219
|
+
resolveResult.subType
|
|
220
|
+
) {
|
|
221
|
+
if (isCollection) {
|
|
222
|
+
if (!Array.isArray(newDoc[prop])) {
|
|
223
|
+
continue
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (resolveResult.subType) {
|
|
227
|
+
const result = await this.serializeProperties(newDoc[prop], resolveResult.subType)
|
|
228
|
+
newDoc[prop] = result
|
|
229
|
+
}
|
|
230
|
+
} else {
|
|
231
|
+
const result = await this.serializeProperties([newDoc[prop]], resolveResult.subType)
|
|
232
|
+
newDoc[prop] = result[0]
|
|
233
|
+
}
|
|
234
|
+
} else if (propDef.type === 'Edm.Binary') {
|
|
235
|
+
newDoc[prop] = Buffer.from(newDoc[prop]).toString('base64') // eslint-disable-line
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return newDoc
|
|
240
|
+
}))
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
async deserializeProperties (docs, customTypeDef) {
|
|
244
|
+
let typeDef
|
|
245
|
+
|
|
246
|
+
if (customTypeDef == null) {
|
|
247
|
+
const entitySetInfo = model.entitySets[entitySet]
|
|
248
|
+
|
|
249
|
+
if (!entitySetInfo) {
|
|
250
|
+
return []
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const entityType = entitySetInfo.entityTypeDef
|
|
254
|
+
|
|
255
|
+
if (!entityType) {
|
|
256
|
+
return []
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
typeDef = entityType
|
|
260
|
+
} else {
|
|
261
|
+
typeDef = customTypeDef
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return Promise.all(docs.map(async (doc) => {
|
|
265
|
+
if (doc == null) {
|
|
266
|
+
return doc
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const newDoc = Object.assign({}, doc)
|
|
270
|
+
|
|
271
|
+
for (const prop in newDoc) {
|
|
272
|
+
if (!prop) {
|
|
273
|
+
continue
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const propDef = typeDef[prop]
|
|
277
|
+
|
|
278
|
+
if (!propDef || propDef.type == null) {
|
|
279
|
+
continue
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const resolveResult = resolvePropDefinition(model, propDef)
|
|
283
|
+
|
|
284
|
+
if (!resolveResult) {
|
|
285
|
+
continue
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const isCollection = resolveResult.def.type.startsWith('Collection(')
|
|
289
|
+
|
|
290
|
+
if (
|
|
291
|
+
isCollection ||
|
|
292
|
+
resolveResult.subType
|
|
293
|
+
) {
|
|
294
|
+
if (isCollection) {
|
|
295
|
+
if (!Array.isArray(newDoc[prop])) {
|
|
296
|
+
continue
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (resolveResult.subType) {
|
|
300
|
+
const result = await this.deserializeProperties(newDoc[prop], resolveResult.subType)
|
|
301
|
+
newDoc[prop] = result
|
|
302
|
+
}
|
|
303
|
+
} else {
|
|
304
|
+
const result = await this.deserializeProperties([newDoc[prop]], resolveResult.subType)
|
|
305
|
+
newDoc[prop] = result[0]
|
|
306
|
+
}
|
|
307
|
+
} else if (propDef.type === 'Edm.Binary') {
|
|
308
|
+
newDoc[prop] = Buffer.from(newDoc[prop], 'base64') // eslint-disable-line
|
|
309
|
+
} else if (propDef.type === 'Edm.DateTimeOffset') {
|
|
310
|
+
newDoc[prop] = new Date(newDoc[prop])
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (propDef.encrypted === true) {
|
|
314
|
+
if (isCollection && resolveResult.subType == null) {
|
|
315
|
+
if (Array.isArray(newDoc[prop])) {
|
|
316
|
+
for (const [idx, value] of Object.entries(newDoc[prop])) {
|
|
317
|
+
newDoc[prop][idx] = await encryption.encrypt(value)
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
} else if (resolveResult.def.type.startsWith('Edm')) {
|
|
321
|
+
newDoc[prop] = await encryption.encrypt(newDoc[prop])
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return newDoc
|
|
327
|
+
}))
|
|
328
|
+
}
|
|
329
|
+
})
|