dobo 2.18.1 → 2.19.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.
- package/index.js +35 -8
- package/lib/collect-models.js +4 -2
- package/lib/factory/model/_util.js +12 -46
- package/lib/factory/model/sanitize-record.js +4 -6
- package/package.json +1 -1
- package/wiki/CHANGES.md +14 -0
package/index.js
CHANGED
|
@@ -501,9 +501,12 @@ async function factory (pkgName) {
|
|
|
501
501
|
}
|
|
502
502
|
|
|
503
503
|
getDefaultValues = (options = {}) => {
|
|
504
|
+
const { defaultsDeep } = this.app.lib.aneka
|
|
504
505
|
const key = 'default.filter'
|
|
505
|
-
let config = this.
|
|
506
|
-
|
|
506
|
+
let config = this.getConfig(key)
|
|
507
|
+
config.hardCap = this.config.default.hardCap
|
|
508
|
+
config.warnings = this.config.default.warnings
|
|
509
|
+
if (options.req) config = defaultsDeep({}, options.req.getSetting('dobo:default'), config)
|
|
507
510
|
const { limit, maxLimit, maxPage, hardCap, warnings } = config
|
|
508
511
|
const t = options.req ? options.req.t : this.t
|
|
509
512
|
return { limit, maxLimit, hardCap, maxPage, warnings, t }
|
|
@@ -536,23 +539,47 @@ async function factory (pkgName) {
|
|
|
536
539
|
return nql(sanitized).parse()
|
|
537
540
|
}
|
|
538
541
|
|
|
539
|
-
|
|
540
|
-
const {
|
|
542
|
+
parseAny = (query, model) => {
|
|
543
|
+
const { isEmpty } = this.app.lib._
|
|
544
|
+
let q = {}
|
|
545
|
+
if (!model) throw this.error('invalidQuery')
|
|
546
|
+
let scanables = [...model.scanables]
|
|
547
|
+
if (scanables.length === 0) scanables = [...model.sortables]
|
|
548
|
+
const fields = scanables.filter(f => {
|
|
549
|
+
const field = find(model.properties, { name: f, type: 'string' })
|
|
550
|
+
return !!field
|
|
551
|
+
})
|
|
552
|
+
const parts = fields.map(f => {
|
|
553
|
+
if (query[0] === '*') return `${f}:~$'${query.replaceAll('*', '')}'`
|
|
554
|
+
if (query[query.length - 1] === '*') return `${f}:~^'${query.replaceAll('*', '')}'`
|
|
555
|
+
return `${f}:~'${query.replaceAll('*', '')}'`
|
|
556
|
+
})
|
|
557
|
+
if (parts.length === 1) q = this.parseNql(parts[0])
|
|
558
|
+
else if (parts.length > 1) q = this.parseNql(parts.join(','))
|
|
559
|
+
if (isEmpty(q)) throw this.error('invalidQuery')
|
|
560
|
+
return q
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
parseQuery = (query, model, silent = true) => {
|
|
564
|
+
const { isEmpty, isPlainObject, trim } = this.app.lib._
|
|
541
565
|
let result = {}
|
|
542
566
|
if (isPlainObject(query)) result = query
|
|
543
567
|
else {
|
|
544
568
|
query = trim(query)
|
|
569
|
+
if (isEmpty(query)) return result
|
|
545
570
|
try {
|
|
546
571
|
if (query.startsWith('{')) result = JSON.parse(query)
|
|
547
|
-
else result = this.parseNql(query)
|
|
572
|
+
else if (query.includes(':')) result = this.parseNql(query)
|
|
573
|
+
else result = this.parseAny(query, model)
|
|
548
574
|
} catch (err) {
|
|
549
575
|
if (silent) return {}
|
|
550
576
|
throw err
|
|
551
577
|
}
|
|
552
578
|
}
|
|
579
|
+
let strQ = this.replaceRegexInJson(result)
|
|
580
|
+
if (model && model.driver.idField.name !== 'id') strQ = strQ.replaceAll('"id"', `"${model.driver.idField.name}"`)
|
|
553
581
|
try {
|
|
554
|
-
|
|
555
|
-
if (text.includes('["__REGEXP__",')) result = this.reviveRegexInJson(text)
|
|
582
|
+
result = this.reviveRegexInJson(strQ)
|
|
556
583
|
} catch (err) {}
|
|
557
584
|
return result
|
|
558
585
|
}
|
|
@@ -572,7 +599,7 @@ async function factory (pkgName) {
|
|
|
572
599
|
const { isPlainObject } = this.app.lib._
|
|
573
600
|
if (isPlainObject(input)) input = JSON.stringify(input)
|
|
574
601
|
const result = JSON.parse(input, (key, value) => {
|
|
575
|
-
if (Array.isArray(value) && value[0] === '__REGEXP__') return
|
|
602
|
+
if (Array.isArray(value) && value[0] === '__REGEXP__') return new RegExp(value[1], value[2])
|
|
576
603
|
return value
|
|
577
604
|
})
|
|
578
605
|
return returnObject ? result : JSON.stringify(result)
|
package/lib/collect-models.js
CHANGED
|
@@ -10,7 +10,7 @@ import actionFactory from './factory/action.js'
|
|
|
10
10
|
* @param {Array} [indexes] - Container array to fill up found index
|
|
11
11
|
*/
|
|
12
12
|
async function sanitizeProp (model, prop, indexes) {
|
|
13
|
-
const { isEmpty, isString, keys, pick, isArray, isPlainObject } = this.app.lib._
|
|
13
|
+
const { isEmpty, isString, keys, pick, isArray, isPlainObject, omit } = this.app.lib._
|
|
14
14
|
const allPropKeys = this.getAllPropertyKeys(model.connection.driver)
|
|
15
15
|
const propType = this.constructor.propertyType
|
|
16
16
|
if (isString(prop)) {
|
|
@@ -39,7 +39,9 @@ async function sanitizeProp (model, prop, indexes) {
|
|
|
39
39
|
else {
|
|
40
40
|
const feature = this.getFeature(prop.type)
|
|
41
41
|
if (!feature) this.fatal('unknownPropType%s%s', prop.type, model.name)
|
|
42
|
-
|
|
42
|
+
const opts = omit(prop, ['name', 'type'])
|
|
43
|
+
opts.field = prop.name
|
|
44
|
+
await applyFeature.call(this, model, feature, opts, indexes)
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
|
|
@@ -77,7 +77,6 @@ export async function getFilterAndOptions (filter = {}, options = {}, action) {
|
|
|
77
77
|
if (!nOptions.noModelHook) await runModelHook(this, 'beforeBuilSearch', nFilter.search, nOptions)
|
|
78
78
|
nFilter.search = buildFilterSearch.call(this, nFilter) ?? {}
|
|
79
79
|
if (!nOptions.noModelHook) await runModelHook(this, 'afterBuildSearch', nFilter.search, nOptions)
|
|
80
|
-
if (this.driver.idField.name !== 'id') replaceIdInQuerySearch.call(this, nFilter)
|
|
81
80
|
const { limit, page, skip, sort } = preparePagination.call(this, nFilter, nOptions)
|
|
82
81
|
nFilter.limit = limit
|
|
83
82
|
nFilter.page = page
|
|
@@ -190,7 +189,7 @@ export async function getSingleRef (record = {}, options = {}) {
|
|
|
190
189
|
let query = {}
|
|
191
190
|
query[ref.field] = record[prop.name]
|
|
192
191
|
if (ref.field === 'id') query[ref.field] = this.sanitizeId(query[ref.field])
|
|
193
|
-
if (ref.query) query = { $and: [query, parseQuery(ref.query)] }
|
|
192
|
+
if (ref.query) query = { $and: [query, parseQuery(ref.query, rModel)] }
|
|
194
193
|
const filter = { query }
|
|
195
194
|
const resp = await _getRef.call(this, { ref, rModel, prop, key, options, filter })
|
|
196
195
|
if (!resp) continue
|
|
@@ -228,7 +227,7 @@ export async function getMultiRefs (records = [], options = {}) {
|
|
|
228
227
|
matches = uniq(without(matches, undefined, null, NaN))
|
|
229
228
|
let query = {}
|
|
230
229
|
query[ref.field] = { $in: matches }
|
|
231
|
-
if (ref.query) query = { $and: [query, parseQuery(ref.query)] }
|
|
230
|
+
if (ref.query) query = { $and: [query, parseQuery(ref.query, rModel)] }
|
|
232
231
|
const filter = { query, limit: matches.length }
|
|
233
232
|
const resp = await _getRef.call(this, { ref, rModel, prop, key, options, filter })
|
|
234
233
|
if (!resp) continue
|
|
@@ -247,35 +246,9 @@ export async function getMultiRefs (records = [], options = {}) {
|
|
|
247
246
|
}
|
|
248
247
|
|
|
249
248
|
export function buildFilterQuery (filter = {}) {
|
|
250
|
-
const {
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
let q = {}
|
|
254
|
-
if (isString(query)) {
|
|
255
|
-
try {
|
|
256
|
-
query = trim(query)
|
|
257
|
-
if (query.startsWith('{')) q = JSON.parse(query) // JSON formatted query
|
|
258
|
-
else if (query.includes(':')) q = parseNql(query) // NQL
|
|
259
|
-
else {
|
|
260
|
-
let scanables = [...this.scanables]
|
|
261
|
-
if (scanables.length === 0) scanables = [...this.sortables]
|
|
262
|
-
const fields = scanables.filter(f => {
|
|
263
|
-
const field = find(this.properties, { name: f, type: 'string' })
|
|
264
|
-
return !!field
|
|
265
|
-
})
|
|
266
|
-
const parts = fields.map(f => {
|
|
267
|
-
if (query[0] === '*') return `${f}:~$'${query.replaceAll('*', '')}'`
|
|
268
|
-
if (query[query.length - 1] === '*') return `${f}:~^'${query.replaceAll('*', '')}'`
|
|
269
|
-
return `${f}:~'${query.replaceAll('*', '')}'`
|
|
270
|
-
})
|
|
271
|
-
if (parts.length === 1) q = parseNql(parts[0])
|
|
272
|
-
else if (parts.length > 1) q = parseNql(parts.join(','))
|
|
273
|
-
}
|
|
274
|
-
} catch (err) {
|
|
275
|
-
this.plugin.error('invalidQuery', { orgMessage: err.message })
|
|
276
|
-
}
|
|
277
|
-
} else if (isPlainObject(query)) q = query
|
|
278
|
-
return sanitizeQuery.call(this, q)
|
|
249
|
+
const { parseQuery } = this.app.dobo
|
|
250
|
+
const query = parseQuery(filter.query ?? {}, this, false)
|
|
251
|
+
return sanitizeQuery.call(this, query)
|
|
279
252
|
}
|
|
280
253
|
|
|
281
254
|
function sanitizeQuery (query = {}, parent) {
|
|
@@ -346,7 +319,7 @@ export function buildFilterSearch (filter = {}) {
|
|
|
346
319
|
items[part.field].push(...part.value.split(' ').filter(v => ![''].includes(v)))
|
|
347
320
|
}
|
|
348
321
|
}
|
|
349
|
-
|
|
322
|
+
let s = {}
|
|
350
323
|
for (const index of this.indexes.filter(i => i.type === 'fulltext')) {
|
|
351
324
|
for (const f of index.fields) {
|
|
352
325
|
const value = []
|
|
@@ -357,22 +330,15 @@ export function buildFilterSearch (filter = {}) {
|
|
|
357
330
|
}
|
|
358
331
|
}
|
|
359
332
|
if (has(items, '*')) s['*'] = items['*']
|
|
333
|
+
if (this.driver.idField.name !== 'id') {
|
|
334
|
+
const search = JSON.stringify(s).replaceAll('"id"', `"${this.driver.idField.name}"`)
|
|
335
|
+
try {
|
|
336
|
+
s = JSON.parse(search)
|
|
337
|
+
} catch (err) {}
|
|
338
|
+
}
|
|
360
339
|
return s
|
|
361
340
|
}
|
|
362
341
|
|
|
363
|
-
export function replaceIdInQuerySearch (filter) {
|
|
364
|
-
const { replaceRegexInJson, reviveRegexInJson } = this.app.dobo
|
|
365
|
-
const query = replaceRegexInJson(filter.query).replaceAll('"id"', `"${this.driver.idField.name}"`)
|
|
366
|
-
try {
|
|
367
|
-
filter.query = reviveRegexInJson(query)
|
|
368
|
-
} catch (err) {}
|
|
369
|
-
// search
|
|
370
|
-
const search = JSON.stringify(filter.search ?? {}).replaceAll('"id"', `"${this.driver.idField.name}"`)
|
|
371
|
-
try {
|
|
372
|
-
filter.search = JSON.parse(search)
|
|
373
|
-
} catch (err) {}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
342
|
/**
|
|
377
343
|
* Prepare records pagination:
|
|
378
344
|
* - making sure records limit is obeyed
|
|
@@ -46,10 +46,10 @@ async function sanitizeRecord (record = {}, opts = {}) {
|
|
|
46
46
|
})
|
|
47
47
|
value = (values.find(v => v.value === value) ?? {}).text ?? value
|
|
48
48
|
}
|
|
49
|
-
if (prop.format)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
if (prop.format === false) newRecord[key] = value + ''
|
|
50
|
+
else if (isFunction(prop.format)) newRecord[key] = await prop.format.call(this, value, newRecord, opts)
|
|
51
|
+
else if (isString(prop.format)) newRecord[key] = await callHandler(this.plugin, this, value, newRecord, opts)
|
|
52
|
+
else {
|
|
53
53
|
const options = {
|
|
54
54
|
lang: get(opts, 'req.lang'),
|
|
55
55
|
latitude: ['lat', 'latitude'].includes(key),
|
|
@@ -57,8 +57,6 @@ async function sanitizeRecord (record = {}, opts = {}) {
|
|
|
57
57
|
}
|
|
58
58
|
newRecord[key] = format(value, prop.type, options)
|
|
59
59
|
}
|
|
60
|
-
// exception
|
|
61
|
-
if (['year'].includes(key)) newRecord[key] = (get(newRecord, `_orig.${key}`, newRecord[key]) + '')
|
|
62
60
|
}
|
|
63
61
|
}
|
|
64
62
|
if (record._ref) newRecord._ref = record._ref
|
package/package.json
CHANGED
package/wiki/CHANGES.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-04-19
|
|
4
|
+
|
|
5
|
+
- [2.19.0] Add ```queryAny()``` for query using model's scanables fields
|
|
6
|
+
- [2.19.0] Bug fix in ```reviveRegexInJson()```
|
|
7
|
+
- [2.19.0] Bug fix in query sanitizing especially for regex existance
|
|
8
|
+
- [2.19.0] Remove ```replaceIdInQuerySearch()``` in ```_util.js``` as it isn't needed anymore
|
|
9
|
+
|
|
10
|
+
## 2026-04-18
|
|
11
|
+
|
|
12
|
+
- [2.18.2] Bug fix in ```config``` object
|
|
13
|
+
- [2.18.2] Bug fix in ```getDefaultValues```
|
|
14
|
+
- [2.18.2] Bug fix in ```sanitizeProp()``` in ```collect-models.js```
|
|
15
|
+
- [2.18.2] Bug fix in ```sanitizeRecord()``` for prop with ```format``` set to ```false```
|
|
16
|
+
|
|
3
17
|
## 2026-04-17
|
|
4
18
|
|
|
5
19
|
- [2.18.1] Bug fix in ```model.createAttachment()```
|