waibu-db 2.17.2 → 2.18.1

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.
@@ -116,27 +116,21 @@ async function table () {
116
116
  const lines = []
117
117
  if (selection) {
118
118
  const tag = selection === 'single' ? 'formRadio' : 'formCheck'
119
- const attr = { 'x-model': 'selected', name: '_rt', value: d._orig.id, noLabel: true, noWrapper: true }
119
+ const attr = { 'x-model': 'selected', name: '_rt', value: d.id, noLabel: true, noWrapper: true }
120
120
  const type = find(schema.properties, { name: 'id' }).type
121
- const prepend = `<td data-value="${d._orig.id}" data-key="id" data-type="${type}">`
121
+ const prepend = `<td data-value="${d.id}" data-key="id" data-type="${type}">`
122
122
  lines.push(await this.component.buildTag({ tag, attr, prepend, append: '</td>' }))
123
123
  }
124
124
  for (const f of schema.view.fields) {
125
125
  if (!fields.includes(f)) continue
126
- let prop = find(schema.properties, { name: f })
127
- if (!prop) prop = find(schema.view.calcFields, { name: f })
126
+ const prop = find(schema.properties, { name: f })
128
127
  if (!prop) continue
129
- let dataValue = d._orig[f]
128
+ let dataValue = d[f]
130
129
  if (['datetime'].includes(prop.type) && dataValue instanceof Date && !isNaN(dataValue)) dataValue = escape(dataValue.toISOString())
131
130
  else if (['string', 'text'].includes(prop.type)) dataValue = escape(dataValue)
132
131
  else if (['array', 'object'].includes(prop.type)) dataValue = escape(JSON.stringify(dataValue))
133
132
  const refName = get(schema, `view.widget.${f}.attr.refName`)
134
- let value = this.getRefValue({ field: f, data: d, refName }) ?? d[f]
135
- const formatValue = get(schema, `view.formatValue.${f}`)
136
- if (formatValue) {
137
- value = await formatValue.call(this, value, d, { params: this.params, req })
138
- dataValue = value
139
- }
133
+ let value = this.getRefValue({ field: f, data: d, refName }) ?? get(d, `_fmt.${f}`, d[f])
140
134
  if (!get(schema, 'view.noEscape', []).includes(f)) value = escape(value)
141
135
  const attr = { dataValue, dataKey: prop.name, dataType: prop.type }
142
136
  if (!disableds.includes('get')) attr.style = { cursor: 'pointer' }
@@ -150,9 +144,9 @@ async function table () {
150
144
  const line = await this.component.buildTag({ tag: 'td', attr, html: value })
151
145
  lines.push(line)
152
146
  }
153
- const attr = { id: `rec-${d._orig.id}` }
154
- if (!disableds.includes('update') || !disableds.includes('remove') || !disableds.includes('get')) attr['@click'] = `toggle('${d._orig.id}')`
155
- if (!disableds.includes('get')) attr['@dblclick'] = `goDetails('${d._orig.id}')`
147
+ const attr = { id: `rec-${d.id}` }
148
+ if (!disableds.includes('update') || !disableds.includes('remove') || !disableds.includes('get')) attr['@click'] = `toggle('${d.id}')`
149
+ if (!disableds.includes('get')) attr['@dblclick'] = `goDetails('${d.id}')`
156
150
  items.push(await this.component.buildTag({ tag: 'tr', attr, html: lines.join('\n') }))
157
151
  }
158
152
  html.push(await this.component.buildTag({ tag: 'tbody', attr: group.body, html: items.join('\n') }))
@@ -12,11 +12,10 @@ async function form () {
12
12
  const { get, has } = this.app.lib._
13
13
  const { stringifyAttribs } = this.app.waibuMpa
14
14
  attr.dataType = prop.type
15
- const cmp = prop.ref ? 'wdb-lookup-select' : widget.component
16
15
  if (has(attr, 'name') && !has(attr, 'value')) {
17
- attr.value = cmp === 'form-plaintext' ? get(this, `oldData.${attr.name}`, attr.dataValue) : attr.dataValue
16
+ attr.value = widget.component === 'form-plaintext' ? get(this, `oldData.${attr.name}`, attr.dataValue) : attr.dataValue
18
17
  }
19
- return `<c:${cmp} ${stringifyAttribs(attr)} />`
18
+ return `<c:${widget.component} ${stringifyAttribs(attr)} />`
20
19
  }
21
20
 
22
21
  build = async () => {
@@ -21,10 +21,10 @@ async function lookupSelect () {
21
21
  }
22
22
 
23
23
  this.params.attr.url = this.params.attr.url ?? `waibuDb.restapi:/lookup/${kebabCase(ref.model)}`
24
- const omitted = ['url', 'searchField', 'labelField', 'valueField']
25
- const attr = omit(this.params.attr, omitted)
26
- for (const k of omitted) {
27
- attr[camelCase(`remote ${k}`)] = this.params.attr[k] ?? ref[k]
24
+ const keys = ['url', 'searchField', 'labelField', 'valueField']
25
+ const attr = omit(this.params.attr, keys)
26
+ for (const k of keys) {
27
+ attr[camelCase(`remote ${k}`)] = this.params.attr[k] ?? ref[k] ?? ref.field
28
28
  }
29
29
  const q = set({}, this.params.attr.searchField ?? get(ref, 'searchField', 'id'), ['__REGEXP__', '{searchItem}', 'i'])
30
30
  attr.remoteQuery = base64JsonEncode({ $and: [parseQuery(get(ref, 'query', {})), q] })
@@ -32,7 +32,7 @@ async function lookupSelect () {
32
32
  attr.clearBtn = true
33
33
  const sentence = `<c:form-select-ext ${Object.entries(attr).map(([k, v]) => `${kebabCase(k)}="${v}"`).join(' ')} />`
34
34
  this.params.html = await this.component.buildSentence(sentence, this.component.locals)
35
- this.params.attr = omit(this.params.attr, ['model', 'field', ...omitted])
35
+ this.params.attr = omit(this.params.attr, ['model', 'field', ...keys])
36
36
  }
37
37
  }
38
38
  }
@@ -1,5 +1,5 @@
1
- async function get (req, reply) {
2
- return await this.getRecord({ req, reply })
1
+ async function get (req, reply, options) {
2
+ return await this.getRecord({ req, reply, options, transaction: true })
3
3
  }
4
4
 
5
5
  export default get
@@ -1,5 +1,5 @@
1
- async function remove (req, reply) {
2
- return await this.removeRecord({ req, reply })
1
+ async function remove (req, reply, options) {
2
+ return await this.removeRecord({ req, reply, options, transaction: true })
3
3
  }
4
4
 
5
5
  export default remove
@@ -1,5 +1,5 @@
1
- async function update (req, reply) {
2
- return await this.updateRecord({ req, reply })
1
+ async function update (req, reply, options) {
2
+ return await this.updateRecord({ req, reply, options, transaction: true })
3
3
  }
4
4
 
5
5
  export default update
@@ -1,5 +1,5 @@
1
- async function create (req, reply) {
2
- return await this.createRecord({ req, reply })
1
+ async function create (req, reply, options) {
2
+ return await this.createRecord({ req, reply, options, transaction: true })
3
3
  }
4
4
 
5
5
  export default create
@@ -1,5 +1,5 @@
1
- async function find (req, reply) {
2
- return await this.findRecord({ req, reply })
1
+ async function find (req, reply, options) {
2
+ return await this.findRecord({ req, reply, options, transaction: true })
3
3
  }
4
4
 
5
5
  export default find
@@ -1,8 +1,8 @@
1
- async function stat (req, reply) {
1
+ async function stat (req, reply, options) {
2
2
  const { camelCase } = this.app.lib._
3
3
  const method = camelCase(`create ${req.params.stat}`)
4
4
  if (!this[method]) throw this.error('_notFound')
5
- return await this[method]({ req, reply })
5
+ return await this[method]({ req, reply, options })
6
6
  }
7
7
 
8
8
  export default stat
package/index.js CHANGED
@@ -167,53 +167,6 @@ async function factory (pkgName) {
167
167
  return await this.findAllRecord({ model, req, options })
168
168
  }
169
169
 
170
- formatRecord = async ({ data, req, schema, options = {} }) => {
171
- const { isArray } = this.app.lib._
172
- if (!isArray(data)) return await this.formatRow({ data, req, schema, options })
173
- const items = []
174
- for (const d of data) {
175
- const item = await this.formatRow({ data: d, req, schema, options })
176
- items.push(item)
177
- }
178
- return items
179
- }
180
-
181
- formatRow = async ({ data, req, schema, options = {} }) => {
182
- const { get, find, isFunction, cloneDeep } = this.app.lib._
183
- const { format, callHandler } = this.app.bajo
184
- const { escape } = this.app.waibu
185
- const fields = get(schema, 'view.fields', Object.keys(schema.properties))
186
- const rec = cloneDeep(data)
187
- const lang = get(req, 'lang')
188
- const unitSys = get(req, 'site.setting.sumba.unitSys')
189
- const timeZone = get(req, 'site.setting.sumba.timeZone', this.app.bajo.config.intl.format.datetime.timeZone)
190
- for (const f of fields) {
191
- if (f === '_ref') continue
192
- let prop = find(schema.properties, { name: f })
193
- if (!prop) prop = find(schema.view.calcFields, { name: f })
194
- if (!prop) continue
195
- const opts = {
196
- lang: options.lang ?? lang,
197
- longitude: ['lng', 'longitude'].includes(f),
198
- latitude: ['lat', 'latitude'].includes(f),
199
- speed: ['speed'].includes(f),
200
- degree: ['course', 'heading'].includes(f),
201
- distance: ['distance'].includes(f),
202
- unitSys: options.unitSys ?? unitSys,
203
- datetime: options.datetime ?? { timeZone },
204
- date: options.date ?? { timeZone },
205
- time: options.time ?? { timeZone }
206
- }
207
- rec[f] = format(data[f], prop.type, opts)
208
- const vf = get(schema, `view.formatValue.${f}`)
209
- if (vf) {
210
- if (isFunction(vf)) rec[f] = await vf.call(this, data[f], data, { req })
211
- else rec[f] = await callHandler(vf, { req, value: data[f], data })
212
- } else if (['string', 'text'].includes(prop.type)) rec[f] = escape(rec[f])
213
- }
214
- return rec
215
- }
216
-
217
170
  countRecord = countRecord
218
171
  createAggregate = createAggregate
219
172
  createHistogram = createHistogram
@@ -17,7 +17,7 @@ async function addHandler ({ req, reply, model, params = {}, template, addOnsHan
17
17
  const omitted = ['id', 'createdAt', 'updatedAt']
18
18
  if (req.query.mode === 'clone' && req.query.id) {
19
19
  const resp = await getRecord({ model, req, id: req.query.id, options: { fields: map(schema.properties, 'name'), ...opts } })
20
- def = omit(resp.data._orig, omitted)
20
+ def = omit(resp.data, omitted)
21
21
  } else {
22
22
  const picked = map(schema.properties, 'name')
23
23
  def = omit(pick(req.query, picked), omitted)
@@ -20,8 +20,7 @@ async function allHandler ({ model, action, req, reply, template, params = {}, o
20
20
  const { upperFirst, merge, keys } = this.app.lib._
21
21
  if (!keys(handler).includes(action)) throw this.error('_notFound')
22
22
  options.modelOpts = options.modelOpts ?? {}
23
- options.modelOpts.formatValue = true
24
- options.modelOpts.retainOriginalValue = true
23
+ options.modelOpts.fmt = true
25
24
  if (['delete', 'export'].includes(action)) {
26
25
  if (req.method === 'GET') throw this.error('_notFound')
27
26
  return await handler[action].call(this, { model, req, reply, options })
@@ -23,7 +23,7 @@ async function editHandler ({ req, reply, model, id, params = {}, template, addO
23
23
  const old = await getRecord({ model, req, id, options: opts })
24
24
  if (isEmpty(old.data)) return await reply.view(notFoundTpl, params)
25
25
  opts._data = old
26
- const def = cloneDeep(old.data._orig)
26
+ const def = cloneDeep(old.data)
27
27
  for (const k in def) {
28
28
  if (isArray(def[k]) || isPlainObject(def[k])) def[k] = JSON.stringify(def[k])
29
29
  }
@@ -7,12 +7,10 @@ const defFormatter = {}
7
7
  function getCommons (action, schema, ext, options = {}) {
8
8
  const { defaultsDeep } = this.app.lib.aneka
9
9
  const { merge, map, get, set, without, uniq, pull } = this.app.lib._
10
- const calcFields = get(ext, `view.${action}.calcFields`, get(ext, 'common.calcFields', []))
11
10
  const forceVisible = get(ext, `view.${action}.forceVisible`, get(ext, 'common.forceVisible', []))
12
11
  const widget = defaultsDeep(get(ext, `view.${action}.widget`), get(ext, 'common.widget', {}))
13
12
  const noEscape = get(ext, `view.${action}.noEscape`, get(ext, 'common.noEscape', []))
14
13
  const control = defaultsDeep(get(ext, `view.${action}.control`), get(ext, 'common.control', {}))
15
- const formatValue = defaultsDeep(get(ext, `view.${action}.formatValue`), get(ext, 'common.formatValue', {}))
16
14
  const formatCell = defaultsDeep(get(ext, `view.${action}.formatCell`), get(ext, 'common.formatCell', {}))
17
15
  const format = defaultsDeep(get(ext, `view.${action}.format`), get(ext, 'common.format', {}))
18
16
  const card = get(ext, `view.${action}.card`, get(ext, 'common.card', true))
@@ -20,7 +18,7 @@ function getCommons (action, schema, ext, options = {}) {
20
18
  const disabled = get(ext, `view.${action}.disabled`, get(ext, 'common.disabled', []))
21
19
  const x = defaultsDeep(get(ext, `view.${action}.x`), get(ext, 'common.x', {}))
22
20
  const aggregate = get(ext, `view.${action}.stat.aggregate`, get(ext, 'common.stat.aggregate', []))
23
- let attachment = get(ext, `view.${action}.attachment`, get(ext, 'common.attachment', false))
21
+ let attachment = get(ext, `view.${action}.attachment`, get(ext, 'common.attachment', schema.attachment))
24
22
  if (!schema.attachment || action === 'list') attachment = false
25
23
  hidden.push('siteId', ...schema.hidden, ...(options.hidden ?? []))
26
24
  hidden = uniq(hidden)
@@ -28,10 +26,8 @@ function getCommons (action, schema, ext, options = {}) {
28
26
  const allFields = without(map(schema.properties, 'name'), ...hidden)
29
27
  const forFields = get(ext, `view.${action}.fields`, get(ext, 'common.fields', allFields))
30
28
  set(schema, 'view.attachment', attachment)
31
- set(schema, 'view.calcFields', calcFields)
32
29
  set(schema, 'view.noEscape', noEscape)
33
30
  set(schema, 'view.widget', widget)
34
- set(schema, 'view.formatValue', formatValue)
35
31
  set(schema, 'view.formatCell', formatCell)
36
32
  set(schema, 'view.format', merge({}, defFormatter, format))
37
33
  set(schema, 'view.stat.aggregate', aggregate)
@@ -40,9 +36,8 @@ function getCommons (action, schema, ext, options = {}) {
40
36
  set(schema, 'view.x', x)
41
37
  if (schema.disabled.length > 0) schema.view.disabled.push(...schema.disabled)
42
38
  let fields = []
43
- const calcFieldNames = map(calcFields, 'name')
44
39
  for (const f of forFields) {
45
- if (calcFieldNames.includes(f) || allFields.includes(f)) fields.push(f)
40
+ if (allFields.includes(f)) fields.push(f)
46
41
  }
47
42
  fields = uniq(without(fields, ...hidden))
48
43
 
@@ -52,7 +47,7 @@ function getCommons (action, schema, ext, options = {}) {
52
47
  if (noWrap === true) noWrap = fields
53
48
  else if (noWrap === false) noWrap = []
54
49
  set(schema, 'view.noWrap', noWrap)
55
- return { fields, allFields, card, calcFields }
50
+ return { fields, allFields, card }
56
51
  }
57
52
 
58
53
  function autoLayout ({ action, schema, ext, layout }) {
@@ -91,14 +86,13 @@ function customLayout ({ action, schema, ext, layout, readonly }) {
91
86
 
92
87
  function applyLayout (action, schema, ext) {
93
88
  const { defaultsDeep } = this.app.lib.aneka
94
- const { set, get, isEmpty, find, kebabCase } = this.app.lib._
95
- const { fields, card, calcFields } = getCommons.call(this, action, schema, ext)
89
+ const { set, get, isEmpty, find } = this.app.lib._
90
+ const { fields, card } = getCommons.call(this, action, schema, ext)
96
91
  const layout = get(ext, `view.${action}.layout`, get(ext, 'common.layout', []))
97
92
  const readonly = get(ext, `view.${action}.readonly`, get(ext, 'common.readonly', defReadonly))
98
93
  const widget = {}
99
94
  for (const f of fields) {
100
- let prop = find(schema.properties, { name: f })
101
- if (!prop) prop = find(calcFields, { name: f })
95
+ const prop = find(schema.properties, { name: f })
102
96
  if (!prop) continue
103
97
  const result = schema.view.widget[f] ?? {}
104
98
  result.name = result.name ?? f
@@ -111,8 +105,11 @@ function applyLayout (action, schema, ext) {
111
105
  if (action === 'details') {
112
106
  result.component = 'form-plaintext'
113
107
  } else {
108
+ if (prop.ref) {
109
+ result.component = result.component ?? 'wdb-lookup-select'
110
+ }
114
111
  if (prop.type === 'boolean') {
115
- result.component = 'form-select'
112
+ result.component = result.component ?? 'form-select'
116
113
  result.attr.options = 'false:no;true:yes'
117
114
  }
118
115
  if (prop.values) {
@@ -126,6 +123,7 @@ function applyLayout (action, schema, ext) {
126
123
  if (readonly.includes(f)) result.component = 'form-plaintext'
127
124
  if (!result.component) result.component = 'form-input'
128
125
  }
126
+ /*
129
127
  for (const k in result.attr ?? {}) {
130
128
  const newKey = kebabCase(k)
131
129
  if (k !== newKey) {
@@ -133,6 +131,7 @@ function applyLayout (action, schema, ext) {
133
131
  delete result.attr[k]
134
132
  }
135
133
  }
134
+ */
136
135
  widget[f] = result
137
136
  }
138
137
  set(schema, 'view.widget', widget)
@@ -182,7 +181,7 @@ async function getSchemaExt (modelName, view, options = {}) {
182
181
 
183
182
  const model = isString(modelName) ? this.app.dobo.getModel(modelName) : modelName
184
183
  const ns = model.plugin.ns
185
- const schema = pick(model, ['name', 'properties', 'indexes', 'disabled', 'attachment', 'sortables', 'scanables', 'view', 'hidden'])
184
+ const schema = pick(model, ['name', 'properties', 'indexes', 'disabled', 'attachment', 'sortables', 'scanables', 'view', 'hidden', 'attachment'])
186
185
  const base = options.base ?? path.basename(model.file, path.extname(model.file))
187
186
  const parserOpts = { args: options.args }
188
187
  let ext = await readConfig(`${ns}:/extend/waibuDb/schema/${base}.*`, { ns, baseNs: 'waibuDb', parserOpts })
package/lib/util.js CHANGED
@@ -38,7 +38,7 @@ export async function prepCrud ({ model, id, req, reply, transaction, options =
38
38
 
39
39
  const recId = id ?? params.id ?? req.query.id
40
40
  let mdl = model
41
- if (isString(model)) {
41
+ if (!model || isString(model)) {
42
42
  model = model ?? pascalCase(params.model)
43
43
  mdl = this.app.dobo.getModel(model)
44
44
  }
@@ -59,7 +59,7 @@ export async function getOneRecord (model, id, filter, options) {
59
59
  const { cloneDeep, pick, isEmpty } = this.app.lib._
60
60
  let query = cloneDeep(filter.query || {})
61
61
  query = { $and: [query, { id }] }
62
- const opts = pick(options, ['forceNoHidden', 'trx', 'req', 'refs', 'formatValue', 'retainOriginalValue'])
62
+ const opts = pick(options, ['forceNoHidden', 'trx', 'req', 'refs', 'fmt'])
63
63
  opts.dataOnly = false
64
64
  const data = await model.findOneRecord({ query }, opts)
65
65
  if (isEmpty(data.data) && options.throwNotFound) throw this.error('_notFound')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waibu-db",
3
- "version": "2.17.2",
3
+ "version": "2.18.1",
4
4
  "description": "DB Helper",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/wiki/CHANGES.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-04-25
4
+
5
+ - [2.18.0] Change options to format value using the new key set by dobo
6
+ - [2.18.0] Remove ```options.retainOriginalValue``` since it is not needed anymore
7
+ - [2.18.0] Add all necessary ```options``` for all auto generated api endpoints
8
+
3
9
  ## 2026-04-23
4
10
 
5
11
  - [2.17.2] Bug fix in ```getSchemaExt()```