dobo 2.4.0 → 2.5.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.
@@ -37,6 +37,7 @@ async function driverFactory () {
37
37
  uniqueIndex: false,
38
38
  nullableField: true
39
39
  }
40
+ this.useUtc = false
40
41
  this.maxChunkSize = 500
41
42
  this.memory = false
42
43
  this.options = options
@@ -81,18 +82,28 @@ async function driverFactory () {
81
82
  }
82
83
 
83
84
  sanitizeRecord (model, record = {}) {
85
+ const { dayjs } = this.app.lib
86
+ const { isString } = this.app.lib._
84
87
  const item = { ...record }
85
88
  if (has(item, this.idField.name) && this.idField.name !== 'id') {
86
89
  item.id = item[this.idField.name]
87
90
  delete item[this.idField.name]
88
91
  }
89
92
  for (const prop of model.properties) {
90
- if (isSet(item[prop.name]) && !this.support.propType[prop.type]) {
91
- try {
92
- if (prop.type === 'datetime') item[prop.name] = new Date(item[prop.name])
93
- else if (['object', 'array'].includes(prop.type)) item[prop.name] = JSON.parse(item[prop.name])
94
- } catch (err) {
95
- item[prop.name] = null
93
+ if (isSet(item[prop.name])) {
94
+ if (!this.support.propType[prop.type]) {
95
+ try {
96
+ if (prop.type === 'datetime') {
97
+ const dt = this.useUtc ? dayjs.utc(item[prop.name]) : dayjs(item[prop.name])
98
+ item[prop.name] = dt.toDate()
99
+ } else if (['object', 'array'].includes(prop.type)) item[prop.name] = JSON.parse(item[prop.name])
100
+ } catch (err) {
101
+ item[prop.name] = null
102
+ }
103
+ }
104
+ if (prop.type === 'datetime' && isString(item[prop.name])) {
105
+ const dt = this.useUtc ? dayjs.utc(item[prop.name]) : dayjs(item[prop.name])
106
+ item[prop.name] = dt.toDate()
96
107
  }
97
108
  }
98
109
  }
@@ -247,9 +258,11 @@ async function driverFactory () {
247
258
 
248
259
  async _updateRecord (model, id, body = {}, options = {}) {
249
260
  if (!this.support.uniqueIndex) await this._checkUnique(model, body, options)
250
- const resp = await this.getRecord(model, id, { noHook: true })
251
- if (!resp.data) throw this.plugin.error('recordNotFound%s%s', id, model.name)
252
- options._data = resp.data
261
+ if (!options._data) {
262
+ const resp = await this.getRecord(model, id, { noHook: true })
263
+ if (!resp.data) throw this.plugin.error('recordNotFound%s%s', id, model.name)
264
+ options._data = resp.data
265
+ }
253
266
  const input = this.sanitizeBody(model, body, true)
254
267
  delete input.id
255
268
  const result = await this.updateRecord(model, id, input, options)
@@ -262,9 +275,11 @@ async function driverFactory () {
262
275
  async _upsertRecord (model, body = {}, options = {}) {
263
276
  if (!this.uniqueIndexSupport) await this._checkUnique(model, body, options)
264
277
  if (isSet(body.id)) {
265
- const resp = await this.getRecord(model, body.id, { noHook: true })
266
- if (!resp.data) throw this.plugin.error('recordNotFound%s%s', body.id, model.name)
267
- options._data = resp.data
278
+ if (!options._data) {
279
+ const resp = await this.getRecord(model, body.id, { noHook: true })
280
+ if (!resp.data) throw this.plugin.error('recordNotFound%s%s', body.id, model.name)
281
+ options._data = resp.data
282
+ }
268
283
  }
269
284
  const input = this.sanitizeBody(model, body)
270
285
  const result = await this.upsertRecord(model, input, options)
@@ -275,9 +290,11 @@ async function driverFactory () {
275
290
  }
276
291
 
277
292
  async _removeRecord (model, id, options = {}) {
278
- const resp = await this.getRecord(model, id, { noHook: true })
279
- if (!resp.data) throw this.plugin.error('recordNotFound%s%s', id, model.name)
280
- options._data = resp.data
293
+ if (!options._data) {
294
+ const resp = await this.getRecord(model, id, { noHook: true })
295
+ if (!resp.data) throw this.plugin.error('recordNotFound%s%s', id, model.name)
296
+ options._data = resp.data
297
+ }
281
298
  const result = await this.removeRecord(model, id, options)
282
299
  if (options.noResult) return
283
300
  result.oldData = this.sanitizeRecord(model, result.oldData)
@@ -124,7 +124,7 @@ export async function copyAttachment (id, options = {}) {
124
124
  if (parts.length === 0) continue
125
125
  fieldName = setField ?? fieldName
126
126
  const file = setFile ?? parts.join('@')
127
- const opts = { source: f, fieldName, file, mimeType, stats, req, silent: true }
127
+ const opts = { source: f, fieldName, file, mimeType, stats, req }
128
128
  const rec = await this.createAttachment(id, opts)
129
129
  if (!rec) continue
130
130
  delete rec.dir
@@ -253,26 +253,36 @@ function sanitizeQuery (query = {}, parent) {
253
253
  const { dayjs } = this.app.lib
254
254
  const obj = cloneDeep(query)
255
255
  const keys = Object.keys(obj)
256
- const sanitize = (key, val, p) => {
257
- if (!isSet(val)) return val
258
- const prop = find(this.properties, { name: key.startsWith('$') ? p : key })
256
+
257
+ const sanitizeField = (prop, val) => {
259
258
  if (!prop) return val
260
- if (['datetime', 'date', 'time'].includes(prop.type)) {
259
+ if (['datetime'].includes(prop.type)) {
261
260
  const dt = dayjs(val)
262
261
  return dt.isValid() ? dt.toDate() : val
263
262
  } else if (['smallint', 'integer'].includes(prop.type)) return parseInt(val) || val
264
263
  else if (['float', 'double'].includes(prop.type)) return parseFloat(val) || val
265
264
  else if (['boolean'].includes(prop.type)) return !!val
265
+ else if (['string', 'text'].includes(prop.type)) return val + ''
266
266
  return val
267
267
  }
268
+
269
+ const sanitizeChild = (key, val, p) => {
270
+ if (!isSet(val)) return val
271
+ const prop = find(this.properties, { name: key.startsWith('$') ? p : key })
272
+ if (!prop) return val
273
+ return sanitizeField(prop, val)
274
+ }
275
+
268
276
  keys.forEach(k => {
269
277
  const v = obj[k]
278
+ const prop = find(this.properties, { name: k })
270
279
  if (isPlainObject(v)) obj[k] = sanitizeQuery.call(this, v, k)
271
280
  else if (isArray(v)) {
272
281
  v.forEach((i, idx) => {
273
282
  if (isPlainObject(i)) obj[k][idx] = sanitizeQuery.call(this, i, k)
283
+ else obj[k][idx] = sanitizeField(prop, i)
274
284
  })
275
- } else obj[k] = sanitize(k, v, parent)
285
+ } else obj[k] = sanitizeChild(k, v, parent)
276
286
  })
277
287
  return obj
278
288
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dobo",
3
- "version": "2.4.0",
3
+ "version": "2.5.1",
4
4
  "description": "DBMS for Bajo Framework",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/wiki/CHANGES.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-01-30
4
+
5
+ - [2.5.0] Add feature to push custom ```options._data```. If provided, this will be used instead of auto generated one.
6
+ - [2.5.0] Remove ```silent``` in ```options``` object
7
+ - [2.5.1] Driver now support ```this.useUtc``` for database that store values in UTC string
8
+ - [2.5.1] Bug fix on ```driver.sanitizeRecord()```
9
+
3
10
  ## 2026-01-29
4
11
 
5
12
  - [2.4.0] Add ```bulkCreateRecords()``` on model & driver