dobo 2.11.0 → 2.11.2
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/index.js +3 -0
- package/lib/collect-models.js +2 -0
- package/lib/factory/model/find-all-record.js +25 -16
- package/lib/factory/model/find-one-record.js +1 -1
- package/lib/factory/model/find-record.js +18 -14
- package/lib/factory/model/get-record.js +12 -11
- package/lib/factory/model/validate.js +2 -3
- package/lib/factory/model.js +0 -1
- package/package.json +1 -1
- package/wiki/CHANGES.md +8 -0
package/index.js
CHANGED
|
@@ -153,6 +153,9 @@ async function factory (pkgName) {
|
|
|
153
153
|
hardLimit: 10000,
|
|
154
154
|
maxPage: 50,
|
|
155
155
|
sort: ['dt:-1', 'updatedAt:-1', 'updated_at:-1', 'createdAt:-1', 'createdAt:-1', 'ts:-1', 'username', 'name']
|
|
156
|
+
},
|
|
157
|
+
cache: {
|
|
158
|
+
ttlDur: '10s'
|
|
156
159
|
}
|
|
157
160
|
},
|
|
158
161
|
memDb: {
|
package/lib/collect-models.js
CHANGED
|
@@ -245,6 +245,8 @@ async function createSchema (item) {
|
|
|
245
245
|
item.hooks = item.hooks ?? []
|
|
246
246
|
item.disabled = item.disabled ?? []
|
|
247
247
|
item.scanables = item.scanables ?? []
|
|
248
|
+
item.cache = item.cache ?? this.config.default.cache
|
|
249
|
+
if (item.cache === true) item.cache = this.config.default.cache
|
|
248
250
|
if (item.disabled === 'all') item.disabled = ['find', 'get', 'create', 'update', 'remove']
|
|
249
251
|
else if (item.disabled === 'readonly') item.disabled = ['create', 'update', 'remove']
|
|
250
252
|
// Is there any overwritten connection?
|
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
import { getMultiRefs, execHook, execModelHook, execDynHook, getFilterAndOptions, cloneOptions } from './_util.js'
|
|
2
2
|
const action = 'findAllRecord'
|
|
3
3
|
|
|
4
|
-
async function native (
|
|
4
|
+
async function native (...args) {
|
|
5
5
|
const { isSet } = this.app.lib.aneka
|
|
6
|
-
const {
|
|
6
|
+
const { cloneDeep } = this.app.lib._
|
|
7
|
+
const [params = {}, opts = {}] = args
|
|
8
|
+
const { dataOnly = true } = opts
|
|
9
|
+
const { get: getCache, set: setCache } = this.app.bajoCache
|
|
10
|
+
const { filter, options } = await getFilterAndOptions.call(this, params, opts, action)
|
|
7
11
|
if (dataOnly) options.count = false
|
|
8
12
|
let { noResultSanitizer, noCache } = options
|
|
9
|
-
if (!this.cacheable) noCache = true
|
|
10
13
|
await execHook.call(this, 'beforeFindRecord', filter, options)
|
|
11
14
|
await execModelHook.call(this, 'beforeFindRecord', filter, options)
|
|
12
15
|
await execDynHook.call(this, 'beforeFindRecord', filter, options)
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
if (this.cache.ttlDur === 0 || options.record) noCache = true
|
|
17
|
+
const cacheFilter = cloneDeep(filter)
|
|
18
|
+
if (!noCache && getCache) {
|
|
19
|
+
const result = await getCache({ model: this, filter: cacheFilter, options })
|
|
20
|
+
if (result) {
|
|
21
|
+
for (const idx in result.data) {
|
|
22
|
+
result.data[idx] = await this.sanitizeRecord(result.data[idx], options)
|
|
23
|
+
}
|
|
24
|
+
result.cached = true
|
|
25
|
+
return dataOnly ? result.data : result
|
|
19
26
|
}
|
|
20
27
|
}
|
|
21
28
|
const result = options.record ?? (await this.driver._findAllRecord(this, filter, options)) ?? {}
|
|
@@ -28,12 +35,17 @@ async function native (filter, options, dataOnly) {
|
|
|
28
35
|
await execDynHook.call(this, 'afterFindRecord', filter, result, options)
|
|
29
36
|
await execModelHook.call(this, 'afterFindRecord', filter, result, options)
|
|
30
37
|
await execHook.call(this, 'afterFindRecord', filter, result, options)
|
|
31
|
-
if (
|
|
38
|
+
if (!noCache && setCache) {
|
|
39
|
+
await setCache({ model: this, filter: cacheFilter, result, options })
|
|
40
|
+
result.cached = false
|
|
41
|
+
}
|
|
32
42
|
return dataOnly ? result.data : result
|
|
33
43
|
}
|
|
34
44
|
|
|
35
|
-
async function loop (
|
|
45
|
+
async function loop (...args) {
|
|
36
46
|
const { cloneDeep } = this.app.lib._
|
|
47
|
+
const [params = {}, opts = {}] = args
|
|
48
|
+
const { dataOnly = true } = opts
|
|
37
49
|
const { filter, options } = await getFilterAndOptions.call(this, params, opts, action)
|
|
38
50
|
const { maxLimit, hardLimit } = this.app.dobo.config.default.filter
|
|
39
51
|
const nFilter = cloneDeep(filter || {})
|
|
@@ -64,13 +76,10 @@ async function loop (params, opts, dataOnly) {
|
|
|
64
76
|
async function findAllRecord (...args) {
|
|
65
77
|
// can't use action here, because people tends to use is without arguments
|
|
66
78
|
// if (args.length === 0) return this.action(action, ...args)
|
|
67
|
-
const [params = {}, opts = {}] = args
|
|
68
|
-
const { dataOnly = true } = opts
|
|
69
79
|
if (this.driver.findAllRecord) {
|
|
70
|
-
|
|
71
|
-
return await native.call(this, filter, options, dataOnly)
|
|
80
|
+
return await native.call(this, ...args)
|
|
72
81
|
}
|
|
73
|
-
return await loop.call(this,
|
|
82
|
+
return await loop.call(this, ...args)
|
|
74
83
|
}
|
|
75
84
|
|
|
76
85
|
export default findAllRecord
|
|
@@ -15,7 +15,7 @@ async function findOneRecord (...args) {
|
|
|
15
15
|
nFilter.limit = 1
|
|
16
16
|
const result = await this.findRecord(nFilter, nOptions)
|
|
17
17
|
const data = result.data[0]
|
|
18
|
-
return dataOnly ? data : { data }
|
|
18
|
+
return dataOnly ? data : { data, cached: result.cached, warnings: result.warnings }
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export default findOneRecord
|
|
@@ -68,26 +68,27 @@ async function findRecord (...args) {
|
|
|
68
68
|
if (args.length === 0) return this.action(action, ...args)
|
|
69
69
|
const [params = {}, opts = {}] = args
|
|
70
70
|
const { isSet } = this.app.lib.aneka
|
|
71
|
-
const {
|
|
71
|
+
const { cloneDeep } = this.app.lib._
|
|
72
72
|
const { dataOnly = true } = opts
|
|
73
|
+
const { get: getCache, set: setCache } = this.app.bajoCache
|
|
73
74
|
const { filter, options } = await getFilterAndOptions.call(this, params, opts, action)
|
|
74
75
|
if (dataOnly) options.count = false
|
|
75
76
|
let { noResultSanitizer, noCache } = options
|
|
76
|
-
if (!this.cacheable || !options.record) noCache = true
|
|
77
|
-
if (!noCache) {
|
|
78
|
-
try {
|
|
79
|
-
await runHook('cache:getByFilter', this, filter)
|
|
80
|
-
} catch (err) {
|
|
81
|
-
if (err.code === 'CACHED_RESULT') {
|
|
82
|
-
const result = err.payload
|
|
83
|
-
result.cache = true
|
|
84
|
-
return dataOnly ? result.data : result
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
77
|
await execHook.call(this, 'beforeFindRecord', filter, options)
|
|
89
78
|
await execModelHook.call(this, 'beforeFindRecord', filter, options)
|
|
90
79
|
await execDynHook.call(this, 'beforeFindRecord', filter, options)
|
|
80
|
+
if (this.cache.ttlDur === 0 || options.record) noCache = true
|
|
81
|
+
const cacheFilter = cloneDeep(filter)
|
|
82
|
+
if (!noCache && getCache) {
|
|
83
|
+
const result = await getCache({ model: this, filter: cacheFilter, options })
|
|
84
|
+
if (result) {
|
|
85
|
+
for (const idx in result.data) {
|
|
86
|
+
result.data[idx] = await this.sanitizeRecord(result.data[idx], options)
|
|
87
|
+
}
|
|
88
|
+
result.cached = true
|
|
89
|
+
return dataOnly ? result.data : result
|
|
90
|
+
}
|
|
91
|
+
}
|
|
91
92
|
const result = options.record ?? (await this.driver._findRecord(this, filter, options)) ?? {}
|
|
92
93
|
if (!noResultSanitizer) {
|
|
93
94
|
for (const idx in result.data) {
|
|
@@ -98,7 +99,10 @@ async function findRecord (...args) {
|
|
|
98
99
|
await execDynHook.call(this, 'afterFindRecord', filter, result, options)
|
|
99
100
|
await execModelHook.call(this, 'afterFindRecord', filter, result, options)
|
|
100
101
|
await execHook.call(this, 'afterFindRecord', filter, result, options)
|
|
101
|
-
if (!noCache
|
|
102
|
+
if (!noCache && setCache) {
|
|
103
|
+
await setCache({ model: this, filter: cacheFilter, result, options })
|
|
104
|
+
result.cached = false
|
|
105
|
+
}
|
|
102
106
|
return dataOnly ? result.data : result
|
|
103
107
|
}
|
|
104
108
|
|
|
@@ -47,7 +47,7 @@ async function getRecord (...args) {
|
|
|
47
47
|
let [id, opts = {}] = args
|
|
48
48
|
const { isEmpty } = this.app.lib._
|
|
49
49
|
const { isSet } = this.app.lib.aneka
|
|
50
|
-
const {
|
|
50
|
+
const { get: getCache, set: setCache } = this.app.bajoCache
|
|
51
51
|
const { dataOnly = true } = opts
|
|
52
52
|
const { options } = await getFilterAndOptions.call(this, null, opts, action)
|
|
53
53
|
let { noResultSanitizer, noCache } = options
|
|
@@ -56,15 +56,13 @@ async function getRecord (...args) {
|
|
|
56
56
|
await execHook.call(this, 'beforeGetRecord', id, options)
|
|
57
57
|
await execModelHook.call(this, 'beforeGetRecord', id, options)
|
|
58
58
|
await execDynHook.call(this, 'beforeGetRecord', id, options)
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return dataOnly ? result.data : result
|
|
67
|
-
}
|
|
59
|
+
if (this.cache.ttlDur === 0 || options.record) noCache = true
|
|
60
|
+
if (!noCache && getCache) {
|
|
61
|
+
const result = await getCache({ model: this, id, options })
|
|
62
|
+
if (result) {
|
|
63
|
+
result.data = await this.sanitizeRecord(result.data, options)
|
|
64
|
+
result.cached = true
|
|
65
|
+
return dataOnly ? result.data : result
|
|
68
66
|
}
|
|
69
67
|
}
|
|
70
68
|
const result = options.record ?? (await this.driver._getRecord(this, id, options)) ?? {}
|
|
@@ -74,7 +72,10 @@ async function getRecord (...args) {
|
|
|
74
72
|
await execDynHook.call(this, 'afterGetRecord', id, result, options)
|
|
75
73
|
await execModelHook.call(this, 'afterGetRecord', id, result, options)
|
|
76
74
|
await execHook.call(this, 'afterGetRecord', id, result, options)
|
|
77
|
-
if (!noCache
|
|
75
|
+
if (!noCache && setCache) {
|
|
76
|
+
await setCache({ model: this, id, result, options })
|
|
77
|
+
result.cached = false
|
|
78
|
+
}
|
|
78
79
|
return dataOnly ? result.data : result
|
|
79
80
|
}
|
|
80
81
|
|
|
@@ -155,7 +155,6 @@ async function buildFromDbModel (opts = {}) {
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
const props = [...this.properties, ...extFields]
|
|
158
|
-
|
|
159
158
|
for (const p of props) {
|
|
160
159
|
if (excludedTypes.includes(p.type) || excludedNames.includes(p.name)) continue
|
|
161
160
|
if (opts.partial && fields.length > 0 && !fields.includes(p.name)) continue
|
|
@@ -229,11 +228,11 @@ async function buildFromDbModel (opts = {}) {
|
|
|
229
228
|
async function validate (body, joiModel, opts = {}) {
|
|
230
229
|
const { defaultsDeep } = this.app.lib.aneka
|
|
231
230
|
const { isEmpty } = this.app.lib._
|
|
232
|
-
let {
|
|
233
|
-
|
|
231
|
+
let { extFields = [], params = {}, partial } = opts
|
|
234
232
|
params = defaultsDeep(params, this.app.dobo.config.validationParams)
|
|
235
233
|
const { rule = {} } = params
|
|
236
234
|
delete params.rule
|
|
235
|
+
const fields = partial ? Object.keys(body) : [...opts.fields]
|
|
237
236
|
if (isEmpty(joiModel)) joiModel = await buildFromDbModel.call(this, { fields, rule, extFields, partial })
|
|
238
237
|
if (!joiModel) return { value: body }
|
|
239
238
|
try {
|
package/lib/factory/model.js
CHANGED
package/package.json
CHANGED
package/wiki/CHANGES.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-03-25
|
|
4
|
+
|
|
5
|
+
- [2.11.2] Bug fix in result sets cache
|
|
6
|
+
|
|
7
|
+
## 2026-03-17
|
|
8
|
+
|
|
9
|
+
- [2.11.1] Bug fix on ```model.validate()```: if ```partial``` is true, set ```fields``` from ```body``` keys
|
|
10
|
+
|
|
3
11
|
## 2026-03-16
|
|
4
12
|
|
|
5
13
|
- [2.11.0] Attachment can now listed by its type (```image```, ```video```, etc)
|