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 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: {
@@ -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 (filter, options, dataOnly) {
4
+ async function native (...args) {
5
5
  const { isSet } = this.app.lib.aneka
6
- const { get, set } = this.plugin.cache ?? {}
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 (get && !noCache && !options.record) {
14
- const cachedResult = await get({ model: this.name, filter, options })
15
- if (cachedResult) {
16
- cachedResult.cached = true
17
- await execModelHook.call(this, 'afterFindRecord', filter, cachedResult, options)
18
- return dataOnly ? cachedResult.data : cachedResult
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 (set && !noCache) await set({ model: this.name, filter, options, result })
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 (params, opts, dataOnly) {
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
- const { filter, options } = await getFilterAndOptions.call(this, params, opts, action)
71
- return await native.call(this, filter, options, dataOnly)
80
+ return await native.call(this, ...args)
72
81
  }
73
- return await loop.call(this, params, opts, dataOnly)
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 { runHook } = this.app.bajo
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) await runHook('cache:setByFilter', this, filter, result, options)
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 { runHook } = this.app.bajo
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 (!noCache) {
60
- try {
61
- await runHook('cache:getById', this, id)
62
- } catch (err) {
63
- if (err.code === 'CACHED_RESULT') {
64
- const result = err.payload
65
- result.cache = true
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) await runHook('cache:setById', this, id, result, options)
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 { fields, extFields = [], params = {}, partial } = opts
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 {
@@ -72,7 +72,6 @@ async function modelFactory () {
72
72
  super(plugin)
73
73
  defaults(this, options)
74
74
  this.driver = this.connection.driver
75
- this.cacheable = this.cacheable ?? this.driver.cacheable ?? true
76
75
  }
77
76
 
78
77
  action = (name, ...args) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dobo",
3
- "version": "2.11.0",
3
+ "version": "2.11.2",
4
4
  "description": "DBMS for Bajo Framework",
5
5
  "main": "index.js",
6
6
  "scripts": {
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)