waibu-db 2.32.1 → 2.33.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/extend/waibuBootstrap/theme/component/widget/query.js +157 -136
- package/extend/waibuBootstrap/theme/component/widget/recs-info.js +3 -3
- package/index.js +4 -4
- package/lib/crud/export-handler.js +5 -4
- package/lib/crud/helper.js +2 -2
- package/lib/method/{create-aggregate.js → aggregate.js} +5 -5
- package/lib/method/count-record.js +2 -2
- package/lib/method/find-all-record.js +2 -2
- package/lib/method/find-one-record.js +2 -2
- package/lib/method/find-record.js +2 -2
- package/lib/method/get-record.js +2 -2
- package/lib/method/{create-histogram.js → histogram.js} +5 -5
- package/lib/util.js +11 -7
- package/package.json +1 -1
- package/wiki/CHANGES.md +8 -0
|
@@ -4,12 +4,141 @@ async function query () {
|
|
|
4
4
|
const WdbBase = await wdbBase.call(this)
|
|
5
5
|
|
|
6
6
|
return class WdbQuery extends WdbBase {
|
|
7
|
+
modal = ({ container, models, columns, fields, id }) => {
|
|
8
|
+
const { jsonStringify } = this.app.waibuMpa
|
|
9
|
+
const { upperFirst } = this.app.lib._
|
|
10
|
+
const qsKey = this.app.waibu.config.qsKey
|
|
11
|
+
const icon = this.params.attr.mini ? 'search' : (this.params.attr.icon ?? 'dotsThree')
|
|
12
|
+
const applyBtn = !this.params.attr.mini ? '<c:btn color="primary" t:content="apply" margin="start-2" @click="submit()" />' : ''
|
|
13
|
+
let parse = 'parse () {},'
|
|
14
|
+
if (!this.params.attr.mini) {
|
|
15
|
+
parse = `parse () {
|
|
16
|
+
this.builder = document.getElementById('${id}').value
|
|
17
|
+
if (!this.builder.includes(':')) this.builder = ''
|
|
18
|
+
if (_.isEmpty(this.builder)) return
|
|
19
|
+
const tokens = _.merge({}, this.ops, {
|
|
20
|
+
in: ':[',
|
|
21
|
+
between: ':{',
|
|
22
|
+
contains: ':~',
|
|
23
|
+
starts: ':~^',
|
|
24
|
+
ends: ':~$$',
|
|
25
|
+
'!in': ':-[',
|
|
26
|
+
'!between': ':-{',
|
|
27
|
+
'!contains': ':-~',
|
|
28
|
+
'!starts': ':-~^',
|
|
29
|
+
'!ends': ':-~$$'
|
|
30
|
+
})
|
|
31
|
+
for (const part of this.builder.split('+')) {
|
|
32
|
+
let [f, ...opv] = part.split(':')
|
|
33
|
+
opv = ':' + opv.join(':')
|
|
34
|
+
this.selected.push(f)
|
|
35
|
+
let op
|
|
36
|
+
let val
|
|
37
|
+
_.each(tokens, (v, k) => {
|
|
38
|
+
if (opv.slice(0, v.length) === v) {
|
|
39
|
+
op = k
|
|
40
|
+
val = opv.slice(v.length).replaceAll('[', '').replaceAll('{', '').replaceAll(']', '').replaceAll('}', '').replaceAll('\\'', '')
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
if (_.isEmpty(op)) continue
|
|
44
|
+
this[f + 'Op'] = op
|
|
45
|
+
if (op === 'between') {
|
|
46
|
+
const vals = val.split(',')
|
|
47
|
+
this[f + 'Val'] = vals[0]
|
|
48
|
+
this[f + 'Val2'] = vals[1]
|
|
49
|
+
} else {
|
|
50
|
+
this[f + 'Val'] = val
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
`
|
|
55
|
+
}
|
|
56
|
+
return `
|
|
57
|
+
<c:${container} trigger-color="secondary-outline" trigger-icon="${icon}" trigger-on-end t:title="queryBuilder" x-ref="query" x-data="{
|
|
58
|
+
fields: ${jsonStringify(fields, true)},
|
|
59
|
+
builder: '',
|
|
60
|
+
selected: [],
|
|
61
|
+
${models.join(',\n')},
|
|
62
|
+
ops: { eq: ':', neq: ':-', gt: ':>', gte: ':>=', lt: ':<', lte: ':<=' },
|
|
63
|
+
opsIn (v, neg) { return ':' + (neg ? '-' : '') + '[' + this.expandArray(v) + ']' },
|
|
64
|
+
opsBetween (v, v2, neg) { return ':' + (neg ? '-' : '') + '{' + this.expandArray(v) + ',' + this.expandArray(v2) + '}' },
|
|
65
|
+
opsExt (v, neg, ext) {
|
|
66
|
+
let prefix = (neg ? '-' : '') + '~'
|
|
67
|
+
if (ext) prefix += ext
|
|
68
|
+
return ':' + prefix + '\\'' + v + '\\''
|
|
69
|
+
},
|
|
70
|
+
${parse}
|
|
71
|
+
expandArray (val = '') {
|
|
72
|
+
return _.map(val.split(','), item => {
|
|
73
|
+
item = _.trim(item)
|
|
74
|
+
if (Number(item)) return item
|
|
75
|
+
return '\\'' + item + '\\''
|
|
76
|
+
})
|
|
77
|
+
},
|
|
78
|
+
rebuild () {
|
|
79
|
+
const items = []
|
|
80
|
+
for (const sel of this.selected) {
|
|
81
|
+
const key = this[sel + 'Op']
|
|
82
|
+
let val = this[sel + 'Val']
|
|
83
|
+
let val2 = this[sel + 'Val2']
|
|
84
|
+
if (_.isEmpty(val)) continue
|
|
85
|
+
if (key === 'between' && _.isEmpty(val2)) continue
|
|
86
|
+
let item
|
|
87
|
+
if (key === 'in') item = this.opsIn(val)
|
|
88
|
+
else if (key === '!in') item = this.opsIn(val, true)
|
|
89
|
+
else if (key === 'between') item = this.opsBetween(val, val2, false)
|
|
90
|
+
else if (key === '!between') item = this.opsBetween(val, val2, true)
|
|
91
|
+
else if (key === 'contains') item = this.opsExt(val)
|
|
92
|
+
else if (key === '!contains') item = this.opsExt(val, true)
|
|
93
|
+
else if (key === 'starts') item = this.opsExt(val, false, '^')
|
|
94
|
+
else if (key === '!starts') item = this.opsExt(val, true, '^')
|
|
95
|
+
else if (key === 'ends') item = this.opsExt(val, false, '$$')
|
|
96
|
+
else if (key === '!ends') item = this.opsExt(val, true, '$$')
|
|
97
|
+
else if (val.includes(' ')) item = this.ops[key] + '\\'' + val + '\\''
|
|
98
|
+
else item = this.ops[key] + val
|
|
99
|
+
items.push(sel + item)
|
|
100
|
+
}
|
|
101
|
+
this.builder = items.join('+')
|
|
102
|
+
},
|
|
103
|
+
submit (run) {
|
|
104
|
+
if (run) {
|
|
105
|
+
const url = new URL(window.location.href)
|
|
106
|
+
const params = new URLSearchParams(url.search)
|
|
107
|
+
params.set('${qsKey.page}', 1)
|
|
108
|
+
params.set('${qsKey.query}', this.builder ?? '')
|
|
109
|
+
window.location.href = '?' + params.toString()
|
|
110
|
+
} else $dispatch('on-query', this.builder)
|
|
111
|
+
const instance = wbs.getInstance('${upperFirst(container)}', $refs.query)
|
|
112
|
+
instance.hide()
|
|
113
|
+
}
|
|
114
|
+
}" x-init="
|
|
115
|
+
parse()
|
|
116
|
+
const ops = _.map(fields, f => (f + 'Op'))
|
|
117
|
+
const vals = _.map(fields, f => (f + 'Val'))
|
|
118
|
+
const vals2 = _.map(fields, f => (f + 'Val2'))
|
|
119
|
+
const watcher = ['selected', ...ops, ...vals, ...vals2].join(',')
|
|
120
|
+
$watch(watcher, v => rebuild())
|
|
121
|
+
" ${this.params.attr.modal ? '' : 'style="width:600px;"'}>
|
|
122
|
+
<c:grid-row gutter="2">
|
|
123
|
+
<c:grid-col col="12">
|
|
124
|
+
<c:form-textarea x-model="builder" readonly rows="4"/>
|
|
125
|
+
</c:grid-col>
|
|
126
|
+
${columns.join('\n')}
|
|
127
|
+
</c:grid-row>
|
|
128
|
+
<c:div flex="justify-content:end" margin="top-3">
|
|
129
|
+
<c:btn color="secondary" t:content="close" dismiss="${container}" />
|
|
130
|
+
${applyBtn}
|
|
131
|
+
<c:btn color="primary" t:content="submitQuery" margin="start-2" @click="submit(true)" />
|
|
132
|
+
</c:div>
|
|
133
|
+
</c:${container}>
|
|
134
|
+
`
|
|
135
|
+
}
|
|
136
|
+
|
|
7
137
|
build = async () => {
|
|
8
138
|
const { req } = this.component
|
|
9
139
|
const { generateId } = this.app.lib.aneka
|
|
10
140
|
const { join } = this.app.bajo
|
|
11
|
-
const {
|
|
12
|
-
const { find, get, without, isEmpty, filter, upperFirst } = this.app.lib._
|
|
141
|
+
const { find, get, without, isEmpty, filter } = this.app.lib._
|
|
13
142
|
const qsKey = this.app.waibu.config.qsKey
|
|
14
143
|
const schema = get(this, 'component.locals.schema', {})
|
|
15
144
|
if (schema.view.disabled.includes('find')) {
|
|
@@ -62,144 +191,36 @@ async function query () {
|
|
|
62
191
|
this.params.noTag = true
|
|
63
192
|
const container = this.params.attr.modal ? 'modal' : 'drawer'
|
|
64
193
|
const scanables = (this.schema.scanables ?? []).map(item => req.t(`field.${item}`))
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return ':' + prefix + '\\'' + v + '\\''
|
|
85
|
-
},
|
|
86
|
-
parse () {
|
|
87
|
-
this.builder = document.getElementById('${id}').value
|
|
88
|
-
if (!this.builder.includes(':')) this.builder = ''
|
|
89
|
-
if (_.isEmpty(this.builder)) return
|
|
90
|
-
const tokens = _.merge({}, this.ops, {
|
|
91
|
-
in: ':[',
|
|
92
|
-
between: ':{',
|
|
93
|
-
contains: ':~',
|
|
94
|
-
starts: ':~^',
|
|
95
|
-
ends: ':~$$',
|
|
96
|
-
'!in': ':-[',
|
|
97
|
-
'!between': ':-{',
|
|
98
|
-
'!contains': ':-~',
|
|
99
|
-
'!starts': ':-~^',
|
|
100
|
-
'!ends': ':-~$$'
|
|
101
|
-
})
|
|
102
|
-
for (const part of this.builder.split('+')) {
|
|
103
|
-
let [f, ...opv] = part.split(':')
|
|
104
|
-
opv = ':' + opv.join(':')
|
|
105
|
-
this.selected.push(f)
|
|
106
|
-
let op
|
|
107
|
-
let val
|
|
108
|
-
_.each(tokens, (v, k) => {
|
|
109
|
-
if (opv.slice(0, v.length) === v) {
|
|
110
|
-
op = k
|
|
111
|
-
val = opv.slice(v.length).replaceAll('[', '').replaceAll('{', '').replaceAll(']', '').replaceAll('}', '').replaceAll('\\'', '')
|
|
112
|
-
}
|
|
113
|
-
})
|
|
114
|
-
if (_.isEmpty(op)) continue
|
|
115
|
-
this[f + 'Op'] = op
|
|
116
|
-
if (op === 'between') {
|
|
117
|
-
const vals = val.split(',')
|
|
118
|
-
this[f + 'Val'] = vals[0]
|
|
119
|
-
this[f + 'Val2'] = vals[1]
|
|
120
|
-
} else {
|
|
121
|
-
this[f + 'Val'] = val
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
expandArray (val = '') {
|
|
126
|
-
return _.map(val.split(','), item => {
|
|
127
|
-
item = _.trim(item)
|
|
128
|
-
if (Number(item)) return item
|
|
129
|
-
return '\\'' + item + '\\''
|
|
130
|
-
})
|
|
131
|
-
},
|
|
132
|
-
rebuild () {
|
|
133
|
-
const items = []
|
|
134
|
-
for (const sel of this.selected) {
|
|
135
|
-
const key = this[sel + 'Op']
|
|
136
|
-
let val = this[sel + 'Val']
|
|
137
|
-
let val2 = this[sel + 'Val2']
|
|
138
|
-
if (_.isEmpty(val)) continue
|
|
139
|
-
if (key === 'between' && _.isEmpty(val2)) continue
|
|
140
|
-
let item
|
|
141
|
-
if (key === 'in') item = this.opsIn(val)
|
|
142
|
-
else if (key === '!in') item = this.opsIn(val, true)
|
|
143
|
-
else if (key === 'between') item = this.opsBetween(val, val2, false)
|
|
144
|
-
else if (key === '!between') item = this.opsBetween(val, val2, true)
|
|
145
|
-
else if (key === 'contains') item = this.opsExt(val)
|
|
146
|
-
else if (key === '!contains') item = this.opsExt(val, true)
|
|
147
|
-
else if (key === 'starts') item = this.opsExt(val, false, '^')
|
|
148
|
-
else if (key === '!starts') item = this.opsExt(val, true, '^')
|
|
149
|
-
else if (key === 'ends') item = this.opsExt(val, false, '$$')
|
|
150
|
-
else if (key === '!ends') item = this.opsExt(val, true, '$$')
|
|
151
|
-
else if (val.includes(' ')) item = this.ops[key] + '\\'' + val + '\\''
|
|
152
|
-
else item = this.ops[key] + val
|
|
153
|
-
items.push(sel + item)
|
|
154
|
-
}
|
|
155
|
-
this.builder = items.join('+')
|
|
156
|
-
},
|
|
157
|
-
submit (run) {
|
|
158
|
-
if (run) {
|
|
194
|
+
if (this.params.attr.mini) {
|
|
195
|
+
this.params.html = await this.component.buildSentence(`
|
|
196
|
+
${this.modal({ container, models, columns, fields, id })}
|
|
197
|
+
`)
|
|
198
|
+
} else {
|
|
199
|
+
let placeholder = this.params.attr.placeholder
|
|
200
|
+
if (!placeholder) placeholder = scanables.length > 0 ? req.t('queryHint%s', join(scanables, { separator: ', ', lastSeparator: 'or' })) : req.t('query')
|
|
201
|
+
this.params.html = await this.component.buildSentence(`
|
|
202
|
+
<c:form-input type="search" placeholder="${placeholder}" id="${id}" x-data="{ query: '' }" x-init="
|
|
203
|
+
const url = new URL(window.location.href)
|
|
204
|
+
query = url.searchParams.get('${qsKey.query}') ?? ''
|
|
205
|
+
" x-model="query" @on-query.window="query = $event.detail ?? ''" @keyup.enter="$dispatch('on-submit')">
|
|
206
|
+
<c:form-input-addon>
|
|
207
|
+
${this.modal({ container, models, columns, fields, id })}
|
|
208
|
+
</c:form-input-addon>
|
|
209
|
+
<c:form-input-addon>
|
|
210
|
+
<c:btn t:content="submit" x-data="{
|
|
211
|
+
submit () {
|
|
212
|
+
const val = document.getElementById('${id}').value ?? ''
|
|
159
213
|
const url = new URL(window.location.href)
|
|
160
214
|
const params = new URLSearchParams(url.search)
|
|
161
215
|
params.set('${qsKey.page}', 1)
|
|
162
|
-
params.set('${qsKey.query}',
|
|
216
|
+
params.set('${qsKey.query}', val)
|
|
163
217
|
window.location.href = '?' + params.toString()
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const ops = _.map(fields, f => (f + 'Op'))
|
|
171
|
-
const vals = _.map(fields, f => (f + 'Val'))
|
|
172
|
-
const vals2 = _.map(fields, f => (f + 'Val2'))
|
|
173
|
-
const watcher = ['selected', ...ops, ...vals, ...vals2].join(',')
|
|
174
|
-
$watch(watcher, v => rebuild())
|
|
175
|
-
" ${this.params.attr.modal ? '' : 'style="width:600px;"'}>
|
|
176
|
-
<c:grid-row gutter="2">
|
|
177
|
-
<c:grid-col col="12">
|
|
178
|
-
<c:form-textarea x-model="builder" readonly rows="4"/>
|
|
179
|
-
</c:grid-col>
|
|
180
|
-
${columns.join('\n')}
|
|
181
|
-
</c:grid-row>
|
|
182
|
-
<c:div flex="justify-content:end" margin="top-3">
|
|
183
|
-
<c:btn color="secondary" t:content="close" dismiss="${container}" />
|
|
184
|
-
<c:btn color="primary" t:content="apply" margin="start-2" @click="submit()" />
|
|
185
|
-
<c:btn color="primary" t:content="submitQuery" margin="start-2" @click="submit(true)" />
|
|
186
|
-
</c:div>
|
|
187
|
-
</c:${container}>
|
|
188
|
-
</c:form-input-addon>
|
|
189
|
-
<c:form-input-addon>
|
|
190
|
-
<c:btn t:content="submit" x-data="{
|
|
191
|
-
submit () {
|
|
192
|
-
const val = document.getElementById('${id}').value ?? ''
|
|
193
|
-
const url = new URL(window.location.href)
|
|
194
|
-
const params = new URLSearchParams(url.search)
|
|
195
|
-
params.set('${qsKey.page}', 1)
|
|
196
|
-
params.set('${qsKey.query}', val)
|
|
197
|
-
window.location.href = '?' + params.toString()
|
|
198
|
-
}
|
|
199
|
-
}" @click="submit" @on-submit.window="submit()" />
|
|
200
|
-
</c:form-input-addon>
|
|
201
|
-
</c:form-input>
|
|
202
|
-
`)
|
|
218
|
+
}
|
|
219
|
+
}" @click="submit" @on-submit.window="submit()" />
|
|
220
|
+
</c:form-input-addon>
|
|
221
|
+
</c:form-input>
|
|
222
|
+
`)
|
|
223
|
+
}
|
|
203
224
|
}
|
|
204
225
|
}
|
|
205
226
|
}
|
|
@@ -23,9 +23,9 @@ async function recsInfo () {
|
|
|
23
23
|
this.params.html = ''
|
|
24
24
|
return
|
|
25
25
|
}
|
|
26
|
-
page =
|
|
27
|
-
limit =
|
|
28
|
-
pages =
|
|
26
|
+
page = get(this, 'component.locals.list.page', page ?? 1)
|
|
27
|
+
limit = get(this, 'component.locals.list.limit', limit ?? 25)
|
|
28
|
+
pages = get(this, 'component.locals.list.pages', pages ?? 0)
|
|
29
29
|
|
|
30
30
|
this.params.tag = 'div'
|
|
31
31
|
this.params.attr.flex = 'justify-center:start align-items:center'
|
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import countRecord from './lib/method/count-record.js'
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import aggregate from './lib/method/aggregate.js'
|
|
3
|
+
import histogram from './lib/method/histogram.js'
|
|
4
4
|
import createRecord from './lib/method/create-record.js'
|
|
5
5
|
import findOneRecord from './lib/method/find-one-record.js'
|
|
6
6
|
import findRecord from './lib/method/find-record.js'
|
|
@@ -59,8 +59,8 @@ async function factory (pkgName) {
|
|
|
59
59
|
|
|
60
60
|
this.bindThis(
|
|
61
61
|
countRecord,
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
aggregate,
|
|
63
|
+
histogram,
|
|
64
64
|
createRecord,
|
|
65
65
|
findOneRecord,
|
|
66
66
|
findRecord,
|
|
@@ -45,15 +45,16 @@ async function exportHandler (opts = {}) {
|
|
|
45
45
|
data.opts.lang = req.lang
|
|
46
46
|
data.opts.fields = isEmpty(req.query.fields) ? get(schema, 'view.fields', []) : req.query.fields.split(',')
|
|
47
47
|
|
|
48
|
-
data.opts.
|
|
49
|
-
data.opts.
|
|
50
|
-
data.opts.
|
|
48
|
+
data.opts.datetime = get(opts, 'req.site.setting.bajo.intl.datetime', this.app.bajo.config.intl.datetime)
|
|
49
|
+
data.opts.date = get(opts, 'req.site.setting.bajo.intl.date', this.app.bajo.config.intl.date)
|
|
50
|
+
data.opts.time = get(opts, 'req.site.setting.bajo.intl.time', this.app.bajo.config.intl.time)
|
|
51
|
+
data.opts.timeZone = get(opts, 'req.site.setting.bajo.intl.timeZone', this.app.bajo.config.intl.timeZone)
|
|
52
|
+
|
|
51
53
|
const source = `${this.ns}:/export-handler`
|
|
52
54
|
const worker = `${this.ns}:exportData`
|
|
53
55
|
const type = get(crud, 'input.ftype', 'json')
|
|
54
56
|
data.exportOpts = get(crud, 'input.options', '').split(',')
|
|
55
57
|
const ext = data.exportOpts.includes('zip') ? `${type}.gz` : type
|
|
56
|
-
// const file = `${kebabCase(model)}_${dayjs().format('YYYYMMDDhhmmss')}.${ext}`
|
|
57
58
|
const file = `${kebabCase(model)}.${ext}`
|
|
58
59
|
if (this.app.sumba) {
|
|
59
60
|
const description = kebabCase(model).split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')
|
package/lib/crud/helper.js
CHANGED
|
@@ -22,7 +22,7 @@ export async function addOnsHandler (opts = {}) {
|
|
|
22
22
|
const { req, reply, schema } = opts
|
|
23
23
|
const { escape } = this.app.waibu
|
|
24
24
|
const { base64JsonEncode } = this.app.waibu
|
|
25
|
-
const {
|
|
25
|
+
const { aggregate } = this.app.waibuDb
|
|
26
26
|
const { get, map, pick, pullAt } = this.app.lib._
|
|
27
27
|
const _opts = map(get(schema, 'view.stat.aggregate', []), item => {
|
|
28
28
|
const dbOpts = pick(item, ['fields', 'group', 'aggregate'])
|
|
@@ -34,7 +34,7 @@ export async function addOnsHandler (opts = {}) {
|
|
|
34
34
|
for (const idx in _opts) {
|
|
35
35
|
const o = _opts[idx]
|
|
36
36
|
try {
|
|
37
|
-
const resp = await
|
|
37
|
+
const resp = await aggregate({ model: schema.name, req, reply, options: o.dbOpts })
|
|
38
38
|
const data = []
|
|
39
39
|
for (const d of resp.data) {
|
|
40
40
|
const key = o.dbOpts.fields[0]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { prepCrud, processHandler } from '../util.js'
|
|
2
2
|
|
|
3
|
-
async function
|
|
4
|
-
const { model: mdl, opts, filter } = await prepCrud.call(this, { model, req, reply, options, args: ['model'], transaction })
|
|
3
|
+
async function aggregate ({ model, req, reply, options = {}, noAutoFilter, transaction } = {}) {
|
|
4
|
+
const { model: mdl, opts, filter } = await prepCrud.call(this, { model, req, reply, options, args: ['model'], noAutoFilter, transaction })
|
|
5
5
|
const params = {}
|
|
6
6
|
for (const item of ['group', 'field', 'aggregates']) {
|
|
7
7
|
params[item] = options[item] ?? req.params[item] ?? req.query[item]
|
|
@@ -10,10 +10,10 @@ async function createAggregate ({ model, req, reply, options = {}, transaction }
|
|
|
10
10
|
|
|
11
11
|
async function handler (trx) {
|
|
12
12
|
if (opts.trx === true) opts.trx = trx
|
|
13
|
-
return await mdl.
|
|
13
|
+
return await mdl.aggregate(filter, params, opts)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
return await processHandler.call(this, { action: '
|
|
16
|
+
return await processHandler.call(this, { action: 'aggregate', model: mdl, handler, options: opts })
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export default
|
|
19
|
+
export default aggregate
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { prepCrud, processHandler } from '../util.js'
|
|
2
2
|
|
|
3
|
-
async function countRecord ({ model, req, reply, options = {}, transaction } = {}) {
|
|
4
|
-
const { model: mdl, opts, filter } = await prepCrud.call(this, { model, req, reply, options, args: ['model'], transaction })
|
|
3
|
+
async function countRecord ({ model, req, reply, options = {}, noAutoFilter, transaction } = {}) {
|
|
4
|
+
const { model: mdl, opts, filter } = await prepCrud.call(this, { model, req, reply, options, args: ['model'], noAutoFilter, transaction })
|
|
5
5
|
|
|
6
6
|
async function handler (trx) {
|
|
7
7
|
if (opts.trx === true) opts.trx = trx
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { prepCrud, processHandler } from '../util.js'
|
|
2
2
|
|
|
3
|
-
async function findAllRecord ({ model, req, reply, options = {}, transaction } = {}) {
|
|
4
|
-
const { model: mdl, opts, filter, attachment, stats, mimeType } = await prepCrud.call(this, { model, req, reply, options, args: ['model'], transaction })
|
|
3
|
+
async function findAllRecord ({ model, req, reply, options = {}, noAutoFilter, transaction } = {}) {
|
|
4
|
+
const { model: mdl, opts, filter, attachment, stats, mimeType } = await prepCrud.call(this, { model, req, reply, options, args: ['model'], noAutoFilter, transaction })
|
|
5
5
|
|
|
6
6
|
async function handler (trx) {
|
|
7
7
|
if (opts.trx === true) opts.trx = trx
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { prepCrud, processHandler } from '../util.js'
|
|
2
2
|
|
|
3
|
-
async function findOneRecord ({ model, req, reply, options = {}, transaction } = {}) {
|
|
4
|
-
const { model: mdl, opts, filter, attachment, stats, mimeType } = await prepCrud.call(this, { model, req, reply, options, args: ['model'], transaction })
|
|
3
|
+
async function findOneRecord ({ model, req, reply, options = {}, noAutoFilter, transaction } = {}) {
|
|
4
|
+
const { model: mdl, opts, filter, attachment, stats, mimeType } = await prepCrud.call(this, { model, req, reply, options, args: ['model'], noAutoFilter, transaction })
|
|
5
5
|
|
|
6
6
|
async function handler (trx) {
|
|
7
7
|
if (opts.trx === true) opts.trx = trx
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { prepCrud, processHandler } from '../util.js'
|
|
2
2
|
|
|
3
|
-
async function findRecord ({ model, req, reply, options = {}, transaction } = {}) {
|
|
4
|
-
const { model: mdl, opts, filter, attachment, stats, mimeType } = await prepCrud.call(this, { model, req, reply, options, args: ['model'], transaction })
|
|
3
|
+
async function findRecord ({ model, req, reply, noAutoFilter, options = {}, transaction } = {}) {
|
|
4
|
+
const { model: mdl, opts, filter, attachment, stats, mimeType } = await prepCrud.call(this, { model, req, reply, options, args: ['model'], noAutoFilter, transaction })
|
|
5
5
|
|
|
6
6
|
async function handler (trx) {
|
|
7
7
|
if (opts.trx === true) opts.trx = trx
|
package/lib/method/get-record.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { prepCrud, getOneRecord, processHandler } from '../util.js'
|
|
2
2
|
|
|
3
|
-
async function getRecord ({ model, req, reply, id, options = {}, transaction } = {}) {
|
|
4
|
-
const { model: mdl, recId, filter, attachment, stats, mimeType, opts } = await prepCrud.call(this, { model, req, reply, id, options, args: ['model', 'id'], transaction })
|
|
3
|
+
async function getRecord ({ model, req, reply, id, options = {}, transaction, noAutoFilter } = {}) {
|
|
4
|
+
const { model: mdl, recId, filter, attachment, stats, mimeType, opts } = await prepCrud.call(this, { model, req, reply, id, options, args: ['model', 'id'], transaction, noAutoFilter })
|
|
5
5
|
const me = this
|
|
6
6
|
|
|
7
7
|
async function handler (trx) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { prepCrud, processHandler } from '../util.js'
|
|
2
2
|
|
|
3
|
-
async function
|
|
4
|
-
const { model: mdl, opts, filter } = await prepCrud.call(this, { model, req, reply, options, args: ['model'], transaction })
|
|
3
|
+
async function histogram ({ model, req, reply, options = {}, noAutoFilter, transaction } = {}) {
|
|
4
|
+
const { model: mdl, opts, filter } = await prepCrud.call(this, { model, req, reply, options, args: ['model'], noAutoFilter, transaction })
|
|
5
5
|
const params = {}
|
|
6
6
|
for (const item of ['type', 'group', 'field', 'aggregates']) {
|
|
7
7
|
params[item] = options[item] ?? req.params[item] ?? req.query[item]
|
|
@@ -10,10 +10,10 @@ async function createHistogram ({ model, req, reply, options = {}, transaction }
|
|
|
10
10
|
|
|
11
11
|
async function handler (trx) {
|
|
12
12
|
if (opts.trx === true) opts.trx = trx
|
|
13
|
-
return await mdl.
|
|
13
|
+
return await mdl.histogram(filter, params, opts)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
return await processHandler.call(this, { action: '
|
|
16
|
+
return await processHandler.call(this, { action: 'histogram', model: mdl, handler, options: opts })
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export default
|
|
19
|
+
export default histogram
|
package/lib/util.js
CHANGED
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
* @typedef TActions
|
|
23
23
|
* @type {Object}
|
|
24
24
|
* @property {number} 0='countRecord' - Count the number of records
|
|
25
|
-
* @property {number} 1='
|
|
26
|
-
* @property {number} 2='
|
|
25
|
+
* @property {number} 1='aggregate' - Create an aggregate record
|
|
26
|
+
* @property {number} 2='histogram' - Create a histogram record
|
|
27
27
|
* @property {number} 3='createRecord' - Create a new record
|
|
28
28
|
* @property {number} 4='findAllRecord' - Find all records
|
|
29
29
|
* @property {number} 5='findOneRecord' - Find one record
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
* @property {number} 8='removeRecord' - Remove a record
|
|
33
33
|
* @property {number} 9='updateRecord' - Update a record
|
|
34
34
|
*/
|
|
35
|
-
export const actions = ['countRecord', '
|
|
35
|
+
export const actions = ['countRecord', 'aggregate', 'histogram', 'createRecord', 'findAllRecord', 'findOneRecord', 'findRecord', 'getRecord', 'removeRecord', 'updateRecord']
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* Prepare CRUD operation parameters.
|
|
@@ -43,12 +43,13 @@ export const actions = ['countRecord', 'createAggregate', 'createHistogram', 'cr
|
|
|
43
43
|
* @param {Object} [options.req] - The request object
|
|
44
44
|
* @param {Object} [options.reply] - The reply object
|
|
45
45
|
* @param {Object} [options.transaction] - The transaction object
|
|
46
|
+
* @param {boolean} [options.noAutoFilter] - Disable automatic filter parsing from `req.query`
|
|
46
47
|
* @param {Object} [options.options] - Additional options
|
|
47
48
|
* @param {Array} [options.args] - Additional arguments
|
|
48
49
|
* @returns {Object} Prepared CRUD parameters
|
|
49
50
|
*/
|
|
50
51
|
export async function prepCrud (options = {}) {
|
|
51
|
-
let { model, id, req, reply, transaction, options: _options = {}, args } = options
|
|
52
|
+
let { model, id, req, reply, transaction, options: _options = {}, args, noAutoFilter } = options
|
|
52
53
|
const { isSet } = this.app.lib.aneka
|
|
53
54
|
const { importModule } = this.app.bajo
|
|
54
55
|
const { parseFilter } = this.app.waibu
|
|
@@ -93,9 +94,12 @@ export async function prepCrud (options = {}) {
|
|
|
93
94
|
}
|
|
94
95
|
opts.bboxLatField = req.query[cfgWeb.qsKey.bboxLatField]
|
|
95
96
|
opts.bboxLngField = req.query[cfgWeb.qsKey.bboxLngField]
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
let filter = { query: {}, search: {} }
|
|
98
|
+
if (!noAutoFilter) {
|
|
99
|
+
filter = parseFilter(req)
|
|
100
|
+
filter.query = buildFilterQuery.call(mdl, filter)
|
|
101
|
+
filter.search = buildFilterSearch.call(mdl, filter)
|
|
102
|
+
}
|
|
99
103
|
if (_options.query) filter.query = cloneDeep(_options.query)
|
|
100
104
|
if (_options.search) filter.search = cloneDeep(_options.search)
|
|
101
105
|
if (_options.limit) filter.limit = _options.limit
|
package/package.json
CHANGED