dobo 2.0.1 → 2.2.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 (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 +291 -366
  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 +319 -0
  91. package/lib/factory/action.js +161 -0
  92. package/lib/factory/connection.js +62 -0
  93. package/lib/factory/driver.js +358 -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 +62 -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 +46 -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,358 @@
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
+ }
39
+ this.memory = false
40
+ this.options = options
41
+ }
42
+
43
+ /**
44
+ * Sanitize connection object
45
+ *
46
+ * @method
47
+ * @param {Object} conn - Connection object
48
+ */
49
+ async sanitizeConnection (conn) {
50
+ conn.memory = false
51
+ }
52
+
53
+ sanitizeBody (model, body = {}) {
54
+ const item = cloneDeep(body)
55
+ if (has(item, 'id') && this.idField.name !== 'id') {
56
+ item[this.idField.name] = item.id
57
+ delete item.id
58
+ }
59
+ for (const prop of model.properties) {
60
+ if (isSet(item[prop.name]) && !this.support.propType[prop.type]) {
61
+ if (prop.type === 'datetime') item[prop.name] = item[prop.name].toISOString()
62
+ else if (['object', 'array'].includes(prop.type)) item[prop.name] = JSON.stringify(item[prop.name])
63
+ }
64
+ }
65
+ return item
66
+ }
67
+
68
+ sanitizeRecord (model, record = {}) {
69
+ const item = { ...record }
70
+ if (has(item, this.idField.name) && this.idField.name !== 'id') {
71
+ item.id = item[this.idField.name]
72
+ delete item[this.idField.name]
73
+ }
74
+ for (const prop of model.properties) {
75
+ if (isSet(item[prop.name]) && !this.support.propType[prop.type]) {
76
+ try {
77
+ if (prop.type === 'datetime') item[prop.name] = new Date(item[prop.name])
78
+ else if (['object', 'array'].includes(prop.type)) item[prop.name] = JSON.parse(item[prop.name])
79
+ } catch (err) {
80
+ item[prop.name] = null
81
+ }
82
+ }
83
+ }
84
+ return item
85
+ }
86
+
87
+ _getReturningFields (model, { fields = [] } = {}) {
88
+ if (!this.support.returning) return []
89
+ let items = fields.length > 0 ? [...fields] : model.properties.map(prop => prop.name)
90
+ if (!items.includes(this.idField.name)) items.unshift(this.idField.name)
91
+ if (this.idField.name !== 'id') items = without(items, ['id'])
92
+ return uniq(items)
93
+ }
94
+
95
+ /**
96
+ * Check uniqueness of fields with unique index
97
+ *
98
+ * @param {Object} [params]
99
+ */
100
+ _checkUnique = async (model, body = {}, options = {}) => {
101
+ const { isSet } = this.app.lib.aneka
102
+ const { filter, map, isEmpty, forOwn } = this.app.lib._
103
+ const indexes = filter(model.indexes ?? [], idx => idx.type === 'unique')
104
+ for (const index of indexes) {
105
+ const query = {}
106
+ for (const field of index.fields) {
107
+ if (isSet(body[field])) query[field] = body[field]
108
+ }
109
+ if (isEmpty(query)) continue
110
+ const resp = await this.findRecord(model, { query, limit: 1 }, options)
111
+ const data = resp.data[0]
112
+ if (!isEmpty(data)) {
113
+ if (['updateRecord', 'upsertRecord'].includes(options.action)) {
114
+ let eq = true
115
+ forOwn(query, (v, k) => {
116
+ if (data[k] !== v) eq = false
117
+ })
118
+ if (!eq) continue
119
+ }
120
+ const error = this.app.dobo.t('uniqueConstraintError')
121
+ const details = map(index.fields, field => {
122
+ return { field, error }
123
+ })
124
+ throw this.app.dobo.error(error, { details, body })
125
+ }
126
+ }
127
+ }
128
+
129
+ // Internal calls that will be called by model
130
+
131
+ async _modelExists (model, options = {}) {
132
+ return await this.modelExists(model, options)
133
+ }
134
+
135
+ async _buildModel (model, options = {}) {
136
+ return await this.buildModel(model, options)
137
+ }
138
+
139
+ async _dropModel (model, options = {}) {
140
+ return await this.dropModel(model, options)
141
+ }
142
+
143
+ async _createRecord (model, body = {}, options = {}) {
144
+ const { isSet, generateId } = this.app.lib.aneka
145
+ const { pick, isFunction } = this.app.lib._
146
+ const prop = model.properties.find(p => p.name === 'id')
147
+ if (!isSet(body.id) && prop.type === 'string') {
148
+ if (options.checksumId) {
149
+ if (options.checksumId === true) options.checksumId = Object.keys(body)
150
+ const checksum = pick(body, options.checksumId)
151
+ body.id = crypto.createHash('md5').update(JSON.stringify(checksum)).digest('hex')
152
+ } else if (this.idGenerator) {
153
+ if (['uuid', 'uuidv4'].includes(this.idGenerator)) body.id = uuidv4()
154
+ else if (['uuidv7'].includes(this.idGenerator)) body.id = uuidv7()
155
+ else if (this.idGenerator === 'generateId') body.id = generateId()
156
+ else if (isFunction(this.idGenerator)) body.id = await this.idGenerator(model, body, options)
157
+ }
158
+ if (!body.id) body.id = ulid()
159
+ body.id = body.id.slice(0, prop.maxLength)
160
+ }
161
+ if (!this.uniqueIndexSupport) await this._checkUnique(model, body, options)
162
+ for (const prop of model.properties) {
163
+ if (!isSet(body[prop.name]) && isSet(prop.default)) {
164
+ if (isFunction(prop.default)) body[prop.name] = await prop.default.call(model)
165
+ else if (typeof prop.default === 'string') {
166
+ if (['now()', 'current_timestamp()'].includes(prop.default.toLowerCase()) && ['datetime', 'date', 'timestamp'].includes(prop.type)) {
167
+ body[prop.name] = new Date()
168
+ } else if (['uuid()', 'uuidv4()'].includes(prop.default.toLowerCase()) && prop.type === 'string') {
169
+ body[prop.name] = uuidv4().slice(0, prop.maxLength)
170
+ } else if (['uuidv7()'].includes(prop.default.toLowerCase()) && prop.type === 'string') {
171
+ body[prop.name] = uuidv7().slice(0, prop.maxLength)
172
+ } else if (['ulid()'].includes(prop.default.toLowerCase()) && prop.type === 'string') {
173
+ body[prop.name] = ulid().slice(0, prop.maxLength)
174
+ } else if (prop.default.toLowerCase() === 'generateId' && prop.type === 'string') {
175
+ body[prop.name] = generateId()
176
+ }
177
+ }
178
+ body[prop.name] = isFunction(prop.default) ? await prop.default.call(model) : prop.default
179
+ }
180
+ }
181
+ if (isSet(body.id)) {
182
+ const resp = await this.getRecord(model, body.id, { noHook: true })
183
+ if (!isEmpty(resp.data)) throw this.plugin.error('recordExists%s%s', body.id, model.name)
184
+ }
185
+ const result = await this.createRecord(model, this.sanitizeBody(model, body), options)
186
+ if (options.noResult) return
187
+ result.data = this.sanitizeRecord(model, result.data)
188
+ return result
189
+ }
190
+
191
+ async _getRecord (model, id, options = {}) {
192
+ const result = await this.getRecord(model, id, options)
193
+ if (isEmpty(result.data) && options.throwNotFound) throw this.plugin.error('recordNotFound%s%s', id, model.name)
194
+ result.data = this.sanitizeRecord(model, result.data)
195
+ return result
196
+ }
197
+
198
+ async _updateRecord (model, id, body = {}, options = {}) {
199
+ if (!this.support.uniqueIndex) await this._checkUnique(model, body, options)
200
+ const resp = await this.getRecord(model, id, { noHook: true })
201
+ if (!resp.data) throw this.plugin.error('recordNotFound%s%s', id, model.name)
202
+ options._data = resp.data
203
+ const result = await this.updateRecord(model, id, this.sanitizeBody(model, body), options)
204
+ if (options.noResult) return
205
+ result.oldData = this.sanitizeRecord(model, result.oldData)
206
+ result.data = this.sanitizeRecord(model, result.data)
207
+ return result
208
+ }
209
+
210
+ async _upsertRecord (model, body = {}, options = {}) {
211
+ if (!this.uniqueIndexSupport) await this._checkUnique(model, body, options)
212
+ if (isSet(body.id)) {
213
+ const resp = await this.getRecord(model, body.id, { noHook: true })
214
+ if (!resp.data) throw this.plugin.error('recordNotFound%s%s', body.id, model.name)
215
+ options._data = resp.data
216
+ }
217
+ const result = await this.upsertRecord(model, this.sanitizeBody(model, body), options)
218
+ if (options.noResult) return
219
+ if (result.oldData) result.oldData = this.sanitizeRecord(model, result.oldData)
220
+ result.data = this.sanitizeRecord(model, result.data)
221
+ return result
222
+ }
223
+
224
+ async _removeRecord (model, id, options = {}) {
225
+ const resp = await this.getRecord(model, id, { noHook: true })
226
+ if (!resp.data) throw this.plugin.error('recordNotFound%s%s', id, model.name)
227
+ options._data = resp.data
228
+ const result = await this.removeRecord(model, id, options)
229
+ if (options.noResult) return
230
+ result.oldData = this.sanitizeRecord(model, result.oldData)
231
+ return result
232
+ }
233
+
234
+ async _clearRecord (model, options = {}) {
235
+ const result = await this.clearRecord(model, options)
236
+ return result
237
+ }
238
+
239
+ async _findRecord (model, filter = {}, options = {}) {
240
+ const result = await this.findRecord(model, filter, options)
241
+ for (const idx in result.data) {
242
+ result.data[idx] = this.sanitizeRecord(model, result.data[idx])
243
+ }
244
+ return result
245
+ }
246
+
247
+ async _findAllRecord (model, filter = {}, options = {}) {
248
+ const result = await this.findAllRecord(model, filter, options)
249
+ for (const idx in result.data) {
250
+ result.data[idx] = this.sanitizeRecord(model, result.data[idx])
251
+ }
252
+ return result
253
+ }
254
+
255
+ async _countRecord (model, filter = {}, options = {}) {
256
+ return await this.countRecord(model, filter, options)
257
+ }
258
+
259
+ async _createAggregate (model, filter = {}, params = {}, options = {}) {
260
+ const fieldPropTypes = ['integer', 'smallint', 'float', 'double']
261
+ const groupPropTypes = ['string', ...fieldPropTypes]
262
+ this.app.dobo.checkAggregateParams(params)
263
+ const { group, field } = params
264
+
265
+ let prop = model.properties.find(p => p.name === group)
266
+ if (!prop) throw this.plugin.error('unknown%s%s', this.plugin.t('field.field'), group)
267
+ if (!groupPropTypes.includes(prop.type)) throw this.plugin.error('allowedPropType%s%s', group, groupPropTypes.join(', '))
268
+
269
+ prop = model.properties.find(p => p.name === field)
270
+ if (!prop) throw this.plugin.error('unknown%s%s', this.plugin.t('field.field'), field)
271
+ // if (!fieldPropTypes.includes(prop.type)) throw this.plugin.error('allowedPropType%s%s', field, fieldPropTypes.join(', '))
272
+
273
+ const result = await this.createAggregate(model, filter, params, options)
274
+ for (const idx in result.data) {
275
+ result.data[idx] = this.sanitizeRecord(model, result.data[idx])
276
+ }
277
+ return result
278
+ }
279
+
280
+ async _createHistogram (model, filter = {}, params, options = {}) {
281
+ // const fieldPropTypes = ['integer', 'smallint', 'float', 'double']
282
+ const groupPropTypes = ['datetime', 'date']
283
+ this.app.dobo.checkHistogramParams(params)
284
+ const { group, field } = params
285
+
286
+ let prop = model.properties.find(p => p.name === group)
287
+ if (!prop) throw this.plugin.error('unknown%s%s', this.plugin.t('field.field'), group)
288
+ if (!groupPropTypes.includes(prop.type)) throw this.plugin.error('allowedPropType%s%s', group, groupPropTypes.join(', '))
289
+
290
+ prop = model.properties.find(p => p.name === field)
291
+ if (!prop) throw this.plugin.error('unknown%s%s', this.plugin.t('field.field'), field)
292
+ // if (!fieldPropTypes.includes(prop.type)) throw this.plugin.error('allowedPropType%s%s', field, fieldPropTypes.join(', '))
293
+ const result = await this.createHistogram(model, filter, params, options)
294
+ for (const idx in result.data) {
295
+ result.data[idx] = this.sanitizeRecord(model, result.data[idx])
296
+ }
297
+ return result
298
+ }
299
+
300
+ // Public calls that need to be implemented by child drivers
301
+
302
+ async connect (connection, noRebuild) {
303
+ }
304
+
305
+ async modelExists (model, options = {}) {
306
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'modelExists')
307
+ }
308
+
309
+ async buildModel (model, options = {}) {
310
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'buildModel')
311
+ }
312
+
313
+ async dropModel (model, options = {}) {
314
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'dropModel')
315
+ }
316
+
317
+ async createRecord (model, body = {}, options = {}) {
318
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'createRecord')
319
+ }
320
+
321
+ async getRecord (model, id, options = {}) {
322
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'getRecord')
323
+ }
324
+
325
+ async updateRecord (model, id, body = {}, options = {}) {
326
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'updateRecord')
327
+ }
328
+
329
+ async removeRecord (model, id, options = {}) {
330
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'removeRecord')
331
+ }
332
+
333
+ async clearRecord (model, options = {}) {
334
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'clearRecord')
335
+ }
336
+
337
+ async findRecord (model, filter = {}, options = {}) {
338
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'findRecord')
339
+ }
340
+
341
+ async countRecord (model, filter = {}, options = {}) {
342
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'countRecord')
343
+ }
344
+
345
+ async createAggregate (model, filter = {}, params = {}, options = {}) {
346
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'createAggregate')
347
+ }
348
+
349
+ async createHistogram (model, filter = {}, params = {}, options = {}) {
350
+ throw this.plugin.error('notSupported%s%s', this.app.t('method'), 'createHistogram')
351
+ }
352
+ }
353
+
354
+ this.app.baseClass.DoboDriver = DoboDriver
355
+ return DoboDriver
356
+ }
357
+
358
+ 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