dobo 2.30.7 → 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.
Files changed (123) hide show
  1. package/.jsdoc.conf.json +1 -1
  2. package/docs/Dobo.html +1 -24
  3. package/docs/DoboAction.html +13 -0
  4. package/docs/DoboAdapter.html +3 -0
  5. package/docs/DoboConnection.html +3 -0
  6. package/docs/DoboFeature.html +3 -0
  7. package/docs/DoboModel.html +51 -0
  8. package/docs/data/search.json +1 -1
  9. package/docs/extend_bajo_hook-docs.js.html +241 -0
  10. package/docs/external-Tools.html +3 -0
  11. package/docs/global.html +1 -5
  12. package/docs/index.html +1 -1
  13. package/docs/index.js.html +434 -380
  14. package/docs/lib_factory_action.js.html +290 -0
  15. package/docs/lib_factory_adapter.js.html +1057 -0
  16. package/docs/lib_factory_connection.js.html +112 -0
  17. package/docs/lib_factory_feature.js.html +55 -0
  18. package/docs/lib_factory_model.js.html +503 -0
  19. package/docs/lib_factory_model_build.js.html +28 -0
  20. package/docs/lib_factory_model_clear-record.js.html +33 -0
  21. package/docs/lib_factory_model_count-record.js.html +45 -0
  22. package/docs/lib_factory_model_create-record.js.html +52 -0
  23. package/docs/lib_factory_model_drop.js.html +29 -0
  24. package/docs/lib_factory_model_exists.js.html +29 -0
  25. package/docs/lib_factory_model_find-all-record.js.html +115 -0
  26. package/docs/lib_factory_model_find-one-record.js.html +41 -0
  27. package/docs/lib_factory_model_find-record.js.html +85 -0
  28. package/docs/lib_factory_model_get-record.js.html +55 -0
  29. package/docs/lib_factory_model_helper.js.html +579 -0
  30. package/docs/lib_factory_model_remove-record.js.html +47 -0
  31. package/docs/lib_factory_model_sanitize-body.js.html +60 -0
  32. package/docs/lib_factory_model_sanitize-fixture.js.html +59 -0
  33. package/docs/lib_factory_model_sanitize-record.js.html +73 -0
  34. package/docs/lib_factory_model_update-record.js.html +61 -0
  35. package/docs/lib_factory_model_upsert-record.js.html +74 -0
  36. package/docs/{method_validate.js.html → lib_factory_model_validate.js.html} +109 -73
  37. package/docs/lib_helper.js.html +466 -0
  38. package/docs/module-Helper.html +3 -0
  39. package/docs/module-Helper_Model.html +3 -0
  40. package/docs/module-Hook.html +15 -0
  41. package/docs/scripts/core.js +477 -476
  42. package/docs/scripts/resize.js +36 -36
  43. package/docs/scripts/search.js +105 -105
  44. package/docs/scripts/third-party/fuse.js +1 -1
  45. package/docs/scripts/third-party/hljs-line-num-original.js +285 -282
  46. package/docs/scripts/third-party/hljs-line-num.js +1 -1
  47. package/docs/scripts/third-party/hljs-original.js +1202 -1195
  48. package/docs/scripts/third-party/hljs.js +1 -1
  49. package/docs/scripts/third-party/popper.js +1 -1
  50. package/docs/scripts/third-party/tippy.js +1 -1
  51. package/docs/scripts/third-party/tocbot.js +509 -508
  52. package/docs/static/home.md +3 -1
  53. package/extend/bajo/hook-docs.js +238 -0
  54. package/extend/bajo/intl/en-US.json +9 -9
  55. package/extend/bajo/intl/id.json +9 -9
  56. package/extend/bajoCli/applet/rebuild-model.js +2 -2
  57. package/extend/dobo/{driver → adapter}/memory.js +6 -6
  58. package/extend/dobo/feature/immutable.js +2 -2
  59. package/extend/dobo/feature/removed-at.js +1 -1
  60. package/index.js +33 -30
  61. package/lib/factory/action.js +145 -18
  62. package/lib/factory/adapter.js +1054 -0
  63. package/lib/factory/connection.js +46 -22
  64. package/lib/factory/feature.js +23 -3
  65. package/lib/factory/model/build.js +11 -2
  66. package/lib/factory/model/bulk-create-record.js +2 -2
  67. package/lib/factory/model/clear-record.js +13 -3
  68. package/lib/factory/model/count-record.js +13 -2
  69. package/lib/factory/model/create-aggregate.js +2 -2
  70. package/lib/factory/model/create-attachment.js +1 -1
  71. package/lib/factory/model/create-histogram.js +2 -2
  72. package/lib/factory/model/create-record.js +15 -2
  73. package/lib/factory/model/drop.js +12 -2
  74. package/lib/factory/model/exists.js +10 -6
  75. package/lib/factory/model/find-all-record.js +14 -3
  76. package/lib/factory/model/find-attachment.js +1 -1
  77. package/lib/factory/model/find-one-record.js +13 -1
  78. package/lib/factory/model/find-record.js +17 -53
  79. package/lib/factory/model/get-record.js +11 -39
  80. package/lib/factory/model/{_util.js → helper.js} +176 -16
  81. package/lib/factory/model/remove-attachment.js +1 -1
  82. package/lib/factory/model/remove-record.js +11 -28
  83. package/lib/factory/model/sanitize-body.js +14 -12
  84. package/lib/factory/model/sanitize-fixture.js +17 -4
  85. package/lib/factory/model/sanitize-record.js +9 -6
  86. package/lib/factory/model/transaction.js +2 -2
  87. package/lib/factory/model/update-record.js +12 -40
  88. package/lib/factory/model/upsert-record.js +13 -42
  89. package/lib/factory/model/validate.js +47 -14
  90. package/lib/factory/model.js +301 -23
  91. package/lib/{collect-models.js → helper.js} +463 -364
  92. package/package.json +1 -1
  93. package/wiki/CHANGES.md +17 -7
  94. package/wiki/ECOSYSTEM.md +7 -7
  95. package/wiki/GETTING-STARTED.md +3 -3
  96. package/wiki/QUERY-LANGUAGE.md +1 -1
  97. package/docs/lib_collect-connections.js.html +0 -39
  98. package/docs/lib_collect-drivers.js.html +0 -52
  99. package/docs/lib_collect-features.js.html +0 -36
  100. package/docs/lib_collect-schemas.js.html +0 -94
  101. package/docs/lib_index.js.html +0 -6
  102. package/docs/method_model_create.js.html +0 -35
  103. package/docs/method_model_drop.js.html +0 -34
  104. package/docs/method_model_exists.js.html +0 -40
  105. package/docs/method_record_count.js.html +0 -69
  106. package/docs/method_record_create.js.html +0 -114
  107. package/docs/method_record_find-all.js.html +0 -44
  108. package/docs/method_record_find-one.js.html +0 -73
  109. package/docs/method_record_find.js.html +0 -118
  110. package/docs/method_record_get.js.html +0 -92
  111. package/docs/method_record_remove.js.html +0 -75
  112. package/docs/method_record_update.js.html +0 -107
  113. package/docs/method_record_upsert.js.html +0 -54
  114. package/docs/method_sanitize_body.js.html +0 -88
  115. package/docs/method_sanitize_date.js.html +0 -30
  116. package/docs/method_sanitize_id.js.html +0 -20
  117. package/docs/module-Lib.html +0 -3
  118. package/lib/collect-connections.js +0 -56
  119. package/lib/collect-drivers.js +0 -35
  120. package/lib/collect-features.js +0 -40
  121. package/lib/factory/driver.js +0 -574
  122. package/lib/factory/model/sanitize-id.js +0 -7
  123. 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} 2=max
