dobo 2.2.4 → 2.3.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/dobo/feature/unique.js +30 -0
- package/lib/collect-models.js +8 -5
- package/lib/factory/driver.js +31 -25
- package/lib/factory/model/_util.js +22 -4
- package/lib/factory/model/clear-record.js +3 -1
- package/lib/factory/model/count-record.js +3 -1
- package/lib/factory/model/create-aggregate.js +3 -1
- package/lib/factory/model/create-histogram.js +3 -1
- package/lib/factory/model/create-record.js +3 -1
- package/lib/factory/model/find-all-record.js +3 -1
- package/lib/factory/model/find-record.js +3 -1
- package/lib/factory/model/get-record.js +4 -2
- package/lib/factory/model/remove-record.js +3 -1
- package/lib/factory/model/update-record.js +3 -1
- package/lib/factory/model/upsert-record.js +3 -1
- package/package.json +1 -1
- package/wiki/CHANGES.md +10 -0
- package/extend/dobo/feature/int-id.js +0 -13
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import crypto from 'crypto'
|
|
2
|
+
|
|
3
|
+
async function unique (opts = {}) {
|
|
4
|
+
const { omit } = this.app.lib._
|
|
5
|
+
opts.fieldName = opts.fieldName ?? 'id'
|
|
6
|
+
opts.fields = opts.fields ?? []
|
|
7
|
+
return {
|
|
8
|
+
properties: [{
|
|
9
|
+
name: opts.fieldName,
|
|
10
|
+
type: 'string',
|
|
11
|
+
maxLength: 32,
|
|
12
|
+
required: true,
|
|
13
|
+
index: 'primary'
|
|
14
|
+
}],
|
|
15
|
+
hooks: [{
|
|
16
|
+
name: 'beforeCreateRecord',
|
|
17
|
+
level: 1000,
|
|
18
|
+
handler: async function (body, options) {
|
|
19
|
+
if (opts.fields.length === 0) opts.fields = omit(this.properties.map(prop => prop.name), [opts.fieldName])
|
|
20
|
+
const item = {}
|
|
21
|
+
for (const f of opts.fields) {
|
|
22
|
+
item[f] = body[f]
|
|
23
|
+
}
|
|
24
|
+
body[opts.fieldName] = crypto.createHash('md5').update(JSON.stringify(item)).digest('hex')
|
|
25
|
+
}
|
|
26
|
+
}]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default unique
|
package/lib/collect-models.js
CHANGED
|
@@ -65,8 +65,12 @@ async function findAllProps (model, inputs = [], indexes = [], isExtender) {
|
|
|
65
65
|
* @param {Object} options - Options to the feature
|
|
66
66
|
* @returns {Array} New properties found in feature
|
|
67
67
|
*/
|
|
68
|
-
async function applyFeature (model, feature, options, indexes) {
|
|
69
|
-
const { isArray } = this.app.lib._
|
|
68
|
+
async function applyFeature (model, feature, options, indexes, isExtender) {
|
|
69
|
+
const { isArray, findIndex } = this.app.lib._
|
|
70
|
+
if (feature.name === 'dobo:unique' && options.fieldName === 'id') {
|
|
71
|
+
const idx = findIndex(model.properties, { name: 'id' })
|
|
72
|
+
if (idx > -1) model.properties.pullAt(idx)
|
|
73
|
+
}
|
|
70
74
|
const item = await feature.handler(options)
|
|
71
75
|
if (item.rules) model.rules.push(...item.rules)
|
|
72
76
|
if (!isArray(item.properties)) item.properties = [item.properties]
|
|
@@ -88,14 +92,14 @@ async function applyFeature (model, feature, options, indexes) {
|
|
|
88
92
|
* @param {Object} model - Model
|
|
89
93
|
* @param {Array} [inputs] - Array of properties
|
|
90
94
|
*/
|
|
91
|
-
async function findAllFeats (model, inputs = [], indexes = []) {
|
|
95
|
+
async function findAllFeats (model, inputs = [], indexes = [], isExtender) {
|
|
92
96
|
const { isString, omit } = this.app.lib._
|
|
93
97
|
for (let feat of inputs) {
|
|
94
98
|
if (isString(feat)) feat = { name: feat }
|
|
95
99
|
const featName = feat.name.indexOf(':') === -1 ? `dobo:${feat.name}` : feat.name
|
|
96
100
|
const feature = this.app.dobo.getFeature(featName)
|
|
97
101
|
if (!feature) this.fatal('invalidFeature%s%s', model.name, featName)
|
|
98
|
-
await applyFeature.call(this, model, feature, omit(feat, 'name'), indexes)
|
|
102
|
+
await applyFeature.call(this, model, feature, omit(feat, 'name'), indexes, isExtender)
|
|
99
103
|
}
|
|
100
104
|
}
|
|
101
105
|
|
|
@@ -307,7 +311,6 @@ async function collectModels () {
|
|
|
307
311
|
const idProp = schema.properties.find(p => p.name === 'id')
|
|
308
312
|
if (!this.constructor.idTypes.includes(idProp.type)) this.fatal('invalidIdType%s%s', schema.name, this.constructor.idTypes.join(', '))
|
|
309
313
|
if (idProp.type === 'string' && !has(idProp, 'maxLength')) idProp.maxLength = 50
|
|
310
|
-
// schema.properties = without(schema.properties, undefined)
|
|
311
314
|
const model = new DoboModel(plugin, schema)
|
|
312
315
|
me.models.push(model)
|
|
313
316
|
}
|
package/lib/factory/driver.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import crypto from 'crypto'
|
|
2
1
|
import { ulid } from 'ulid'
|
|
3
2
|
import { v4 as uuidv4, v7 as uuidv7 } from 'uuid'
|
|
3
|
+
import crypto from 'crypto'
|
|
4
4
|
|
|
5
5
|
const defIdField = {
|
|
6
6
|
name: '_id',
|
|
@@ -48,6 +48,7 @@ async function driverFactory () {
|
|
|
48
48
|
* @param {Object} conn - Connection object
|
|
49
49
|
*/
|
|
50
50
|
async sanitizeConnection (conn) {
|
|
51
|
+
conn.proto = conn.proto ?? 'http' // used by driver that use url based connection
|
|
51
52
|
conn.memory = false
|
|
52
53
|
}
|
|
53
54
|
|
|
@@ -155,42 +156,47 @@ async function driverFactory () {
|
|
|
155
156
|
|
|
156
157
|
async _createRecord (model, body = {}, options = {}) {
|
|
157
158
|
const { isSet, generateId } = this.app.lib.aneka
|
|
158
|
-
const {
|
|
159
|
-
const prop = model.properties.find(p => p.name === 'id')
|
|
160
|
-
if (!isSet(body.id) && prop.type === 'string') {
|
|
161
|
-
if (options.checksumId) {
|
|
162
|
-
if (options.checksumId === true) options.checksumId = Object.keys(body)
|
|
163
|
-
const checksum = pick(body, options.checksumId)
|
|
164
|
-
body.id = crypto.createHash('md5').update(JSON.stringify(checksum)).digest('hex')
|
|
165
|
-
} else if (this.idGenerator) {
|
|
166
|
-
if (['uuid', 'uuidv4'].includes(this.idGenerator)) body.id = uuidv4()
|
|
167
|
-
else if (['uuidv7'].includes(this.idGenerator)) body.id = uuidv7()
|
|
168
|
-
else if (this.idGenerator === 'generateId') body.id = generateId()
|
|
169
|
-
else if (isFunction(this.idGenerator)) body.id = await this.idGenerator(model, body, options)
|
|
170
|
-
}
|
|
171
|
-
if (!body.id) body.id = ulid()
|
|
172
|
-
body.id = body.id.slice(0, prop.maxLength)
|
|
173
|
-
}
|
|
174
|
-
if (!this.uniqueIndexSupport) await this._checkUnique(model, body, options)
|
|
159
|
+
const { isFunction } = this.app.lib._
|
|
175
160
|
for (const prop of model.properties) {
|
|
176
161
|
if (!isSet(body[prop.name]) && isSet(prop.default)) {
|
|
177
162
|
if (isFunction(prop.default)) body[prop.name] = await prop.default.call(model)
|
|
178
|
-
else if (typeof prop.default
|
|
179
|
-
|
|
163
|
+
else if (typeof prop.default !== 'string') body[prop.name] = prop.default
|
|
164
|
+
else {
|
|
165
|
+
if (['now'].includes(prop.default) && prop.type === 'datetime') {
|
|
180
166
|
body[prop.name] = new Date()
|
|
181
|
-
} else if (['uuid
|
|
167
|
+
} else if (['uuid', 'uuidv4'].includes(prop.default) && prop.type === 'string') {
|
|
182
168
|
body[prop.name] = uuidv4().slice(0, prop.maxLength)
|
|
183
|
-
} else if (
|
|
169
|
+
} else if (prop.default === 'uuidv7' && prop.type === 'string') {
|
|
184
170
|
body[prop.name] = uuidv7().slice(0, prop.maxLength)
|
|
185
|
-
} else if (
|
|
171
|
+
} else if (prop.default === 'ulid' && prop.type === 'string') {
|
|
186
172
|
body[prop.name] = ulid().slice(0, prop.maxLength)
|
|
187
|
-
} else if (prop.default
|
|
173
|
+
} else if (prop.default === 'generateid' && prop.type === 'string') {
|
|
188
174
|
body[prop.name] = generateId()
|
|
175
|
+
} else if (prop.default.startsWith('md5:') && prop.type === 'string') {
|
|
176
|
+
const [, field] = prop.default.split(':')
|
|
177
|
+
const fields = field.split(',')
|
|
178
|
+
if (model.properties.filter(item => fields.includes(item.name)).length === fields.length) {
|
|
179
|
+
const values = fields.map(f => body[f])
|
|
180
|
+
body[prop.name] = crypto.createHash('md5').update(values.join(':')).digest('hex')
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
body[prop.name] = prop.default
|
|
189
184
|
}
|
|
190
185
|
}
|
|
191
|
-
body[prop.name] = isFunction(prop.default) ? await prop.default.call(model) : prop.default
|
|
192
186
|
}
|
|
193
187
|
}
|
|
188
|
+
const prop = model.properties.find(p => p.name === 'id')
|
|
189
|
+
if (!isSet(body.id) && prop.type === 'string') {
|
|
190
|
+
if (this.idGenerator) {
|
|
191
|
+
if (['uuid', 'uuidv4'].includes(this.idGenerator)) body.id = uuidv4()
|
|
192
|
+
else if (['uuidv7'].includes(this.idGenerator)) body.id = uuidv7()
|
|
193
|
+
else if (this.idGenerator === 'generateId') body.id = generateId()
|
|
194
|
+
else if (isFunction(this.idGenerator)) body.id = await this.idGenerator(model, body, options)
|
|
195
|
+
}
|
|
196
|
+
if (!body.id) body.id = ulid()
|
|
197
|
+
body.id = body.id.slice(0, prop.maxLength)
|
|
198
|
+
}
|
|
199
|
+
if (!this.uniqueIndexSupport) await this._checkUnique(model, body, options)
|
|
194
200
|
if (isSet(body.id)) {
|
|
195
201
|
const resp = await this.getRecord(model, body.id, { noHook: true })
|
|
196
202
|
if (!isEmpty(resp.data)) throw this.plugin.error('recordExists%s%s', body.id, model.name)
|
|
@@ -13,13 +13,28 @@ export async function execHook (name, ...args) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export async function execModelHook (name, ...args) {
|
|
16
|
-
const { last } = this.app.lib._
|
|
16
|
+
const { last, orderBy } = this.app.lib._
|
|
17
17
|
const { noModelHook } = last(args)
|
|
18
18
|
const results = []
|
|
19
19
|
if (!noModelHook) {
|
|
20
|
-
const hooks = this.hooks.filter(hook => hook.name === name)
|
|
20
|
+
const hooks = orderBy(this.hooks.filter(hook => hook.name === name), ['level'])
|
|
21
21
|
for (const hook of hooks) {
|
|
22
|
-
|
|
22
|
+
if (hook.noWait) hook.handler.call(this, ...args)
|
|
23
|
+
else await hook.handler.call(this, ...args)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return results
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function execDynHook (name, ...args) {
|
|
30
|
+
const { last, orderBy } = this.app.lib._
|
|
31
|
+
const opts = last(args)
|
|
32
|
+
const results = []
|
|
33
|
+
if (!opts.noDynHook) {
|
|
34
|
+
const hooks = orderBy((opts.dynHooks ?? []).filter(hook => hook.name === name), ['level'])
|
|
35
|
+
for (const hook of hooks) {
|
|
36
|
+
if (hook.noWait) hook.handler.call(this, ...args)
|
|
37
|
+
else await hook.handler.call(this, ...args)
|
|
23
38
|
}
|
|
24
39
|
}
|
|
25
40
|
return results
|
|
@@ -142,6 +157,7 @@ export async function handleAttachmentUpload (id, trigger, options = {}) {
|
|
|
142
157
|
|
|
143
158
|
export async function getSingleRef (record = {}, options = {}) {
|
|
144
159
|
const { isSet } = this.app.lib.aneka
|
|
160
|
+
const { get } = this.app.lib._
|
|
145
161
|
const props = this.properties.filter(p => isSet(p.ref) && !(options.hidden ?? []).includes(p.name))
|
|
146
162
|
const refs = {}
|
|
147
163
|
options.refs = options.refs ?? []
|
|
@@ -151,6 +167,7 @@ export async function getSingleRef (record = {}, options = {}) {
|
|
|
151
167
|
if (!((typeof options.refs === 'string' && ['*', 'all'].includes(options.refs)) || options.refs.includes(key))) continue
|
|
152
168
|
const ref = prop.ref[key]
|
|
153
169
|
if (ref.fields.length === 0) continue
|
|
170
|
+
if (get(record, `_ref.${key}`)) continue
|
|
154
171
|
const rModel = this.app.dobo.getModel(ref.model)
|
|
155
172
|
const query = {}
|
|
156
173
|
query[ref.propName] = record[prop.name]
|
|
@@ -172,7 +189,7 @@ export async function getSingleRef (record = {}, options = {}) {
|
|
|
172
189
|
|
|
173
190
|
export async function getMultiRefs (records = [], options = {}) {
|
|
174
191
|
const { isSet } = this.app.lib.aneka
|
|
175
|
-
const { uniq, map } = this.app.lib._
|
|
192
|
+
const { uniq, map, get } = this.app.lib._
|
|
176
193
|
const props = this.properties.filter(p => isSet(p.ref) && !(options.hidden ?? []).includes(p.name))
|
|
177
194
|
options.refs = options.refs ?? []
|
|
178
195
|
if (props.length > 0) {
|
|
@@ -182,6 +199,7 @@ export async function getMultiRefs (records = [], options = {}) {
|
|
|
182
199
|
const ref = prop.ref[key]
|
|
183
200
|
if (ref.fields.length === 0) continue
|
|
184
201
|
if (ref.type !== '1:1') continue
|
|
202
|
+
if (get(records, `0._ref.${key}`)) continue
|
|
185
203
|
const rModel = this.app.dobo.getModel(ref.model)
|
|
186
204
|
const matches = uniq(map(records, r => {
|
|
187
205
|
let v = r[prop.name]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execModelHook } from './_util.js'
|
|
1
|
+
import { getFilterAndOptions, execHook, execModelHook, execDynHook } from './_util.js'
|
|
2
2
|
const action = 'clearRecord'
|
|
3
3
|
|
|
4
4
|
async function clearRecord (...args) {
|
|
@@ -8,7 +8,9 @@ async function clearRecord (...args) {
|
|
|
8
8
|
const { options } = await getFilterAndOptions.call(this, null, opts, action)
|
|
9
9
|
await execHook.call(this, 'beforeClearRecord', options)
|
|
10
10
|
await execModelHook.call(this, 'beforeClearRecord', options)
|
|
11
|
+
await execDynHook.call(this, 'beforeClearRecord', options)
|
|
11
12
|
const result = (await this.driver._clearRecord(this, options)) ?? {}
|
|
13
|
+
await execDynHook.call(this, 'beforeClearRecord', result, options)
|
|
12
14
|
await execModelHook.call(this, 'afterClearRecord', result, options)
|
|
13
15
|
await execHook.call(this, 'afterClearRecord', result, options)
|
|
14
16
|
return dataOnly ? result.data : result
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execModelHook } from './_util.js'
|
|
1
|
+
import { getFilterAndOptions, execHook, execModelHook, execDynHook } from './_util.js'
|
|
2
2
|
const action = 'countRecord'
|
|
3
3
|
|
|
4
4
|
async function countRecord (...args) {
|
|
@@ -8,7 +8,9 @@ async function countRecord (...args) {
|
|
|
8
8
|
const { filter, options } = await getFilterAndOptions.call(this, params, opts, action)
|
|
9
9
|
await execHook.call(this, 'beforeCountRecord', options)
|
|
10
10
|
await execModelHook.call(this, 'beforeCountRecord', filter, options)
|
|
11
|
+
await execDynHook.call(this, 'beforeCountRecord', filter, options)
|
|
11
12
|
const result = (await this.driver._countRecord(this, filter, options)) ?? {}
|
|
13
|
+
await execDynHook.call(this, 'afterCountRecord', filter, result, options)
|
|
12
14
|
await execModelHook.call(this, 'afterCountRecord', filter, result, options)
|
|
13
15
|
await execHook.call(this, 'afterCountRecord', filter, result, options)
|
|
14
16
|
return dataOnly ? result.data : result
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execModelHook } from './_util.js'
|
|
1
|
+
import { getFilterAndOptions, execHook, execModelHook, execDynHook } from './_util.js'
|
|
2
2
|
const action = 'createAggregate'
|
|
3
3
|
|
|
4
4
|
async function createAggregate (...args) {
|
|
@@ -8,7 +8,9 @@ async function createAggregate (...args) {
|
|
|
8
8
|
const { filter, options } = await getFilterAndOptions.call(this, _filter, opts, action)
|
|
9
9
|
await execHook.call(this, 'beforeCreateAggregate', filter, params, options)
|
|
10
10
|
await execModelHook.call(this, 'beforeCreateAggregate', filter, params, options)
|
|
11
|
+
await execDynHook.call(this, 'beforeCreateAggregate', filter, params, options)
|
|
11
12
|
const result = (await this.driver._createAggregate(this, filter, params, options)) ?? {}
|
|
13
|
+
await execDynHook.call(this, 'afterCreateAggregate', filter, params, result, options)
|
|
12
14
|
await execModelHook.call(this, 'afterCreateAggregate', filter, params, result, options)
|
|
13
15
|
await execHook.call(this, 'afterCreateAggregate', filter, params, result, options)
|
|
14
16
|
return dataOnly ? result.data : result
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execModelHook } from './_util.js'
|
|
1
|
+
import { getFilterAndOptions, execHook, execModelHook, execDynHook } from './_util.js'
|
|
2
2
|
const action = 'createHistogram'
|
|
3
3
|
|
|
4
4
|
async function createHistogram (...args) {
|
|
@@ -8,7 +8,9 @@ async function createHistogram (...args) {
|
|
|
8
8
|
const { filter, options } = await getFilterAndOptions.call(this, _filter, opts, action)
|
|
9
9
|
await execHook.call(this, 'beforeCreateHistogram', filter, params, options)
|
|
10
10
|
await execModelHook.call(this, 'beforeCreateHistogram', filter, params, options)
|
|
11
|
+
await execDynHook.call(this, 'beforeCreateHistogram', filter, params, options)
|
|
11
12
|
const result = (await this.driver._createHistogram(this, filter, params, options)) ?? {}
|
|
13
|
+
await execDynHook.call(this, 'afterCreateHistogram', filter, params, result, options)
|
|
12
14
|
await execModelHook.call(this, 'afterCreateHistogram', filter, params, result, options)
|
|
13
15
|
await execHook.call(this, 'afterCreateHistogram', filter, params, result, options)
|
|
14
16
|
return dataOnly ? result.data : result
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execValidation, execModelHook, getSingleRef, handleReq } from './_util.js'
|
|
1
|
+
import { getFilterAndOptions, execHook, execValidation, execModelHook, execDynHook, getSingleRef, handleReq } from './_util.js'
|
|
2
2
|
|
|
3
3
|
export const onlyTypes = ['datetime', 'date', 'time', 'timestamp']
|
|
4
4
|
const action = 'createRecord'
|
|
@@ -16,6 +16,7 @@ async function createRecord (...args) {
|
|
|
16
16
|
const input = noBodySanitizer ? cloneDeep(body) : await this.sanitizeBody({ body, extFields, strict: true, truncateString, onlyTypes })
|
|
17
17
|
await execHook.call(this, 'beforeCreateRecord', input, options)
|
|
18
18
|
await execModelHook.call(this, 'beforeCreateRecord', input, options)
|
|
19
|
+
await execDynHook.call(this, 'beforeCreateRecord', input, options)
|
|
19
20
|
if (!noValidation) await execValidation.call(this, input, options)
|
|
20
21
|
let result = options.record ?? (await this.driver._createRecord(this, input, options)) ?? {}
|
|
21
22
|
if (noResult) {
|
|
@@ -26,6 +27,7 @@ async function createRecord (...args) {
|
|
|
26
27
|
if (!noResultSanitizer) result.data = await this.sanitizeRecord(result.data, options)
|
|
27
28
|
if (isSet(options.refs)) await getSingleRef.call(this, result.data, options)
|
|
28
29
|
await handleReq.call(this, result.data.id, 'created', options)
|
|
30
|
+
await execDynHook.call(this, 'afterCreateRecord', input, result, options)
|
|
29
31
|
await execModelHook.call(this, 'afterCreateRecord', input, result, options)
|
|
30
32
|
await execHook.call(this, 'afterCreateRecord', input, result, options)
|
|
31
33
|
await runHook('cache:clear', this, 'create', body, result)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getMultiRefs, execHook, execModelHook, getFilterAndOptions } from './_util.js'
|
|
1
|
+
import { getMultiRefs, execHook, execModelHook, execDynHook, getFilterAndOptions } from './_util.js'
|
|
2
2
|
const action = 'findAllRecord'
|
|
3
3
|
|
|
4
4
|
async function native (filter, options, dataOnly) {
|
|
@@ -9,6 +9,7 @@ async function native (filter, options, dataOnly) {
|
|
|
9
9
|
if (!this.cacheable) noCache = true
|
|
10
10
|
await execHook.call(this, 'beforeFindAllRecord', filter, options)
|
|
11
11
|
await execModelHook.call(this, 'beforeFindAllRecord', filter, options)
|
|
12
|
+
await execDynHook.call(this, 'beforeFindAllRecord', filter, options)
|
|
12
13
|
if (get && !noCache && !options.record) {
|
|
13
14
|
const cachedResult = await get({ model: this.name, filter, options })
|
|
14
15
|
if (cachedResult) {
|
|
@@ -24,6 +25,7 @@ async function native (filter, options, dataOnly) {
|
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
if (isSet(options.refs)) await getMultiRefs.call(this, result.data, options)
|
|
28
|
+
await execDynHook.call(this, 'beforeCreateRecord', filter, result, options)
|
|
27
29
|
await execModelHook.call(this, 'afterFindAllRecord', filter, result, options)
|
|
28
30
|
await execHook.call(this, 'afterFindAllRecord', filter, result, options)
|
|
29
31
|
if (set && !noCache) await set({ model: this.name, filter, options, result })
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execModelHook, getMultiRefs } from './_util.js'
|
|
1
|
+
import { getFilterAndOptions, execHook, execModelHook, execDynHook, getMultiRefs } from './_util.js'
|
|
2
2
|
const action = 'findRecord'
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -87,6 +87,7 @@ async function findRecord (...args) {
|
|
|
87
87
|
}
|
|
88
88
|
await execHook.call(this, 'beforeFindRecord', filter, options)
|
|
89
89
|
await execModelHook.call(this, 'beforeFindRecord', filter, options)
|
|
90
|
+
await execDynHook.call(this, 'beforeFindRecord', filter, options)
|
|
90
91
|
const result = options.record ?? (await this.driver._findRecord(this, filter, options)) ?? {}
|
|
91
92
|
if (!noResultSanitizer) {
|
|
92
93
|
for (const idx in result.data) {
|
|
@@ -94,6 +95,7 @@ async function findRecord (...args) {
|
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
97
|
if (isSet(options.refs)) await getMultiRefs.call(this, result.data, options)
|
|
98
|
+
await execDynHook.call(this, 'afterFindRecord', filter, result, options)
|
|
97
99
|
await execModelHook.call(this, 'afterFindRecord', filter, result, options)
|
|
98
100
|
await execHook.call(this, 'afterFindRecord', filter, result, options)
|
|
99
101
|
if (!noCache) await runHook('cache:setByFilter', this, filter, result)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execModelHook, getSingleRef } from './_util.js'
|
|
1
|
+
import { getFilterAndOptions, execHook, execModelHook, execDynHook, getSingleRef } from './_util.js'
|
|
2
2
|
const action = 'getRecord'
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -55,6 +55,7 @@ async function getRecord (...args) {
|
|
|
55
55
|
id = this.sanitizeId(id)
|
|
56
56
|
await execHook.call(this, 'beforeGetRecord', id, options)
|
|
57
57
|
await execModelHook.call(this, 'beforeGetRecord', id, options)
|
|
58
|
+
await execDynHook.call(this, 'beforeGetRecord', id, options)
|
|
58
59
|
if (!noCache) {
|
|
59
60
|
try {
|
|
60
61
|
await runHook('cache:getById', this, id)
|
|
@@ -70,7 +71,8 @@ async function getRecord (...args) {
|
|
|
70
71
|
if (isEmpty(result.data) && !options.throwNotFound) return dataOnly ? undefined : { data: undefined }
|
|
71
72
|
if (!noResultSanitizer) result.data = await this.sanitizeRecord(result.data, options)
|
|
72
73
|
if (isSet(options.refs)) await getSingleRef.call(this, result.data, options)
|
|
73
|
-
await
|
|
74
|
+
await execDynHook.call(this, 'afterGetRecord', id, result, options)
|
|
75
|
+
await execModelHook.call(this, 'afterGetRecord', id, result, options)
|
|
74
76
|
await execHook.call(this, 'afterGetRecord', id, result, options)
|
|
75
77
|
if (!noCache) await runHook('cache:setById', this, id, result)
|
|
76
78
|
return dataOnly ? result.data : result
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execModelHook, getSingleRef, handleReq } from './_util.js'
|
|
1
|
+
import { getFilterAndOptions, execHook, execModelHook, execDynHook, getSingleRef, handleReq } from './_util.js'
|
|
2
2
|
const action = 'removeRecord'
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -42,6 +42,7 @@ async function removeRecord (...args) {
|
|
|
42
42
|
id = this.sanitizeId(id)
|
|
43
43
|
await execHook.call(this, 'beforeRemoveRecord', id, options)
|
|
44
44
|
await execModelHook.call(this, 'beforeRemoveRecord', id, options)
|
|
45
|
+
await execDynHook.call(this, 'beforeRemoveRecord', id, options)
|
|
45
46
|
const result = options.record ?? (await this.driver._removeRecord(this, id, options)) ?? {}
|
|
46
47
|
if (noResult) {
|
|
47
48
|
await runHook('cache:clear', this, 'remove', id)
|
|
@@ -50,6 +51,7 @@ async function removeRecord (...args) {
|
|
|
50
51
|
if (!noResultSanitizer) result.oldData = await this.sanitizeRecord(result.oldData, options)
|
|
51
52
|
if (isSet(options.refs)) await getSingleRef.call(this, result.data, options)
|
|
52
53
|
await handleReq.call(this, result.oldData.id, 'removed', options)
|
|
54
|
+
await execDynHook.call(this, 'afterRemoveRecord', id, result, options)
|
|
53
55
|
await execModelHook.call(this, 'afterRemoveRecord', id, result, options)
|
|
54
56
|
await execHook.call(this, 'afterRemoveRecord', id, result, options)
|
|
55
57
|
await runHook('cache:clear', this, 'remove', id, result)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execValidation, execModelHook, getSingleRef, handleReq } from './_util.js'
|
|
1
|
+
import { getFilterAndOptions, execHook, execValidation, execModelHook, execDynHook, getSingleRef, handleReq } from './_util.js'
|
|
2
2
|
import { onlyTypes } from './create-record.js'
|
|
3
3
|
const action = 'updateRecord'
|
|
4
4
|
|
|
@@ -60,6 +60,7 @@ async function updateRecord (...args) {
|
|
|
60
60
|
delete input.id
|
|
61
61
|
await execHook.call(this, 'beforeUpdateRecord', id, input, options)
|
|
62
62
|
await execModelHook.call(this, 'beforeUpdateRecord', id, input, options)
|
|
63
|
+
await execDynHook.call(this, 'beforeUpdateRecord', id, input, options)
|
|
63
64
|
if (!noValidation) await execValidation.call(this, input, options)
|
|
64
65
|
const result = options.record ?? (await this.driver._updateRecord(this, id, input, options)) ?? {}
|
|
65
66
|
if (noResult) {
|
|
@@ -72,6 +73,7 @@ async function updateRecord (...args) {
|
|
|
72
73
|
}
|
|
73
74
|
if (isSet(options.refs)) await getSingleRef.call(this, result.data, options)
|
|
74
75
|
await handleReq.call(this, result.data.id, 'updated', options)
|
|
76
|
+
await execDynHook.call(this, 'afterUpdateRecord', id, input, result, options)
|
|
75
77
|
await execModelHook.call(this, 'afterUpdateRecord', id, input, result, options)
|
|
76
78
|
await execHook.call(this, 'afterUpdateRecord', id, input, result, options)
|
|
77
79
|
await runHook('cache:clear', this, 'update', id, body, result)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execModelHook, execValidation, getSingleRef, handleReq } from './_util.js'
|
|
1
|
+
import { getFilterAndOptions, execHook, execModelHook, execDynHook, execValidation, getSingleRef, handleReq } from './_util.js'
|
|
2
2
|
const action = 'upsertRecord'
|
|
3
3
|
|
|
4
4
|
async function native (body = {}, opts = {}) {
|
|
@@ -13,6 +13,7 @@ async function native (body = {}, opts = {}) {
|
|
|
13
13
|
if (!noValidation) input = await execValidation.call(this, input, options)
|
|
14
14
|
await execHook.call(this, 'beforeUpsertRecord', input, options)
|
|
15
15
|
await execModelHook.call(this, 'beforeUpsertRecord', input, options)
|
|
16
|
+
await execDynHook.call(this, 'beforeUpsertRecord', input, options)
|
|
16
17
|
const result = options.record ?? (await this.driver._upsertRecord(this, input, options)) ?? {}
|
|
17
18
|
if (noResult) {
|
|
18
19
|
await runHook('cache:clear', this, 'upsert', body)
|
|
@@ -21,6 +22,7 @@ async function native (body = {}, opts = {}) {
|
|
|
21
22
|
if (!noResultSanitizer) result.data = await this.sanitizeRecord(result.data, options)
|
|
22
23
|
if (isSet(options.refs)) await getSingleRef.call(this, result.data, options)
|
|
23
24
|
await handleReq.call(this, result.data.id, 'upserted', options)
|
|
25
|
+
await execDynHook.call(this, 'afterUpsertRecord', input, result, options)
|
|
24
26
|
await execModelHook.call(this, 'afterUpsertRecord', input, result, options)
|
|
25
27
|
await execHook.call(this, 'afterUpsertRecord', input, result, options)
|
|
26
28
|
await runHook('cache:clear', this, 'upsert', body, result)
|
package/package.json
CHANGED
package/wiki/CHANGES.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 2026-01-24
|
|
4
|
+
|
|
5
|
+
- [2.3.0] Add ```dynHooks``` to model's options
|
|
6
|
+
- [2.3.0] Add ```dobo:unique``` feature
|
|
7
|
+
- [2.3.0] Add ```noWait``` handler for model's hook
|
|
8
|
+
|
|
9
|
+
## 2026-01-21
|
|
10
|
+
|
|
11
|
+
- [2.2.5] Add ```proto``` to ```connection.options```
|
|
12
|
+
|
|
3
13
|
## 2026-01-19
|
|
4
14
|
|
|
5
15
|
- [2.2.4] Bug fix on route ```dobo:/attachment/...```
|