dobo 2.0.1 → 2.2.1

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 (194) hide show
  1. package/.github/FUNDING.yml +0 -0
  2. package/.github/workflows/repo-lockdown.yml +0 -0
  3. package/.jsdoc.conf.json +0 -0
  4. package/LICENSE +0 -0
  5. package/README.md +2 -2
  6. package/docs/Dobo.html +0 -0
  7. package/docs/data/search.json +0 -0
  8. package/docs/fonts/Inconsolata-Regular.ttf +0 -0
  9. package/docs/fonts/OpenSans-Regular.ttf +0 -0
  10. package/docs/fonts/WorkSans-Bold.ttf +0 -0
  11. package/docs/global.html +0 -0
  12. package/docs/index.html +0 -0
  13. package/docs/index.js.html +0 -0
  14. package/docs/lib_collect-connections.js.html +0 -0
  15. package/docs/lib_collect-drivers.js.html +0 -0
  16. package/docs/lib_collect-features.js.html +0 -0
  17. package/docs/lib_collect-schemas.js.html +0 -0
  18. package/docs/lib_index.js.html +0 -0
  19. package/docs/method_model_create.js.html +0 -0
  20. package/docs/method_model_drop.js.html +0 -0
  21. package/docs/method_model_exists.js.html +0 -0
  22. package/docs/method_record_count.js.html +0 -0
  23. package/docs/method_record_create.js.html +0 -0
  24. package/docs/method_record_find-all.js.html +0 -0
  25. package/docs/method_record_find-one.js.html +0 -0
  26. package/docs/method_record_find.js.html +0 -0
  27. package/docs/method_record_get.js.html +0 -0
  28. package/docs/method_record_remove.js.html +0 -0
  29. package/docs/method_record_update.js.html +0 -0
  30. package/docs/method_record_upsert.js.html +0 -0
  31. package/docs/method_sanitize_body.js.html +0 -0
  32. package/docs/method_sanitize_date.js.html +0 -0
  33. package/docs/method_sanitize_id.js.html +0 -0
  34. package/docs/method_validate.js.html +0 -0
  35. package/docs/module-Lib.html +0 -0
  36. package/docs/scripts/core.js +476 -477
  37. package/docs/scripts/core.min.js +0 -0
  38. package/docs/scripts/resize.js +36 -36
  39. package/docs/scripts/search.js +105 -105
  40. package/docs/scripts/search.min.js +0 -0
  41. package/docs/scripts/third-party/Apache-License-2.0.txt +0 -0
  42. package/docs/scripts/third-party/fuse.js +1 -1
  43. package/docs/scripts/third-party/hljs-line-num-original.js +282 -285
  44. package/docs/scripts/third-party/hljs-line-num.js +1 -1
  45. package/docs/scripts/third-party/hljs-original.js +1195 -1202
  46. package/docs/scripts/third-party/hljs.js +1 -1
  47. package/docs/scripts/third-party/popper.js +1 -1
  48. package/docs/scripts/third-party/tippy.js +1 -1
  49. package/docs/scripts/third-party/tocbot.js +508 -509
  50. package/docs/scripts/third-party/tocbot.min.js +0 -0
  51. package/docs/static/bitcoin.jpeg +0 -0
  52. package/docs/static/home.md +0 -0
  53. package/docs/static/logo-ecosystem.png +0 -0
  54. package/docs/static/logo.png +0 -0
  55. package/docs/styles/clean-jsdoc-theme-base.css +0 -0
  56. package/docs/styles/clean-jsdoc-theme-dark.css +0 -0
  57. package/docs/styles/clean-jsdoc-theme-light.css +0 -0
  58. package/docs/styles/clean-jsdoc-theme-scrollbar.css +0 -0
  59. package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +0 -0
  60. package/docs/styles/clean-jsdoc-theme.min.css +0 -0
  61. package/extend/bajo/intl/en-US.json +66 -28
  62. package/extend/bajo/intl/id.json +55 -27
  63. package/extend/bajoCli/applet/clear-record.js +22 -0
  64. package/extend/bajoCli/applet/connection.js +0 -0
  65. package/extend/bajoCli/applet/count-record.js +27 -0
  66. package/extend/bajoCli/applet/create-aggregate.js +33 -0
  67. package/extend/bajoCli/applet/create-histogram.js +33 -0
  68. package/extend/bajoCli/applet/create-record.js +39 -0
  69. package/extend/bajoCli/applet/find-record.js +27 -0
  70. package/extend/bajoCli/applet/get-record.js +27 -0
  71. package/extend/bajoCli/applet/lib/post-process.js +10 -17
  72. package/extend/bajoCli/applet/model.js +22 -0
  73. package/extend/bajoCli/applet/rebuild-model.js +91 -0
  74. package/extend/bajoCli/applet/remove-record.js +27 -0
  75. package/extend/bajoCli/applet/update-record.js +44 -0
  76. package/extend/bajoCli/applet.js +0 -0
  77. package/extend/dobo/driver/memory.js +170 -0
  78. package/extend/dobo/feature/created-at.js +9 -7
  79. package/extend/dobo/feature/dt.js +0 -0
  80. package/extend/dobo/feature/immutable.js +30 -0
  81. package/extend/dobo/feature/int-id.js +0 -0
  82. package/extend/dobo/feature/removed-at.js +32 -54
  83. package/extend/dobo/feature/updated-at.js +14 -12
  84. package/extend/waibuMpa/route/attachment/@model/@id/@field/@file.js +2 -6
  85. package/extend/waibuStatic/virtual.json +0 -0
  86. package/index.js +284 -371
  87. package/lib/collect-connections.js +49 -21
  88. package/lib/collect-drivers.js +19 -33
  89. package/lib/collect-features.js +24 -17
  90. package/lib/collect-models.js +321 -0
  91. package/lib/factory/action.js +161 -0
  92. package/lib/factory/connection.js +62 -0
  93. package/lib/factory/driver.js +372 -0
  94. package/lib/factory/feature.js +33 -0
  95. package/lib/factory/model/_util.js +402 -0
  96. package/lib/factory/model/build.js +15 -0
  97. package/lib/factory/model/clear-record.js +17 -0
  98. package/lib/factory/model/count-record.js +17 -0
  99. package/lib/factory/model/create-aggregate.js +17 -0
  100. package/lib/factory/model/create-attachment.js +29 -0
  101. package/lib/factory/model/create-histogram.js +17 -0
  102. package/lib/factory/model/create-record.js +35 -0
  103. package/lib/factory/model/drop.js +15 -0
  104. package/lib/factory/model/exists.js +21 -0
  105. package/lib/factory/model/find-all-record.js +71 -0
  106. package/lib/factory/model/find-attachment.js +29 -0
  107. package/lib/factory/model/find-one-record.js +19 -0
  108. package/{method/record/find.js → lib/factory/model/find-record.js} +103 -115
  109. package/lib/factory/model/get-attachment.js +15 -0
  110. package/lib/factory/model/get-record.js +79 -0
  111. package/lib/factory/model/list-attachment.js +37 -0
  112. package/lib/{add-fixtures.js → factory/model/load-fixtures.js} +69 -67
  113. package/lib/factory/model/remove-attachment.js +15 -0
  114. package/lib/factory/model/remove-record.js +59 -0
  115. package/lib/factory/model/sanitize-body.js +56 -0
  116. package/lib/factory/model/sanitize-id.js +7 -0
  117. package/lib/factory/model/sanitize-record.js +26 -0
  118. package/lib/factory/model/update-attachment.js +9 -0
  119. package/lib/factory/model/update-record.js +81 -0
  120. package/lib/factory/model/upsert-record.js +95 -0
  121. package/{method → lib/factory/model}/validate.js +38 -52
  122. package/lib/factory/model.js +150 -0
  123. package/lib/index.js +0 -0
  124. package/package.json +8 -4
  125. package/wiki/APPLETS.md +0 -0
  126. package/wiki/CHANGES.md +50 -0
  127. package/wiki/CONFIG.md +0 -0
  128. package/wiki/CONTRIBUTING.md +0 -0
  129. package/wiki/DEV-GUIDE.md +0 -0
  130. package/wiki/ECOSYSTEM.md +0 -0
  131. package/wiki/GETTING-STARTED.md +10 -10
  132. package/wiki/QUERY-LANGUAGE.md +0 -0
  133. package/wiki/USER-GUIDE.md +0 -0
  134. package/extend/bajoCli/applet/model-clear.js +0 -11
  135. package/extend/bajoCli/applet/model-rebuild.js +0 -101
  136. package/extend/bajoCli/applet/record-create.js +0 -43
  137. package/extend/bajoCli/applet/record-find.js +0 -28
  138. package/extend/bajoCli/applet/record-get.js +0 -24
  139. package/extend/bajoCli/applet/record-remove.js +0 -24
  140. package/extend/bajoCli/applet/record-update.js +0 -47
  141. package/extend/bajoCli/applet/schema.js +0 -22
  142. package/extend/bajoCli/applet/stat-count.js +0 -24
  143. package/lib/build-bulk-action.js +0 -12
  144. package/lib/check-unique.js +0 -39
  145. package/lib/collect-schemas.js +0 -91
  146. package/lib/exec-feature-hook.js +0 -13
  147. package/lib/exec-validation.js +0 -21
  148. package/lib/generic-prop-sanitizer.js +0 -32
  149. package/lib/handle-attachment-upload.js +0 -16
  150. package/lib/mem-db/conn-sanitizer.js +0 -8
  151. package/lib/mem-db/instantiate.js +0 -41
  152. package/lib/mem-db/method/model/clear.js +0 -6
  153. package/lib/mem-db/method/model/create.js +0 -5
  154. package/lib/mem-db/method/model/drop.js +0 -5
  155. package/lib/mem-db/method/model/exists.js +0 -5
  156. package/lib/mem-db/method/record/create.js +0 -12
  157. package/lib/mem-db/method/record/find.js +0 -20
  158. package/lib/mem-db/method/record/get.js +0 -9
  159. package/lib/mem-db/method/record/remove.js +0 -13
  160. package/lib/mem-db/method/record/update.js +0 -15
  161. package/lib/mem-db/method/stat/count.js +0 -11
  162. package/lib/mem-db/start.js +0 -25
  163. package/lib/merge-attachment-info.js +0 -16
  164. package/lib/multi-rel-rows.js +0 -42
  165. package/lib/resolve-method.js +0 -16
  166. package/lib/sanitize-schema.js +0 -198
  167. package/lib/single-rel-rows.js +0 -38
  168. package/method/attachment/copy-uploaded.js +0 -34
  169. package/method/attachment/create.js +0 -29
  170. package/method/attachment/find.js +0 -27
  171. package/method/attachment/get-path.js +0 -12
  172. package/method/attachment/get.js +0 -12
  173. package/method/attachment/pre-check.js +0 -9
  174. package/method/attachment/remove.js +0 -11
  175. package/method/attachment/update.js +0 -7
  176. package/method/bulk/create.js +0 -46
  177. package/method/model/clear.js +0 -22
  178. package/method/model/create.js +0 -32
  179. package/method/model/drop.js +0 -31
  180. package/method/model/exists.js +0 -37
  181. package/method/record/clear.js +0 -24
  182. package/method/record/count.js +0 -66
  183. package/method/record/create.js +0 -111
  184. package/method/record/find-all.js +0 -41
  185. package/method/record/find-one.js +0 -70
  186. package/method/record/get.js +0 -89
  187. package/method/record/remove.js +0 -72
  188. package/method/record/update.js +0 -104
  189. package/method/record/upsert.js +0 -51
  190. package/method/sanitize/body.js +0 -85
  191. package/method/sanitize/date.js +0 -27
  192. package/method/sanitize/id.js +0 -17
  193. package/method/stat/aggregate.js +0 -23
  194. package/method/stat/histogram.js +0 -26
