dobo 2.7.0 → 2.8.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.
@@ -145,6 +145,9 @@
145
145
  "inMemoryDb%s%s": "'%s' is an in-memory database, %s is not allowed",
146
146
  "buildOp": "'build' operation",
147
147
  "dropOp": "'drop' operation",
148
+ "maxLimitWarning%s%s": "Records per page (%s rows) above the allowed threshold (%s rows)",
149
+ "hardLimitWarning%s%s": "Max records returned (%s rows) above the allowed threshold (%s rows)",
150
+ "maxPageError%s%s": "Page number (%s) above the allowed threshold (%s)",
148
151
  "field": {
149
152
  "id": "ID",
150
153
  "code": "Kode",
@@ -143,6 +143,9 @@
143
143
  "inMemoryDb%s%s": "'%s' adalah database in-memory, %s tidak diizinkan",
144
144
  "buildOp": "operasi 'build'",
145
145
  "dropOp": "operasi 'drop'",
146
+ "maxLimitWarning%s": "Data per halaman (%s baris) melampaui batas yang diijinkan (%s baris)",
147
+ "hardLimitWarning%s": "Maksimum data yang dihasilkan (%s baris) melampaui batas yang diijinkan (%s baris)",
148
+ "maxPageError%s%s": "Nomor halaman (%s) melampaui batas yang diijinkan (%s)",
146
149
  "field": {
147
150
  "id": "ID",
148
151
  "code": "Kode",
package/index.js CHANGED
@@ -151,6 +151,7 @@ async function factory (pkgName) {
151
151
  limit: 25,
152
152
  maxLimit: 200,
153
153
  hardLimit: 10000,
154
+ maxPage: 50,
154
155
  sort: ['dt:-1', 'updatedAt:-1', 'updated_at:-1', 'createdAt:-1', 'createdAt:-1', 'ts:-1', 'username', 'name']
155
156
  }
156
157
  },
@@ -216,6 +216,11 @@ async function driverFactory () {
216
216
  }
217
217
  }
218
218
 
