dobo 2.31.0 → 2.33.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.js +236 -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 +349 -69
  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 -577
  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,287 @@ 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`
58
77
  */
59
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
224
+ */
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
255
+
256
+ this.bindThis(
257
+ build,
258
+ exists,
259
+ drop,
260
+
261
+ createRecord,
262
+ getRecord,
263
+ updateRecord,
264
+ upsertRecord,
265
+ removeRecord,
266
+ clearRecord,
267
+ findRecord,
268
+ findOneRecord,
269
+ findAllRecord,
270
+
271
+ transaction,
272
+ bulkCreateRecord,
273
+
274
+ createAggregate,
275
+ createHistogram,
276
+ countRecord,
277
+
278
+ createAttachment,
279
+ getAttachment,
280
+ updateAttachment,
281
+ removeAttachment,
282
+ findAttachment,
283
+ listAttachment,
284
+
285
+ loadFixtures,
286
+ sanitizeRecord,
287
+ sanitizeBody,
288
+ sanitizeFixture,
289
+ validate
290
+ )
291
+
292
+ // aliases
293
+ this.deleteRecord = this.removeRecord
294
+ this.clearRecords = this.clearRecord
295
+ this.countRecords = this.countRecord
296
+ this.findRecords = this.findRecord
297
+ this.findAllRecords = this.findAllRecord
298
+ this.listAttachments = this.listAttachment
299
+ this.bulkCreateRecords = this.bulkCreateRecord
300
+
301
+ this.getField = this.getProperty
302
+ this.hasField = this.hasProperty
76
303
  }
77
304
 
305
+ /**
306
+ * Invoke a model's action. It will create a new instance of {@link DoboAction} and return it.
307
+ * @method
308
+ * @memberof DoboModel
309
+ * @param {string} name - The name of the action to invoke
310
+ * @param {...any} args - Arguments to pass to the action
311
+ * @returns {DoboAction} Returns an instance of {@link DoboAction}
312
+ */
78
313
  action = (name, ...args) => {
79
314
  const action = new this.app.baseClass.DoboAction(this, name, ...args)
80
315
  return action
@@ -84,47 +319,123 @@ async function modelFactory () {
84
319
  await sanitizeAll.call(this.app.dobo, obj)
85
320
  }
86
321
 
322
+ /**
323
+ * Sanitize a reference object based on the model's properties and rules.
324
+ * @method
325
+ * @memberof DoboModel
326
+ * @async
327
+ * @param {*} obj - The reference object to sanitize
328
+ * @param {boolean} [fatal=true] - Whether to throw an error if sanitization fails
329
+ */
87
330
  sanitizeRef = async (obj, fatal = true) => {
88
331
  await sanitizeRef.call(this.app.dobo, obj, this.app.dobo.models, fatal)
89
332
  }
90
333
 
334
+ /**
335
+ * Sanitize the given ID based on the model's properties.
336
+ * @method
337
+ * @memberof DoboModel
338
+ * @param {string|number} id - The ID to sanitize
339
+ * @returns {string|number} Returns the sanitized ID
340
+ */
341
+ sanitizeId = (id) => {
342
+ const prop = this.properties.find(p => p.name === 'id')
343
+ if (prop.type === 'integer') id = parseInt(id)
344
+ return id
345
+ }
346
+
347
+ /**
348
+ * Get a property by its name.
349
+ * @method
350
+ * @memberof DoboModel
351
+ * @param {string} name - The name of the property to retrieve
352
+ * @returns {Object|null} Returns the property object if found, otherwise `undefined`
353
+ */
91
354
  getProperty = (name) => {
92
355
  return this.properties.find(prop => prop.name === name)
93
356
  }
94
357
 
95
- getProperties = ({ noVirtual, namesOnly } = {}) => {
358
+ /**
359
+ * Get the model's properties based on the given options.
360
+ * @method
361
+ * @memberof DoboModel
362
+ * @param {Object} [options={}] - Options object
363
+ * @param {boolean} [options.noVirtual=false] - If `true`, exclude virtual properties
364
+ * @param {boolean} [options.namesOnly=false] - If `true`, return only property names instead of full property objects
365
+ * @returns {Array<object|string>} Returns an array of properties or property names based on the options
366
+ */
367
+ getProperties = (options = {}) => {
368
+ const { noVirtual, namesOnly } = options
96
369
  const items = noVirtual ? this.properties.filter(prop => !prop.virtual) : this.properties
97
370
  return namesOnly ? items.map(item => item.name) : items
98
371
  }
99
372
 
373
+ /**
374
+ * Get the model's virtual properties.
375
+ * @method
376
+ * @memberof DoboModel
377
+ * @param {boolean} [namesOnly=false] - If `true`, return only property names instead of full property objects
378
+ * @returns {Array<object|string>} Returns an array of virtual properties or property names based on the `namesOnly` option
379
+ */
100
380
  getVirtualProperties = (namesOnly) => {
101
381
  const items = this.properties.filter(prop => prop.virtual)
102
382
  return namesOnly ? items.map(item => item.name) : items
103
383
  }
104
384
 
385
+ /**
386
+ * Get the model's non-virtual properties.
387
+ * @method
388
+ * @memberof DoboModel
389
+ * @param {boolean} [namesOnly=false] - If `true`, return only property names instead of full property objects
390
+ * @returns {Array<object|string>} Returns an array of non-virtual properties or property names based on the `namesOnly` option
391
+ */
105
392
  getNonVirtualProperties = (namesOnly) => {
106
393
  const items = this.properties.filter(prop => !prop.virtual)
107
394
  return namesOnly ? items.map(item => item.name) : items
108
395
  }
109
396
 
397
+ /**
398
+ * Returns the model's indexes.
399
+ * @method
400
+ * @memberof DoboModel
401
+ * @returns {Array<object>} Returns an array of index objects defined in the model
402
+ */
110
403
  getIndexes = () => {
111
404
  return this.indexes
112
405
  }
113
406
 
407
+ /**
408
+ * Checks if the model has a property with the given name.
409
+ * @method
410
+ * @memberof DoboModel
411
+ * @param {string} name - The name of the property to check
412
+ * @returns {boolean} Returns `true` if the property exists, otherwise `false`
413
+ */
114
414
  hasProperty = (name) => {
115
415
  return !!this.getProperty(name)
116
416
  }
117
417
 
118
418
  syncIdField = (idField) => {
119
419
  const { cloneDeep, findIndex } = this.app.lib._
120
- if (!this.driver) return
121
- if (!idField) idField = cloneDeep(this.driver.idField)
420
+ if (!this.adapter) return
421
+ if (!idField) idField = cloneDeep(this.adapter.idField)
122
422
  const idx = findIndex(this.properties, { name: 'id' })
123
423
  if (idx === -1) return
124
424
  this.properties.splice(idx, 1)
125
425
  this.properties.unshift(idField)
126
426
  }
127
427
 
428
+ /**
429
+ * Internal method to perform a simple lookup based on the provided value and lookupValue.
430
+ * @method
431
+ * @internal
432
+ * @memberof DoboModel
433
+ * @async
434
+ * @param {string|object|Array} value - The value to look up
435
+ * @param {object} lookupValue - The lookup values to replace in the query
436
+ * @param {object} [options={}] - Additional options for the lookup
437
+ * @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
438
+ */
128
439
  _simpleLookup = async (value, lookupValue, options = {}) => {
129
440
  const { get, isEmpty, isString, isPlainObject, isArray } = this.app.lib._
130
441
  let model
@@ -148,6 +459,22 @@ async function modelFactory () {
148
459
  return get(rec, field, null)
149
460
  }
150
461
 
462
+ /**
463
+ * Builds the values for a given property if `prop.values` is set:
464
+ * - If a string, it will be treated as a handler and executed to get the values.
465
+ * - If a function, it will be executed to get the values.
466
+ * - If an array, it will be used as is.
467
+ *
468
+ * Values are returned as an array of {@link DoboModel.TPropertyValues}.
469
+ * If a request object is provided in the options, the `text` will be translated using
470
+ * the request's translation function.
471
+ * @async
472
+ * @method
473
+ * @memberof DoboModel
474
+ * @param {object} prop - The property definition
475
+ * @param {DoboModel.TOptions} opts - Additional options for building the property values
476
+ * @returns {Array<DoboModel.TPropertyValue>} Returns an array of property values
477
+ */
151
478
  buildPropValues = async (prop, opts) => {
152
479
  const { isString, camelCase, isFunction } = this.app.lib._
153
480
  const { callHandler } = this.app.bajo
@@ -162,57 +489,10 @@ async function modelFactory () {
162
489
  })
163
490
  }
164
491
 
165
- build = build
166
- exists = exists
167
- drop = drop
168
-
169
- createRecord = createRecord
170
- getRecord = getRecord
171
- updateRecord = updateRecord
172
- upsertRecord = upsertRecord
173
- removeRecord = removeRecord
174
- clearRecord = clearRecord
175
- findRecord = findRecord
176
- findOneRecord = findOneRecord
177
- findAllRecord = findAllRecord
178
-
179
- transaction = transaction
180
- bulkCreateRecord = bulkCreateRecord
181
-
182
- createAggregate = createAggregate
183
- createHistogram = createHistogram
184
- countRecord = countRecord
185
-
186
- createAttachment = createAttachment
187
- getAttachment = getAttachment
188
- updateAttachment = updateAttachment
189
- removeAttachment = removeAttachment
190
- findAttachment = findAttachment
191
- listAttachment = listAttachment
192
-
193
- loadFixtures = loadFixtures
194
- sanitizeRecord = sanitizeRecord
195
- sanitizeBody = sanitizeBody
196
- sanitizeId = sanitizeId
197
- sanitizeFixture = sanitizeFixture
198
- validate = validate
199
-
200
- // aliases
201
- deleteRecord = removeRecord
202
- clearRecords = clearRecord
203
- countRecords = countRecord
204
- findRecords = findRecord
205
- findAllRecords = findAllRecord
206
- listAttachments = listAttachment
207
- bulkCreateRecords = bulkCreateRecord
208
-
209
- getField = (name) => this.getProperty(name)
210
- hasField = (name) => this.hasProperty(name)
211
-
212
492
  dispose = async () => {
213
493
  await super.dispose()
214
494
  this.connection = null
215
- this.driver = null
495
+ this.adapter = null
216
496
  }
217
497
  }
218
498