64
- * @property {string} 2=min
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
- async function buildFromDbModel (opts = {}) {
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 = [] } = opts
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, opts)
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 (opts.partial && fields.length > 0 && !fields.includes(p.name)) continue
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 value against JOI model
250
+ * Validate body object against JOI model
217
251
  *
218
252
  * @method
219
- * @memberof Dobo
253
+ * @memberof DoboModel
220
254
  * @async
221
- * @param {Object} value - value to validate
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, opts = {}) {
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 } = opts
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) : [...opts.fields]
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 {
@@ -1,4 +1,4 @@
1
- import { sanitizeAll, sanitizeRef } from '../collect-models.js'
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 {string} TRecordSortKey
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
- * Key value pairs used as sort information:
38
- * - Key represent model's field name
39
- * - value represent its sort order: ```1``` for ascending order, and ```-1``` for descending order
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
- * Example: to sort by firstName (ascending) and lastName (descending)
42
- * ```javascript
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} TRecordPagination
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
- * @property {TRecordSort} sort - Sort order
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
- * Feature class
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
- this.driver = this.connection.driver
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
- getProperties = ({ noVirtual, namesOnly } = {}) => {
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.driver) return
121
- if (!idField) idField = cloneDeep(this.driver.idField)
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.driver = null
493
+ this.adapter = null
216
494
  }
217
495
  }
218
496