dobo 2.9.2 → 2.10.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/bajoCli/applet/rebuild-model.js +1 -1
- package/index.js +1 -1
- package/lib/collect-models.js +1 -0
- package/lib/factory/model/find-all-record.js +7 -7
- package/lib/factory/model/load-fixtures.js +46 -41
- package/lib/factory/model/update-record.js +4 -2
- package/lib/factory/model.js +18 -0
- package/package.json +1 -1
- package/wiki/CHANGES.md +32 -20
package/index.js
CHANGED
|
@@ -81,7 +81,7 @@ const propertyType = {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
const commonPropertyTypes = ['name', 'type', 'required', 'rules', 'validator', 'ref', 'default', 'values', 'rulesMsg']
|
|
84
|
+
const commonPropertyTypes = ['name', 'type', 'required', 'rules', 'validator', 'ref', 'default', 'values', 'rulesMsg', 'immutable', 'feature']
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
87
|
* Plugin factory
|
package/lib/collect-models.js
CHANGED
|
@@ -82,6 +82,7 @@ async function applyFeature (model, feature, options, indexes, isExtender) {
|
|
|
82
82
|
if (item.rules) model.rules.push(...item.rules)
|
|
83
83
|
if (!isArray(item.properties)) item.properties = [item.properties]
|
|
84
84
|
for (const prop of item.properties) {
|
|
85
|
+
prop.feature = `${feature.plugin.ns}:${feature.name}`
|
|
85
86
|
await sanitizeProp.call(this, model, prop, indexes)
|
|
86
87
|
}
|
|
87
88
|
if (item.hooks) {
|
|
@@ -7,14 +7,14 @@ async function native (filter, options, dataOnly) {
|
|
|
7
7
|
if (dataOnly) options.count = false
|
|
8
8
|
let { noResultSanitizer, noCache } = options
|
|
9
9
|
if (!this.cacheable) noCache = true
|
|
10
|
-
await execHook.call(this, '
|
|
11
|
-
await execModelHook.call(this, '
|
|
12
|
-
await execDynHook.call(this, '
|
|
10
|
+
await execHook.call(this, 'beforeFindRecord', filter, options)
|
|
11
|
+
await execModelHook.call(this, 'beforeFindRecord', filter, options)
|
|
12
|
+
await execDynHook.call(this, 'beforeFindRecord', filter, options)
|
|
13
13
|
if (get && !noCache && !options.record) {
|
|
14
14
|
const cachedResult = await get({ model: this.name, filter, options })
|
|
15
15
|
if (cachedResult) {
|
|
16
16
|
cachedResult.cached = true
|
|
17
|
-
await execModelHook.call(this, '
|
|
17
|
+
await execModelHook.call(this, 'afterFindRecord', filter, cachedResult, options)
|
|
18
18
|
return dataOnly ? cachedResult.data : cachedResult
|
|
19
19
|
}
|
|
20
20
|
}
|
|
@@ -25,9 +25,9 @@ async function native (filter, options, dataOnly) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
if (isSet(options.refs)) await getMultiRefs.call(this, result.data, options)
|
|
28
|
-
await execDynHook.call(this, '
|
|
29
|
-
await execModelHook.call(this, '
|
|
30
|
-
await execHook.call(this, '
|
|
28
|
+
await execDynHook.call(this, 'afterFindRecord', filter, result, options)
|
|
29
|
+
await execModelHook.call(this, 'afterFindRecord', filter, result, options)
|
|
30
|
+
await execHook.call(this, 'afterFindRecord', filter, result, options)
|
|
31
31
|
if (set && !noCache) await set({ model: this.name, filter, options, result })
|
|
32
32
|
return dataOnly ? result.data : result
|
|
33
33
|
}
|
|
@@ -1,10 +1,30 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
|
|
3
|
-
async function
|
|
4
|
-
const {
|
|
5
|
-
const {
|
|
6
|
-
const { isEmpty, isArray, isString } = this.app.lib._
|
|
3
|
+
async function exec ({ item, spinner, options, result, items } = {}) {
|
|
4
|
+
const { isArray, isString } = this.app.lib._
|
|
5
|
+
const { getPluginDataDir } = this.app.bajo
|
|
7
6
|
const { fs } = this.app.lib
|
|
7
|
+
const resp = await this.createRecord(item, options)
|
|
8
|
+
if (isArray(item._attachments) && item._attachments.length > 0) {
|
|
9
|
+
for (let att of item._attachments) {
|
|
10
|
+
if (isString(att)) att = { field: 'file', file: att }
|
|
11
|
+
const fname = path.basename(att.file)
|
|
12
|
+
if (fs.existsSync(att.file)) {
|
|
13
|
+
const dest = `${getPluginDataDir(this.plugin.ns)}/${resp.id}/${att.field}/${fname}`
|
|
14
|
+
try {
|
|
15
|
+
fs.copySync(att.file, dest)
|
|
16
|
+
} catch (err) {}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
result.success++
|
|
21
|
+
if (spinner) spinner.setText('recordsAdded%s%d%d', this.name, result.success, items.length)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function loadFixtures ({ spinner, ignoreError = true, collectItems = false, noLookup = false } = {}, options = {}) {
|
|
25
|
+
const { readConfig, eachPlugins } = this.app.bajo
|
|
26
|
+
const { resolvePath } = this.app.lib.aneka
|
|
27
|
+
const { isEmpty, isArray, omit } = this.app.lib._
|
|
8
28
|
if (this.connection.proxy) {
|
|
9
29
|
this.log.warn('proxiedConnBound%s', this.name)
|
|
10
30
|
return
|
|
@@ -26,47 +46,32 @@ async function loadFixtures ({ spinner } = {}) {
|
|
|
26
46
|
const extend = await readConfig(`${dir}/extend/dobo/extend/${me.plugin.ns}/fixture/${base}.*`, { ns, ignoreError: true })
|
|
27
47
|
if (isArray(extend) && !isEmpty(extend)) items.push(...extend)
|
|
28
48
|
})
|
|
29
|
-
|
|
30
|
-
const opts = { noHook: true, noCache: true }
|
|
49
|
+
const opts = { noHook: true, noCache: true, ...(omit(options, ['noHook', 'noCache'])) }
|
|
31
50
|
for (const item of items) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const recs = await ref.findRecord({ query: query.join(':') }, opts)
|
|
40
|
-
item[k] = (recs[0] ?? {})[field]
|
|
41
|
-
}
|
|
42
|
-
if (v === null) item[k] = undefined
|
|
43
|
-
else {
|
|
44
|
-
const prop = this.properties.find(item => item.name === k)
|
|
45
|
-
if (prop && ['string', 'text'].includes(prop.type)) item[k] += ''
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
const resp = await this.createRecord(item, { force: true })
|
|
49
|
-
if (isArray(item._attachments) && item._attachments.length > 0) {
|
|
50
|
-
for (let att of item._attachments) {
|
|
51
|
-
if (isString(att)) att = { field: 'file', file: att }
|
|
52
|
-
const fname = path.basename(att.file)
|
|
53
|
-
if (fs.existsSync(att.file)) {
|
|
54
|
-
const dest = `${getPluginDataDir(this.plugin.ns)}/${resp.id}/${att.field}/${fname}`
|
|
55
|
-
try {
|
|
56
|
-
fs.copySync(att.file, dest)
|
|
57
|
-
} catch (err) {}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
51
|
+
for (const k in item) {
|
|
52
|
+
const v = item[k]
|
|
53
|
+
if (!noLookup && typeof v === 'string' && v.slice(0, 2) === '?:') item[k] = await this._simpleLookup(v.slice(2), opts)
|
|
54
|
+
if (v === null) item[k] = undefined
|
|
55
|
+
else {
|
|
56
|
+
const prop = this.properties.find(item => item.name === k)
|
|
57
|
+
if (prop && ['string', 'text'].includes(prop.type)) item[k] += ''
|
|
60
58
|
}
|
|
61
|
-
result.success++
|
|
62
|
-
if (spinner) spinner.setText('recordsAdded%s%d%d', this.name, result.success, items.length)
|
|
63
|
-
} catch (err) {
|
|
64
|
-
console.log(err)
|
|
65
|
-
err.model = this.name
|
|
66
|
-
if (this.app.applet) this.plugin.print.fail(this.app.dobo.validationErrorMessage(err))
|
|
67
|
-
result.failed++
|
|
68
59
|
}
|
|
69
60
|
}
|
|
61
|
+
if (collectItems) return items
|
|
62
|
+
if (isEmpty(items)) return result
|
|
63
|
+
for (const item of items) {
|
|
64
|
+
if (ignoreError) {
|
|
65
|
+
try {
|
|
66
|
+
await exec.call(this, { item, spinner, opts, options, result, items })
|
|
67
|
+
} catch (err) {
|
|
68
|
+
// console.log(err)
|
|
69
|
+
err.model = this.name
|
|
70
|
+
if (this.app.applet) this.plugin.print.fail(this.app.dobo.validationErrorMessage(err))
|
|
71
|
+
result.failed++
|
|
72
|
+
}
|
|
73
|
+
} else await exec.call(this, { item, spinner, opts, options, result, items })
|
|
74
|
+
}
|
|
70
75
|
return result
|
|
71
76
|
}
|
|
72
77
|
|
|
@@ -49,14 +49,16 @@ async function updateRecord (...args) {
|
|
|
49
49
|
let [id, body = {}, opts = {}] = args
|
|
50
50
|
const { isSet } = this.app.lib.aneka
|
|
51
51
|
const { runHook } = this.app.bajo
|
|
52
|
-
const { cloneDeep, get } = this.app.lib._
|
|
52
|
+
const { cloneDeep, get, omit } = this.app.lib._
|
|
53
53
|
const { dataOnly = true } = opts
|
|
54
54
|
const { options } = await getFilterAndOptions.call(this, null, opts, action)
|
|
55
55
|
options.partial = options.partial ?? true
|
|
56
56
|
const { truncateString, noResult, noBodySanitizer, noResultSanitizer, noValidation, partial } = options
|
|
57
57
|
const extFields = get(options, 'validation.extFields', [])
|
|
58
58
|
id = this.sanitizeId(id)
|
|
59
|
-
|
|
59
|
+
let input = noBodySanitizer ? cloneDeep(body) : await this.sanitizeBody({ body, extFields, strict: true, truncateString, partial, onlyTypes })
|
|
60
|
+
const immutables = this.properties.filter(prop => prop.immutable)
|
|
61
|
+
if (immutables.length > 0) input = omit(input, immutables)
|
|
60
62
|
delete input.id
|
|
61
63
|
await execHook.call(this, 'beforeUpdateRecord', id, input, options)
|
|
62
64
|
await execModelHook.call(this, 'beforeUpdateRecord', id, input, options)
|
package/lib/factory/model.js
CHANGED
|
@@ -96,6 +96,24 @@ async function modelFactory () {
|
|
|
96
96
|
return !!this.getProperty(name)
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
_simpleLookup = async (value, options = {}) => {
|
|
100
|
+
const { get, isEmpty, isString, isPlainObject, isArray } = this.app.lib._
|
|
101
|
+
let model
|
|
102
|
+
let field
|
|
103
|
+
let query
|
|
104
|
+
if (isString(value)) {
|
|
105
|
+
[model, field, ...query] = value.split(':')
|
|
106
|
+
query = query.join(':')
|
|
107
|
+
} else if (isPlainObject(value)) ({ model, field, query } = value)
|
|
108
|
+
else if (isArray(value)) [model, field, query] = value
|
|
109
|
+
else return
|
|
110
|
+
if (isEmpty(field)) field = 'id'
|
|
111
|
+
const { getModel } = this.app.dobo
|
|
112
|
+
const ref = getModel(model)
|
|
113
|
+
const rec = await ref.findOneRecord({ query }, { noHook: true, noCache: true, ...options })
|
|
114
|
+
return get(rec, field)
|
|
115
|
+
}
|
|
116
|
+
|
|
99
117
|
build = build
|
|
100
118
|
exists = exists
|
|
101
119
|
drop = drop
|
package/package.json
CHANGED
package/wiki/CHANGES.md
CHANGED
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-03-11
|
|
4
|
+
|
|
5
|
+
- [2.10.0] Add ```immutable``` and ```feature``` to the list of allowed property keys
|
|
6
|
+
- [2.10.0] Set ```property.feature``` to the name of feature name if property is build using ```feature```
|
|
7
|
+
- [2.10.0] Add ```model._simpleLookup()```
|
|
8
|
+
- [2.10.0] Refactor ```model.loadFixtures()```
|
|
9
|
+
- [2.10.0] Add ```property.immutable``` for property that can't be updated
|
|
10
|
+
|
|
11
|
+
## 2026-03-09
|
|
12
|
+
|
|
13
|
+
- [2.9.3] Bug fix in ```model.findAllRecord```
|
|
14
|
+
|
|
3
15
|
## 2026-03-07
|
|
4
16
|
|
|
5
|
-
- [2.9.2] Bug fix
|
|
6
|
-
- [2.9.2] Bug fix
|
|
17
|
+
- [2.9.2] Bug fix in ```model.loadFixtures()```
|
|
18
|
+
- [2.9.2] Bug fix in ```collect-connections.js```
|
|
7
19
|
|
|
8
20
|
## 2026-03-06
|
|
9
21
|
|
|
10
|
-
- [2.9.1] Bug fix
|
|
22
|
+
- [2.9.1] Bug fix in ```model.sanitizeBody()```
|
|
11
23
|
|
|
12
24
|
## 2026-03-05
|
|
13
25
|
|
|
@@ -17,17 +29,17 @@
|
|
|
17
29
|
|
|
18
30
|
## 2026-02-25
|
|
19
31
|
|
|
20
|
-
- [2.8.3] Bug fix
|
|
32
|
+
- [2.8.3] Bug fix in attachment route
|
|
21
33
|
|
|
22
34
|
## 2026-02-24
|
|
23
35
|
|
|
24
|
-
- [2.8.2] Bug fix
|
|
25
|
-
- [2.8.2] Bug fix
|
|
36
|
+
- [2.8.2] Bug fix in field type ```textType```
|
|
37
|
+
- [2.8.2] Bug fix in ```collect-models.js``` when empty model is returned
|
|
26
38
|
|
|
27
39
|
## 2026-02-23
|
|
28
40
|
|
|
29
|
-
- [2.8.1] Bug fix
|
|
30
|
-
- [2.8.1] Bug fix
|
|
41
|
+
- [2.8.1] Bug fix in ```memory._getCursor()```
|
|
42
|
+
- [2.8.1] Bug fix in ```model.upsertRecord()```
|
|
31
43
|
|
|
32
44
|
## 2026-02-22
|
|
33
45
|
|
|
@@ -42,21 +54,21 @@
|
|
|
42
54
|
|
|
43
55
|
## 2026-02-17
|
|
44
56
|
|
|
45
|
-
- [2.6.5] Bug fix
|
|
46
|
-
- [2.6.5] Bug fix
|
|
47
|
-
- [2.6.6] Bug fix
|
|
57
|
+
- [2.6.5] Bug fix in model extender
|
|
58
|
+
- [2.6.5] Bug fix in trace logging
|
|
59
|
+
- [2.6.6] Bug fix in extender indexes
|
|
48
60
|
|
|
49
61
|
## 2026-02-05
|
|
50
62
|
|
|
51
|
-
- [2.6.4] Bug fix
|
|
63
|
+
- [2.6.4] Bug fix in driver options, ```noCheckUnique``` must be perform in ```create```, ```update``` and ```upsert```
|
|
52
64
|
|
|
53
65
|
## 2026-02-03
|
|
54
66
|
|
|
55
|
-
- [2.6.3] Bug fix
|
|
67
|
+
- [2.6.3] Bug fix in ```model.sanitizeRecord()```
|
|
56
68
|
|
|
57
69
|
## 2026-02-02
|
|
58
70
|
|
|
59
|
-
- [2.6.2] Bug fix
|
|
71
|
+
- [2.6.2] Bug fix in query & search resolver: Do not remove old query/search, should always copied to oldQuery/oldSearch
|
|
60
72
|
|
|
61
73
|
## 2026-02-01
|
|
62
74
|
|
|
@@ -69,20 +81,20 @@
|
|
|
69
81
|
- [2.5.0] Add feature to push custom ```options._data```. If provided, this will be used instead of auto generated one.
|
|
70
82
|
- [2.5.0] Remove ```silent``` in ```options``` object
|
|
71
83
|
- [2.5.1] Driver now support ```this.useUtc``` for database that store values in UTC string
|
|
72
|
-
- [2.5.1] Bug fix
|
|
84
|
+
- [2.5.1] Bug fix in ```driver.sanitizeRecord()```
|
|
73
85
|
|
|
74
86
|
## 2026-01-29
|
|
75
87
|
|
|
76
88
|
- [2.4.0] Add ```bulkCreateRecords()``` on model & driver
|
|
77
89
|
- [2.4.0] Add ```execModelHook()```
|
|
78
|
-
- [2.4.0] Bug fix
|
|
90
|
+
- [2.4.0] Bug fix in models collection
|
|
79
91
|
- [2.4.0] Add ```DoboAction``` to the ```app.baseClass```
|
|
80
92
|
- [2.4.0] ```findAllRecord()``` can't be called as action
|
|
81
93
|
|
|
82
94
|
## 2026-01-26
|
|
83
95
|
|
|
84
96
|
- [2.3.1] Bug fix if reference model isn't loaded only yield warning
|
|
85
|
-
- [2.3.1] Bug fix
|
|
97
|
+
- [2.3.1] Bug fix in fetching multi references
|
|
86
98
|
|
|
87
99
|
## 2026-01-24
|
|
88
100
|
|
|
@@ -96,16 +108,16 @@
|
|
|
96
108
|
|
|
97
109
|
## 2026-01-19
|
|
98
110
|
|
|
99
|
-
- [2.2.4] Bug fix
|
|
111
|
+
- [2.2.4] Bug fix in route ```dobo:/attachment/...```
|
|
100
112
|
|
|
101
113
|
## 2026-01-18
|
|
102
114
|
|
|
103
115
|
- [2.2.2] Revert back to ```mingo@6.5.1``` because of bugs in ```skip``` operation
|
|
104
|
-
- [2.2.3] Bug fix
|
|
116
|
+
- [2.2.3] Bug fix in driver's ```sanitizeBody()```
|
|
105
117
|
|
|
106
118
|
## 2026-01-16
|
|
107
119
|
|
|
108
|
-
- [2.2.1] Bug fix
|
|
120
|
+
- [2.2.1] Bug fix in model references
|
|
109
121
|
|
|
110
122
|
## 2026-01-11
|
|
111
123
|
|