219
+ _injectMeta (result = {}, options = {}) {
220
+ result.warnings = result.warnings ?? []
221
+ result.warnings.push(...(options.warnings ?? []))
222
+ }
223
+
219
224
  async _createRecord (model, body = {}, options = {}) {
220
225
  const { isSet } = this.app.lib.aneka
221
226
  await this._prepBodyForCreate(model, body, options)
@@ -231,6 +236,7 @@ async function driverFactory () {
231
236
  const result = await this.createRecord(model, input, options)
232
237
  if (options.noResult) return
233
238
  result.data = this.sanitizeRecord(model, result.data)
239
+ this._injectMeta(result, options)
234
240
  return result
235
241
  }
236
242
 
@@ -254,6 +260,7 @@ async function driverFactory () {
254
260
  const result = await this.getRecord(model, id, options)
255
261
  if (isEmpty(result.data) && options.throwNotFound) throw this.plugin.error('recordNotFound%s%s', id, model.name)
256
262
  result.data = this.sanitizeRecord(model, result.data)
263
+ this._injectMeta(result, options)
257
264
  return result
258
265
  }
259
266
 
@@ -272,6 +279,7 @@ async function driverFactory () {
272
279
  if (options.noResult) return
273
280
  result.oldData = this.sanitizeRecord(model, result.oldData)
274
281
  result.data = this.sanitizeRecord(model, result.data)
282
+ this._injectMeta(result, options)
275
283
  return result
276
284
  }
277
285
 
@@ -291,6 +299,7 @@ async function driverFactory () {
291
299
  if (options.noResult) return
292
300
  if (result.oldData) result.oldData = this.sanitizeRecord(model, result.oldData)
293
301
  result.data = this.sanitizeRecord(model, result.data)
302
+ this._injectMeta(result, options)
294
303
  return result
295
304
  }
296
305
 
@@ -303,11 +312,13 @@ async function driverFactory () {
303
312
  const result = await this.removeRecord(model, id, options)
304
313
  if (options.noResult) return
305
314
  result.oldData = this.sanitizeRecord(model, result.oldData)
315
+ this._injectMeta(result, options)
306
316
  return result
307
317
  }
308
318
 
309
319
  async _clearRecord (model, options = {}) {
310
320
  const result = await this.clearRecord(model, options)
321
+ this._injectMeta(result, options)
311
322
  return result
312
323
  }
313
324
 
@@ -316,6 +327,7 @@ async function driverFactory () {
316
327
  for (const idx in result.data) {
317
328
  result.data[idx] = this.sanitizeRecord(model, result.data[idx])
318
329
  }
330
+ this._injectMeta(result, options)
319
331
  return result
320
332
  }
321
333
 
@@ -324,6 +336,7 @@ async function driverFactory () {
324
336
  for (const idx in result.data) {
325
337
  result.data[idx] = this.sanitizeRecord(model, result.data[idx])
326
338
  }
339
+ this._injectMeta(result, options)
327
340
  return result
328
341
  }
329
342
 
@@ -349,6 +362,7 @@ async function driverFactory () {
349
362
  for (const idx in result.data) {
350
363
  result.data[idx] = this.sanitizeRecord(model, result.data[idx])
351
364
  }
365
+ this._injectMeta(result, options)
352
366
  return result
353
367
  }
354
368
 
@@ -369,6 +383,7 @@ async function driverFactory () {
369
383
  for (const idx in result.data) {
370
384
  result.data[idx] = this.sanitizeRecord(model, result.data[idx])
371
385
  }
386
+ this._injectMeta(result, options)
372
387
  return result
373
388
  }
374
389
 
@@ -53,14 +53,14 @@ export async function execValidation (body, options = {}) {
53
53
  export async function getFilterAndOptions (filter = {}, options = {}, action) {
54
54
  const { cloneDeep, omit } = this.app.lib._
55
55
  const { runModelHook } = this.app.dobo
56
- const keys = ['req', 'reply']
57
- const nFilter = cloneDeep(omit(filter, keys))
58
- const nOptions = cloneDeep(omit(options, keys))
56
+ const omittedKeys = ['req', 'reply']
57
+ const nFilter = cloneDeep(omit(filter, omittedKeys))
58
+ const nOptions = cloneDeep(omit(options, omittedKeys))
59
59
  nOptions.action = action
60
60
  nOptions.dataOnly = false
61
61
  nOptions.truncateString = nOptions.truncateString ?? false
62
62
  nOptions.throwNotFound = nOptions.throwNotFound ?? true
63
- for (const key of keys) {
63
+ for (const key of omittedKeys) {
64
64
  nOptions[key] = options[key]
65
65
  }
66
66
  nFilter.orgQuery = nFilter.query
@@ -234,10 +234,7 @@ export function buildFilterQuery (filter = {}) {
234
234
  query = trim(query)
235
235
  if (query.startsWith('{')) q = JSON.parse(query) // JSON formatted query
236
236
  else if (query.includes(':')) q = nql(query).parse() // NQL
237
- else if (this.driver.support.search) {
238
- filter.search = q
239
- return {} //
240
- } else {
237
+ else {
241
238
  let scanables = [...this.scanables]
242
239
  if (scanables.length === 0) scanables = [...this.sortables]
243
240
  const fields = scanables.filter(f => {
@@ -380,10 +377,15 @@ export function preparePagination (filter = {}, options = {}) {
380
377
  const buildPageSkipLimit = (filter) => {
381
378
  let limit = parseInt(filter.limit) || config.default.filter.limit
382
379
  if (limit === -1) limit = config.default.filter.maxLimit
383
- if (limit > config.default.filter.maxLimit) limit = config.default.filter.maxLimit
380
+ if (limit > config.default.filter.maxLimit) {
381
+ options.warnings = options.warnings ?? []
382
+ options.warnings.push(options.req ? options.req.t('maxLimitWarning%s%s', limit, config.default.filter.maxLimit) : this.plugin.t('maxLimitWarning%s', limit, config.default.filter.maxLimit))
383
+ limit = config.default.filter.maxLimit // TODO: notify as warning in response object
384
+ }
384
385
  if (limit < 1) limit = 1
385
386
  let page = parseInt(filter.page) || 1
386
387
  if (page < 1) page = 1
388
+ if (page > config.default.filter.maxPage) throw this.plugin.error('maxPageError%s%s', page, config.default.filter.maxPage)
387
389
  let skip = (page - 1) * limit
388
390
  if (filter.skip) {
389
391
  skip = parseInt(filter.skip) || skip
@@ -43,12 +43,14 @@ async function loop (params, opts, dataOnly) {
43
43
  nFilter.limit = maxLimit
44
44
  nFilter.page = 1
45
45
  let count = 0
46
+ const warnings = options.warnings ?? []
46
47
  const data = []
47
48
  for (;;) {
48
49
  const result = await this.findRecord(nFilter, nOptions)
49
50
  if (result.data.length === 0) break
50
51
  if (count + result.data.length > hardLimit) {
51
52
  const sliced = result.data.slice(0, hardLimit - count)
53
+ warnings.push(options.req ? options.req.t('hardLimitWarning%s%s', result.data.length, hardLimit) : this.plugin.t('hardLimitWarning%s%s', result.data.length, hardLimit))
52
54
  data.push(...sliced)
53
55
  break
54
56
  }
@@ -56,7 +58,7 @@ async function loop (params, opts, dataOnly) {
56
58
  count = count + result.data.length
57
59
  nFilter.page++
58
60
  }
59
- return dataOnly ? data : { data, count }
61
+ return dataOnly ? data : { data, count, warnings }
60
62
  }
61
63
 
62
64
  async function findAllRecord (...args) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dobo",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "description": "DBMS for Bajo Framework",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/wiki/CHANGES.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-02-22
4
+
5
+ - [2.8.0] Add ```warnings``` to response object
6
+ - [2.8.0] Throw error if ```page``` above the allowed threshold
7
+
3
8
  ## 2026-02-20
4
9
 
5
10
  - [2.7.0] Add ```prop.values``` support