dobo 2.18.2 → 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 +30 -6
- package/lib/factory/model/_util.js +12 -46
- package/package.json +1 -1
- package/wiki/CHANGES.md +7 -0
package/index.js
CHANGED
|
@@ -539,23 +539,47 @@ async function factory (pkgName) {
|
|
|
539
539
|
return nql(sanitized).parse()
|
|
540
540
|
}
|
|
541
541
|
|
|
542
|
-
|
|
543
|
-
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._
|
|
544
565
|
let result = {}
|
|
545
566
|
if (isPlainObject(query)) result = query
|
|
546
567
|
else {
|
|
547
568
|
query = trim(query)
|
|
569
|
+
if (isEmpty(query)) return result
|
|
548
570
|
try {
|
|
549
571
|
if (query.startsWith('{')) result = JSON.parse(query)
|
|
550
|
-
else result = this.parseNql(query)
|
|
572
|
+
else if (query.includes(':')) result = this.parseNql(query)
|
|
573
|
+
else result = this.parseAny(query, model)
|
|
551
574
|
} catch (err) {
|
|
552
575
|
if (silent) return {}
|
|
553
576
|
throw err
|
|
554
577
|
}
|
|
555
578
|
}
|
|
579
|
+
let strQ = this.replaceRegexInJson(result)
|
|
580
|
+
if (model && model.driver.idField.name !== 'id') strQ = strQ.replaceAll('"id"', `"${model.driver.idField.name}"`)
|
|
556
581
|
try {
|
|
557
|
-
|
|
558
|
-
if (text.includes('["__REGEXP__",')) result = this.reviveRegexInJson(text)
|
|
582
|
+
result = this.reviveRegexInJson(strQ)
|
|
559
583
|
} catch (err) {}
|
|
560
584
|
return result
|
|
561
585
|
}
|
|
@@ -575,7 +599,7 @@ async function factory (pkgName) {
|
|
|
575
599
|
const { isPlainObject } = this.app.lib._
|
|
576
600
|
if (isPlainObject(input)) input = JSON.stringify(input)
|
|
577
601
|
const result = JSON.parse(input, (key, value) => {
|
|
578
|
-
if (Array.isArray(value) && value[0] === '__REGEXP__') return
|
|
602
|
+
if (Array.isArray(value) && value[0] === '__REGEXP__') return new RegExp(value[1], value[2])
|
|
579
603
|
return value
|
|
580
604
|
})
|
|
581
605
|
return returnObject ? result : JSON.stringify(result)
|
|
@@ -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
|
package/package.json
CHANGED
package/wiki/CHANGES.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
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
|
+
|
|
3
10
|
## 2026-04-18
|
|
4
11
|
|
|
5
12
|
- [2.18.2] Bug fix in ```config``` object
|