waibu-db 2.16.0 → 2.16.2

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.
@@ -1,50 +1,5 @@
1
1
  async function wdbBase () {
2
2
  return class WdbBase extends this.app.baseClass.MpaWidget {
3
- constructor (options) {
4
- super(options)
5
- const { getModel } = this.app.dobo
6
- const { get } = this.app.lib._
7
- this.schema = get(this, 'component.locals.schema', {})
8
- this.formData = get(this, 'component.locals.form', {})
9
- this.oldData = get(this, 'component.locals.oldData', {})
10
- this.model = getModel(this.schema.name, true)
11
- }
12
-
13
- getRef = ({ field, refName, returning } = {}) => {
14
- const { get } = this.app.lib._
15
- if (!this.model) return {}
16
- const prop = this.model.getProperty(field)
17
- if (!prop) return {}
18
- if (!refName && field.endsWith('Id')) refName = field.slice(0, -2)
19
- const key = this.params.attr.refName ?? refName
20
- const ref = get(prop, `ref.${key}`, {})
21
- if (returning === 'all') return { ref, key }
22
- else if (returning === 'key') return key
23
- return ref
24
- }
25
-
26
- getRefValue = ({ field, data, labelField, refName } = {}) => {
27
- const { get, isEmpty } = this.app.lib._
28
- const { ref, key } = this.getRef({ field, refName, returning: 'all' })
29
- if (isEmpty(ref)) return undefined
30
- labelField = labelField ?? ref.labelField ?? 'id'
31
- return (get(data ?? this.formData, `_ref.${key}.${labelField}`))
32
- }
33
-
34
- getRefName = (field) => {
35
- const { get } = this.app.lib._
36
- let refName = get(this.schema, `view.widget.${field}.attr.ref-name`, this.params.attr.refName)
37
- if (!refName && this.params.attr[field] && this.params.attr[field].endsWith('Id')) refName = this.params.attr[field].slice(0, -2)
38
- return refName
39
- }
40
-
41
- getSetting = (key, defValue) => {
42
- const { get, camelCase } = this.app.lib._
43
- const widgetName = camelCase(this.constructor.name)
44
- key = key.replaceAll('{self}', widgetName)
45
- const cfg = this.app.waibu.getSetting(`${this.plugin.ns}:${key}`, { defValue, req: this.component.req })
46
- return get(this.schema, `view.${key}`, cfg)
47
- }
48
3
  }
49
4
  }
50
5
 
