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.
- package/.github/FUNDING.yml +0 -0
- package/.github/workflows/repo-lockdown.yml +0 -0
- package/.jsdoc.conf.json +0 -0
- package/LICENSE +0 -0
- package/README.md +2 -2
- package/docs/Dobo.html +0 -0
- package/docs/data/search.json +0 -0
- package/docs/fonts/Inconsolata-Regular.ttf +0 -0
- package/docs/fonts/OpenSans-Regular.ttf +0 -0
- package/docs/fonts/WorkSans-Bold.ttf +0 -0
- package/docs/global.html +0 -0
- package/docs/index.html +0 -0
- package/docs/index.js.html +0 -0
- package/docs/lib_collect-connections.js.html +0 -0
- package/docs/lib_collect-drivers.js.html +0 -0
- package/docs/lib_collect-features.js.html +0 -0
- package/docs/lib_collect-schemas.js.html +0 -0
- package/docs/lib_index.js.html +0 -0
- package/docs/method_model_create.js.html +0 -0
- package/docs/method_model_drop.js.html +0 -0
- package/docs/method_model_exists.js.html +0 -0
- package/docs/method_record_count.js.html +0 -0
- package/docs/method_record_create.js.html +0 -0
- package/docs/method_record_find-all.js.html +0 -0
- package/docs/method_record_find-one.js.html +0 -0
- package/docs/method_record_find.js.html +0 -0
- package/docs/method_record_get.js.html +0 -0
- package/docs/method_record_remove.js.html +0 -0
- package/docs/method_record_update.js.html +0 -0
- package/docs/method_record_upsert.js.html +0 -0
- package/docs/method_sanitize_body.js.html +0 -0
- package/docs/method_sanitize_date.js.html +0 -0
- package/docs/method_sanitize_id.js.html +0 -0
- package/docs/method_validate.js.html +0 -0
- package/docs/module-Lib.html +0 -0
- package/docs/scripts/core.js +476 -477
- package/docs/scripts/core.min.js +0 -0
- package/docs/scripts/resize.js +36 -36
- package/docs/scripts/search.js +105 -105
- package/docs/scripts/search.min.js +0 -0
- package/docs/scripts/third-party/Apache-License-2.0.txt +0 -0
- package/docs/scripts/third-party/fuse.js +1 -1
- package/docs/scripts/third-party/hljs-line-num-original.js +282 -285
- package/docs/scripts/third-party/hljs-line-num.js +1 -1
- package/docs/scripts/third-party/hljs-original.js +1195 -1202
- package/docs/scripts/third-party/hljs.js +1 -1
- package/docs/scripts/third-party/popper.js +1 -1
- package/docs/scripts/third-party/tippy.js +1 -1
- package/docs/scripts/third-party/tocbot.js +508 -509
- package/docs/scripts/third-party/tocbot.min.js +0 -0
- package/docs/static/bitcoin.jpeg +0 -0
- package/docs/static/home.md +0 -0
- package/docs/static/logo-ecosystem.png +0 -0
- package/docs/static/logo.png +0 -0
- package/docs/styles/clean-jsdoc-theme-base.css +0 -0
- package/docs/styles/clean-jsdoc-theme-dark.css +0 -0
- package/docs/styles/clean-jsdoc-theme-light.css +0 -0
- package/docs/styles/clean-jsdoc-theme-scrollbar.css +0 -0
- package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +0 -0
- package/docs/styles/clean-jsdoc-theme.min.css +0 -0
- package/extend/bajo/intl/en-US.json +66 -28
- package/extend/bajo/intl/id.json +55 -27
- package/extend/bajoCli/applet/clear-record.js +22 -0
- package/extend/bajoCli/applet/connection.js +0 -0
- package/extend/bajoCli/applet/count-record.js +27 -0
- package/extend/bajoCli/applet/create-aggregate.js +33 -0
- package/extend/bajoCli/applet/create-histogram.js +33 -0
- package/extend/bajoCli/applet/create-record.js +39 -0
- package/extend/bajoCli/applet/find-record.js +27 -0
- package/extend/bajoCli/applet/get-record.js +27 -0
- package/extend/bajoCli/applet/lib/post-process.js +10 -17
- package/extend/bajoCli/applet/model.js +22 -0
- package/extend/bajoCli/applet/rebuild-model.js +91 -0
- package/extend/bajoCli/applet/remove-record.js +27 -0
- package/extend/bajoCli/applet/update-record.js +44 -0
- package/extend/bajoCli/applet.js +0 -0
- package/extend/dobo/driver/memory.js +170 -0
- package/extend/dobo/feature/created-at.js +9 -7
- package/extend/dobo/feature/dt.js +0 -0
- package/extend/dobo/feature/immutable.js +30 -0
- package/extend/dobo/feature/int-id.js +0 -0
- package/extend/dobo/feature/removed-at.js +32 -54
- package/extend/dobo/feature/updated-at.js +14 -12
- package/extend/waibuMpa/route/attachment/@model/@id/@field/@file.js +2 -6
- package/extend/waibuStatic/virtual.json +0 -0
- package/index.js +291 -366
- package/lib/collect-connections.js +49 -21
- package/lib/collect-drivers.js +19 -33
- package/lib/collect-features.js +24 -17
- package/lib/collect-models.js +319 -0
- package/lib/factory/action.js +161 -0
- package/lib/factory/connection.js +62 -0
- package/lib/factory/driver.js +358 -0
- package/lib/factory/feature.js +33 -0
- package/lib/factory/model/_util.js +402 -0
- package/lib/factory/model/build.js +15 -0
- package/lib/factory/model/clear-record.js +17 -0
- package/lib/factory/model/count-record.js +17 -0
- package/lib/factory/model/create-aggregate.js +17 -0
- package/lib/factory/model/create-attachment.js +29 -0
- package/lib/factory/model/create-histogram.js +17 -0
- package/lib/factory/model/create-record.js +35 -0
- package/lib/factory/model/drop.js +15 -0
- package/lib/factory/model/exists.js +21 -0
- package/lib/factory/model/find-all-record.js +71 -0
- package/lib/factory/model/find-attachment.js +29 -0
- package/lib/factory/model/find-one-record.js +19 -0
- package/{method/record/find.js → lib/factory/model/find-record.js} +103 -115
- package/lib/factory/model/get-attachment.js +15 -0
- package/lib/factory/model/get-record.js +79 -0
- package/lib/factory/model/list-attachment.js +37 -0
- package/lib/{add-fixtures.js → factory/model/load-fixtures.js} +69 -67
- package/lib/factory/model/remove-attachment.js +15 -0
- package/lib/factory/model/remove-record.js +59 -0
- package/lib/factory/model/sanitize-body.js +62 -0
- package/lib/factory/model/sanitize-id.js +7 -0
- package/lib/factory/model/sanitize-record.js +26 -0
- package/lib/factory/model/update-attachment.js +9 -0
- package/lib/factory/model/update-record.js +81 -0
- package/lib/factory/model/upsert-record.js +95 -0
- package/{method → lib/factory/model}/validate.js +38 -52
- package/lib/factory/model.js +150 -0
- package/lib/index.js +0 -0
- package/package.json +8 -4
- package/wiki/APPLETS.md +0 -0
- package/wiki/CHANGES.md +46 -0
- package/wiki/CONFIG.md +0 -0
- package/wiki/CONTRIBUTING.md +0 -0
- package/wiki/DEV-GUIDE.md +0 -0
- package/wiki/ECOSYSTEM.md +0 -0
- package/wiki/GETTING-STARTED.md +10 -10
- package/wiki/QUERY-LANGUAGE.md +0 -0
- package/wiki/USER-GUIDE.md +0 -0
- package/extend/bajoCli/applet/model-clear.js +0 -11
- package/extend/bajoCli/applet/model-rebuild.js +0 -101
- package/extend/bajoCli/applet/record-create.js +0 -43
- package/extend/bajoCli/applet/record-find.js +0 -28
- package/extend/bajoCli/applet/record-get.js +0 -24
- package/extend/bajoCli/applet/record-remove.js +0 -24
- package/extend/bajoCli/applet/record-update.js +0 -47
- package/extend/bajoCli/applet/schema.js +0 -22
- package/extend/bajoCli/applet/stat-count.js +0 -24
- package/lib/build-bulk-action.js +0 -12
- package/lib/check-unique.js +0 -39
- package/lib/collect-schemas.js +0 -91
- package/lib/exec-feature-hook.js +0 -13
- package/lib/exec-validation.js +0 -21
- package/lib/generic-prop-sanitizer.js +0 -32
- package/lib/handle-attachment-upload.js +0 -16
- package/lib/mem-db/conn-sanitizer.js +0 -8
- package/lib/mem-db/instantiate.js +0 -41
- package/lib/mem-db/method/model/clear.js +0 -6
- package/lib/mem-db/method/model/create.js +0 -5
- package/lib/mem-db/method/model/drop.js +0 -5
- package/lib/mem-db/method/model/exists.js +0 -5
- package/lib/mem-db/method/record/create.js +0 -12
- package/lib/mem-db/method/record/find.js +0 -20
- package/lib/mem-db/method/record/get.js +0 -9
- package/lib/mem-db/method/record/remove.js +0 -13
- package/lib/mem-db/method/record/update.js +0 -15
- package/lib/mem-db/method/stat/count.js +0 -11
- package/lib/mem-db/start.js +0 -25
- package/lib/merge-attachment-info.js +0 -16
- package/lib/multi-rel-rows.js +0 -42
- package/lib/resolve-method.js +0 -16
- package/lib/sanitize-schema.js +0 -198
- package/lib/single-rel-rows.js +0 -38
- package/method/attachment/copy-uploaded.js +0 -34
- package/method/attachment/create.js +0 -29
- package/method/attachment/find.js +0 -27
- package/method/attachment/get-path.js +0 -12
- package/method/attachment/get.js +0 -12
- package/method/attachment/pre-check.js +0 -9
- package/method/attachment/remove.js +0 -11
- package/method/attachment/update.js +0 -7
- package/method/bulk/create.js +0 -46
- package/method/model/clear.js +0 -22
- package/method/model/create.js +0 -32
- package/method/model/drop.js +0 -31
- package/method/model/exists.js +0 -37
- package/method/record/clear.js +0 -24
- package/method/record/count.js +0 -66
- package/method/record/create.js +0 -111
- package/method/record/find-all.js +0 -41
- package/method/record/find-one.js +0 -70
- package/method/record/get.js +0 -89
- package/method/record/remove.js +0 -72
- package/method/record/update.js +0 -104
- package/method/record/upsert.js +0 -51
- package/method/sanitize/body.js +0 -85
- package/method/sanitize/date.js +0 -27
- package/method/sanitize/id.js +0 -17
- package/method/stat/aggregate.js +0 -23
- 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
|