@jsreport/jsreport-core 4.0.0 → 4.0.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.
package/README.md
CHANGED
|
@@ -282,8 +282,13 @@ jsreport.documentStore.collection('templates')
|
|
|
282
282
|
|
|
283
283
|
## Changelog
|
|
284
284
|
|
|
285
|
+
### 4.0.1
|
|
286
|
+
|
|
287
|
+
- fix parameter mutations passed to store methods producing unexpected changes in store
|
|
288
|
+
|
|
285
289
|
### 4.0.0
|
|
286
290
|
|
|
291
|
+
- minimum node.js version is now `18.15.0`
|
|
287
292
|
- remove old migration options `migrateXlsxTemplatesToAssets`, `migrateResourcesToAssets`
|
|
288
293
|
- sandbox now uses SES instead of vm2 for evaluating user code
|
|
289
294
|
- internal changes to support multi admin users
|
|
@@ -1,99 +1,104 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright(c) 2018 Jan Blaha
|
|
3
|
-
*
|
|
4
|
-
* DocumentStore data layer provider using just memory.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const extend = require('node.extend.without.arrays')
|
|
8
|
-
const { nanoid } = require('nanoid')
|
|
9
|
-
const omit = require('lodash.omit')
|
|
10
|
-
const mingo = require('@jsreport/mingo')
|
|
11
|
-
const Transaction = require('./transaction')
|
|
12
|
-
const Queue = require('./queue')
|
|
13
|
-
|
|
14
|
-
module.exports = () => {
|
|
15
|
-
return {
|
|
16
|
-
load (model) {
|
|
17
|
-
this.model = model
|
|
18
|
-
this.transaction = Transaction({ queue: Queue() })
|
|
19
|
-
|
|
20
|
-
return this.transaction.operation(async (documents) => {
|
|
21
|
-
Object.keys(model.entitySets).forEach((e) => (documents[e] = []))
|
|
22
|
-
})
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
beginTransaction () {
|
|
26
|
-
return this.transaction.begin()
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
async commitTransaction (tran) {
|
|
30
|
-
await this.transaction.commit(tran)
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
async rollbackTransaction (tran) {
|
|
34
|
-
return this.transaction.rollback(tran)
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
find (entitySet, query, fields, opts = {}) {
|
|
38
|
-
const documents = this.transaction.getCurrentDocuments(opts)
|
|
39
|
-
const cursor = mingo.find(documents[entitySet], query, fields)
|
|
40
|
-
|
|
41
|
-
// the queue is not used here because reads are supposed to not block
|
|
42
|
-
cursor.toArray = () => cursor.all().map((e) => extend(true, {}, omit(e, '$$etag')))
|
|
43
|
-
|
|
44
|
-
return cursor
|
|
45
|
-
},
|
|
46
|
-
|
|
47
|
-
insert (entitySet, doc, opts = {}) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright(c) 2018 Jan Blaha
|
|
3
|
+
*
|
|
4
|
+
* DocumentStore data layer provider using just memory.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const extend = require('node.extend.without.arrays')
|
|
8
|
+
const { nanoid } = require('nanoid')
|
|
9
|
+
const omit = require('lodash.omit')
|
|
10
|
+
const mingo = require('@jsreport/mingo')
|
|
11
|
+
const Transaction = require('./transaction')
|
|
12
|
+
const Queue = require('./queue')
|
|
13
|
+
|
|
14
|
+
module.exports = () => {
|
|
15
|
+
return {
|
|
16
|
+
load (model) {
|
|
17
|
+
this.model = model
|
|
18
|
+
this.transaction = Transaction({ queue: Queue() })
|
|
19
|
+
|
|
20
|
+
return this.transaction.operation(async (documents) => {
|
|
21
|
+
Object.keys(model.entitySets).forEach((e) => (documents[e] = []))
|
|
22
|
+
})
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
beginTransaction () {
|
|
26
|
+
return this.transaction.begin()
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
async commitTransaction (tran) {
|
|
30
|
+
await this.transaction.commit(tran)
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
async rollbackTransaction (tran) {
|
|
34
|
+
return this.transaction.rollback(tran)
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
find (entitySet, query, fields, opts = {}) {
|
|
38
|
+
const documents = this.transaction.getCurrentDocuments(opts)
|
|
39
|
+
const cursor = mingo.find(documents[entitySet], query, fields)
|
|
40
|
+
|
|
41
|
+
// the queue is not used here because reads are supposed to not block
|
|
42
|
+
cursor.toArray = () => cursor.all().map((e) => extend(true, {}, omit(e, '$$etag')))
|
|
43
|
+
|
|
44
|
+
return cursor
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
insert (entitySet, doc, opts = {}) {
|
|
48
|
+
doc._id = doc._id || nanoid(16)
|
|
49
|
+
const clonnedDoc = extend(true, {}, doc)
|
|
50
|
+
clonnedDoc.$$etag = Date.now()
|
|
51
|
+
|
|
52
|
+
return this.transaction.operation(opts, async (documents) => {
|
|
53
|
+
documents[entitySet].push(clonnedDoc)
|
|
54
|
+
return doc
|
|
55
|
+
})
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
async update (entitySet, q, u, opts = {}) {
|
|
59
|
+
let count
|
|
60
|
+
const qClone = extend(true, {}, q)
|
|
61
|
+
const setClone = extend(true, {}, u.$set)
|
|
62
|
+
|
|
63
|
+
const res = await this.transaction.operation(opts, async (documents) => {
|
|
64
|
+
const toUpdate = mingo.find(documents[entitySet], qClone).all()
|
|
65
|
+
|
|
66
|
+
count = toUpdate.length
|
|
67
|
+
|
|
68
|
+
// need to get of queue first before calling insert, otherwise we get a deathlock
|
|
69
|
+
if (toUpdate.length === 0 && opts.upsert) {
|
|
70
|
+
return 'insert'
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for (const doc of toUpdate) {
|
|
74
|
+
Object.assign(doc, setClone)
|
|
75
|
+
doc.$$etag = Date.now()
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
if (res === 'insert') {
|
|
80
|
+
await this.insert(entitySet, setClone, opts)
|
|
81
|
+
return 1
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return count
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
remove (entitySet, q, opts = {}) {
|
|
88
|
+
const qClone = extend(true, {}, q)
|
|
89
|
+
|
|
90
|
+
return this.transaction.operation(opts, async (documents) => {
|
|
91
|
+
const toRemove = mingo.find(documents[entitySet], qClone).all()
|
|
92
|
+
documents[entitySet] = documents[entitySet].filter(d => !toRemove.includes(d))
|
|
93
|
+
})
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
drop (opts = {}) {
|
|
97
|
+
return this.transaction.operation(opts, async (documents) => {
|
|
98
|
+
for (const [entitySetName] of Object.entries(documents)) {
|
|
99
|
+
documents[entitySetName] = []
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const extend = require('node.extend.without.arrays')
|
|
2
2
|
const groupBy = require('lodash.groupby')
|
|
3
3
|
const get = require('lodash.get')
|
|
4
|
-
const set = require('
|
|
4
|
+
const set = require('set-value')
|
|
5
5
|
const hasOwn = require('has-own-deep')
|
|
6
6
|
const unsetValue = require('unset-value')
|
|
7
7
|
|
|
@@ -420,7 +420,7 @@ function sortPropertiesByLevel (a, b) {
|
|
|
420
420
|
}
|
|
421
421
|
|
|
422
422
|
function omitProp (context, prop) {
|
|
423
|
-
// if property has value, then set it to
|
|
423
|
+
// if property has value, then set it to some value first,
|
|
424
424
|
// unsetValue expects that property has some non empty value to remove the property
|
|
425
425
|
// so we set to "true" to ensure it works for all cases,
|
|
426
426
|
// we use unsetValue instead of lodash.omit because
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsreport/jsreport-core",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "javascript based business reporting",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"report",
|
|
@@ -61,13 +61,13 @@
|
|
|
61
61
|
"lodash.get": "4.4.2",
|
|
62
62
|
"lodash.groupby": "4.6.0",
|
|
63
63
|
"lodash.omit": "4.5.0",
|
|
64
|
-
"lodash.set": "4.3.2",
|
|
65
64
|
"lru-cache": "4.1.1",
|
|
66
65
|
"ms": "2.1.3",
|
|
67
66
|
"nanoid": "3.2.0",
|
|
68
67
|
"nconf": "0.12.0",
|
|
69
68
|
"node.extend.without.arrays": "1.1.6",
|
|
70
69
|
"semver": "7.5.4",
|
|
70
|
+
"set-value": "4.1.0",
|
|
71
71
|
"stack-trace": "0.0.10",
|
|
72
72
|
"triple-beam": "1.3.0",
|
|
73
73
|
"unset-value": "2.0.1",
|
package/test/store/common.js
CHANGED
|
@@ -141,6 +141,34 @@ function collectionTests (store, isInternal, runTransactions) {
|
|
|
141
141
|
res[0].phantom.header.should.be.eql('original')
|
|
142
142
|
})
|
|
143
143
|
|
|
144
|
+
it('update should use clones', async () => {
|
|
145
|
+
const colName = !isInternal ? 'templates' : 'internalTemplates'
|
|
146
|
+
|
|
147
|
+
await store().collection('folders').insert({
|
|
148
|
+
name: 'f1',
|
|
149
|
+
shortid: 'f1'
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
await getCollection(colName).insert({
|
|
153
|
+
name: 'test',
|
|
154
|
+
engine: 'none',
|
|
155
|
+
recipe: 'html',
|
|
156
|
+
content: 'original'
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
const set = {
|
|
160
|
+
folder: {
|
|
161
|
+
shortid: 'f1'
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
await getCollection(colName).update({ name: 'test' }, { $set: set })
|
|
166
|
+
set.folder.shortid = 'changing'
|
|
167
|
+
|
|
168
|
+
const res = await getCollection(colName).findOne({})
|
|
169
|
+
res.folder.shortid.should.be.eql('f1')
|
|
170
|
+
})
|
|
171
|
+
|
|
144
172
|
it('skip and limit', async () => {
|
|
145
173
|
const colName = !isInternal ? 'templates' : 'internalTemplates'
|
|
146
174
|
|
|
@@ -443,6 +471,33 @@ function collectionTests (store, isInternal, runTransactions) {
|
|
|
443
471
|
should(found != null).be.True()
|
|
444
472
|
})
|
|
445
473
|
|
|
474
|
+
it('insert with transaction should use clones', async () => {
|
|
475
|
+
const colName = !isInternal ? 'templates' : 'internalTemplates'
|
|
476
|
+
const req = Request({})
|
|
477
|
+
|
|
478
|
+
await store().beginTransaction(req)
|
|
479
|
+
|
|
480
|
+
try {
|
|
481
|
+
const t1 = {
|
|
482
|
+
name: 't1',
|
|
483
|
+
engine: 'none',
|
|
484
|
+
recipe: 'html'
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const newT1 = await getCollection(colName).insert(t1, req)
|
|
488
|
+
|
|
489
|
+
newT1.name = 'fake-t1'
|
|
490
|
+
|
|
491
|
+
await store().commitTransaction(req)
|
|
492
|
+
} catch (e) {
|
|
493
|
+
await store().rollbackTransaction(req)
|
|
494
|
+
throw e
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const found = await getCollection(colName).findOne({ name: 't1' })
|
|
498
|
+
should(found).not.be.null()
|
|
499
|
+
})
|
|
500
|
+
|
|
446
501
|
it('should be able to rollback (insert)', async () => {
|
|
447
502
|
const colName = !isInternal ? 'templates' : 'internalTemplates'
|
|
448
503
|
const req = Request({})
|