@@ -67,16 +67,13 @@ async function btnExport () {
67
67
  let items = []
68
68
  let checker = false
69
69
  const keys = []
70
- const types = []
71
70
  let els = document.querySelectorAll(selector + ' thead th')
72
71
  for (const el of els) {
73
72
  keys.push(this.options.includes('fkey') ? el.innerText : el.dataset.key)
74
- types.push(el.dataset.type)
75
73
  }
76
74
  if (_.isEmpty(keys[0])) {
77
75
  checker = true
78
76
  keys.shift()
79
- types.shift()
80
77
  }
81
78
  els = document.querySelectorAll(selector + ' tbody tr')
82
79
  for (const el of els) {
@@ -85,12 +82,7 @@ async function btnExport () {
85
82
  i = i + ''
86
83
  if (i === '0' && checker) return undefined
87
84
  if (this.options.includes('fvalue')) data.push(v.innerText)
88
- else {
89
- const type = types[parseInt(i)]
90
- let val = wmpa.parseValue(v.dataset.value, type)
91
- if (['datetime', 'date', 'time'].includes(type)) val = val.toISOString()
92
- data.push(val)
93
- }
85
+ else data.push(wmpa.parseValue(v.dataset.value, v.dataset.value))
94
86
  })
95
87
  const item = {}
96
88
  for (const i in keys) {
@@ -1,58 +1,24 @@
1
1
  import wdbBase from '../wdb-base.js'
2
2
 
3
- async function handleRo (attr = {}, prop = {}, widget = {}) {
4
- const { get, camelCase, isEmpty, isString } = this.app.lib._
5
- const { callHandler } = this.app.bajo
6
- const { escape } = this.app.waibu
7
- const { req } = this.component
8
- const dataValue = get(this.formData, `_orig.${prop.name}`, prop.dataValue ?? '')
9
- let value = get(this.oldData, prop.name, get(this.formData, prop.name, prop.value ?? ''))
10
- const format = get(this.schema, `view.format.${prop.name}`)
11
- const formatValue = get(this.schema, `view.formatValue.${prop.name}`)
12
- const labelField = get(this.schema, `view.widget.${prop.name}.attr.labelField`)
13
- if (formatValue) value = await formatValue.call(this, value, this.formData, { req })
14
- else if (prop.ref) {
15
- value = this.getRefValue({ field: prop.name, labelField, refName: this.getRefName(prop.name) })
16
- if (format && !isEmpty(value)) attr.href = await format.call(this, value, this.formData, { linkOnly: true })
17
- } else if (prop.values) {
18
- const values = isString(prop.values) ? (await callHandler(prop.values)) : prop.values
19
- value = values.find(v => v.value === dataValue)
20
- if (value) {
21
- const key = camelCase(`${prop.name} ${value.text}`)
22
- value = req.te(key) ? req.t(key) : value.text
23
- }
24
- } else if (format && !isEmpty(value)) value = await format.call(this, value, this.formData)
25
- attr.dataValue = escape(dataValue)
26
- attr.value = escape(value)
27
- attr.dataType = prop.type
28
-
29
- if (['object', 'array', 'text'].includes(prop.type)) {
30
- attr.style = 'min-height: 100px'
31
- return await this.component.buildTag({ tag: 'formTextarea', attr, html: value })
32
- }
33
- return await this.component.buildTag({ tag: 'formPlaintext', attr, selfCosing: true, noEscape: true })
34
- }
35
-
36
- async function handleRw (attr = {}, prop = {}, widget = {}) {
37
- const { get, has, isPlainObject, isArray } = this.app.lib._
38
- const { escape } = this.app.waibu
39
- const { stringifyAttribs } = this.app.waibuMpa
40
- if (has(attr, 'name') && !has(attr, 'value')) {
41
- attr.dataType = attr.dataType ?? prop.type
42
- attr.dataValue = get(this, `formData.${attr.name}`)
43
- if (isPlainObject(attr.dataValue) || isArray(attr.dataValue)) attr.dataValue = JSON.stringify(attr.dataValue)
44
- attr.dataValue = escape(attr.dataValue)
45
- attr.value = widget.component === 'form-plaintext' ? get(this, `oldData.${attr.name}`, attr.dataValue) : attr.dataValue
46
- }
47
-
48
- const cmp = prop.ref ? 'wdb-lookup-select' : widget.component
49
- return `<c:${cmp} ${stringifyAttribs(attr)} data-type="${prop.type}" />`
50
- }
51
-
52
3
  async function form () {
53
4
  const WdbBase = await wdbBase.call(this)
54
5
 
55
6
  return class WdbForm extends WdbBase {
7
+ static async handleRo ({ attr = {}, prop = {} } = {}) {
8
+ return await this.component.buildTag({ tag: 'formPlaintext', attr, selfCosing: true, noEscape: true })
9
+ }
10
+
11
+ static async handleRw ({ attr = {}, prop = {}, widget = {} } = {}) {
12
+ const { get, has } = this.app.lib._
13
+ const { stringifyAttribs } = this.app.waibuMpa
14
+ if (has(attr, 'name') && !has(attr, 'value')) {
15
+ attr.value = widget.component === 'form-plaintext' ? get(this, `oldData.${attr.name}`, attr.dataValue) : attr.dataValue
16
+ }
17
+ attr.dataType = prop.type
18
+ const cmp = prop.ref ? 'wdb-lookup-select' : widget.component
19
+ return `<c:${cmp} ${stringifyAttribs(attr)} />`
20
+ }
21
+
56
22
  build = async () => {
57
23
  const { get, find, filter, forOwn, isEmpty } = this.app.lib._
58
24
  const { base64JsonEncode } = this.app.waibu
@@ -85,9 +51,9 @@ async function form () {
85
51
  }
86
52
  if (widget.componentOpts) attr['c-opts'] = base64JsonEncode(widget.componentOpts)
87
53
  if (widget.component === 'form-plaintext' || this.params.attr.method !== 'POST') {
88
- body.push(await handleRo.call(this, attr, prop, widget))
54
+ body.push(await WdbForm.handleRo.call(this, { attr, prop, widget }))
89
55
  } else {
90
- body.push(await handleRw.call(this, attr, prop, widget))
56
+ body.push(await WdbForm.handleRw.call(this, { attr, prop, widget }))
91
57
  }
92
58
  }
93
59
  body.push('</c:fieldset>')
@@ -4,8 +4,6 @@ async function table () {
4
4
  const WdbBase = await wdbBase.call(this)
5
5
 
6
6
  return class WdbTable extends WdbBase {
7
- propValues = {}
8
-
9
7
  isRightAligned = (field, schema) => {
10
8
  const { get, find } = this.app.lib._
11
9
  const prop = find(schema.properties, { name: field })
@@ -22,11 +20,10 @@ async function table () {
22
20
  }
23
21
 
24
22
  build = async () => {
25
- const { callHandler } = this.app.bajo
26
23
  const { req } = this.component
27
24
  const { escape, attrToArray } = this.app.waibu
28
25
  const { groupAttrs } = this.app.waibuMpa
29
- const { get, omit, set, find, isEmpty, without, merge, camelCase } = this.app.lib._
26
+ const { get, omit, set, find, isEmpty, without, merge } = this.app.lib._
30
27
  const group = groupAttrs(this.params.attr, ['body', 'head', 'foot'])
31
28
  this.params.attr = group._
32
29
  const prettyUrl = this.params.attr.prettyUrl
@@ -35,11 +32,6 @@ async function table () {
35
32
  const data = get(this, 'component.locals.list.data', [])
36
33
  const filter = get(this, 'component.locals.list.filter', {})
37
34
  const count = get(this, 'component.locals.list.count', 0)
38
- // collect prop.values for later use
39
- for (const prop of schema.properties) {
40
- if (typeof prop.values === 'string') this.propValues[prop.name] = await callHandler(prop.values)
41
- else if (prop.values) this.propValues[prop.name] = prop.values
42
- }
43
35
  if (count === 0 || data.length === 0) {
44
36
  const alert = '<c:alert color="warning" t:content="noRecordFound" margin="top-4"/>'
45
37
  this.params.noTag = true
@@ -134,12 +126,10 @@ async function table () {
134
126
  let prop = find(schema.properties, { name: f })
135
127
  if (!prop) prop = find(schema.view.calcFields, { name: f })
136
128
  if (!prop) continue
137
- let dataValue = d._orig[f] ?? ''
138
- if (!isEmpty(dataValue)) {
139
- if (['datetime'].includes(prop.type)) dataValue = escape(dataValue.toISOString())
140
- if (['string', 'text'].includes(prop.type)) dataValue = escape(dataValue)
141
- if (['array', 'object'].includes(prop.type)) dataValue = escape(JSON.stringify(d[f]))
142
- }
129
+ let dataValue = d._orig[f]
130
+ if (['datetime'].includes(prop.type)) dataValue = escape(dataValue.toISOString())
131
+ else if (['string', 'text'].includes(prop.type)) dataValue = escape(dataValue)
132
+ else if (['array', 'object'].includes(prop.type)) dataValue = escape(JSON.stringify(d[f]))
143
133
  const refName = get(schema, `view.widget.${f}.attr.refName`)
144
134
  let value = this.getRefValue({ field: f, data: d, refName }) ?? d[f]
145
135
  const formatValue = get(schema, `view.formatValue.${f}`)
@@ -154,21 +144,9 @@ async function table () {
154
144
  if (formatCell) merge(attr, await formatCell.call(this, value, d, { params: this.params, req }))
155
145
  const noWrap = this.isNoWrap(f, schema, group.body.nowrap) ? 'nowrap' : ''
156
146
  if (this.isRightAligned(f, schema)) attr.text = `align:end ${noWrap}`
157
- else attr.text = noWrap
158
- const lookup = get(schema, `view.lookup.${f}`)
159
- if (lookup) {
160
- const item = find(lookup.values, set({}, lookup.id ?? 'id', dataValue))
161
- if (item) value = req.t(item[lookup.field ?? 'name'])
162
- }
147
+ else attr.text = `${noWrap}`
163
148
  const format = get(schema, `view.format.${f}`)
164
149
  if (format) value = await format.call(this, value, d, { params: this.params, req })
165
- if (this.propValues[f]) {
166
- const item = find(this.propValues[f], { value: dataValue })
167
- if (item) {
168
- const key = camelCase(`${f} ${item.text}`)
169
- value = req.te(key) ? req.t(key) : item.text
170
- }
171
- }
172
150
  const line = await this.component.buildTag({ tag: 'td', attr, html: value })
173
151
  lines.push(line)
174
152
  }
@@ -1,11 +1,11 @@
1
1
  import { prepCrud, processHandler } from '../util.js'
2
2
 
3
- async function createRecord ({ model, req, reply, body, options = {}, transaction } = {}) {
4
- const { model: mdl, input, opts, attachment, stats, mimeType } = await prepCrud.call(this, { model, req, reply, body, options, args: ['model'], transaction })
3
+ async function createRecord ({ model, req, reply, options = {}, transaction } = {}) {
4
+ const { model: mdl, opts, attachment, stats, mimeType } = await prepCrud.call(this, { model, req, reply, options, args: ['model'], transaction })
5
5
 
6
6
  async function handler (trx) {
7
7
  if (opts.trx === true) opts.trx = trx
8
- const ret = await mdl.createRecord(input, opts)
8
+ const ret = await mdl.createRecord(req.body, { ...opts, partial: true, strict: true })
9
9
  if (attachment) ret.data._attachment = await mdl.findAttachment(ret.data.id, { stats, mimeType })
10
10
  return ret
11
11
  }
@@ -1,7 +1,7 @@
1
1
  import { prepCrud, getOneRecord, processHandler } from '../util.js'
2
2
 
3
3
  async function updateRecord ({ model, req, reply, id, body, options = {}, transaction } = {}) {
4
- const { model: mdl, filter, input, opts, recId, attachment, stats, mimeType } = await prepCrud.call(this, { model, req, reply, body, id, options, args: ['model', 'id'], transaction })
4
+ const { model: mdl, filter, opts, recId, attachment, stats, mimeType } = await prepCrud.call(this, { model, req, reply, id, options, args: ['model', 'id'], transaction })
5
5
  const me = this
6
6
 
7
7
  async function handler (trx) {
@@ -10,7 +10,7 @@ async function updateRecord ({ model, req, reply, id, body, options = {}, transa
10
10
  const resp = await getOneRecord.call(me, mdl, recId, filter, opts)
11
11
  opts._data = resp.data
12
12
  }
13
- const ret = await mdl.updateRecord(recId, input, opts)
13
+ const ret = await mdl.updateRecord(recId, body ?? req.body, { ...opts, partial: true, strict: true })
14
14
  if (attachment) ret.data._attachment = await mdl.findAttachment(id, { stats, mimeType })
15
15
  return ret
16
16
  }
package/lib/util.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export const actions = ['countRecord', 'createAggregate', 'createHistogram', 'createRecord', 'findAllRecord', 'findOneRecord', 'findRecord', 'getRecord', 'removeRecord', 'updateRecord']
2
2
 
3
- export async function prepCrud ({ model, body, id, req, reply, transaction, options = {}, args } = {}) {
3
+ export async function prepCrud ({ model, id, req, reply, transaction, options = {}, args } = {}) {
4
4
  const { isSet } = this.app.lib.aneka
5
5
  const { importModule } = this.app.bajo
6
6
  const { parseFilter } = this.app.waibu
@@ -42,8 +42,6 @@ export async function prepCrud ({ model, body, id, req, reply, transaction, opti
42
42
  model = model ?? pascalCase(params.model)
43
43
  mdl = this.app.dobo.getModel(model)
44
44
  }
45
- const input = await mdl.sanitizeBody({ body: body ?? params.body, partial: true, strict: true })
46
-
47
45
  opts.bboxLatField = req.query[cfgWeb.qsKey.bboxLatField]
48
46
  opts.bboxLngField = req.query[cfgWeb.qsKey.bboxLngField]
49
47
  const filter = parseFilter(req)
@@ -54,7 +52,7 @@ export async function prepCrud ({ model, body, id, req, reply, transaction, opti
54
52
  if (options.limit) filter.limit = options.limit
55
53
  if (options.sort) filter.sort = options.sort
56
54
  if (options.page) filter.page = options.page
57
- return { model: mdl, recId, input, opts, filter, attachment, stats, mimeType }
55
+ return { model: mdl, recId, opts, filter, attachment, stats, mimeType }
58
56
  }
59
57
 
60
58
  export async function getOneRecord (model, id, filter, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waibu-db",
3
- "version": "2.16.0",
3
+ "version": "2.16.2",
4
4
  "description": "DB Helper",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/wiki/CHANGES.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-04-17
4
+
5
+ - [2.16.2] Bug fix in ```WdbTable``` widget
6
+ - [2.16.2] Bug fix in ```WdbForm``` widget
7
+ - [2.16.2] Remove reduncat codes in ```WdbBase``` widget
8
+
9
+ ## 2026-04-16
10
+
11
+ - [2.16.1] Bug fix in ```WdbBtnExport``` widget
12
+ - [2.16.1] Bug fix in ```WdbForm``` widget
13
+ - [2.16.1] Bug fix in ```WdbTable``` widget
14
+ - [2.16.1] Bug fix in ```prepCrud()```
15
+ - [2.16.1] Bug fix in ```createRecord()```
16
+ - [2.16.1] Bug fix in ```updateRecord()```
17
+
3
18
  ## 2026-04-13
4
19
 
5
20
  - [2.16.0] Add ```oldData``` propety to ```WdbBase``` widget