@@ -0,0 +1,62 @@
1
+ async function connectionFactory () {
2
+ const { Tools } = this.app.baseClass
3
+ const { omit } = this.app.lib._
4
+
5
+ /**
6
+ * Connection class
7
+ *
8
+ * @class
9
+ */
10
+ class DoboConnection extends Tools {
11
+ constructor (plugin, options = {}) {
12
+ super(plugin)
13
+ /**
14
+ * Driver object
15
+ *
16
+ * @type {Object}
17
+ */
18
+ this.driver = undefined
19
+
20
+ /**
21
+ * Client instance
22
+ */
23
+ this.client = undefined
24
+
25
+ /**
26
+ * Connection name
27
+ *
28
+ * @type {string}
29
+ */
30
+ this.name = options.name
31
+
32
+ /**
33
+ * Options object from connection defined on ```dobo.config.connections```
34
+ *
35
+ * @type {Object}
36
+ */
37
+ this.options = omit(options, ['name', 'driver'])
38
+ this.options.models = this.options.models ?? []
39
+ }
40
+
41
+ /**
42
+ * Establish this connection through the driver to the actual database system. Driver developer must
43
+ * provide a method named ```connect()``` to connect the underlying database and (optionally) return its client instance.
44
+ *
45
+ * @param {boolean} [noRebuild] - If ```true```, the database table/collection won't be build automatically
46
+ */
47
+ async connect (noRebuild) {
48
+ const client = await this.driver.connect(this, noRebuild)
49
+ if (client) this.client = client
50
+ }
51
+
52
+ dispose () {
53
+ super.dispose()
54
+ this.driver = null
55
+ }
56
+ }
57
+
58
+ this.app.baseClass.DoboConnection = DoboConnection
59
+ return DoboConnection
60
+ }
61
+
62
+ export default connectionFactory
@@ -0,0 +1,372 @@
1
+ import crypto from 'crypto'
2
+ import { ulid } from 'ulid'
3
+ import { v4 as uuidv4, v7 as uuidv7 } from 'uuid'
4
+
5
+ const defIdField = {
6
+ name: '_id',
7
+ type: 'string',
8
+ maxLength: 50,
9
+ required: true,
10
+ index: 'primary'
11
+ }
12
+
13
+ async function driverFactory () {
14
+ const { Tools } = this.app.baseClass
15
+ const { cloneDeep, has, uniq, without, isEmpty } = this.app.lib._
16
+ const { isSet } = this.app.lib.aneka
17
+
18
+ /**
19
+ * Driver class
20
+ *
21
+ * ```this.plugin``` should be the one who owned this driver
22
+ *
23
+ * @class
24
+ */
25
+ class DoboDriver extends Tools {
26
+ constructor (plugin, name, options = {}) {
27
+ super(plugin)
28
+ this.name = name
29
+ this.idField = cloneDeep(defIdField)
30
+ this.propertyType = {}
31
+ this.support = {
32
+ propType: {
33
+ object: false,
34
+ array: false,
35
+ datetime: true
36
+ },
37
+ uniqueIndex: false,
38
+ nullableField: true
39
+ }
40
+ this.memory = false
41
+ this.options = options
42
+ }
43
+
44
+ /**
45
+ * Sanitize connection object
46
+ *
47
+ * @method
48
+ * @param {Object} conn - Connection object
49
+ */
50
+ async sanitizeConnection (conn) {
51
+ conn.memory = false
52
+ }
53
+
54
+ sanitizeBody (model, body = {}) {
55
+ const item = cloneDeep(body)
56
+ if (has(item, 'id') && this.idField.name !== 'id') {
57
+ item[this.idField.name] = item.id
58
+ delete item.id
59
+ }
60
+ for (const prop of model.properties) {
61
+ if (!isSet(item[prop.name]) && !this.support.nullableField) {
62
+ switch (prop.type) {
63
+ case 'datetime': item[prop.name] = new Date(0); break
64
+ case 'float':
65
+ case 'double': item[prop.name] = 0; break
66
+ case 'string':
67
+ case 'text': item[prop.name] = ''; break
68
+ case 'object': item[prop.name] = {}; break
69
+ case 'array': item[prop.name] = []; break
70
+ }
71
+ }
72
+ if (isSet(item[prop.name]) && !this.support.propType[prop.type]) {
73
+ if (prop.type === 'datetime') item[prop.name] = item[prop.name].toISOString()
74
+ else if (['object', 'array'].includes(prop.type)) item[prop.name] = JSON.stringify(item[prop.name])
75
+ }
76
+ }
77
+ return item
78
+ }
79
+
80
+ sanitizeRecord (model, record = {}) {
81
+ const item = { ...record }
82
+ if (has(item, this.idField.name) && this.idField.name !== 'id') {
83
+ item.id = item[this.idField.name]
84
+ delete item[this.idField.name]
85
+ }
86
+ for (const prop of model.properties) {
87
+ if (isSet(item[prop.name]) && !this.support.propType[prop.type]) {
88
+ try {
89
+ if (prop.type === 'datetime') item[prop.name] = new Date(item[prop.name])
90
+ else if (['object', 'array'].includes(prop.type)) item[prop.name] = JSON.parse(item[prop.name])
91
+ } catch (err) {
92
+ item[prop.name] = null
93
+ }
94
+ }
95
+ }
96
+ return item
97
+ }
98
+
99
+ _getReturningFields (model, { fields = [] } = {}) {
100
+ if (!this.support.returning) return []
101
+ let items = fields.length > 0 ? [...fields] : model.properties.map(prop => prop.name)
102
+ if (!items.includes(this.idField.name)) items.unshift(this.idField.name)
103
+ if (this.idField.name !== 'id') items = without(items, ['id'])
104
+ return uniq(items)
105
+ }
106
+
107
+ /**
108
+ * Check uniqueness of fields with unique index
109
+ *
110
+ * @param {Object} [params]
111
+ */
112
+ _checkUnique = async (model, body = {}, options = {}) => {
113
+ const { isSet } = this.app.lib.aneka
114
+ const { filter, map, isEmpty, forOwn } = this.app.lib._
115
+ const indexes = filter(model.indexes ?? [], idx => idx.type === 'unique')
116
+ for (const index of indexes) {
117
+ const query = {}
118
+ for (const field of index.fields) {
119
+ if (isSet(body[field])) query[field] = body[field]
120
+ }
121
+ if (isEmpty(query)) continue
122
+ const resp = await this.findRecord(model, { query, limit: 1 }, options)
123
+ const data = resp.data[0]
124
+ if (!isEmpty(data)) {
125
+ if (['updateRecord', 'upsertRecord'].includes(options.action)) {
126
+ let eq = true
127
+ forOwn(query, (v, k) => {
128
+ if (data[k] !== v) eq = false
129
+ })
130
+ if (!eq) continue
131
+ }
132
+ const error = this.app.dobo.t('uniqueConstraintError')
133
+ const details = map(index.fields, field => {
134
+ return { field, error }
135
+ })
136
+ throw this.app.dobo.error(error, { details, body })
137
+ }
138
+ }
139
+ }
140
+
141
+ // Internal calls that will be called by model
142
+
143
+ async _modelExists (model, options = {}) {
144
+ return await this.modelExists(model, options)
145
+ }
146
+
147
+ async _buildModel (model, options = {}) {
148
+ return await this.buildModel(model, options)
149
+ }
150
+
151
+ async _dropModel (model, options = {}) {
152
+ return await this.dropModel(model, options)
153
+ }
154
+
155
+ async _createRecord (model, body = {}, options = {}) {
156
+ const { isSet, generateId } = this.app.lib.aneka
157
+ const { pick, isFunction } = this.app.lib._
158
+ const prop = model.properties.find(p => p.name === 'id')
159
+ if (!isSet(body.id) && prop.type === 'string') {
160
+ if (options.checksumId) {
161
+ if (options.checksumId === true) options.checksumId = Object.keys(body)
162
+ const checksum = pick(body, options.checksumId)
163
+ body.id = crypto.createHash('md5').update(JSON.stringify(checksum)).digest('hex')
164
+ } else if (this.idGenerator) {
165
+ if (['uuid', 'uuidv4'].includes(this.idGenerator)) body.id = uuidv4()
166
+ else if (['uuidv7'].includes(this.idGenerator)) body.id = uuidv7()
167
+ else if (this.idGenerator === 'generateId') body.id = generateId()
168
+ else if (isFunction(this.idGenerator)) body.id = await this.idGenerator(model, body, options)
169
+ }
170
+ if (!body.id) body.id = ulid()
171
+ body.id = body.id.slice(0, prop.maxLength)
172
+ }
173
+ if (!this.uniqueIndexSupport) await this._checkUnique(model, body, options)
174
+ for (const prop of model.properties) {
175
+ if (!isSet(body[prop.name]) && isSet(prop.default)) {
176
+ if (isFunction(prop.default)) body[prop.name] = await prop.default.call(model)
177
+ else if (typeof prop.default === 'string') {
178
+ if (['now()', 'current_timestamp()'].includes(prop.default.toLowerCase()) && ['datetime', 'date', 'timestamp'].includes(prop.type)) {
179
+ body[prop.name] = new Date()
180
+ } else if (['uuid()', 'uuidv4()'].includes(prop.default.toLowerCase()) && prop.type === 'string') {
181
+ body[prop.name] = uuidv4().slice(0, prop.maxLength)
182
+ } else if (['uuidv7()'].includes(prop.default.toLowerCase()) && prop.type === 'string') {
183
+ body[prop.name] = uuidv7().slice(0, prop.maxLength)
184
+ } else if (['ulid()'].includes(prop.default.toLowerCase()) && prop.type === 'string') {
185
+ body[prop.name] = ulid().slice(0, prop.maxLength)
186
+ } else if (prop.default.toLowerCase() === 'generateId' && prop.type === 'string') {
187
+ body[prop.name] = generateId()
188
+ }
189
+ }
190
+ body[prop.name] = isFunction(prop.default) ? await prop.default.call(model) : prop.default
191
+ }
192
+ }
193
+ if (isSet(body.id)) {
194
+ const resp = await this.getRecord(model, body.id, { noHook: true })
195
+ if (!isEmpty(resp.data)) throw this.plugin.error('recordExists%s%s', body.id, model.name)
196
+ }
197
+ const result = await this.createRecord(model, this.sanitizeBody(model, body), options)
198
+ if (options.noResult) return
199
+ result.data = this.sanitizeRecord(model, result.data)
200
+ return result
201
+ }
202
+
203
+ async _getRecord (model, id, options = {}) {
204
+ const result = await this.getRecord(model, id, options)
205
+ if (isEmpty(result.data) && options.throwNotFound) throw this.plugin.error('recordNotFound%s%s', id, model.name)
206
+ result.data = this.sanitizeRecord(model, result.data)
207
+ return result
208
+ }
209
+
210
+ async _updateRecord (model, id, body = {}, options = {}) {
211
+ if (!this.support.uniqueIndex) await this._checkUnique(model, body, options)
212
+ const resp = await this.getRecord(model, id, { noHook: true })
213
+ if (!resp.data) throw this.plugin.error('recordNotFound%s%s', id, model.name)
214
+ options._data = resp.data
215
+ const input = this.sanitizeBody(model, body)
216
+ delete input.id
217
+ const result = await this.updateRecord(model, id, input, options)
218
+ if (options.noResult) return
219
+ result.oldData = this.sanitizeRecord(model, result.oldData)
220
+ result.data = this.sanitizeRecord(model, result.data)
221
+ return result
222
+ }
223
+
224
+ async _upsertRecord (model, body = {}, options = {}) {
225
+ if (!this.uniqueIndexSupport) await this._checkUnique(model, body, options)
226
+ if (isSet(body.id)) {
227
+ const resp = await this.getRecord(model, body.id, { noHook: true })
228
+ if (!resp.data) throw this.plugin.error('recordNotFound%s%s', body.id, model.name)
229
+ options._data = resp.data
230
+ }
231
+ const result = await this.upsertRecord(model, this.sanitizeBody(model, body), options)
232
+ if (options.noResult) return
233
+ if (result.oldData) result.oldData = this.sanitizeRecord(model, result.oldData)
234
+ result.data = this.sanitizeRecord(model, result.data)
235
+ return result
236
+ }
237
+
238
+ async _removeRecord (model, id, options = {}) {
239
+ const resp = await this.getRecord(model, id, { noHook: true })
240
+ if (!resp.data) throw this.plugin.error('recordNotFound%s%s', id, model.name)
241
+ options._data = resp.data
242
+ const result = await this.removeRecord(model, id, options)
243
+ if (options.noResult) return
244
+ result.oldData = this.sanitizeRecord(model, result.oldData)
245
+ return result
246
+ }
247
+
248
+ async _clearRecord (model, options = {}) {
249
+ const result = await this.clearRecord(model, options)
250
+ return result
251
+ }
252
+
253
+ async _findRecord (model, filter = {}, options = {}) {
254
+ const result = await this.findRecord(model, filter, options)
255
+ for (const idx in result.data) {
256
+ result.data[idx] = this.sanitizeRecord(model, result.data[idx])
257
+ }
258
+ return result
259
+ }
260
+
261
+ async _findAllRecord (model, filter = {}, options = {}) {
262
+ const result = await this.findAllRecord(model, filter, options)
263
+ for (const idx in result.data) {
264
+ result.data[idx] = this.sanitizeRecord(model, result.data[idx])
265
+ }
266
+ return result
267
+ }
268
+
269
+ async _countRecord (model, filter = {}, options = {}) {
270
+ return await this.countRecord(model, filter, options)
271
+ }
272
+
273
+ async _createAggregate (model, filter = {}, params = {}, options = {}) {
274
+ const fieldPropTypes = ['integer', 'smallint', 'float', 'double']
275
+ const groupPropTypes = ['string', ...fieldPropTypes]
276
+ this.app.dobo.checkAggregateParams(params)
277
+ const { group, field } = params
278
+
279
+ let prop = model.properties.find(p => p.name === group)
280
+ if (!prop) throw this.plugin.error('unknown%s%s', this.plugin.t('field.field'), group)
281
+ if (!groupPropTypes.includes(prop.type)) throw this.plugin.error('allowedPropType%s%s', group, groupPropTypes.join(', '))
282
+
283
+ prop = model.properties.find(p => p.name === field)
284
+ if (!prop) throw this.plugin.error('unknown%s%s', this.plugin.t('field.field'), field)
285
+ // if (!fieldPropTypes.includes(prop.type)) throw this.plugin.error('allowedPropType%s%s', field, fieldPropTypes.join(', '))
286
+
287
+ const result = await this.createAggregate(model, filter, params, options)
288
+ for (const idx in result.data) {
289
+ result.data[idx] = this.sanitizeRecord(model, result.data[idx])
290
+ }
291
+ return result
292
+ }
293
+
294
+ async _createHistogram (model, filter = {}, params, options = {}) {
295
+ // const fieldPropTypes = ['integer', 'smallint', 'float', 'double']
296
+ const groupPropTypes = ['datetime', 'date']
297
+ this.app.dobo.checkHistogramParams(params)
298
+ const { group, field } = params
299
+
300
+ let prop = model.properties.find(p => p.name === group)
301
+ if (!prop) throw this.plugin.error('unknown%s%s', this.plugin.t('field.field'), group)
302
+ if (!groupPropTypes.includes(prop.type)) throw this.plugin.error('allowedPropType%s%s', group, groupPropTypes.join(', '))
303
+
304
+ prop = model.properties.find(p => p.name === field)
305
+ if (!prop) throw this.plugin.error('unknown%s%s', this.plugin.t('field.field'), field)
306
+ // if (!fieldPropTypes.includes(prop.type)) throw this.plugin.error('allowedPropType%s%s', field, fieldPropTypes.join(', '))
307
+ const result = await this.createHistogram(model, filter, params, options)
308
+ for (const idx in result.data) {
309
+ result.data[idx] = this.sanitizeRecord(model, result.data[idx])
310
+ }
311
+ return result
312
+ }
313
+
314
+ // Public calls that need to be implemented by child drivers
315
+
316
+ async connect (connection, noRebuild) {
317
+ }
318
+
319
+ async modelExists (model, options = {}) {
320
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'modelExists')
321
+ }
322
+
323
+ async buildModel (model, options = {}) {
324
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'buildModel')
325
+ }
326
+
327
+ async dropModel (model, options = {}) {
328
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'dropModel')
329
+ }
330
+
331
+ async createRecord (model, body = {}, options = {}) {
332
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'createRecord')
333
+ }
334
+
335
+ async getRecord (model, id, options = {}) {
336
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'getRecord')
337
+ }
338
+
339
+ async updateRecord (model, id, body = {}, options = {}) {
340
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'updateRecord')
341
+ }
342
+
343
+ async removeRecord (model, id, options = {}) {
344
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'removeRecord')
345
+ }
346
+
347
+ async clearRecord (model, options = {}) {
348
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'clearRecord')
349
+ }
350
+
351
+ async findRecord (model, filter = {}, options = {}) {
352
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'findRecord')
353
+ }
354
+
355
+ async countRecord (model, filter = {}, options = {}) {
356
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'countRecord')
357
+ }
358
+
359
+ async createAggregate (model, filter = {}, params = {}, options = {}) {
360
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'createAggregate')
361
+ }
362
+
363
+ async createHistogram (model, filter = {}, params = {}, options = {}) {
364
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'createHistogram')
365
+ }
366
+ }
367
+
368
+ this.app.baseClass.DoboDriver = DoboDriver
369
+ return DoboDriver
370
+ }
371
+
372
+ export default driverFactory
@@ -0,0 +1,33 @@
1
+ async function featureFactory () {
2
+ const { Tools } = this.app.baseClass
3
+
4
+ /**
5
+ * Feature class
6
+ *
7
+ * ```this.plugin``` should be the one who owned this driver
8
+ * @class
9
+ */
10
+ class DoboFeature extends Tools {
11
+ constructor (plugin, options = {}) {
12
+ super(plugin)
13
+ /**
14
+ * Feature name
15
+ *
16
+ * @type {string}
17
+ */
18
+ this.name = options.name
19
+ this.handler = options.handler
20
+ }
21
+
22
+ dispose () {
23
+ super.dispose()
24
+ this.name = null
25
+ this.handler = null
26
+ }
27
+ }
28
+
29
+ this.app.baseClass.DoboFeature = DoboFeature
30
+ return DoboFeature
31
+ }
32
+
33
+ export default featureFactory