dobo 2.31.0 → 2.32.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/.jsdoc.conf.json +1 -1
- package/docs/Dobo.html +1 -24
- package/docs/DoboAction.html +13 -0
- package/docs/DoboAdapter.html +3 -0
- package/docs/DoboConnection.html +3 -0
- package/docs/DoboFeature.html +3 -0
- package/docs/DoboModel.html +51 -0
- package/docs/data/search.json +1 -1
- package/docs/extend_bajo_hook-docs.js.html +241 -0
- package/docs/external-Tools.html +3 -0
- package/docs/global.html +1 -5
- package/docs/index.html +1 -1
- package/docs/index.js.html +434 -380
- package/docs/lib_factory_action.js.html +290 -0
- package/docs/lib_factory_adapter.js.html +1057 -0
- package/docs/lib_factory_connection.js.html +112 -0
- package/docs/lib_factory_feature.js.html +55 -0
- package/docs/lib_factory_model.js.html +503 -0
- package/docs/lib_factory_model_build.js.html +28 -0
- package/docs/lib_factory_model_clear-record.js.html +33 -0
- package/docs/lib_factory_model_count-record.js.html +45 -0
- package/docs/lib_factory_model_create-record.js.html +52 -0
- package/docs/lib_factory_model_drop.js.html +29 -0
- package/docs/lib_factory_model_exists.js.html +29 -0
- package/docs/lib_factory_model_find-all-record.js.html +115 -0
- package/docs/lib_factory_model_find-one-record.js.html +41 -0
- package/docs/lib_factory_model_find-record.js.html +85 -0
- package/docs/lib_factory_model_get-record.js.html +55 -0
- package/docs/lib_factory_model_helper.js.html +579 -0
- package/docs/lib_factory_model_remove-record.js.html +47 -0
- package/docs/lib_factory_model_sanitize-body.js.html +60 -0
- package/docs/lib_factory_model_sanitize-fixture.js.html +59 -0
- package/docs/lib_factory_model_sanitize-record.js.html +73 -0
- package/docs/lib_factory_model_update-record.js.html +61 -0
- package/docs/lib_factory_model_upsert-record.js.html +74 -0
- package/docs/{method_validate.js.html → lib_factory_model_validate.js.html} +109 -73
- package/docs/lib_helper.js.html +466 -0
- package/docs/module-Helper.html +3 -0
- package/docs/module-Helper_Model.html +3 -0
- package/docs/module-Hook.html +15 -0
- package/docs/scripts/core.js +477 -476
- package/docs/scripts/resize.js +36 -36
- package/docs/scripts/search.js +105 -105
- package/docs/scripts/third-party/fuse.js +1 -1
- package/docs/scripts/third-party/hljs-line-num-original.js +285 -282
- package/docs/scripts/third-party/hljs-line-num.js +1 -1
- package/docs/scripts/third-party/hljs-original.js +1202 -1195
- package/docs/scripts/third-party/hljs.js +1 -1
- package/docs/scripts/third-party/popper.js +1 -1
- package/docs/scripts/third-party/tippy.js +1 -1
- package/docs/scripts/third-party/tocbot.js +509 -508
- package/docs/static/home.md +3 -1
- package/extend/bajo/hook-docs.js +238 -0
- package/extend/bajo/intl/en-US.json +9 -9
- package/extend/bajo/intl/id.json +9 -9
- package/extend/bajoCli/applet/rebuild-model.js +2 -2
- package/extend/dobo/{driver → adapter}/memory.js +6 -6
- package/extend/dobo/feature/immutable.js +2 -2
- package/extend/dobo/feature/removed-at.js +1 -1
- package/index.js +33 -30
- package/lib/factory/action.js +145 -18
- package/lib/factory/adapter.js +1054 -0
- package/lib/factory/connection.js +46 -22
- package/lib/factory/feature.js +23 -3
- package/lib/factory/model/build.js +11 -2
- package/lib/factory/model/bulk-create-record.js +2 -2
- package/lib/factory/model/clear-record.js +13 -3
- package/lib/factory/model/count-record.js +13 -2
- package/lib/factory/model/create-aggregate.js +2 -2
- package/lib/factory/model/create-attachment.js +1 -1
- package/lib/factory/model/create-histogram.js +2 -2
- package/lib/factory/model/create-record.js +15 -2
- package/lib/factory/model/drop.js +12 -2
- package/lib/factory/model/exists.js +10 -6
- package/lib/factory/model/find-all-record.js +14 -3
- package/lib/factory/model/find-attachment.js +1 -1
- package/lib/factory/model/find-one-record.js +13 -1
- package/lib/factory/model/find-record.js +17 -53
- package/lib/factory/model/get-record.js +11 -39
- package/lib/factory/model/{_util.js → helper.js} +176 -16
- package/lib/factory/model/remove-attachment.js +1 -1
- package/lib/factory/model/remove-record.js +11 -28
- package/lib/factory/model/sanitize-body.js +14 -12
- package/lib/factory/model/sanitize-fixture.js +17 -4
- package/lib/factory/model/sanitize-record.js +9 -6
- package/lib/factory/model/transaction.js +2 -2
- package/lib/factory/model/update-record.js +12 -40
- package/lib/factory/model/upsert-record.js +13 -42
- package/lib/factory/model/validate.js +47 -14
- package/lib/factory/model.js +301 -23
- package/lib/{collect-models.js → helper.js} +463 -364
- package/package.json +1 -1
- package/wiki/CHANGES.md +13 -7
- package/wiki/ECOSYSTEM.md +7 -7
- package/wiki/GETTING-STARTED.md +3 -3
- package/wiki/QUERY-LANGUAGE.md +1 -1
- package/docs/lib_collect-connections.js.html +0 -39
- package/docs/lib_collect-drivers.js.html +0 -52
- package/docs/lib_collect-features.js.html +0 -36
- package/docs/lib_collect-schemas.js.html +0 -94
- package/docs/lib_index.js.html +0 -6
- package/docs/method_model_create.js.html +0 -35
- package/docs/method_model_drop.js.html +0 -34
- package/docs/method_model_exists.js.html +0 -40
- package/docs/method_record_count.js.html +0 -69
- package/docs/method_record_create.js.html +0 -114
- package/docs/method_record_find-all.js.html +0 -44
- package/docs/method_record_find-one.js.html +0 -73
- package/docs/method_record_find.js.html +0 -118
- package/docs/method_record_get.js.html +0 -92
- package/docs/method_record_remove.js.html +0 -75
- package/docs/method_record_update.js.html +0 -107
- package/docs/method_record_upsert.js.html +0 -54
- package/docs/method_sanitize_body.js.html +0 -88
- package/docs/method_sanitize_date.js.html +0 -30
- package/docs/method_sanitize_id.js.html +0 -20
- package/docs/module-Lib.html +0 -3
- package/lib/collect-connections.js +0 -56
- package/lib/collect-drivers.js +0 -35
- package/lib/collect-features.js +0 -40
- package/lib/factory/driver.js +0 -577
- package/lib/factory/model/sanitize-id.js +0 -7
- package/lib/index.js +0 -3
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Helper functions for model operations in the Dobo framework.
|
|
5
|
+
*
|
|
6
|
+
* @module Helper/Model
|
|
7
|
+
*/
|
|
4
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Clone options object and omit some keys to avoid reference issues
|
|
11
|
+
*
|
|
12
|
+
* @method
|
|
13
|
+
* @name cloneOptions
|
|
14
|
+
* @memberof module:Helper/Model
|
|
15
|
+
* @param {DoboModel.TOptions} [options={}]
|
|
16
|
+
* @returns {DoboModel.TOptions} Cloned options object
|
|
17
|
+
*/
|
|
5
18
|
export function cloneOptions (options = {}) {
|
|
6
19
|
const { cloneDeep, omit } = this.app.lib._
|
|
20
|
+
const omittedOptionsKeys = ['req', 'reply', 'trx']
|
|
7
21
|
const nOptions = cloneDeep(omit(options, omittedOptionsKeys))
|
|
8
22
|
for (const key of omittedOptionsKeys) {
|
|
9
23
|
nOptions[key] = options[key]
|
|
@@ -11,6 +25,16 @@ export function cloneOptions (options = {}) {
|
|
|
11
25
|
return nOptions
|
|
12
26
|
}
|
|
13
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Executes a hook function with the provided name and arguments.
|
|
30
|
+
* @async
|
|
31
|
+
* @memberof module:Helper/Model
|
|
32
|
+
* @method
|
|
33
|
+
* @name execHook
|
|
34
|
+
* @param {string} name - The name of the hook to execute.
|
|
35
|
+
* @param {...any} args - Arguments to pass to the hook function.
|
|
36
|
+
* @returns {Promise<void>}
|
|
37
|
+
*/
|
|
14
38
|
export async function execHook (name, ...args) {
|
|
15
39
|
const { runHook } = this.app.bajo
|
|
16
40
|
const { camelCase, last, kebabCase } = this.app.lib._
|
|
@@ -28,6 +52,16 @@ export async function execHook (name, ...args) {
|
|
|
28
52
|
}
|
|
29
53
|
}
|
|
30
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Executes a model hook function with the provided name and arguments.
|
|
57
|
+
* @async
|
|
58
|
+
* @memberof module:Helper/Model
|
|
59
|
+
* @method
|
|
60
|
+
* @name execModelHook
|
|
61
|
+
* @param {string} name - The name of the model hook to execute.
|
|
62
|
+
* @param {...any} args - Arguments to pass to the model hook function.
|
|
63
|
+
* @returns {Promise<void>}
|
|
64
|
+
*/
|
|
31
65
|
export async function execModelHook (name, ...args) {
|
|
32
66
|
const { last } = this.app.lib._
|
|
33
67
|
const { runModelHook } = this.app.dobo
|
|
@@ -35,6 +69,16 @@ export async function execModelHook (name, ...args) {
|
|
|
35
69
|
if (!noModelHook) await runModelHook(this, name, ...args)
|
|
36
70
|
}
|
|
37
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Executes a dynamic hook function with the provided name and arguments.
|
|
74
|
+
* @async
|
|
75
|
+
* @memberof module:Helper/Model
|
|
76
|
+
* @method
|
|
77
|
+
* @name execDynHook
|
|
78
|
+
* @param {string} name - The name of the dynamic hook to execute.
|
|
79
|
+
* @param {...any} args - Arguments to pass to the dynamic hook function.
|
|
80
|
+
* @returns {Promise<void>}
|
|
81
|
+
*/
|
|
38
82
|
export async function execDynHook (name, ...args) {
|
|
39
83
|
const { last, orderBy } = this.app.lib._
|
|
40
84
|
const opts = last(args)
|
|
@@ -49,6 +93,16 @@ export async function execDynHook (name, ...args) {
|
|
|
49
93
|
return results
|
|
50
94
|
}
|
|
51
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Executes validation on the provided body with the given options.
|
|
98
|
+
* @async
|
|
99
|
+
* @memberof module:Helper/Model
|
|
100
|
+
* @method
|
|
101
|
+
* @name execValidation
|
|
102
|
+
* @param {Object} body - The data to validate.
|
|
103
|
+
* @param {DoboModel.TOptions} [options={}] - Validation options.
|
|
104
|
+
* @returns {Promise<Object>} The result of the validation.
|
|
105
|
+
*/
|
|
52
106
|
export async function execValidation (body, options = {}) {
|
|
53
107
|
const { uniq } = this.app.lib._
|
|
54
108
|
const { validation = {} } = options
|
|
@@ -62,10 +116,15 @@ export async function execValidation (body, options = {}) {
|
|
|
62
116
|
}
|
|
63
117
|
|
|
64
118
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* @
|
|
68
|
-
* @
|
|
119
|
+
* Prepares and returns the filter and options for a given action.
|
|
120
|
+
* @async
|
|
121
|
+
* @memberof module:Helper/Model
|
|
122
|
+
* @method
|
|
123
|
+
* @name getFilterAndOptions
|
|
124
|
+
* @param {DoboModel.TFilter} filter - The filter criteria.
|
|
125
|
+
* @param {DoboModel.TOptions} options - The options for the action.
|
|
126
|
+
* @param {string} action - The action being performed.
|
|
127
|
+
* @returns {Promise<{filter: DoboModel.TFilter, options: DoboModel.TOptions}>} The prepared filter and options.
|
|
69
128
|
*/
|
|
70
129
|
export async function getFilterAndOptions (filter = {}, options = {}, action) {
|
|
71
130
|
const { cloneDeep } = this.app.lib._
|
|
@@ -100,6 +159,17 @@ export async function getFilterAndOptions (filter = {}, options = {}, action) {
|
|
|
100
159
|
return { filter: nFilter, options: nOptions }
|
|
101
160
|
}
|
|
102
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Handles a request for a given action trigger.
|
|
164
|
+
* @async
|
|
165
|
+
* @memberof module:Helper/Model
|
|
166
|
+
* @method
|
|
167
|
+
* @name handleReq
|
|
168
|
+
* @param {string|number} id - The ID of the record.
|
|
169
|
+
* @param {string} trigger - The action trigger (e.g., 'created', 'updated', 'removed').
|
|
170
|
+
* @param {DoboModel.TOptions} [options={}] - Additional options for handling the request.
|
|
171
|
+
* @returns {Promise<void>}
|
|
172
|
+
*/
|
|
103
173
|
export async function handleReq (id, trigger, options = {}) {
|
|
104
174
|
const { upperFirst } = this.app.lib._
|
|
105
175
|
if (options.req) {
|
|
@@ -108,6 +178,17 @@ export async function handleReq (id, trigger, options = {}) {
|
|
|
108
178
|
}
|
|
109
179
|
}
|
|
110
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Merges attachment information into the given record.
|
|
183
|
+
* @async
|
|
184
|
+
* @memberof module:Helper/Model
|
|
185
|
+
* @method
|
|
186
|
+
* @name mergeAttachmentInfo
|
|
187
|
+
* @param {Object} rec - The record to merge attachment info into.
|
|
188
|
+
* @param {string} source - The source file path of the attachment.
|
|
189
|
+
* @param {Object} options - Additional options including mimeType, stats, and fullPath.
|
|
190
|
+
* @returns {Promise<void>}
|
|
191
|
+
*/
|
|
111
192
|
export async function mergeAttachmentInfo (rec, source, options = {}) {
|
|
112
193
|
if (!this.app.waibu) return
|
|
113
194
|
const { mimeType, stats, fullPath } = options
|
|
@@ -124,6 +205,18 @@ export async function mergeAttachmentInfo (rec, source, options = {}) {
|
|
|
124
205
|
}
|
|
125
206
|
}
|
|
126
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Gets the attachment path for a given record and field.
|
|
210
|
+
* @async
|
|
211
|
+
* @memberof module:Helper/Model
|
|
212
|
+
* @method
|
|
213
|
+
* @name getAttachmentPath
|
|
214
|
+
* @param {string|number} id - The ID of the record.
|
|
215
|
+
* @param {string} field - The field name of the attachment.
|
|
216
|
+
* @param {string} file - The file name of the attachment.
|
|
217
|
+
* @param {Object} options - Additional options, including dirOnly.
|
|
218
|
+
* @returns {Promise<string>} The path to the attachment.
|
|
219
|
+
*/
|
|
127
220
|
export async function getAttachmentPath (id, field, file, options = {}) {
|
|
128
221
|
const { fs } = this.app.lib
|
|
129
222
|
const dir = `${this.app.getPluginDataDir(this.app.dobo.ns)}/attachment/${this.name}/${id}`
|
|
@@ -133,6 +226,16 @@ export async function getAttachmentPath (id, field, file, options = {}) {
|
|
|
133
226
|
return path
|
|
134
227
|
}
|
|
135
228
|
|
|
229
|
+
/**
|
|
230
|
+
* Copies attachments for a given record.
|
|
231
|
+
* @name copyAttachment
|
|
232
|
+
* @async
|
|
233
|
+
* @memberof module:Helper/Model
|
|
234
|
+
* @method
|
|
235
|
+
* @param {string|number} id - The ID of the record.
|
|
236
|
+
* @param {Object} options - Additional options for copying attachments.
|
|
237
|
+
* @returns {Promise<Array>} The copied attachment records.
|
|
238
|
+
*/
|
|
136
239
|
export async function copyAttachment (id, options = {}) {
|
|
137
240
|
if (!this.app.waibu) return
|
|
138
241
|
if (!this.options.attachment) return
|
|
@@ -157,6 +260,17 @@ export async function copyAttachment (id, options = {}) {
|
|
|
157
260
|
return result
|
|
158
261
|
}
|
|
159
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Handles attachment uploads for a given record and trigger.
|
|
265
|
+
* @async
|
|
266
|
+
* @memberof module:Helper/Model
|
|
267
|
+
* @method
|
|
268
|
+
* @name handleAttachmentUpload
|
|
269
|
+
* @param {string|number} id - The ID of the record.
|
|
270
|
+
* @param {string} trigger - The action trigger (e.g., 'added', 'removed').
|
|
271
|
+
* @param {Object} options - Additional options for handling the upload.
|
|
272
|
+
* @returns {Promise<void>}
|
|
273
|
+
*/
|
|
160
274
|
export async function handleAttachmentUpload (id, trigger, options = {}) {
|
|
161
275
|
if (!this.options.attachment) return
|
|
162
276
|
const { fs } = this.app.lib
|
|
@@ -169,6 +283,16 @@ export async function handleAttachmentUpload (id, trigger, options = {}) {
|
|
|
169
283
|
return copyAttachment.call(this, id, { req, mimeType, stats, setFile, setField })
|
|
170
284
|
}
|
|
171
285
|
|
|
286
|
+
/**
|
|
287
|
+
* Gets reference records for the given records.
|
|
288
|
+
* @async
|
|
289
|
+
* @memberof module:Helper/Model
|
|
290
|
+
* @method
|
|
291
|
+
* @name getRefs
|
|
292
|
+
* @param {Array<Object>} records - The records to get references for.
|
|
293
|
+
* @param {Object} options - Additional options for fetching references.
|
|
294
|
+
* @returns {Promise<void>}
|
|
295
|
+
*/
|
|
172
296
|
export async function getRefs (records = [], options = {}) {
|
|
173
297
|
const { isSet } = this.app.lib.aneka
|
|
174
298
|
const { uniq, without, get } = this.app.lib._
|
|
@@ -224,12 +348,29 @@ export async function getRefs (records = [], options = {}) {
|
|
|
224
348
|
}
|
|
225
349
|
}
|
|
226
350
|
|
|
351
|
+
/**
|
|
352
|
+
* Builds a sanitized filter query for the given filter.
|
|
353
|
+
* @memberof module:Helper/Model
|
|
354
|
+
* @method
|
|
355
|
+
* @name buildFilterQuery
|
|
356
|
+
* @param {Object} filter - The filter object containing query parameters.
|
|
357
|
+
* @returns {Object} The sanitized query object.
|
|
358
|
+
*/
|
|
227
359
|
export function buildFilterQuery (filter = {}) {
|
|
228
360
|
const { parseQuery } = this.app.dobo
|
|
229
361
|
const query = parseQuery(filter.query ?? {}, this, false)
|
|
230
362
|
return sanitizeQuery.call(this, query)
|
|
231
363
|
}
|
|
232
364
|
|
|
365
|
+
/**
|
|
366
|
+
* Sanitizes a query object by ensuring that its fields and values conform to the model's schema.
|
|
367
|
+
* @memberof module:Helper/Model
|
|
368
|
+
* @method
|
|
369
|
+
* @name sanitizeQuery
|
|
370
|
+
* @param {Object} query - The query object to sanitize.
|
|
371
|
+
* @param {string} parent - The parent field name, if applicable.
|
|
372
|
+
* @returns {Object} The sanitized query object.
|
|
373
|
+
*/
|
|
233
374
|
export function sanitizeQuery (query = {}, parent) {
|
|
234
375
|
const { isPlainObject, isArray, find, cloneDeep } = this.app.lib._
|
|
235
376
|
const { isSet } = this.app.lib.aneka
|
|
@@ -277,6 +418,14 @@ export function sanitizeQuery (query = {}, parent) {
|
|
|
277
418
|
return obj
|
|
278
419
|
}
|
|
279
420
|
|
|
421
|
+
/**
|
|
422
|
+
* Builds a search filter from the given filter object.
|
|
423
|
+
* @memberof module:Helper/Model
|
|
424
|
+
* @method
|
|
425
|
+
* @name buildFilterSearch
|
|
426
|
+
* @param {Object} filter - The filter object containing search parameters.
|
|
427
|
+
* @returns {Object} The constructed search filter.
|
|
428
|
+
*/
|
|
280
429
|
export function buildFilterSearch (filter = {}) {
|
|
281
430
|
const { isPlainObject, trim, has, uniq } = this.app.lib._
|
|
282
431
|
const search = filter.search ?? {}
|
|
@@ -315,8 +464,8 @@ export function buildFilterSearch (filter = {}) {
|
|
|
315
464
|
}
|
|
316
465
|
}
|
|
317
466
|
if (has(items, '*')) s['*'] = items['*']
|
|
318
|
-
if (this.
|
|
319
|
-
const search = JSON.stringify(s).replaceAll('"id"', `"${this.
|
|
467
|
+
if (this.adapter.idField.name !== 'id') {
|
|
468
|
+
const search = JSON.stringify(s).replaceAll('"id"', `"${this.adapter.idField.name}"`)
|
|
320
469
|
try {
|
|
321
470
|
s = JSON.parse(search)
|
|
322
471
|
} catch (err) {}
|
|
@@ -325,17 +474,19 @@ export function buildFilterSearch (filter = {}) {
|
|
|
325
474
|
}
|
|
326
475
|
|
|
327
476
|
/**
|
|
328
|
-
* Prepare
|
|
329
|
-
* -
|
|
330
|
-
* -
|
|
331
|
-
* -
|
|
332
|
-
* -
|
|
477
|
+
* Prepare pagination parameters for a query:
|
|
478
|
+
* - Ensures that the limit does not exceed the maximum allowed limit.
|
|
479
|
+
* - Ensures that the page number is within the allowed range.
|
|
480
|
+
* - Calculates the number of records to skip based on the page and limit.
|
|
481
|
+
* - Builds the sort order based on the provided sort input.
|
|
333
482
|
*
|
|
334
|
-
* @method
|
|
335
483
|
* @async
|
|
336
|
-
* @
|
|
337
|
-
* @
|
|
338
|
-
* @
|
|
484
|
+
* @memberof module:Helper/Model
|
|
485
|
+
* @method
|
|
486
|
+
* @name preparePagination
|
|
487
|
+
* @param {DoboModel.TFilter} filter - The filter object containing pagination parameters.
|
|
488
|
+
* @param {DoboModel.TOptions} options - Additional options for pagination.
|
|
489
|
+
* @returns {Object} The prepared pagination parameters including limit, page, skip, and sort.
|
|
339
490
|
*/
|
|
340
491
|
export function preparePagination (filter = {}, options = {}) {
|
|
341
492
|
const { isEmpty, map, each, isPlainObject, isString, trim, keys } = this.app.lib._
|
|
@@ -406,6 +557,15 @@ export function preparePagination (filter = {}, options = {}) {
|
|
|
406
557
|
return { limit, page, skip, sort }
|
|
407
558
|
}
|
|
408
559
|
|
|
560
|
+
/**
|
|
561
|
+
* Clears the cache for a specific record ID and related find operations.
|
|
562
|
+
* @async
|
|
563
|
+
* @memberof module:Helper/Model
|
|
564
|
+
* @method
|
|
565
|
+
* @name clearCache
|
|
566
|
+
* @param {string|number} id - The ID of the record for which to clear the cache.
|
|
567
|
+
* @returns {Promise<void>}
|
|
568
|
+
*/
|
|
409
569
|
export async function clearCache (id) {
|
|
410
570
|
const { clear } = this.app.bajoCache ?? {}
|
|
411
571
|
if (!clear) return
|
|
@@ -1,35 +1,18 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execModelHook, execDynHook, getRefs, handleReq, clearCache } from './
|
|
1
|
+
import { getFilterAndOptions, execHook, execModelHook, execDynHook, getRefs, handleReq, clearCache } from './helper.js'
|
|
2
2
|
const action = 'removeRecord'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
* @see Dobo#recordRemove
|
|
7
|
-
* @property {boolean} [dataOnly=true] - If ```true``` (default) returns deleted record. Otherwise {@link TRecordRemoveResult}
|
|
8
|
-
* @property {boolean} [noHook=false] - If ```true```, no model's hook will be executed
|
|
9
|
-
* @property {boolean} [noModelHook=false] - If ```true```, no model's feature hook will be executed
|
|
10
|
-
* @property {boolean} [noResult=false] - If ```true```, returns nothing
|
|
11
|
-
* @property {boolean} [fields=[]] - If not empty, return only these fields EXCLUDING hidden fields
|
|
12
|
-
* @property {boolean} [hidden=[]] - Additional fields to hide, in addition the one set in model's model
|
|
13
|
-
* @property {boolean} [forceNoHidden=false] - If ```true```, hidden fields will be ignored and ALL fields will be returned
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Remove existing record by it's ID. All attachments bound to this record will also be removed forever.
|
|
5
|
+
* Removes a record from the model's underlying data store based on the provided ID.
|
|
18
6
|
*
|
|
19
|
-
*
|
|
20
|
-
* ```javascript
|
|
21
|
-
* const { recordRemove } = this.app.dobo
|
|
22
|
-
* const result = await recordRemove('CdbCountry', 'ID')
|
|
23
|
-
* ```
|
|
24
|
-
*
|
|
25
|
-
* @method
|
|
26
|
-
* @memberof Model
|
|
7
|
+
* If no arguments are provided, it automatically turns into a chainable {@link DoboAction} object.
|
|
27
8
|
* @async
|
|
28
|
-
* @
|
|
29
|
-
* @
|
|
30
|
-
* @param
|
|
31
|
-
* @param
|
|
32
|
-
* @
|
|
9
|
+
* @memberof DoboModel
|
|
10
|
+
* @method
|
|
11
|
+
* @param {string|number} id - The ID of the record to be removed.
|
|
12
|
+
* @param {DoboModel.TOptions} [opts={}] - Options object.
|
|
13
|
+
* @see {@link module:Hook.beforeRemoveRecord}
|
|
14
|
+
* @see {@link module:Hook.afterRemoveRecord}
|
|
15
|
+
* @returns {DoboAction|DoboModel.TResultRemoveRecord|DoboModel.TRecord}
|
|
33
16
|
*/
|
|
34
17
|
async function removeRecord (...args) {
|
|
35
18
|
if (args.length === 0) return this.action(action, ...args)
|
|
@@ -44,7 +27,7 @@ async function removeRecord (...args) {
|
|
|
44
27
|
await execHook.call(this, 'beforeRemoveRecord', id, options)
|
|
45
28
|
await execModelHook.call(this, 'beforeRemoveRecord', id, options)
|
|
46
29
|
await execDynHook.call(this, 'beforeRemoveRecord', id, options)
|
|
47
|
-
const result = options.record ?? (await this.
|
|
30
|
+
const result = options.record ?? (await this.adapter._removeRecord(this, id, options)) ?? {}
|
|
48
31
|
if (noResult) return
|
|
49
32
|
await handleReq.call(this, result.oldData.id, 'removed', options)
|
|
50
33
|
await clearCache.call(this, id)
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Sanitize payload body
|
|
3
|
-
*
|
|
2
|
+
* Sanitize the payload body based on the model's properties and rules.
|
|
4
3
|
* @method
|
|
5
|
-
* @memberof
|
|
4
|
+
* @memberof DoboModel
|
|
6
5
|
* @async
|
|
7
|
-
* @param {Object} [options={}]
|
|
8
|
-
* @param {Object} [options.body={}]
|
|
9
|
-
* @param {
|
|
10
|
-
* @param {boolean} [options.
|
|
11
|
-
* @param {
|
|
12
|
-
* @param {
|
|
13
|
-
* @
|
|
6
|
+
* @param {Object} [options={}] - Options object
|
|
7
|
+
* @param {Object} [options.body={}] - Body object to sanitize
|
|
8
|
+
* @param {boolean} [options.partial=false] - If `true`, only the fields present in the body will be sanitized
|
|
9
|
+
* @param {boolean} [options.strict=false] - If `true`, only the fields defined in the model's properties will be included in the sanitized body
|
|
10
|
+
* @param {Array} [options.extFields=[]] - Additional fields to include in the sanitized body
|
|
11
|
+
* @param {boolean} [options.truncateString=false] - If `true`, string fields will be truncated to their maximum length defined in the model's properties
|
|
12
|
+
* @param {string} [options.action] - The action being performed (e.g., 'createRecord', 'updateRecord', etc.)
|
|
13
|
+
* @param {boolean} [options.allProps=false] - If `true`, all properties including virtual ones will be considered for sanitization
|
|
14
|
+
* @returns {Object} Returns sanitized body object
|
|
14
15
|
*/
|
|
15
|
-
async function sanitizeBody (
|
|
16
|
+
async function sanitizeBody (options = {}) {
|
|
17
|
+
const { body = {}, partial, strict, extFields = [], truncateString, action, allProps } = options
|
|
16
18
|
const { isSet } = this.app.lib.aneka
|
|
17
19
|
const { sanitizeByType } = this.app.dobo
|
|
18
20
|
const { omit, has } = this.app.lib._
|
|
@@ -39,7 +41,7 @@ async function sanitizeBody ({ body = {}, partial, strict, extFields = [], noDef
|
|
|
39
41
|
if (isSet(result[prop.name])) sanitize(prop.name, prop.type)
|
|
40
42
|
if (result[prop.name] === null) continue
|
|
41
43
|
if (truncateString && isSet(result[prop.name]) && ['string', 'text'].includes(prop.type)) result[prop.name] = result[prop.name].slice(0, prop.maxLength)
|
|
42
|
-
if (prop.name.endsWith('Id') && isSet(result[prop.name]) && prop.type === 'string' && ['smallint', 'integer'].includes(this.
|
|
44
|
+
if (prop.name.endsWith('Id') && isSet(result[prop.name]) && prop.type === 'string' && ['smallint', 'integer'].includes(this.adapter.idField.type)) result[prop.name] = result[prop.name] + ''
|
|
43
45
|
if (result[prop.name] === undefined) omitted.push(prop.name)
|
|
44
46
|
} catch (err) {
|
|
45
47
|
details.push({ field: prop.name, error: err.message, value: body[prop.name], ext: { type: prop.type } })
|
|
@@ -1,10 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Sanitize a fixture object by resolving lookup values and ensuring proper data types.
|
|
3
|
+
* @method
|
|
4
|
+
* @async
|
|
5
|
+
* @memberof DoboModel
|
|
6
|
+
* @param {Object} [params={}] - Parameters object
|
|
7
|
+
* @param {Object} [params.body={}] - Body object to sanitize
|
|
8
|
+
* @param {Object} [params.lookupValue={}] - Lookup values for resolving references in the body
|
|
9
|
+
* @param {boolean} [params.noLookup=false] - If `true`, skip lookup resolution
|
|
10
|
+
* @param {DoboModel.TOptions} [opts={}] - Options object for additional configurations
|
|
11
|
+
* @returns {Object} Returns sanitized body object
|
|
12
|
+
*/
|
|
13
|
+
async function sanitizeFixture (params = {}, opts = {}) {
|
|
14
|
+
const { body = {}, lookupValue = {}, noLookup } = params
|
|
2
15
|
const { isString, isArray, pullAt, cloneDeep } = this.app.lib._
|
|
3
16
|
const { isSet } = this.app.lib.aneka
|
|
4
17
|
const lv = cloneDeep(lookupValue)
|
|
5
18
|
const deleted = {}
|
|
6
|
-
const
|
|
7
|
-
...
|
|
19
|
+
const options = {
|
|
20
|
+
...opts,
|
|
8
21
|
noModelHook: false,
|
|
9
22
|
noHook: true,
|
|
10
23
|
noDynHook: true,
|
|
@@ -16,7 +29,7 @@ async function sanitizeFixture ({ body = {}, lookupValue = {}, noLookup } = {},
|
|
|
16
29
|
deleted[key] = deleted[key] ?? []
|
|
17
30
|
if (!noLookup) {
|
|
18
31
|
if (isString(val) && val.slice(0, 2) === '?:') {
|
|
19
|
-
body[key] = await this._simpleLookup(val.slice(2), lv,
|
|
32
|
+
body[key] = await this._simpleLookup(val.slice(2), lv, options)
|
|
20
33
|
lv[key] = body[key]
|
|
21
34
|
} else if (isArray(val)) {
|
|
22
35
|
for (const idx in val) {
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Sanitize record
|
|
3
|
-
*
|
|
2
|
+
* Sanitize a record object based on the model's properties and rules.
|
|
4
3
|
* @method
|
|
5
4
|
* @async
|
|
5
|
+
* @memberof DoboModel
|
|
6
6
|
* @param {Object} [record] - Record object
|
|
7
|
-
* @param {
|
|
8
|
-
* @param {
|
|
9
|
-
* @param {
|
|
10
|
-
* @
|
|
7
|
+
* @param {DoboModel.TOptions} [opts={}] - Options object
|
|
8
|
+
* @param {Array} [opts.fields] - If not empty, only these fields will be included in the sanitized record
|
|
9
|
+
* @param {Array<string>} [opts.hidden=[]] - List of fields to hide from the sanitized record
|
|
10
|
+
* @param {boolean} [opts.forceNoHidden=false] - If `true`, force ALL fields to be picked, thus ignoring hidden fields. If an array, force all fields except those in the array to be picked.
|
|
11
|
+
* @param {boolean} [opts.fmt=false] - If `true`, add a `_fmt` property to the sanitized record with formatted values automatically based on the model's properties and rules
|
|
12
|
+
* @param {Object} [opts.req] - Request object, used for formatting values based on request context
|
|
13
|
+
* @returns {Object} Returns sanitized record object
|
|
11
14
|
*/
|
|
12
15
|
async function sanitizeRecord (record = {}, opts = {}) {
|
|
13
16
|
const { fields = [], hidden = [], forceNoHidden } = opts
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
async function transaction (handler, ...args) {
|
|
2
|
-
if (!this.
|
|
2
|
+
if (!this.adapter.support.transaction) return handler.call(this)
|
|
3
3
|
|
|
4
4
|
const { ns } = this.app.dobo
|
|
5
5
|
const { camelCase } = this.app.lib._
|
|
6
6
|
const { runHook } = this.app.bajo
|
|
7
7
|
const name = 'afterTransaction'
|
|
8
|
-
const result = await this.
|
|
8
|
+
const result = await this.adapter.transaction(this, handler, ...args)
|
|
9
9
|
const [action, ...params] = args
|
|
10
10
|
await runHook(`${ns}:${name}`, this.name, action, result, ...params)
|
|
11
11
|
await runHook(`${ns}.${camelCase(this.name)}:${name}`, action, result, ...params)
|
|
@@ -1,48 +1,20 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execValidation, execModelHook, execDynHook, getRefs, handleReq, clearCache } from './
|
|
1
|
+
import { getFilterAndOptions, execHook, execValidation, execModelHook, execDynHook, getRefs, handleReq, clearCache } from './helper.js'
|
|
2
2
|
import { onlyTypes } from './create-record.js'
|
|
3
3
|
const action = 'updateRecord'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* @see Model#updateRecord
|
|
8
|
-
* @property {boolean} [dataOnly=true] - If ```true``` (default) returns record's object. Otherwise {@link TRecordUpdateResult}
|
|
9
|
-
* @property {boolean} [noHook=false] - If ```true```, no model's hook will be executed
|
|
10
|
-
* @property {boolean} [noModelHook=false] - If ```true```, no model's hook will be executed
|
|
11
|
-
* @property {boolean} [noValidation=false] - If ```true```, no validation of data payload performed
|
|
12
|
-
* @property {boolean} [noCheckUnique=false] - If ```true```, no unique validation for ID performed
|
|
13
|
-
* @property {boolean} [noBodySanitizer=false] - If ```true```, accept data payload as is without sanitization
|
|
14
|
-
* @property {boolean} [noRecordSanitizer=false] - If ```true```, accept result payload as is without sanitization
|
|
15
|
-
* @property {boolean} [noResult=false] - If ```true```, returns nothing
|
|
16
|
-
* @property {boolean} [truncateString=true] - If ```true``` (default), string is truncated to its model's ```maxLength```
|
|
17
|
-
* @property {boolean} [partial=true] - If ```true``` (default), only updated values are saved. Otherwise replace all existing values with given payload
|
|
18
|
-
* @property {boolean} [fields=[]] - If not empty, return only these fields EXCLUDING hidden fields
|
|
19
|
-
* @property {boolean} [hidden=[]] - Additional fields to hide, in addition the one set in model's model
|
|
20
|
-
* @property {boolean} [forceNoHidden=false] - If ```true```, hidden fields will be ignored and ALL fields will be returned
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Update a record by it's ID and body payload
|
|
6
|
+
* Updates an existing record in the model's underlying data store based on the provided ID and data.
|
|
25
7
|
*
|
|
26
|
-
*
|
|
27
|
-
* ```javascript
|
|
28
|
-
* const { recordUpdate } = this.app.dobo
|
|
29
|
-
* const { body } = {
|
|
30
|
-
* name: 'Republic of Indonesia',
|
|
31
|
-
* phoneCode: '+62'
|
|
32
|
-
* }
|
|
33
|
-
* const result = await recordUpdate('CdbCountry', 'ID', body)
|
|
34
|
-
* ```
|
|
35
|
-
*
|
|
36
|
-
* @method
|
|
37
|
-
* @memberof Dobo
|
|
8
|
+
* If no arguments are provided, it automatically turns into a chainable {@link DoboAction} object.
|
|
38
9
|
* @async
|
|
39
|
-
* @
|
|
40
|
-
* @
|
|
41
|
-
* @param
|
|
42
|
-
* @param
|
|
43
|
-
* @param
|
|
44
|
-
* @
|
|
45
|
-
* @
|
|
10
|
+
* @memberof DoboModel
|
|
11
|
+
* @method
|
|
12
|
+
* @param {string|number} id - The ID of the record to be updated.
|
|
13
|
+
* @param {object} body - The data to update the record with.
|
|
14
|
+
* @param {DoboModel.TOptions} [opts] - Options object.
|
|
15
|
+
* @see {@link module:Hook.beforeUpdateRecord}
|
|
16
|
+
* @see {@link module:Hook.afterUpdateRecord}
|
|
17
|
+
* @returns {DoboAction|DoboModel.TResultUpdateRecord|DoboModel.TRecord}
|
|
46
18
|
*/
|
|
47
19
|
async function updateRecord (...args) {
|
|
48
20
|
if (args.length === 0) return this.action(action, ...args)
|
|
@@ -66,7 +38,7 @@ async function updateRecord (...args) {
|
|
|
66
38
|
await execModelHook.call(this, 'beforeUpdateRecord', id, input, options)
|
|
67
39
|
await execDynHook.call(this, 'beforeUpdateRecord', id, input, options)
|
|
68
40
|
if (!noValidation) await execValidation.call(this, input, options)
|
|
69
|
-
const result = await this.
|
|
41
|
+
const result = await this.adapter._updateRecord(this, id, input, options)
|
|
70
42
|
if (noResult) return
|
|
71
43
|
await handleReq.call(this, result.data.id, 'updated', options)
|
|
72
44
|
await clearCache.call(this, id)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFilterAndOptions, execHook, execModelHook, execDynHook, execValidation, getRefs, handleReq, clearCache } from './
|
|
1
|
+
import { getFilterAndOptions, execHook, execModelHook, execDynHook, execValidation, getRefs, handleReq, clearCache } from './helper.js'
|
|
2
2
|
const action = 'upsertRecord'
|
|
3
3
|
|
|
4
4
|
async function native (body = {}, opts = {}) {
|
|
@@ -15,7 +15,7 @@ async function native (body = {}, opts = {}) {
|
|
|
15
15
|
await execHook.call(this, 'beforeUpsertRecord', input, options)
|
|
16
16
|
await execModelHook.call(this, 'beforeUpsertRecord', input, options)
|
|
17
17
|
await execDynHook.call(this, 'beforeUpsertRecord', input, options)
|
|
18
|
-
const result = options.record ?? (await this.
|
|
18
|
+
const result = options.record ?? (await this.adapter._upsertRecord(this, input, options)) ?? {}
|
|
19
19
|
if (noResult) return
|
|
20
20
|
await handleReq.call(this, result.data.id, 'upserted', options)
|
|
21
21
|
await clearCache.call(this, body.id)
|
|
@@ -36,7 +36,7 @@ async function manual (body = {}, options = {}) {
|
|
|
36
36
|
let old = false
|
|
37
37
|
if (isSet(body.id)) {
|
|
38
38
|
try {
|
|
39
|
-
old = await this.
|
|
39
|
+
old = await this.adapter._getRecord(this, body.id, { noHook: true, noModelHook: true })
|
|
40
40
|
} catch (err) {
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -46,51 +46,22 @@ async function manual (body = {}, options = {}) {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
50
|
-
* @see Model#updateRecord
|
|
51
|
-
* @property {boolean} [dataOnly=true] - If ```true``` (default) returns record's object. Otherwise {@link TRecordUpdateResult}
|
|
52
|
-
* @property {boolean} [noHook=false] - If ```true```, no model's hook will be executed
|
|
53
|
-
* @property {boolean} [noModelHook=false] - If ```true```, no model's hook will be executed
|
|
54
|
-
* @property {boolean} [noValidation=false] - If ```true```, no validation of data payload performed
|
|
55
|
-
* @property {boolean} [noCheckUnique=false] - If ```true```, no unique validation for ID performed
|
|
56
|
-
* @property {boolean} [noBodySanitizer=false] - If ```true```, accept data payload as is without sanitization
|
|
57
|
-
* @property {boolean} [noRecordSanitizer=false] - If ```true```, accept result payload as is without sanitization
|
|
58
|
-
* @property {boolean} [noResult=false] - If ```true```, returns nothing
|
|
59
|
-
* @property {boolean} [truncateString=true] - If ```true``` (default), string is truncated to its model's ```maxLength```
|
|
60
|
-
* @property {boolean} [partial=true] - If ```true``` (default), only updated values are saved. Otherwise replace all existing values with given payload
|
|
61
|
-
* @property {boolean} [fields=[]] - If not empty, return only these fields EXCLUDING hidden fields
|
|
62
|
-
* @property {boolean} [hidden=[]] - Additional fields to hide, in addition the one set in model's model
|
|
63
|
-
* @property {boolean} [forceNoHidden=false] - If ```true```, hidden fields will be ignored and ALL fields will be returned
|
|
64
|
-
*/
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Update a record by it's ID and body payload
|
|
49
|
+
* Upserts a record in the model's underlying data store. If a record with the specified ID exists, it updates that record; otherwise, it creates a new record.
|
|
68
50
|
*
|
|
69
|
-
*
|
|
70
|
-
* ```javascript
|
|
71
|
-
* const { recordUpdate } = this.app.dobo
|
|
72
|
-
* const { body } = {
|
|
73
|
-
* name: 'Republic of Indonesia',
|
|
74
|
-
* phoneCode: '+62'
|
|
75
|
-
* }
|
|
76
|
-
* const result = await recordUpdate('CdbCountry', 'ID', body)
|
|
77
|
-
* ```
|
|
78
|
-
*
|
|
79
|
-
* @method
|
|
80
|
-
* @memberof Dobo
|
|
51
|
+
* If no arguments are provided, it automatically turns into a chainable {@link DoboAction} object.
|
|
81
52
|
* @async
|
|
82
|
-
* @
|
|
83
|
-
* @
|
|
84
|
-
* @param
|
|
85
|
-
* @param
|
|
86
|
-
* @
|
|
87
|
-
* @
|
|
88
|
-
* @returns {
|
|
53
|
+
* @memberof DoboModel
|
|
54
|
+
* @method
|
|
55
|
+
* @param {object} body - The data for the record to be upserted.
|
|
56
|
+
* @param {DoboModel.TOptions} [opts] - Options object.
|
|
57
|
+
* @see {@link module:Hook.beforeUpsertRecord}
|
|
58
|
+
* @see {@link module:Hook.afterUpsertRecord}
|
|
59
|
+
* @returns {DoboAction|DoboModel.TResultCreateRecord|DoboModel.TResultUpdateRecord|DoboModel.TRecord}
|
|
89
60
|
*/
|
|
90
61
|
async function upsertRecord (...args) {
|
|
91
62
|
if (args.length === 0) return this.action(action, ...args)
|
|
92
63
|
const [body = {}, opts = {}] = args
|
|
93
|
-
if (this.
|
|
64
|
+
if (this.adapter.upsertRecord) {
|
|
94
65
|
const { options } = await getFilterAndOptions.call(this, null, opts, action)
|
|
95
66
|
return await native.call(this, body, options)
|
|
96
67
|
}
|