dobo 2.19.1 → 2.20.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/lib/collect-models.js +17 -30
- package/lib/factory/model/_util.js +9 -0
- package/lib/factory/model/find-all-record.js +33 -28
- package/lib/factory/model/find-record.js +34 -29
- package/lib/factory/model/get-record.js +21 -17
- package/lib/factory/model/remove-record.js +2 -1
- package/lib/factory/model/update-record.js +2 -1
- package/lib/factory/model/upsert-record.js +3 -2
- package/package.json +1 -1
- package/wiki/CHANGES.md +8 -3
package/lib/collect-models.js
CHANGED
|
@@ -52,12 +52,12 @@ async function sanitizeProp (model, prop, indexes) {
|
|
|
52
52
|
* @param {Array} [inputs] - Array of properties
|
|
53
53
|
* @param {Array} [indexes] - Container array to fill up found index
|
|
54
54
|
*/
|
|
55
|
-
async function findAllProps (model, inputs = [], indexes = []
|
|
55
|
+
async function findAllProps (model, inputs = [], indexes = []) {
|
|
56
56
|
const { isPlainObject, cloneDeep } = this.app.lib._
|
|
57
57
|
const isIdProp = inputs.find(p => {
|
|
58
58
|
return isPlainObject(p) ? p.name === 'id' : p.startsWith('id,')
|
|
59
59
|
})
|
|
60
|
-
if (!
|
|
60
|
+
if (!isIdProp) {
|
|
61
61
|
const idField = cloneDeep(model.connection.driver.idField)
|
|
62
62
|
idField.name = 'id'
|
|
63
63
|
inputs.unshift(idField)
|
|
@@ -74,7 +74,7 @@ async function findAllProps (model, inputs = [], indexes = [], isExtender) {
|
|
|
74
74
|
* @param {Object} options - Options to the feature
|
|
75
75
|
* @returns {Array} New properties found in feature
|
|
76
76
|
*/
|
|
77
|
-
async function applyFeature (model, feature, options, indexes
|
|
77
|
+
async function applyFeature (model, feature, options, indexes) {
|
|
78
78
|
const { isArray, findIndex } = this.app.lib._
|
|
79
79
|
if (feature.name === 'dobo:unique' && options.field === 'id') {
|
|
80
80
|
const idx = findIndex(model.properties, { name: 'id' })
|
|
@@ -103,14 +103,14 @@ async function applyFeature (model, feature, options, indexes, isExtender) {
|
|
|
103
103
|
* @param {Object} model - Model
|
|
104
104
|
* @param {Array} [inputs] - Array of properties
|
|
105
105
|
*/
|
|
106
|
-
async function findAllFeats (model, inputs = [], indexes = []
|
|
106
|
+
async function findAllFeats (model, inputs = [], indexes = []) {
|
|
107
107
|
const { isString, omit } = this.app.lib._
|
|
108
108
|
for (let feat of inputs) {
|
|
109
109
|
if (isString(feat)) feat = { name: feat }
|
|
110
110
|
const featName = feat.name.indexOf(':') === -1 ? `dobo:${feat.name}` : feat.name
|
|
111
111
|
const feature = this.app.dobo.getFeature(featName)
|
|
112
112
|
if (!feature) this.fatal('invalidFeature%s%s', model.name, featName)
|
|
113
|
-
await applyFeature.call(this, model, feature, omit(feat, 'name'), indexes
|
|
113
|
+
await applyFeature.call(this, model, feature, omit(feat, 'name'), indexes)
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -235,9 +235,7 @@ export async function sanitizeAll (model) {
|
|
|
235
235
|
* @returns {Object} Sanitized model
|
|
236
236
|
*/
|
|
237
237
|
async function createSchema (item) {
|
|
238
|
-
const {
|
|
239
|
-
const { fastGlob } = this.app.lib
|
|
240
|
-
const { find, isPlainObject, orderBy, get, cloneDeep } = this.app.lib._
|
|
238
|
+
const { find, orderBy, get } = this.app.lib._
|
|
241
239
|
const { mergeObjectsByKey, defaultsDeep, parseObject } = this.app.lib.aneka
|
|
242
240
|
if (item.file && !item.base) item.base = path.basename(item.file, path.extname(item.file))
|
|
243
241
|
item.attachment = item.attachment ?? true
|
|
@@ -265,29 +263,18 @@ async function createSchema (item) {
|
|
|
265
263
|
if (!item.connection && conn === 'default') item.connection = this.getConnection('memory')
|
|
266
264
|
}
|
|
267
265
|
if (!item.connection) this.fatal('unknownConn%s%s', conn, item.name)
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (item.cache ===
|
|
271
|
-
else if (item.cache ===
|
|
272
|
-
item.cache =
|
|
266
|
+
// cache settings
|
|
267
|
+
const defCache = defaultsDeep({}, item.connection.options.cache, get(this, 'app.bajoCache.config.default', this.config.default.cache))
|
|
268
|
+
if (item.cache === false) item.cache = { ttlDur: 0 }
|
|
269
|
+
else if (item.cache === true) item.cache = defCache
|
|
270
|
+
else item.cache = defaultsDeep({}, item.cache, defCache)
|
|
271
|
+
item.cache = parseObject(item.cache)
|
|
272
|
+
if (item.connection.name === 'memory') item.cache.ttlDur = 0
|
|
273
|
+
|
|
274
|
+
// let's run
|
|
273
275
|
await findAllProps.call(this, item, props, indexes)
|
|
274
276
|
await findAllFeats.call(this, item, feats, indexes)
|
|
275
277
|
await findAllIndexes.call(this, item, indexes)
|
|
276
|
-
// item extender
|
|
277
|
-
if (item.base) {
|
|
278
|
-
for (const ns of this.app.getAllNs()) {
|
|
279
|
-
const plugin = this.app[ns]
|
|
280
|
-
const glob = `${plugin.dir.pkg}/extend/dobo/extend/${item.ns}/model/${item.base}.*`
|
|
281
|
-
const files = await fastGlob(glob)
|
|
282
|
-
for (const file of files) {
|
|
283
|
-
const extender = await readConfig(file, { ns: plugin.ns, ignoreError: true })
|
|
284
|
-
if (!isPlainObject(extender)) this.plugin.fatal('invalidModelExtender%s%s', ns, item.name)
|
|
285
|
-
await findAllProps.call(this, item, extender.properties ?? [], indexes, true)
|
|
286
|
-
await findAllFeats.call(this, item, extender.features ?? [], indexes, true)
|
|
287
|
-
await findAllIndexes.call(this, item, extender.indexes ?? [], indexes, true)
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
278
|
for (const key of ['properties', 'indexes']) {
|
|
292
279
|
item[key] = mergeObjectsByKey(item[key], 'name')
|
|
293
280
|
}
|
|
@@ -322,10 +309,11 @@ async function collectModels () {
|
|
|
322
309
|
|
|
323
310
|
const base = path.basename(file, path.extname(file))
|
|
324
311
|
const defName = pascalCase(`${this.alias} ${base}`)
|
|
325
|
-
const item = await readConfig(file, { ns: this.ns,
|
|
312
|
+
const item = await readConfig(file, { ns: this.ns, baseNs: me.ns })
|
|
326
313
|
if (isEmpty(item)) return undefined
|
|
327
314
|
if (!isPlainObject(item)) me.fatal('invalidModel%s', defName)
|
|
328
315
|
item.name = item.name ?? defName
|
|
316
|
+
me.log.trace('- %s', item.name)
|
|
329
317
|
item.collName = item.collName ?? item.name
|
|
330
318
|
item.file = file
|
|
331
319
|
item.ns = this.ns
|
|
@@ -344,7 +332,6 @@ async function collectModels () {
|
|
|
344
332
|
}
|
|
345
333
|
for (const model of me.models) {
|
|
346
334
|
await sanitizeRef.call(this, model, me.models)
|
|
347
|
-
me.log.trace('- %s', model.name)
|
|
348
335
|
}
|
|
349
336
|
this.log.debug('collected%s%d', this.t('model'), this.models.length)
|
|
350
337
|
}
|
|
@@ -430,3 +430,12 @@ export function preparePagination (filter = {}, options = {}) {
|
|
|
430
430
|
const sort = buildSort(sortInput, options.allowSortUnindexed)
|
|
431
431
|
return { limit, page, skip, sort }
|
|
432
432
|
}
|
|
433
|
+
|
|
434
|
+
export async function clearCache (id) {
|
|
435
|
+
const { clear } = this.app.bajoCache
|
|
436
|
+
if (!clear) return
|
|
437
|
+
await clear({ key: `dobo|${this.name}|getRecord|${id}` })
|
|
438
|
+
await clear({ key: `dobo|${this.name}|findRecord` })
|
|
439
|
+
await clear({ key: `dobo|${this.name}|findAllRecord` })
|
|
440
|
+
await clear({ key: `dobo|${this.name}|findOneRecord` })
|
|
441
|
+
}
|
|
@@ -4,45 +4,50 @@ const action = 'findAllRecord'
|
|
|
4
4
|
async function native (...args) {
|
|
5
5
|
const { isSet } = this.app.lib.aneka
|
|
6
6
|
const { getDefaultValues, t } = this.app.dobo
|
|
7
|
-
const { pick, omit } = this.app.lib._
|
|
7
|
+
const { pick, omit, cloneDeep } = this.app.lib._
|
|
8
8
|
const [params = {}, opts = {}] = args
|
|
9
|
+
const { get, set } = this.app.bajoCache ?? {}
|
|
9
10
|
opts.dataOnly = opts.dataOnly ?? true
|
|
10
11
|
const { dataOnly } = opts
|
|
11
12
|
const { filter, options } = await getFilterAndOptions.call(this, params, opts, action)
|
|
12
13
|
const { hardCap, warnings } = getDefaultValues(options)
|
|
13
14
|
if (dataOnly) options.count = false
|
|
14
15
|
const { noResultSanitizer } = options
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
else if (options.count && result.count > hardCap) {
|
|
25
|
-
result.warnings.push(t('hardCapWarning%s%s', result.count, hardCap))
|
|
26
|
-
result.count = hardCap
|
|
27
|
-
result.hardCapped = true
|
|
16
|
+
await execHook.call(this, 'beforeFindRecord', filter, options)
|
|
17
|
+
await execModelHook.call(this, 'beforeFindRecord', filter, options)
|
|
18
|
+
await execDynHook.call(this, 'beforeFindRecord', filter, options)
|
|
19
|
+
const cFilter = cloneDeep(filter)
|
|
20
|
+
if (get) {
|
|
21
|
+
const resp = await get({ model: this, action, filter: cFilter, options })
|
|
22
|
+
if (resp) {
|
|
23
|
+
resp.cached = true
|
|
24
|
+
return dataOnly ? resp.data : resp
|
|
28
25
|
}
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
}
|
|
27
|
+
let result = options.record ?? (await this.driver._findAllRecord(this, filter, options)) ?? {}
|
|
28
|
+
result.limit = filter.limit
|
|
29
|
+
result.filter = pick(filter, ['query', 'match', 'sort'])
|
|
30
|
+
result.warnings = result.warnings ?? []
|
|
31
|
+
if (!options.count) result = omit(result, ['count', 'pages'])
|
|
32
|
+
else if (options.count && result.count > hardCap) {
|
|
33
|
+
result.warnings.push(t('hardCapWarning%s%s', result.count, hardCap))
|
|
34
|
+
result.count = hardCap
|
|
35
|
+
result.hardCapped = true
|
|
36
|
+
}
|
|
37
|
+
result.pages = options.count ? Math.ceil(result.count / filter.limit) : undefined
|
|
38
|
+
if (!warnings) delete result.warnings
|
|
31
39
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
40
|
+
if (!noResultSanitizer) {
|
|
41
|
+
for (const idx in result.data) {
|
|
42
|
+
result.data[idx] = await this.sanitizeRecord(result.data[idx], options)
|
|
36
43
|
}
|
|
37
|
-
if (isSet(options.refs)) await getMultiRefs.call(this, result.data, options)
|
|
38
|
-
await execDynHook.call(this, 'afterFindRecord', filter, result, options)
|
|
39
|
-
await execModelHook.call(this, 'afterFindRecord', filter, result, options)
|
|
40
|
-
await execHook.call(this, 'afterFindRecord', filter, result, options)
|
|
41
|
-
return dataOnly ? result.data : result
|
|
42
|
-
} catch (err) {
|
|
43
|
-
if (err.code === 'cachedResult') return err.data
|
|
44
|
-
throw err
|
|
45
44
|
}
|
|
45
|
+
if (isSet(options.refs)) await getMultiRefs.call(this, result.data, options)
|
|
46
|
+
await execDynHook.call(this, 'afterFindRecord', filter, result, options)
|
|
47
|
+
await execModelHook.call(this, 'afterFindRecord', filter, result, options)
|
|
48
|
+
await execHook.call(this, 'afterFindRecord', filter, result, options)
|
|
49
|
+
if (set) await set({ model: this, action, filter: cFilter, options, result })
|
|
50
|
+
return dataOnly ? result.data : result
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
async function loop (...args) {
|
|
@@ -69,45 +69,50 @@ async function findRecord (...args) {
|
|
|
69
69
|
const { getDefaultValues, t } = this.app.dobo
|
|
70
70
|
const [params = {}, opts = {}] = args
|
|
71
71
|
const { isSet } = this.app.lib.aneka
|
|
72
|
-
const { pick, omit } = this.app.lib._
|
|
72
|
+
const { pick, omit, cloneDeep } = this.app.lib._
|
|
73
|
+
const { get, set } = this.app.bajoCache ?? {}
|
|
73
74
|
opts.dataOnly = opts.dataOnly ?? true
|
|
74
75
|
const { dataOnly } = opts
|
|
75
76
|
const { filter, options } = await getFilterAndOptions.call(this, params, opts, action)
|
|
76
77
|
const { hardCap, warnings } = getDefaultValues(options)
|
|
77
78
|
if (dataOnly) options.count = false
|
|
78
79
|
const { noResultSanitizer } = options
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (!options.count) result = omit(result, ['count', 'pages'])
|
|
89
|
-
else if (options.count && result.count > hardCap) {
|
|
90
|
-
result.warnings.push(t('hardCapWarning%s%s', result.count, hardCap))
|
|
91
|
-
result.count = hardCap
|
|
92
|
-
result.hardCapped = true
|
|
80
|
+
await execHook.call(this, 'beforeFindRecord', filter, options)
|
|
81
|
+
await execModelHook.call(this, 'beforeFindRecord', filter, options)
|
|
82
|
+
await execDynHook.call(this, 'beforeFindRecord', filter, options)
|
|
83
|
+
const cFilter = cloneDeep(filter)
|
|
84
|
+
if (get) {
|
|
85
|
+
const resp = await get({ model: this, action, filter: cFilter, options })
|
|
86
|
+
if (resp) {
|
|
87
|
+
resp.cached = true
|
|
88
|
+
return dataOnly ? resp.data : resp
|
|
93
89
|
}
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
}
|
|
91
|
+
let result = options.record ?? (await this.driver._findRecord(this, filter, options)) ?? {}
|
|
92
|
+
result.page = filter.page
|
|
93
|
+
result.limit = filter.limit
|
|
94
|
+
result.filter = pick(filter, ['query', 'search', 'sort'])
|
|
95
|
+
result.warnings = result.warnings ?? []
|
|
96
|
+
if (!options.count) result = omit(result, ['count', 'pages'])
|
|
97
|
+
else if (options.count && result.count > hardCap) {
|
|
98
|
+
result.warnings.push(t('hardCapWarning%s%s', result.count, hardCap))
|
|
99
|
+
result.count = hardCap
|
|
100
|
+
result.hardCapped = true
|
|
101
|
+
}
|
|
102
|
+
result.pages = options.count ? Math.ceil(result.count / filter.limit) : undefined
|
|
103
|
+
if (!warnings) delete result.warnings
|
|
96
104
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
105
|
+
if (!noResultSanitizer) {
|
|
106
|
+
for (const idx in result.data) {
|
|
107
|
+
result.data[idx] = await this.sanitizeRecord(result.data[idx], options)
|
|
101
108
|
}
|
|
102
|
-
if (isSet(options.refs)) await getMultiRefs.call(this, result.data, options)
|
|
103
|
-
await execDynHook.call(this, 'afterFindRecord', filter, result, options)
|
|
104
|
-
await execModelHook.call(this, 'afterFindRecord', filter, result, options)
|
|
105
|
-
await execHook.call(this, 'afterFindRecord', filter, result, options)
|
|
106
|
-
return dataOnly ? result.data : result
|
|
107
|
-
} catch (err) {
|
|
108
|
-
if (err.code === 'cachedResult') return err.data
|
|
109
|
-
throw err
|
|
110
109
|
}
|
|
110
|
+
if (isSet(options.refs)) await getMultiRefs.call(this, result.data, options)
|
|
111
|
+
await execDynHook.call(this, 'afterFindRecord', filter, result, options)
|
|
112
|
+
await execModelHook.call(this, 'afterFindRecord', filter, result, options)
|
|
113
|
+
await execHook.call(this, 'afterFindRecord', filter, result, options)
|
|
114
|
+
if (set) await set({ model: this, action, filter: cFilter, options, result })
|
|
115
|
+
return dataOnly ? result.data : result
|
|
111
116
|
}
|
|
112
117
|
|
|
113
118
|
export default findRecord
|
|
@@ -48,29 +48,33 @@ async function getRecord (...args) {
|
|
|
48
48
|
const { getDefaultValues } = this.app.dobo
|
|
49
49
|
const { isEmpty } = this.app.lib._
|
|
50
50
|
const { isSet } = this.app.lib.aneka
|
|
51
|
+
const { get, set } = this.app.bajoCache ?? {}
|
|
51
52
|
opts.dataOnly = opts.dataOnly ?? true
|
|
52
53
|
const { dataOnly } = opts
|
|
53
54
|
const { options } = await getFilterAndOptions.call(this, null, opts, action)
|
|
54
55
|
const { noResultSanitizer } = options
|
|
55
56
|
id = this.sanitizeId(id)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (isSet(options.refs)) await getSingleRef.call(this, result.data, options)
|
|
66
|
-
await execDynHook.call(this, 'afterGetRecord', id, result, options)
|
|
67
|
-
await execModelHook.call(this, 'afterGetRecord', id, result, options)
|
|
68
|
-
await execHook.call(this, 'afterGetRecord', id, result, options)
|
|
69
|
-
return dataOnly ? result.data : result
|
|
70
|
-
} catch (err) {
|
|
71
|
-
if (err.code === 'cachedResult') return err.data
|
|
72
|
-
throw err
|
|
57
|
+
await execHook.call(this, 'beforeGetRecord', id, options)
|
|
58
|
+
await execModelHook.call(this, 'beforeGetRecord', id, options)
|
|
59
|
+
await execDynHook.call(this, 'beforeGetRecord', id, options)
|
|
60
|
+
if (get) {
|
|
61
|
+
const resp = await get({ model: this, action, id, options })
|
|
62
|
+
if (resp) {
|
|
63
|
+
resp.cached = true
|
|
64
|
+
return dataOnly ? resp.data : resp
|
|
65
|
+
}
|
|
73
66
|
}
|
|
67
|
+
const result = options.record ?? (await this.driver._getRecord(this, id, options)) ?? {}
|
|
68
|
+
const { warnings } = getDefaultValues(options)
|
|
69
|
+
if (!warnings) delete result.warnings
|
|
70
|
+
if (isEmpty(result.data) && !options.throwNotFound) return dataOnly ? undefined : { data: undefined }
|
|
71
|
+
if (!noResultSanitizer) result.data = await this.sanitizeRecord(result.data, options)
|
|
72
|
+
if (isSet(options.refs)) await getSingleRef.call(this, result.data, options)
|
|
73
|
+
await execDynHook.call(this, 'afterGetRecord', id, result, options)
|
|
74
|
+
await execModelHook.call(this, 'afterGetRecord', id, result, options)
|
|
75
|
+
await execHook.call(this, 'afterGetRecord', id, result, options)
|
|
76
|
+
if (set) await set({ model: this, action, id, options, result })
|
|
77
|
+
return dataOnly ? result.data : result
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
export default getRecord
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execModelHook, execDynHook, getSingleRef, handleReq } from './_util.js'
|
|
1
|
+
import { getFilterAndOptions, execHook, execModelHook, execDynHook, getSingleRef, handleReq, clearCache } from './_util.js'
|
|
2
2
|
const action = 'removeRecord'
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -45,6 +45,7 @@ async function removeRecord (...args) {
|
|
|
45
45
|
await execModelHook.call(this, 'beforeRemoveRecord', id, options)
|
|
46
46
|
await execDynHook.call(this, 'beforeRemoveRecord', id, options)
|
|
47
47
|
const result = options.record ?? (await this.driver._removeRecord(this, id, options)) ?? {}
|
|
48
|
+
await clearCache.call(this, id)
|
|
48
49
|
if (noResult) return
|
|
49
50
|
const { warnings } = getDefaultValues(options)
|
|
50
51
|
if (!warnings) delete result.warnings
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execValidation, execModelHook, execDynHook, getSingleRef, handleReq } from './_util.js'
|
|
1
|
+
import { getFilterAndOptions, execHook, execValidation, execModelHook, execDynHook, getSingleRef, handleReq, clearCache } from './_util.js'
|
|
2
2
|
import { onlyTypes } from './create-record.js'
|
|
3
3
|
const action = 'updateRecord'
|
|
4
4
|
|
|
@@ -67,6 +67,7 @@ async function updateRecord (...args) {
|
|
|
67
67
|
await execDynHook.call(this, 'beforeUpdateRecord', id, input, options)
|
|
68
68
|
if (!noValidation) await execValidation.call(this, input, options)
|
|
69
69
|
const result = options.record ?? (await this.driver._updateRecord(this, id, input, options)) ?? {}
|
|
70
|
+
await clearCache.call(this, id)
|
|
70
71
|
if (noResult) return
|
|
71
72
|
const { warnings } = getDefaultValues(options)
|
|
72
73
|
if (!warnings) delete result.warnings
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execModelHook, execDynHook, execValidation, getSingleRef, handleReq } from './_util.js'
|
|
1
|
+
import { getFilterAndOptions, execHook, execModelHook, execDynHook, execValidation, getSingleRef, handleReq, clearCache } from './_util.js'
|
|
2
2
|
const action = 'upsertRecord'
|
|
3
3
|
|
|
4
4
|
async function native (body = {}, opts = {}) {
|
|
@@ -16,6 +16,7 @@ async function native (body = {}, opts = {}) {
|
|
|
16
16
|
await execModelHook.call(this, 'beforeUpsertRecord', input, options)
|
|
17
17
|
await execDynHook.call(this, 'beforeUpsertRecord', input, options)
|
|
18
18
|
const result = options.record ?? (await this.driver._upsertRecord(this, input, options)) ?? {}
|
|
19
|
+
await clearCache.call(this, body.id)
|
|
19
20
|
if (noResult) return
|
|
20
21
|
const { warnings } = getDefaultValues(options)
|
|
21
22
|
if (!warnings) delete result.warnings
|
|
@@ -39,7 +40,7 @@ async function manual (body = {}, options = {}) {
|
|
|
39
40
|
} catch (err) {
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
|
-
const id = get(old, '
|
|
43
|
+
const id = get(old, 'data.id')
|
|
43
44
|
if (id) return await this.updateRecord(old.data.id, omit(body, ['id']), options)
|
|
44
45
|
return await this.createRecord(body, options)
|
|
45
46
|
}
|
package/package.json
CHANGED
package/wiki/CHANGES.md
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-04-23
|
|
4
|
+
|
|
5
|
+
- [2.20.1] Bug fix in ```collect-models.js```, now with deep merge in advance
|
|
6
|
+
|
|
3
7
|
## 2026-04-21
|
|
4
8
|
|
|
5
|
-
- [2.
|
|
6
|
-
- [2.
|
|
7
|
-
- [2.
|
|
9
|
+
- [2.19.1] Bug fix in ```collect-models.js```, now values are sanitized with ```parseObject()```
|
|
10
|
+
- [2.19.1] Bug fix in ```options.dataOnly``` on all model methods
|
|
11
|
+
- [2.19.1] Add ```options.noMagic```
|
|
12
|
+
- [2.20.0] Revert back to NOT using hooks for caching
|
|
8
13
|
|
|
9
14
|
## 2026-04-19
|
|
10
15
|
|