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.
- package/lib/factory/driver.js +32 -15
- package/lib/factory/model/_util.js +16 -6
- package/package.json +1 -1
- package/wiki/CHANGES.md +7 -0
package/lib/factory/driver.js
CHANGED
|
@@ -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])
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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
|
-
|
|
279
|
-
|
|
280
|
-
|
|
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
|
|
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
|
-
|
|
257
|
-
|
|
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'
|
|
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] =
|
|
285
|
+
} else obj[k] = sanitizeChild(k, v, parent)
|
|
276
286
|
})
|
|
277
287
|
return obj
|
|
278
288
|
}
|
package/package.json
CHANGED
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
|