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
package/method/record/remove.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import resolveMethod from '../../lib/resolve-method.js'
|
|
2
|
-
import handleAttachmentUpload from '../../lib/handle-attachment-upload.js'
|
|
3
|
-
import execFeatureHook from '../../lib/exec-feature-hook.js'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @typedef {Object} TRecordRemoveOptions
|
|
7
|
-
* @see Dobo#recordRemove
|
|
8
|
-
* @property {boolean} [dataOnly=true] - If ```true``` (default) returns deleted record. Otherwise {@link TRecordRemoveResult}
|
|
9
|
-
* @property {boolean} [noHook=false] - If ```true```, no model's hook will be executed
|
|
10
|
-
* @property {boolean} [noFeatureHook=false] - If ```true```, no model's feature hook will be executed
|
|
11
|
-
* @property {boolean} [noResult=false] - If ```true```, returns nothing
|
|
12
|
-
* @property {boolean} [fields=[]] - If not empty, return only these fields EXCLUDING hidden fields
|
|
13
|
-
* @property {boolean} [hidden=[]] - Additional fields to hide, in addition the one set in model's schema
|
|
14
|
-
* @property {boolean} [forceNoHidden=false] - If ```true```, hidden fields will be ignored and ALL fields will be returned
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Remove existing record by it's ID. All attachments bound to this record will also be removed forever.
|
|
19
|
-
*
|
|
20
|
-
* Example:
|
|
21
|
-
* ```javascript
|
|
22
|
-
* const { recordRemove } = this.app.dobo
|
|
23
|
-
* const result = await recordRemove('CdbCountry', 'ID')
|
|
24
|
-
* ```
|
|
25
|
-
*
|
|
26
|
-
* @method
|
|
27
|
-
* @memberof Dobo
|
|
28
|
-
* @async
|
|
29
|
-
* @instance
|
|
30
|
-
* @name recordRemove
|
|
31
|
-
* @param {string} name - Model's name
|
|
32
|
-
* @param {(string|number)} id - Record's ID
|
|
33
|
-
* @param {TRecordRemoveOptions} [options={}]
|
|
34
|
-
* @returns {(TRecordRemoveResult|Object)} Return the removed record if ```options.dataOnly``` is set. {@link TRecordRemoveResult} otherwise
|
|
35
|
-
*/
|
|
36
|
-
async function remove (name, id, opts = {}) {
|
|
37
|
-
const { runHook } = this.app.bajo
|
|
38
|
-
const { clearModel } = this.cache ?? {}
|
|
39
|
-
const { cloneDeep, camelCase, omit } = this.app.lib._
|
|
40
|
-
delete opts.record
|
|
41
|
-
const options = cloneDeep(omit(opts, ['req', 'reply']))
|
|
42
|
-
options.req = opts.req
|
|
43
|
-
options.reply = opts.reply
|
|
44
|
-
options.dataOnly = options.dataOnly ?? true
|
|
45
|
-
const { fields, dataOnly, noHook, noResult, noFeatureHook, hidden, forceNoHidden } = options
|
|
46
|
-
options.dataOnly = false
|
|
47
|
-
await this.modelExists(name, true)
|
|
48
|
-
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-remove', options)
|
|
49
|
-
id = this.sanitizeId(id, schema)
|
|
50
|
-
if (!noHook) {
|
|
51
|
-
await runHook(`${this.ns}:beforeRecordRemove`, name, id, options)
|
|
52
|
-
await runHook(`${this.ns}.${camelCase(name)}:beforeRecordRemove`, id, options)
|
|
53
|
-
}
|
|
54
|
-
if (!noFeatureHook) await execFeatureHook.call(this, 'beforeRemove', { schema, id, options })
|
|
55
|
-
const record = options.record ?? (await handler.call(this.app[driver.ns], { schema, id, options }))
|
|
56
|
-
delete options.record
|
|
57
|
-
if (options.req) {
|
|
58
|
-
if (options.req.file) await handleAttachmentUpload.call(this, { name: schema.name, id, options, action: 'remove' })
|
|
59
|
-
if (options.req.flash && !options.noFlash) options.req.flash('notify', options.req.t('recordRemoved'))
|
|
60
|
-
}
|
|
61
|
-
if (clearModel) await clearModel({ model: name, id, options, record })
|
|
62
|
-
if (noResult) return
|
|
63
|
-
record.oldData = options.record ? options.record.oldData : (await this.pickRecord({ record: record.oldData, fields, schema, hidden, forceNoHidden }))
|
|
64
|
-
if (!noHook) {
|
|
65
|
-
await runHook(`${this.ns}.${camelCase(name)}:afterRecordRemove`, id, options, record)
|
|
66
|
-
await runHook(`${this.ns}:afterRecordRemove`, name, id, options, record)
|
|
67
|
-
}
|
|
68
|
-
if (!noFeatureHook) await execFeatureHook.call(this, 'afterRemove', { schema, id, options, record })
|
|
69
|
-
return dataOnly ? record.oldData : record
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export default remove
|
package/method/record/update.js
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import resolveMethod from '../../lib/resolve-method.js'
|
|
2
|
-
import checkUnique from '../../lib/check-unique.js'
|
|
3
|
-
import handleAttachmentUpload from '../../lib/handle-attachment-upload.js'
|
|
4
|
-
import execValidation from '../../lib/exec-validation.js'
|
|
5
|
-
import execFeatureHook from '../../lib/exec-feature-hook.js'
|
|
6
|
-
import singleRelRows from '../../lib/single-rel-rows.js'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @typedef {Object} TRecordUpdateOptions
|
|
10
|
-
* @see Dobo#recordUpdate
|
|
11
|
-
* @property {boolean} [dataOnly=true] - If ```true``` (default) returns record's object. Otherwise {@link TRecordUpdateResult}
|
|
12
|
-
* @property {boolean} [noHook=false] - If ```true```, no model's hook will be executed
|
|
13
|
-
* @property {boolean} [noFeatureHook=false] - If ```true```, no model's feature hook will be executed
|
|
14
|
-
* @property {boolean} [noValidation=false] - If ```true```, no validation of data payload performed
|
|
15
|
-
* @property {boolean} [noCheckUnique=false] - If ```true```, no unique validation for ID performed
|
|
16
|
-
* @property {boolean} [noSanitize=false] - If ```true```, accept data payload as is without sanitization
|
|
17
|
-
* @property {boolean} [noResult=false] - If ```true```, returns nothing
|
|
18
|
-
* @property {boolean} [truncateString=true] - If ```true``` (default), string is truncated to its schema's ```maxLemngth```
|
|
19
|
-
* @property {boolean} [partial=true] - If ```true``` (default), only updated values are saved. Otherwise replace all existing values with given payload
|
|
20
|
-
* @property {boolean} [fields=[]] - If not empty, return only these fields EXCLUDING hidden fields
|
|
21
|
-
* @property {boolean} [hidden=[]] - Additional fields to hide, in addition the one set in model's schema
|
|
22
|
-
* @property {boolean} [forceNoHidden=false] - If ```true```, hidden fields will be ignored and ALL fields will be returned
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Update a record by it's ID and body payload
|
|
27
|
-
*
|
|
28
|
-
* Example:
|
|
29
|
-
* ```javascript
|
|
30
|
-
* const { recordUpdate } = this.app.dobo
|
|
31
|
-
* const { body } = {
|
|
32
|
-
* name: 'Republic of Indonesia',
|
|
33
|
-
* phoneCode: '+62'
|
|
34
|
-
* }
|
|
35
|
-
* const result = await recordUpdate('CdbCountry', 'ID', body)
|
|
36
|
-
* ```
|
|
37
|
-
*
|
|
38
|
-
* @method
|
|
39
|
-
* @memberof Dobo
|
|
40
|
-
* @async
|
|
41
|
-
* @instance
|
|
42
|
-
* @name recordUpdate
|
|
43
|
-
* @param {string} name - Model's name
|
|
44
|
-
* @param {(string|number)} id - Record's ID
|
|
45
|
-
* @param {Object} body - Body payload
|
|
46
|
-
* @param {TRecordUpdateOptions} [options={}]
|
|
47
|
-
* @returns {(TRecordUpdateResult|Object)} Returns updated record if ```options.dataOnly``` is set. {@link TRecordUpdateResult} otherwise
|
|
48
|
-
*/
|
|
49
|
-
async function update (name, id, input, opts = {}) {
|
|
50
|
-
const { isSet } = this.app.lib.aneka
|
|
51
|
-
const { runHook } = this.app.bajo
|
|
52
|
-
const { clearModel } = this.cache ?? {}
|
|
53
|
-
const { forOwn, find, cloneDeep, camelCase, omit, get } = this.app.lib._
|
|
54
|
-
delete opts.record
|
|
55
|
-
const options = cloneDeep(omit(opts, ['req', 'reply']))
|
|
56
|
-
options.req = opts.req
|
|
57
|
-
options.reply = opts.reply
|
|
58
|
-
options.dataOnly = options.dataOnly ?? true
|
|
59
|
-
input = cloneDeep(input)
|
|
60
|
-
const { fields, dataOnly, noHook, noValidation, noCheckUnique, noFeatureHook, noResult, noSanitize, partial = true, hidden, forceNoHidden } = options
|
|
61
|
-
options.dataOnly = true
|
|
62
|
-
options.truncateString = options.truncateString ?? true
|
|
63
|
-
await this.modelExists(name, true)
|
|
64
|
-
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-update', options)
|
|
65
|
-
id = this.sanitizeId(id, schema)
|
|
66
|
-
const extFields = get(options, 'validation.extFields', [])
|
|
67
|
-
let body = noSanitize ? input : await this.sanitizeBody({ body: input, schema, partial, strict: true, extFields })
|
|
68
|
-
delete body.id
|
|
69
|
-
if (!noHook) {
|
|
70
|
-
await runHook(`${this.ns}:beforeRecordUpdate`, name, id, body, options)
|
|
71
|
-
await runHook(`${this.ns}.${camelCase(name)}:beforeRecordUpdate`, id, body, options)
|
|
72
|
-
}
|
|
73
|
-
if (!noValidation) body = await execValidation.call(this, { name, body, options, partial })
|
|
74
|
-
if (!noCheckUnique) await checkUnique.call(this, { schema, body, id })
|
|
75
|
-
const nbody = {}
|
|
76
|
-
forOwn(body, (v, k) => {
|
|
77
|
-
if (v === undefined) return undefined
|
|
78
|
-
const prop = find(schema.properties, { name: k })
|
|
79
|
-
if (!prop) return undefined
|
|
80
|
-
if (options.truncateString && isSet(v) && ['string', 'text'].includes(prop.type)) v = v.slice(0, prop.maxLength)
|
|
81
|
-
nbody[k] = v
|
|
82
|
-
})
|
|
83
|
-
delete nbody.id
|
|
84
|
-
if (!noFeatureHook) await execFeatureHook.call(this, 'beforeUpdate', { schema, body: nbody, options })
|
|
85
|
-
const record = options.record ?? (await handler.call(this.app[driver.ns], { schema, id, body: nbody, options }))
|
|
86
|
-
delete options.record
|
|
87
|
-
if (isSet(options.rels)) await singleRelRows.call(this, { schema, record: record.data, options })
|
|
88
|
-
if (options.req) {
|
|
89
|
-
if (options.req.file) await handleAttachmentUpload.call(this, { name: schema.name, id, body, options, action: 'update' })
|
|
90
|
-
if (options.req.flash && !options.noFlash) options.req.flash('notify', options.req.t('recordUpdated'))
|
|
91
|
-
}
|
|
92
|
-
if (clearModel) await clearModel({ model: name, id, body: nbody, options, record })
|
|
93
|
-
if (noResult) return
|
|
94
|
-
record.oldData = await this.pickRecord({ record: record.oldData, fields, schema, hidden, forceNoHidden })
|
|
95
|
-
record.data = await this.pickRecord({ record: record.data, fields, schema, hidden, forceNoHidden })
|
|
96
|
-
if (!noHook) {
|
|
97
|
-
await runHook(`${this.ns}.${camelCase(name)}:afterRecordUpdate`, id, nbody, options, record)
|
|
98
|
-
await runHook(`${this.ns}:afterRecordUpdate`, name, id, nbody, options, record)
|
|
99
|
-
}
|
|
100
|
-
if (!noFeatureHook) await execFeatureHook.call(this, 'afterUpdate', { schema, body: nbody, record })
|
|
101
|
-
return dataOnly ? record.data : record
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export default update
|
package/method/record/upsert.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Update a record by payload's ID. If no record is found by given ID, a new one will be created instead.
|
|
3
|
-
*
|
|
4
|
-
* Missing ID in payload always results a new record creation.
|
|
5
|
-
* ```
|
|
6
|
-
*
|
|
7
|
-
* @method
|
|
8
|
-
* @memberof Dobo
|
|
9
|
-
* @async
|
|
10
|
-
* @instance
|
|
11
|
-
* @name recordUpsert
|
|
12
|
-
* @param {string} name - Model's name
|
|
13
|
-
* @param {Object} body - Body payload
|
|
14
|
-
* @param {TRecordUpsertOptions} [options={}]
|
|
15
|
-
* @returns {(TRecordUpdateResult|TRecordCreateResult|Object)} Returns updated/newly created record if ```options.dataOnly``` is set. {@link TRecordUpdateResult} or {@link TRecordCreateResult} otherwise
|
|
16
|
-
*/
|
|
17
|
-
async function upsert (name, input, opts = {}) {
|
|
18
|
-
const { generateId } = this.app.bajo
|
|
19
|
-
const { find } = this.app.lib._
|
|
20
|
-
const { cloneDeep, omit, merge } = this.app.lib._
|
|
21
|
-
const { query, omitOnUpdate = [], omitOnCreate = [] } = opts
|
|
22
|
-
const options = cloneDeep(omit(opts, ['req', 'reply', 'query', 'omitOnUpdate', 'omitOnCreate']))
|
|
23
|
-
options.req = opts.req
|
|
24
|
-
options.reply = opts.reply
|
|
25
|
-
options.dataOnly = options.dataOnly ?? true
|
|
26
|
-
await this.modelExists(name, true)
|
|
27
|
-
const { schema } = this.getInfo(name)
|
|
28
|
-
const idField = find(schema.properties, { name: 'id' })
|
|
29
|
-
let id
|
|
30
|
-
if (idField.type === 'string') id = input.id ?? generateId()
|
|
31
|
-
else if (idField.type === 'integer') id = input.id ?? generateId('int')
|
|
32
|
-
id = this.sanitizeId(id, schema)
|
|
33
|
-
let old
|
|
34
|
-
let body
|
|
35
|
-
const o = { dataOnly: true, noHook: true, noCache: true, hidden: options.hidden, forceNoHidden: options.forceNoHidden }
|
|
36
|
-
if (query) {
|
|
37
|
-
old = await this.recordFindOne(name, { query }, o)
|
|
38
|
-
} else {
|
|
39
|
-
o.thrownNotFound = false
|
|
40
|
-
old = await this.recordGet(name, id, o)
|
|
41
|
-
}
|
|
42
|
-
if (old) {
|
|
43
|
-
body = merge(omit(old, ['id', 'createdAt', 'updatedAt', 'removedAt']), omit(input, omitOnUpdate))
|
|
44
|
-
return await this.recordUpdate(name, old.id, body, options)
|
|
45
|
-
}
|
|
46
|
-
if (!query) input.id = id
|
|
47
|
-
body = omit(input, omitOnCreate)
|
|
48
|
-
return await this.recordCreate(name, body, options)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export default upsert
|
package/method/sanitize/body.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sanitize payload body against schema
|
|
3
|
-
*
|
|
4
|
-
* @method
|
|
5
|
-
* @memberof Dobo
|
|
6
|
-
* @async
|
|
7
|
-
* @param {Object} [options={}]
|
|
8
|
-
* @param {Object} [options.body={}]
|
|
9
|
-
* @param {Object} [options.schema={}]
|
|
10
|
-
* @param {boolean} [options.partial=false]
|
|
11
|
-
* @param {boolean} [options.strict=false]
|
|
12
|
-
* @param {Array} [options.extFields=[]]
|
|
13
|
-
* @returns {Object}
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
async function sanitizeBody ({ body = {}, schema = {}, partial, strict, extFields = [] }) {
|
|
17
|
-
const { isSet } = this.app.lib.aneka
|
|
18
|
-
const { dayjs } = this.app.lib
|
|
19
|
-
const { callHandler } = this.app.bajo
|
|
20
|
-
const { has, isString, isNumber, concat, isNaN } = this.app.lib._
|
|
21
|
-
const result = {}
|
|
22
|
-
for (const p of concat(schema.properties, extFields)) {
|
|
23
|
-
if (partial && !has(body, p.name)) continue
|
|
24
|
-
if (['object', 'array'].includes(p.type)) {
|
|
25
|
-
if (isString(body[p.name])) {
|
|
26
|
-
try {
|
|
27
|
-
result[p.name] = JSON.parse(body[p.name])
|
|
28
|
-
} catch (err) {
|
|
29
|
-
result[p.name] = null
|
|
30
|
-
}
|
|
31
|
-
} else {
|
|
32
|
-
try {
|
|
33
|
-
result[p.name] = JSON.parse(JSON.stringify(body[p.name]))
|
|
34
|
-
} catch (err) {}
|
|
35
|
-
}
|
|
36
|
-
} else result[p.name] = body[p.name]
|
|
37
|
-
if (isSet(body[p.name])) {
|
|
38
|
-
if (p.type === 'boolean') result[p.name] = result[p.name] === null ? null : (['true', true].includes(result[p.name]))
|
|
39
|
-
if (['float', 'double'].includes(p.type)) {
|
|
40
|
-
if (isNumber(body[p.name])) result[p.name] = body[p.name]
|
|
41
|
-
else if (strict) {
|
|
42
|
-
result[p.name] = Number(body[p.name])
|
|
43
|
-
} else {
|
|
44
|
-
result[p.name] = parseFloat(body[p.name]) || null
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (['integer', 'smallint'].includes(p.type)) {
|
|
48
|
-
if (isNumber(body[p.name])) result[p.name] = body[p.name]
|
|
49
|
-
else if (strict) {
|
|
50
|
-
result[p.name] = Number(body[p.name])
|
|
51
|
-
} else {
|
|
52
|
-
result[p.name] = parseInt(body[p.name]) || null
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
if (p.type === 'timestamp') {
|
|
56
|
-
if (!isNumber(body[p.name])) result[p.name] = -1
|
|
57
|
-
else {
|
|
58
|
-
const dt = dayjs.unix(body[p.name])
|
|
59
|
-
result[p.name] = dt.isValid() ? dt.unix() : -1
|
|
60
|
-
}
|
|
61
|
-
} else {
|
|
62
|
-
for (const t of ['datetime', 'date|YYYY-MM-DD', 'time|HH:mm:ss']) {
|
|
63
|
-
const [type, input] = t.split('|')
|
|
64
|
-
if (p.type === type) result[p.name] = this.sanitizeDate(body[p.name], { input })
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
if (['string', 'text'].includes(p.type)) result[p.name] = body[p.name] + ''
|
|
68
|
-
} else {
|
|
69
|
-
if (isSet(p.default)) {
|
|
70
|
-
result[p.name] = p.default
|
|
71
|
-
if (isString(p.default) && p.default.startsWith('handler:')) {
|
|
72
|
-
const [, ...args] = p.default.split(':')
|
|
73
|
-
if (args.length > 0) result[p.name] = await callHandler(args.join(':'))
|
|
74
|
-
} else {
|
|
75
|
-
if (['float', 'double'].includes(p.type)) result[p.name] = parseFloat(result[p.name])
|
|
76
|
-
if (['integer', 'smallint'].includes(p.type)) result[p.name] = parseInt(result[p.name])
|
|
77
|
-
if (isNaN(result[p.name])) result[p.name] = null
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return result
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export default sanitizeBody
|
package/method/sanitize/date.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sanitize value as a date/time value. Parse/format string using {@link https://day.js.org/docs/en/display/format|dayjs format}
|
|
3
|
-
*
|
|
4
|
-
* @method
|
|
5
|
-
* @memberof Dobo
|
|
6
|
-
* @param {(number|string)} value - Value to sanitize
|
|
7
|
-
* @param {Object} [options={}] - Options object
|
|
8
|
-
* @param {boolean} [options.silent=true] - If ```true``` (default) and value isn't valid, returns empty
|
|
9
|
-
* @param {string} [options.inputFormat] - If provided, parse value using this option
|
|
10
|
-
* @param {string} [options.outputFormat] - If not provided or ```native```, returns Javascript Date. Otherwise returns formatted date/time string
|
|
11
|
-
* @returns {(string|Date)}
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
function sanitizeDate (value, { inputFormat, outputFormat, silent = true } = {}) {
|
|
15
|
-
const { dayjs } = this.app.lib
|
|
16
|
-
if (value === 0) return null
|
|
17
|
-
if (!outputFormat) outputFormat = inputFormat
|
|
18
|
-
const dt = dayjs(value, inputFormat)
|
|
19
|
-
if (!dt.isValid()) {
|
|
20
|
-
if (silent) return null
|
|
21
|
-
throw this.error('invalidDate')
|
|
22
|
-
}
|
|
23
|
-
if (outputFormat === 'native' || !outputFormat) return dt.toDate()
|
|
24
|
-
return dt.format(outputFormat)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export default sanitizeDate
|
package/method/sanitize/id.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sanitize id according it's schema
|
|
3
|
-
*
|
|
4
|
-
* @method
|
|
5
|
-
* @memberof Dobo
|
|
6
|
-
* @param {(number|string)} id
|
|
7
|
-
* @param {Object} schema
|
|
8
|
-
* @returns {(number|string)}
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
function sanitizeId (id, schema) {
|
|
12
|
-
const prop = schema.properties.find(p => p.name === 'id')
|
|
13
|
-
if (prop.type === 'integer') id = parseInt(id)
|
|
14
|
-
return id
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export default sanitizeId
|
package/method/stat/aggregate.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import resolveMethod from '../../lib/resolve-method.js'
|
|
2
|
-
|
|
3
|
-
async function aggregate (name, filter = {}, options = {}) {
|
|
4
|
-
const { runHook } = this.app.bajo
|
|
5
|
-
const { dataOnly = true, noHook, aggregate } = options
|
|
6
|
-
options.dataOnly = false
|
|
7
|
-
await this.modelExists(name, true)
|
|
8
|
-
const { handler, schema, driver } = await resolveMethod.call(this, name, 'stat-aggregate', options)
|
|
9
|
-
if (!noHook) {
|
|
10
|
-
await runHook(`${this.ns}:beforeStatAggregate`, name, aggregate, filter, options)
|
|
11
|
-
await runHook(`${this.ns}.${name}:beforeStatAggregate`, aggregate, filter, options)
|
|
12
|
-
}
|
|
13
|
-
filter.query = this.buildQuery({ filter, schema, options }) ?? {}
|
|
14
|
-
filter.match = this.buildMatch({ input: filter.match, schema, options }) ?? {}
|
|
15
|
-
const rec = await handler.call(this.app[driver.ns], { schema, filter, options })
|
|
16
|
-
if (!noHook) {
|
|
17
|
-
await runHook(`${this.ns}.${name}:afterStatAggregate`, aggregate, filter, options, rec)
|
|
18
|
-
await runHook(`${this.ns}:afterStatAggregate`, name, aggregate, filter, options, rec)
|
|
19
|
-
}
|
|
20
|
-
return dataOnly ? rec.data : rec
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default aggregate
|
package/method/stat/histogram.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import resolveMethod from '../../lib/resolve-method.js'
|
|
2
|
-
|
|
3
|
-
const types = ['daily', 'monthly', 'yearly']
|
|
4
|
-
|
|
5
|
-
async function histogram (name, filter = {}, options = {}) {
|
|
6
|
-
const { runHook, join } = this.app.bajo
|
|
7
|
-
const { dataOnly = true, noHook, type } = options
|
|
8
|
-
options.dataOnly = false
|
|
9
|
-
if (!types.includes(type)) throw this.error('histogramTypeMusBe%s', join(types))
|
|
10
|
-
await this.modelExists(name, true)
|
|
11
|
-
const { handler, schema, driver } = await resolveMethod.call(this, name, 'stat-histogram', options)
|
|
12
|
-
filter.query = this.buildQuery({ filter, schema, options }) ?? {}
|
|
13
|
-
filter.match = this.buildMatch({ input: filter.match, schema, options }) ?? {}
|
|
14
|
-
if (!noHook) {
|
|
15
|
-
await runHook(`${this.ns}:beforeStatHistogram`, name, type, filter, options)
|
|
16
|
-
await runHook(`${this.ns}.${name}:beforeStatHistogram`, type, filter, options)
|
|
17
|
-
}
|
|
18
|
-
const rec = await handler.call(this.app[driver.ns], { schema, type, filter, options })
|
|
19
|
-
if (!noHook) {
|
|
20
|
-
await runHook(`${this.ns}.${name}:afterStatHistogram`, type, filter, options, rec)
|
|
21
|
-
await runHook(`${this.ns}:afterStatHistogram`, name, type, filter, options, rec)
|
|
22
|
-
}
|
|
23
|
-
return dataOnly ? rec.data : rec
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default histogram
|