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
|
@@ -4,7 +4,9 @@ const excludedTypes = ['object']
|
|
|
4
4
|
const excludedNames = []
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
+
* List of available string validators to check against model's properties and rules
|
|
7
8
|
* @typedef {string[]} TValidatorString
|
|
9
|
+
* @memberof DoboModel
|
|
8
10
|
* @property {string} 0=alphanum
|
|
9
11
|
* @property {string} 1=base64
|
|
10
12
|
* @property {string} 2=case
|
|
@@ -35,7 +37,9 @@ const excludedNames = []
|
|
|
35
37
|
*/
|
|
36
38
|
|
|
37
39
|
/**
|
|
40
|
+
* List of available number validators to check against model's properties and rules
|
|
38
41
|
* @typedef {string[]} TValidatorNumber
|
|
42
|
+
* @memberof DoboModel
|
|
39
43
|
* @property {string} 0=great
|
|
40
44
|
* @property {string} 1=less
|
|
41
45
|
* @property {string} 2=max
|
|
@@ -49,33 +53,51 @@ const excludedNames = []
|
|
|
49
53
|
*/
|
|
50
54
|
|
|
51
55
|
/**
|
|
56
|
+
* List of available boolean validators to check against model's properties and rules
|
|
52
57
|
* @typedef {string[]} TValidatorBoolean
|
|
58
|
+
* @memberof DoboModel
|
|
53
59
|
* @property {string} 0=falsy
|
|
54
60
|
* @property {string} 1=sensitive
|
|
55
61
|
* @property {string} 2=truthy
|
|
56
62
|
*/
|
|
57
63
|
|
|
58
64
|
/**
|
|
65
|
+
* List of available date validators to check against model's properties and rules
|
|
59
66
|
* @typedef {string[]} TValidatorDate
|
|
67
|
+
* @memberof DoboModel
|
|
60
68
|
* @property {string} 0=greater
|
|
61
69
|
* @property {string} 1=iso
|
|
62
70
|
* @property {string} 2=less
|
|
63
|
-
* @property {string}
|
|
64
|
-
* @property {string}
|
|
71
|
+
* @property {string} 3=max
|
|
72
|
+
* @property {string} 4=min
|
|
65
73
|
*/
|
|
66
74
|
|
|
67
75
|
/**
|
|
76
|
+
* List of available timestamp validators to check against model's properties and rules
|
|
68
77
|
* @typedef {string[]} TValidatorTimestamp
|
|
78
|
+
* @memberof DoboModel
|
|
69
79
|
* @property {string} 0=timestamp
|
|
70
80
|
*/
|
|
71
81
|
|
|
72
82
|
/**
|
|
83
|
+
* All available validators to check against model's properties and rules
|
|
73
84
|
* @typedef {Object} TValidator
|
|
85
|
+
* @memberof DoboModel
|
|
74
86
|
* @property {TValidatorString} string
|
|
75
87
|
* @property {TValidatorNumber} number
|
|
76
88
|
* @property {TValidatorBoolean} boolean
|
|
77
89
|
* @property {TValidatorDate} date
|
|
78
90
|
* @property {TValidatorTimestamp} timestamp
|
|
91
|
+
* @property {TValidatorArray} array
|
|
92
|
+
*/
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* List of available array validators to check against model's properties and rules
|
|
96
|
+
* @typedef {string[]} TValidatorArray
|
|
97
|
+
* @memberof DoboModel
|
|
98
|
+
* @property {string} 0=length
|
|
99
|
+
* @property {string} 1=max
|
|
100
|
+
* @property {string} 2=min
|
|
79
101
|
*/
|
|
80
102
|
const validator = {
|
|
81
103
|
string: ['alphanum', 'base64', 'case', 'creditCard', 'dataUri', 'domain', 'email', 'guid',
|
|
@@ -90,9 +112,21 @@ const validator = {
|
|
|
90
112
|
array: ['length', 'max', 'min']
|
|
91
113
|
}
|
|
92
114
|
|
|
93
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Build JOI model from database model's properties and rules
|
|
117
|
+
* @method
|
|
118
|
+
* @memberof DoboModel
|
|
119
|
+
* @async
|
|
120
|
+
* @param {object} [options={}] - Options object
|
|
121
|
+
* @param {Array} [options.fields=[]] - If not empty, only these fields will be included in the JOI model
|
|
122
|
+
* @param {object} [options.rule={}] - Custom rules to override model's rules
|
|
123
|
+
* @param {Array} [options.extFields=[]] - Additional fields to include in the JOI model
|
|
124
|
+
* @param {boolean} [options.partial=false] - If `true`, only the fields present in the body will be validated
|
|
125
|
+
* @returns {object|boolean} Returns JOI model object or `false` if no properties to validate
|
|
126
|
+
*/
|
|
127
|
+
async function buildFromDbModel (options = {}) {
|
|
94
128
|
const { isPlainObject, get, isEmpty, isString, keys, find, has, without } = this.app.lib._
|
|
95
|
-
const { fields = [], rule = {}, extFields = [] } =
|
|
129
|
+
const { fields = [], rule = {}, extFields = [] } = options
|
|
96
130
|
const obj = {}
|
|
97
131
|
const { propertyType: propType } = this.app.baseClass.Dobo
|
|
98
132
|
const refs = []
|
|
@@ -137,7 +171,7 @@ async function buildFromDbModel (opts = {}) {
|
|
|
137
171
|
}
|
|
138
172
|
if (!['id'].includes(prop.name) && prop.required) obj = obj.required()
|
|
139
173
|
if (prop.values) {
|
|
140
|
-
const values = await me.buildPropValues(prop,
|
|
174
|
+
const values = await me.buildPropValues(prop, options)
|
|
141
175
|
const items = values.map(item => item.value)
|
|
142
176
|
if (prop.type === 'array') {
|
|
143
177
|
obj = obj.items(joi.string().valid(...items))
|
|
@@ -156,7 +190,7 @@ async function buildFromDbModel (opts = {}) {
|
|
|
156
190
|
const props = [...this.properties, ...extFields]
|
|
157
191
|
for (const p of props) {
|
|
158
192
|
if (excludedTypes.includes(p.type) || excludedNames.includes(p.name)) continue
|
|
159
|
-
if (
|
|
193
|
+
if (options.partial && fields.length > 0 && !fields.includes(p.name)) continue
|
|
160
194
|
let item
|
|
161
195
|
switch (p.type) {
|
|
162
196
|
case 'text':
|
|
@@ -213,28 +247,27 @@ async function buildFromDbModel (opts = {}) {
|
|
|
213
247
|
}
|
|
214
248
|
|
|
215
249
|
/**
|
|
216
|
-
* Validate
|
|
250
|
+
* Validate body object against JOI model
|
|
217
251
|
*
|
|
218
252
|
* @method
|
|
219
|
-
* @memberof
|
|
253
|
+
* @memberof DoboModel
|
|
220
254
|
* @async
|
|
221
|
-
* @param {Object}
|
|
255
|
+
* @param {Object} body - Body object to validate
|
|
222
256
|
* @param {Object} joiModel - JOI model
|
|
223
257
|
* @param {Object} [options={}] - Options object
|
|
224
|
-
* @param {string} [options.ns=dobo] - Scope's namespace
|
|
225
|
-
* @param {Array} [options.fields=[]]
|
|
226
258
|
* @param {Array} [options.extFields=[]]
|
|
259
|
+
* @param {boolean} [options.partial=false] - If `true`, only the fields present in the body will be validated
|
|
227
260
|
* @param {Object} [options.params={}] - Validation parameters. See {@tutorial config} and {@link https://joi.dev/api/?v=17.13.3#anyvalidateasyncvalue-options|JOI validate's options}
|
|
228
261
|
* @returns {Object}
|
|
229
262
|
*/
|
|
230
|
-
async function validate (body, joiModel,
|
|
263
|
+
async function validate (body, joiModel, options = {}) {
|
|
231
264
|
const { defaultsDeep } = this.app.lib.aneka
|
|
232
265
|
const { isEmpty } = this.app.lib._
|
|
233
|
-
let { extFields = [], params = {}, partial } =
|
|
266
|
+
let { extFields = [], params = {}, partial } = options
|
|
234
267
|
params = defaultsDeep(params, this.app.dobo.config.validationParams)
|
|
235
268
|
const { rule = {} } = params
|
|
236
269
|
delete params.rule
|
|
237
|
-
const fields = partial ? Object.keys(body) : [...
|
|
270
|
+
const fields = partial ? Object.keys(body) : [...options.fields]
|
|
238
271
|
if (isEmpty(joiModel)) joiModel = await buildFromDbModel.call(this, { fields, rule, extFields, partial })
|
|
239
272
|
if (!joiModel) return { value: body }
|
|
240
273
|
try {
|
package/lib/factory/model.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sanitizeAll, sanitizeRef } from '../
|
|
1
|
+
import { sanitizeAll, sanitizeRef } from '../helper.js'
|
|
2
2
|
import clearRecord from './model/clear-record.js'
|
|
3
3
|
import countRecord from './model/count-record.js'
|
|
4
4
|
import createRecord from './model/create-record.js'
|
|
@@ -21,7 +21,6 @@ import removeAttachment from './model/remove-attachment.js'
|
|
|
21
21
|
import findAttachment from './model/find-attachment.js'
|
|
22
22
|
import sanitizeBody from './model/sanitize-body.js'
|
|
23
23
|
import sanitizeRecord from './model/sanitize-record.js'
|
|
24
|
-
import sanitizeId from './model/sanitize-id.js'
|
|
25
24
|
import sanitizeFixture from './model/sanitize-fixture.js'
|
|
26
25
|
import upsertRecord from './model/upsert-record.js'
|
|
27
26
|
import bulkCreateRecord from './model/bulk-create-record.js'
|
|
@@ -30,51 +29,239 @@ import transaction from './model/transaction.js'
|
|
|
30
29
|
import validate from './model/validate.js'
|
|
31
30
|
|
|
32
31
|
/**
|
|
33
|
-
* @typedef {
|
|
32
|
+
* @typedef {Object} TOptions
|
|
33
|
+
* @memberof DoboModel
|
|
34
|
+
* @type {Object}
|
|
35
|
+
* @property {boolean} [noHook=false] - If `true`, no model's hook will be executed
|
|
36
|
+
* @property {boolean} [noModelHook=false] - If `true`, no model's hook will be executed
|
|
37
|
+
* @property {boolean} [noDynHook=false] - If `true`, no dynamic hook will be executed
|
|
38
|
+
* @property {boolean} [noValidation=false] - If `true`, no validation of data payload performed
|
|
39
|
+
* @property {boolean} [noCheckUnique=false] - If `true`, no unique validation for ID performed
|
|
40
|
+
* @property {boolean} [noBodySanitizer=false] - If `true`, accept data payload as is without sanitization
|
|
41
|
+
* @property {boolean} [noRecordSanitizer=false] - If `true`, accept result payload as is without sanitization
|
|
42
|
+
* @property {boolean} [noResult=false] - If `true`, returns nothing
|
|
43
|
+
* @property {boolean} [truncateString=true] - If `true` (default), string is truncated to its model's `maxLength`
|
|
44
|
+
* @property {boolean} [partial] - If `true`, only updated values are saved. Otherwise replace all existing values with given payload. Defaults to `true` for `updateRecord`
|
|
45
|
+
* @property {boolean} [dataOnly=true] - If `true` (default) returns only record's object. Otherwise {@link DoboModel.TResult}
|
|
34
46
|
*/
|
|
35
47
|
|
|
36
48
|
/**
|
|
37
|
-
*
|
|
38
|
-
* -
|
|
39
|
-
* -
|
|
49
|
+
* Sort order key used in pagination and sorting of records. It can be either:
|
|
50
|
+
* - `1` for ascending order (the default, if none is provided) or
|
|
51
|
+
* - `-1` for descending order.
|
|
52
|
+
* @typedef {string} TSortOrder
|
|
53
|
+
* @memberof DoboModel
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Key value pairs used as sort order in pagination and sorting of records. It is an object where:
|
|
58
|
+
* - Key represents model's field name
|
|
59
|
+
* - Value represents its sort order
|
|
40
60
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
61
|
+
* @typedef {Object.<string, DoboModel.TSortOrder>} TSort
|
|
62
|
+
* @memberof DoboModel
|
|
63
|
+
* @example
|
|
64
|
+
* // to sort by firstName (ascending) and lastName (descending)
|
|
43
65
|
* const sort = {
|
|
44
66
|
* firstName: 1,
|
|
45
67
|
* lastName: -1
|
|
46
68
|
* }
|
|
47
|
-
* ```
|
|
48
|
-
*
|
|
49
|
-
* @typedef {Object.<string, TRecordSortKey>} TRecordSort
|
|
50
69
|
*/
|
|
51
70
|
|
|
52
71
|
/**
|
|
53
|
-
* @typedef {Object}
|
|
72
|
+
* @typedef {Object} TPagination
|
|
73
|
+
* @memberof DoboModel
|
|
54
74
|
* @property {number} limit - Number of records per page
|
|
55
75
|
* @property {number} page - Page number
|
|
56
|
-
* @property {number} skip - Records to skip
|
|
57
|
-
|
|
76
|
+
* @property {number} [skip] - Records to skip. If not provided, it will be calculated based on `limit` and `page`
|
|
77
|
+
*/
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Property value type definition. Used for building property `values` in a model which is an array of this object type.
|
|
81
|
+
* @typedef TPropertyValue
|
|
82
|
+
* @memberof DoboModel
|
|
83
|
+
* @type {Object}
|
|
84
|
+
* @property {string} value - The actual value of the property
|
|
85
|
+
* @property {string} text - The display text for the property value, which can be translated based on the request context
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Formatted version of a record's property values. It is an object where:
|
|
90
|
+
* - Key represents the property name
|
|
91
|
+
* - Value represents its formatted value according to the property's data type or formatting function. Data type is ALWAYS in string.
|
|
92
|
+
*
|
|
93
|
+
* This record is then wrapped in a `_fmt` property.
|
|
94
|
+
* @typedef TRecordFormatted
|
|
95
|
+
* @memberof DoboModel
|
|
96
|
+
* @type {Object}
|
|
97
|
+
* @property {Object} [_fmt={}] - Wrapper
|
|
98
|
+
* @example
|
|
99
|
+
* {
|
|
100
|
+
* _fmt: {
|
|
101
|
+
* id: "1",
|
|
102
|
+
* item: "Laptop",
|
|
103
|
+
* createdAt: "Jan 1, 2024, 12:00 AM",
|
|
104
|
+
* isActive: "True",
|
|
105
|
+
* price: "2,500.00"
|
|
106
|
+
* }
|
|
107
|
+
* }
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Reference record related to a record's result. It is an object where:
|
|
112
|
+
* - Key represents the name of the referenced record. Normally, it is the referenced model's name in camelCase format.
|
|
113
|
+
* - Value represents its reference record. It can be an object or an array of objects, depending on the relationship type.
|
|
114
|
+
*
|
|
115
|
+
* This record is then wrapped in a `_ref` property in the result object.
|
|
116
|
+
* @typedef TRecordRef
|
|
117
|
+
* @memberof DoboModel
|
|
118
|
+
* @type {Object}
|
|
119
|
+
* @property {Object} [_ref={}] - Wrapper
|
|
120
|
+
* @property {Object|Array} [_ref.<string>.<DoboModel.TRecord>] - Reference record
|
|
121
|
+
* @example
|
|
122
|
+
* {
|
|
123
|
+
* _ref: {
|
|
124
|
+
* user: {
|
|
125
|
+
* id: 1,
|
|
126
|
+
* name: "John Doe"
|
|
127
|
+
* },
|
|
128
|
+
* posts: [
|
|
129
|
+
* {
|
|
130
|
+
* id: 1,
|
|
131
|
+
* title: "Post Title"
|
|
132
|
+
* },
|
|
133
|
+
* {
|
|
134
|
+
* id: 2,
|
|
135
|
+
* title: "Another Post Title"
|
|
136
|
+
* }
|
|
137
|
+
* ]
|
|
138
|
+
* }
|
|
139
|
+
* }
|
|
140
|
+
*/
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The record returned from a model's action. It is an object where:
|
|
144
|
+
* - Key represents the property name
|
|
145
|
+
* - Value represents its value according to the property's data type
|
|
146
|
+
*
|
|
147
|
+
* This record is then merged with {@link DoboModel.TRecordFormatted} and {@link DoboModel.TRecordRef} to form the final record returned from a model's action.
|
|
148
|
+
* @typedef TRecord
|
|
149
|
+
* @memberof DoboModel
|
|
150
|
+
* @type {Object & DoboModel.TRecordFormatted & DoboModel.TRecordRef}
|
|
151
|
+
* @example
|
|
152
|
+
* {
|
|
153
|
+
* id: 1,
|
|
154
|
+
* item: "Laptop",
|
|
155
|
+
* createdAt: "2024-01-01T00:00:00.000Z",
|
|
156
|
+
* isActive: true,
|
|
157
|
+
* price: 2500.00,
|
|
158
|
+
* _fmt: {
|
|
159
|
+
* id: "1",
|
|
160
|
+
* item: "Laptop",
|
|
161
|
+
* createdAt: "Jan 1, 2024, 12:00 AM",
|
|
162
|
+
* isActive: "True",
|
|
163
|
+
* price: "2,500.00"
|
|
164
|
+
* },
|
|
165
|
+
* _ref: {
|
|
166
|
+
* user: {
|
|
167
|
+
* id: 1,
|
|
168
|
+
* name: "John Doe"
|
|
169
|
+
* }
|
|
170
|
+
* }
|
|
171
|
+
* }
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* The result returned from a model's action other than `find*`, `{create|update|remove}Record` if `dataOnly` is set to `false`.
|
|
176
|
+
* @typedef TResultRecord
|
|
177
|
+
* @memberof DoboModel
|
|
178
|
+
* @type {Object}
|
|
179
|
+
* @property {Array<DoboModel.TRecord>} data - The data returned from the action
|
|
180
|
+
*/
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* The result returned from a model's `find*` actions if `dataOnly` is set to `false`.
|
|
184
|
+
* @typedef TResultFindRecord
|
|
185
|
+
* @memberof DoboModel
|
|
186
|
+
* @type {Object}
|
|
187
|
+
* @property {Array<DoboModel.TRecord>} data - The data returned from the action
|
|
188
|
+
* @property {number} [count] - The total number of records found, if applicable
|
|
189
|
+
* @property {boolean} [cached] - Indicates if the result was retrieved from cache, if applicable. Only available if `bajoCache` is used
|
|
190
|
+
* @property {Array} [warnings] - Any warnings generated during the action, if applicable
|
|
191
|
+
*/
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* The result returned from a model's `getRecord` action if `dataOnly` is set to `false`.
|
|
195
|
+
* @typedef TResultGetRecord
|
|
196
|
+
* @memberof DoboModel
|
|
197
|
+
* @type {Object}
|
|
198
|
+
* @property {DoboModel.TRecord} data - The data returned from the action
|
|
199
|
+
*/
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* The result returned from a model's `createRecord` action if `dataOnly` is set to `false`.
|
|
203
|
+
* @typedef TResultCreateRecord
|
|
204
|
+
* @memberof DoboModel
|
|
205
|
+
* @type {Object}
|
|
206
|
+
* @property {DoboModel.TRecord} data - The data returned from the action
|
|
207
|
+
*/
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* The result returned from a model's `updateRecord` action if `dataOnly` is set to `false`.
|
|
211
|
+
* @typedef TResultUpdateRecord
|
|
212
|
+
* @memberof DoboModel
|
|
213
|
+
* @type {Object}
|
|
214
|
+
* @property {DoboModel.TRecord} data - The updated data returned from the action
|
|
215
|
+
* @property {DoboModel.TRecord} oldData - The previous data before the update
|
|
216
|
+
*/
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* The result returned from a model's `removeRecord` action if `dataOnly` is set to `false`.
|
|
220
|
+
* @typedef TResultRemoveRecord
|
|
221
|
+
* @memberof DoboModel
|
|
222
|
+
* @type {Object}
|
|
223
|
+
* @property {DoboModel.TRecord} oldData - The removed data returned from the action
|
|
58
224
|
*/
|
|
59
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Model factory.
|
|
228
|
+
*
|
|
229
|
+
* @async
|
|
230
|
+
* @returns {Promise<void>} Returns nothing
|
|
231
|
+
*/
|
|
60
232
|
async function modelFactory () {
|
|
61
233
|
const { Tools } = this.app.baseClass
|
|
62
234
|
const { defaults } = this.app.lib._
|
|
63
235
|
|
|
64
236
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* ```this.plugin``` should be the one who owned this driver
|
|
237
|
+
* Model class defintion.
|
|
68
238
|
*
|
|
69
239
|
* @class
|
|
70
240
|
*/
|
|
71
241
|
class DoboModel extends Tools {
|
|
242
|
+
/**
|
|
243
|
+
* Constructor
|
|
244
|
+
*/
|
|
72
245
|
constructor (plugin, options) {
|
|
73
246
|
super(plugin)
|
|
247
|
+
|
|
74
248
|
defaults(this, options)
|
|
75
|
-
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Model's adapter name
|
|
252
|
+
* @type {string}
|
|
253
|
+
*/
|
|
254
|
+
this.adapter = this.connection.adapter
|
|
76
255
|
}
|
|
77
256
|
|
|
257
|
+
/**
|
|
258
|
+
* Invoke a model's action. It will create a new instance of {@link DoboAction} and return it.
|
|
259
|
+
* @method
|
|
260
|
+
* @memberof DoboModel
|
|
261
|
+
* @param {string} name - The name of the action to invoke
|
|
262
|
+
* @param {...any} args - Arguments to pass to the action
|
|
263
|
+
* @returns {DoboAction} Returns an instance of {@link DoboAction}
|
|
264
|
+
*/
|
|
78
265
|
action = (name, ...args) => {
|
|
79
266
|
const action = new this.app.baseClass.DoboAction(this, name, ...args)
|
|
80
267
|
return action
|
|
@@ -84,47 +271,123 @@ async function modelFactory () {
|
|
|
84
271
|
await sanitizeAll.call(this.app.dobo, obj)
|
|
85
272
|
}
|
|
86
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Sanitize a reference object based on the model's properties and rules.
|
|
276
|
+
* @method
|
|
277
|
+
* @memberof DoboModel
|
|
278
|
+
* @async
|
|
279
|
+
* @param {*} obj - The reference object to sanitize
|
|
280
|
+
* @param {boolean} [fatal=true] - Whether to throw an error if sanitization fails
|
|
281
|
+
*/
|
|
87
282
|
sanitizeRef = async (obj, fatal = true) => {
|
|
88
283
|
await sanitizeRef.call(this.app.dobo, obj, this.app.dobo.models, fatal)
|
|
89
284
|
}
|
|
90
285
|
|
|
286
|
+
/**
|
|
287
|
+
* Sanitize the given ID based on the model's properties.
|
|
288
|
+
* @method
|
|
289
|
+
* @memberof DoboModel
|
|
290
|
+
* @param {string|number} id - The ID to sanitize
|
|
291
|
+
* @returns {string|number} Returns the sanitized ID
|
|
292
|
+
*/
|
|
293
|
+
sanitizeId = (id) => {
|
|
294
|
+
const prop = this.properties.find(p => p.name === 'id')
|
|
295
|
+
if (prop.type === 'integer') id = parseInt(id)
|
|
296
|
+
return id
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Get a property by its name.
|
|
301
|
+
* @method
|
|
302
|
+
* @memberof DoboModel
|
|
303
|
+
* @param {string} name - The name of the property to retrieve
|
|
304
|
+
* @returns {Object|null} Returns the property object if found, otherwise `undefined`
|
|
305
|
+
*/
|
|
91
306
|
getProperty = (name) => {
|
|
92
307
|
return this.properties.find(prop => prop.name === name)
|
|
93
308
|
}
|
|
94
309
|
|
|
95
|
-
|
|
310
|
+
/**
|
|
311
|
+
* Get the model's properties based on the given options.
|
|
312
|
+
* @method
|
|
313
|
+
* @memberof DoboModel
|
|
314
|
+
* @param {Object} [options={}] - Options object
|
|
315
|
+
* @param {boolean} [options.noVirtual=false] - If `true`, exclude virtual properties
|
|
316
|
+
* @param {boolean} [options.namesOnly=false] - If `true`, return only property names instead of full property objects
|
|
317
|
+
* @returns {Array<object|string>} Returns an array of properties or property names based on the options
|
|
318
|
+
*/
|
|
319
|
+
getProperties = (options = {}) => {
|
|
320
|
+
const { noVirtual, namesOnly } = options
|
|
96
321
|
const items = noVirtual ? this.properties.filter(prop => !prop.virtual) : this.properties
|
|
97
322
|
return namesOnly ? items.map(item => item.name) : items
|
|
98
323
|
}
|
|
99
324
|
|
|
325
|
+
/**
|
|
326
|
+
* Get the model's virtual properties.
|
|
327
|
+
* @method
|
|
328
|
+
* @memberof DoboModel
|
|
329
|
+
* @param {boolean} [namesOnly=false] - If `true`, return only property names instead of full property objects
|
|
330
|
+
* @returns {Array<object|string>} Returns an array of virtual properties or property names based on the `namesOnly` option
|
|
331
|
+
*/
|
|
100
332
|
getVirtualProperties = (namesOnly) => {
|
|
101
333
|
const items = this.properties.filter(prop => prop.virtual)
|
|
102
334
|
return namesOnly ? items.map(item => item.name) : items
|
|
103
335
|
}
|
|
104
336
|
|
|
337
|
+
/**
|
|
338
|
+
* Get the model's non-virtual properties.
|
|
339
|
+
* @method
|
|
340
|
+
* @memberof DoboModel
|
|
341
|
+
* @param {boolean} [namesOnly=false] - If `true`, return only property names instead of full property objects
|
|
342
|
+
* @returns {Array<object|string>} Returns an array of non-virtual properties or property names based on the `namesOnly` option
|
|
343
|
+
*/
|
|
105
344
|
getNonVirtualProperties = (namesOnly) => {
|
|
106
345
|
const items = this.properties.filter(prop => !prop.virtual)
|
|
107
346
|
return namesOnly ? items.map(item => item.name) : items
|
|
108
347
|
}
|
|
109
348
|
|
|
349
|
+
/**
|
|
350
|
+
* Returns the model's indexes.
|
|
351
|
+
* @method
|
|
352
|
+
* @memberof DoboModel
|
|
353
|
+
* @returns {Array<object>} Returns an array of index objects defined in the model
|
|
354
|
+
*/
|
|
110
355
|
getIndexes = () => {
|
|
111
356
|
return this.indexes
|
|
112
357
|
}
|
|
113
358
|
|
|
359
|
+
/**
|
|
360
|
+
* Checks if the model has a property with the given name.
|
|
361
|
+
* @method
|
|
362
|
+
* @memberof DoboModel
|
|
363
|
+
* @param {string} name - The name of the property to check
|
|
364
|
+
* @returns {boolean} Returns `true` if the property exists, otherwise `false`
|
|
365
|
+
*/
|
|
114
366
|
hasProperty = (name) => {
|
|
115
367
|
return !!this.getProperty(name)
|
|
116
368
|
}
|
|
117
369
|
|
|
118
370
|
syncIdField = (idField) => {
|
|
119
371
|
const { cloneDeep, findIndex } = this.app.lib._
|
|
120
|
-
if (!this.
|
|
121
|
-
if (!idField) idField = cloneDeep(this.
|
|
372
|
+
if (!this.adapter) return
|
|
373
|
+
if (!idField) idField = cloneDeep(this.adapter.idField)
|
|
122
374
|
const idx = findIndex(this.properties, { name: 'id' })
|
|
123
375
|
if (idx === -1) return
|
|
124
376
|
this.properties.splice(idx, 1)
|
|
125
377
|
this.properties.unshift(idField)
|
|
126
378
|
}
|
|
127
379
|
|
|
380
|
+
/**
|
|
381
|
+
* Internal method to perform a simple lookup based on the provided value and lookupValue.
|
|
382
|
+
* @method
|
|
383
|
+
* @internal
|
|
384
|
+
* @memberof DoboModel
|
|
385
|
+
* @async
|
|
386
|
+
* @param {string|object|Array} value - The value to look up
|
|
387
|
+
* @param {object} lookupValue - The lookup values to replace in the query
|
|
388
|
+
* @param {object} [options={}] - Additional options for the lookup
|
|
389
|
+
* @returns {*|null|undefined} Returns the result of the lookup or `null` if not found or `undefined` if the value is not a string, object, or array
|
|
390
|
+
*/
|
|
128
391
|
_simpleLookup = async (value, lookupValue, options = {}) => {
|
|
129
392
|
const { get, isEmpty, isString, isPlainObject, isArray } = this.app.lib._
|
|
130
393
|
let model
|
|
@@ -148,6 +411,22 @@ async function modelFactory () {
|
|
|
148
411
|
return get(rec, field, null)
|
|
149
412
|
}
|
|
150
413
|
|
|
414
|
+
/**
|
|
415
|
+
* Builds the values for a given property if `prop.values` is set:
|
|
416
|
+
* - If a string, it will be treated as a handler and executed to get the values.
|
|
417
|
+
* - If a function, it will be executed to get the values.
|
|
418
|
+
* - If an array, it will be used as is.
|
|
419
|
+
*
|
|
420
|
+
* Values are returned as an array of {@link DoboModel.TPropertyValues}.
|
|
421
|
+
* If a request object is provided in the options, the `text` will be translated using
|
|
422
|
+
* the request's translation function.
|
|
423
|
+
* @async
|
|
424
|
+
* @method
|
|
425
|
+
* @memberof DoboModel
|
|
426
|
+
* @param {object} prop - The property definition
|
|
427
|
+
* @param {DoboModel.TOptions} opts - Additional options for building the property values
|
|
428
|
+
* @returns {Array<DoboModel.TPropertyValue>} Returns an array of property values
|
|
429
|
+
*/
|
|
151
430
|
buildPropValues = async (prop, opts) => {
|
|
152
431
|
const { isString, camelCase, isFunction } = this.app.lib._
|
|
153
432
|
const { callHandler } = this.app.bajo
|
|
@@ -193,7 +472,6 @@ async function modelFactory () {
|
|
|
193
472
|
loadFixtures = loadFixtures
|
|
194
473
|
sanitizeRecord = sanitizeRecord
|
|
195
474
|
sanitizeBody = sanitizeBody
|
|
196
|
-
sanitizeId = sanitizeId
|
|
197
475
|
sanitizeFixture = sanitizeFixture
|
|
198
476
|
validate = validate
|
|
199
477
|
|
|
@@ -212,7 +490,7 @@ async function modelFactory () {
|
|
|
212
490
|
dispose = async () => {
|
|
213
491
|
await super.dispose()
|
|
214
492
|
this.connection = null
|
|
215
|
-
this.
|
|
493
|
+
this.adapter = null
|
|
216
494
|
}
|
|
217
495
|
}
|
|
218
496
|
|