dobo 1.2.10 → 2.0.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.
- package/.github/FUNDING.yml +13 -0
- package/.github/workflows/repo-lockdown.yml +24 -0
- package/.jsdoc.conf.json +45 -0
- package/LICENSE +1 -1
- package/README.md +38 -19
- package/docs/Dobo.html +26 -0
- package/docs/data/search.json +1 -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 +7 -0
- package/docs/index.html +3 -0
- package/docs/index.js.html +578 -0
- package/docs/lib_collect-connections.js.html +39 -0
- package/docs/lib_collect-drivers.js.html +52 -0
- package/docs/lib_collect-features.js.html +36 -0
- package/docs/lib_collect-schemas.js.html +94 -0
- package/docs/lib_index.js.html +6 -0
- package/docs/method_model_create.js.html +35 -0
- package/docs/method_model_drop.js.html +34 -0
- package/docs/method_model_exists.js.html +40 -0
- package/docs/method_record_count.js.html +69 -0
- package/docs/method_record_create.js.html +114 -0
- package/docs/method_record_find-all.js.html +44 -0
- package/docs/method_record_find-one.js.html +73 -0
- package/docs/method_record_find.js.html +118 -0
- package/docs/method_record_get.js.html +92 -0
- package/docs/method_record_remove.js.html +75 -0
- package/docs/method_record_update.js.html +107 -0
- package/docs/method_record_upsert.js.html +54 -0
- package/docs/method_sanitize_body.js.html +88 -0
- package/docs/method_sanitize_date.js.html +30 -0
- package/docs/method_sanitize_id.js.html +20 -0
- package/docs/method_validate.js.html +249 -0
- package/docs/module-Lib.html +3 -0
- package/docs/scripts/core.js +726 -0
- package/docs/scripts/core.min.js +23 -0
- package/docs/scripts/resize.js +90 -0
- package/docs/scripts/search.js +265 -0
- package/docs/scripts/search.min.js +6 -0
- package/docs/scripts/third-party/Apache-License-2.0.txt +202 -0
- package/docs/scripts/third-party/fuse.js +9 -0
- package/docs/scripts/third-party/hljs-line-num-original.js +369 -0
- package/docs/scripts/third-party/hljs-line-num.js +1 -0
- package/docs/scripts/third-party/hljs-original.js +5171 -0
- package/docs/scripts/third-party/hljs.js +1 -0
- package/docs/scripts/third-party/popper.js +5 -0
- package/docs/scripts/third-party/tippy.js +1 -0
- package/docs/scripts/third-party/tocbot.js +672 -0
- package/docs/scripts/third-party/tocbot.min.js +1 -0
- package/docs/static/bitcoin.jpeg +0 -0
- package/docs/static/home.md +25 -0
- package/docs/static/logo-ecosystem.png +0 -0
- package/docs/static/logo.png +0 -0
- package/docs/styles/clean-jsdoc-theme-base.css +1159 -0
- package/docs/styles/clean-jsdoc-theme-dark.css +412 -0
- package/docs/styles/clean-jsdoc-theme-light.css +482 -0
- package/docs/styles/clean-jsdoc-theme-scrollbar.css +30 -0
- package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
- package/docs/styles/clean-jsdoc-theme.min.css +1 -0
- package/{bajo → extend/bajo}/intl/en-US.json +3 -2
- package/{bajo → extend/bajo}/intl/id.json +3 -2
- package/{bajoCli → extend/bajoCli}/applet/connection.js +5 -5
- package/extend/bajoCli/applet/lib/post-process.js +53 -0
- package/extend/bajoCli/applet/model-clear.js +11 -0
- package/{bajoCli → extend/bajoCli}/applet/model-rebuild.js +13 -13
- package/{bajoCli → extend/bajoCli}/applet/record-create.js +10 -8
- package/{bajoCli → extend/bajoCli}/applet/record-find.js +6 -5
- package/{bajoCli → extend/bajoCli}/applet/record-get.js +5 -5
- package/{bajoCli → extend/bajoCli}/applet/record-remove.js +5 -5
- package/{bajoCli → extend/bajoCli}/applet/record-update.js +9 -9
- package/{bajoCli → extend/bajoCli}/applet/schema.js +4 -4
- package/{bajoCli → extend/bajoCli}/applet/stat-count.js +4 -4
- package/{dobo → extend/dobo}/feature/created-at.js +1 -1
- package/{dobo → extend/dobo}/feature/removed-at.js +3 -3
- package/{dobo → extend/dobo}/feature/updated-at.js +2 -2
- package/{waibuMpa → extend/waibuMpa}/route/attachment/@model/@id/@field/@file.js +3 -3
- package/index.js +230 -72
- package/lib/add-fixtures.js +7 -6
- package/lib/build-bulk-action.js +2 -2
- package/lib/check-unique.js +2 -2
- package/lib/collect-connections.js +15 -4
- package/lib/collect-drivers.js +15 -6
- package/lib/{collect-feature.js → collect-features.js} +13 -4
- package/lib/collect-schemas.js +22 -12
- package/lib/exec-feature-hook.js +1 -1
- package/lib/exec-validation.js +5 -5
- package/lib/generic-prop-sanitizer.js +6 -5
- package/lib/handle-attachment-upload.js +2 -2
- package/lib/index.js +3 -0
- package/lib/mem-db/conn-sanitizer.js +1 -1
- package/lib/mem-db/instantiate.js +4 -4
- package/lib/mem-db/method/record/find.js +1 -1
- package/lib/mem-db/method/record/get.js +1 -1
- package/lib/mem-db/method/record/remove.js +1 -1
- package/lib/mem-db/method/record/update.js +1 -1
- package/lib/mem-db/start.js +1 -1
- package/lib/merge-attachment-info.js +2 -2
- package/lib/multi-rel-rows.js +2 -2
- package/lib/resolve-method.js +3 -3
- package/lib/sanitize-schema.js +8 -7
- package/lib/single-rel-rows.js +2 -2
- package/{plugin-method → method}/attachment/copy-uploaded.js +2 -2
- package/{plugin-method → method}/attachment/create.js +3 -3
- package/{plugin-method → method}/attachment/find.js +2 -2
- package/{plugin-method → method}/attachment/get-path.js +3 -3
- package/{plugin-method → method}/attachment/get.js +1 -1
- package/{plugin-method → method}/attachment/pre-check.js +1 -1
- package/{plugin-method → method}/attachment/remove.js +1 -1
- package/{plugin-method → method}/bulk/create.js +6 -6
- package/{plugin-method → method}/model/clear.js +5 -5
- package/method/model/create.js +32 -0
- package/method/model/drop.js +31 -0
- package/method/model/exists.js +37 -0
- package/{plugin-method → method}/record/clear.js +5 -5
- package/{plugin-method → method}/record/count.js +27 -5
- package/{plugin-method → method}/record/create.js +46 -6
- package/{plugin-method → method}/record/find-all.js +16 -0
- package/{plugin-method → method}/record/find-one.js +20 -6
- package/method/record/find.js +115 -0
- package/method/record/get.js +89 -0
- package/method/record/remove.js +72 -0
- package/{plugin-method → method}/record/update.js +47 -6
- package/{plugin-method → method}/record/upsert.js +18 -2
- package/{plugin-method → method}/sanitize/body.js +18 -3
- package/method/sanitize/date.js +27 -0
- package/{plugin-method → method}/sanitize/id.js +10 -0
- package/{plugin-method → method}/stat/aggregate.js +4 -4
- package/{plugin-method → method}/stat/histogram.js +4 -4
- package/{plugin-method → method}/validate.js +96 -7
- package/package.json +41 -36
- package/wiki/APPLETS.md +57 -0
- package/wiki/CONFIG.md +25 -0
- package/wiki/CONTRIBUTING.md +5 -0
- package/wiki/DEV-GUIDE.md +1 -0
- package/wiki/ECOSYSTEM.md +20 -0
- package/wiki/GETTING-STARTED.md +166 -0
- package/wiki/USER-GUIDE.md +1 -0
- package/bajoCli/applet/lib/post-process.js +0 -47
- package/bajoCli/applet/model-clear.js +0 -11
- package/plugin-method/model/create.js +0 -19
- package/plugin-method/model/drop.js +0 -19
- package/plugin-method/model/exists.js +0 -24
- package/plugin-method/record/find.js +0 -52
- package/plugin-method/record/get.js +0 -47
- package/plugin-method/record/remove.js +0 -41
- package/plugin-method/sanitize/date.js +0 -14
- /package/{bajoCli → extend/bajoCli}/applet.js +0 -0
- /package/{dobo → extend/dobo}/feature/dt.js +0 -0
- /package/{dobo → extend/dobo}/feature/int-id.js +0 -0
- /package/{waibuStatic → extend/waibuStatic}/virtual.json +0 -0
- /package/{plugin-method → method}/attachment/update.js +0 -0
- /package/{docs/query-language.md → wiki/QUERY-LANGUAGE.md} +0 -0
package/lib/collect-schemas.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
import sanitizeSchema from './sanitize-schema.js'
|
|
3
3
|
|
|
4
|
-
async function handler ({ file
|
|
4
|
+
async function handler ({ file }) {
|
|
5
|
+
const { ns, alias } = this
|
|
5
6
|
const { readConfig, eachPlugins } = this.app.bajo
|
|
6
|
-
const { pascalCase } = this.lib.aneka
|
|
7
|
-
const { get, isPlainObject, each, find, has, isArray, forOwn, isString, merge } = this.lib._
|
|
8
|
-
const { fastGlob } = this.lib
|
|
7
|
+
const { pascalCase } = this.app.lib.aneka
|
|
8
|
+
const { get, isPlainObject, each, find, has, isArray, forOwn, isString, merge } = this.app.lib._
|
|
9
|
+
const { fastGlob } = this.app.lib
|
|
9
10
|
|
|
10
11
|
const base = path.basename(file, path.extname(file))
|
|
11
12
|
const defName = pascalCase(`${alias} ${base}`)
|
|
@@ -35,11 +36,12 @@ async function handler ({ file, alias, ns }) {
|
|
|
35
36
|
mod.properties = mod.properties ?? []
|
|
36
37
|
// if ((mod.properties ?? []).length === 0) this.fatal('noPropsFoundOnSchema%s', mod.name)
|
|
37
38
|
// schema extender
|
|
38
|
-
await eachPlugins(async function (
|
|
39
|
-
const
|
|
39
|
+
await eachPlugins(async function ({ dir }) {
|
|
40
|
+
const { ns } = this
|
|
41
|
+
const glob = `${dir}/extend/dobo/extend/${mod.ns}/schema/${base}.*`
|
|
40
42
|
const files = await fastGlob(glob)
|
|
41
43
|
for (const file of files) {
|
|
42
|
-
const extender = await readConfig(file, { ns
|
|
44
|
+
const extender = await readConfig(file, { ns, ignoreError: true })
|
|
43
45
|
if (!isPlainObject(extender)) return undefined
|
|
44
46
|
each(extender.properties ?? [], p => {
|
|
45
47
|
if (isString(p) && mod.properties.includes(p)) return undefined
|
|
@@ -58,23 +60,31 @@ async function handler ({ file, alias, ns }) {
|
|
|
58
60
|
})
|
|
59
61
|
}
|
|
60
62
|
if (feats.length > 0) mod.feature.push(...feats)
|
|
61
|
-
if (
|
|
63
|
+
if (ns === this.app.mainNs) {
|
|
62
64
|
each(['connection', 'name'], i => {
|
|
63
65
|
if (has(extender, i)) mod[i] = extender[i]
|
|
64
66
|
})
|
|
65
67
|
}
|
|
66
68
|
mod.extender = mod.extender ?? []
|
|
67
|
-
mod.extender.push(
|
|
69
|
+
mod.extender.push(ns)
|
|
68
70
|
}
|
|
69
71
|
})
|
|
70
72
|
return mod
|
|
71
73
|
}
|
|
72
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Collect all database schemas from loaded plugins
|
|
77
|
+
*
|
|
78
|
+
* @name collectSchemas
|
|
79
|
+
* @memberof module:Lib
|
|
80
|
+
* @async
|
|
81
|
+
* @see Dobo#init
|
|
82
|
+
*/
|
|
73
83
|
async function collectSchemas () {
|
|
74
84
|
const { eachPlugins } = this.app.bajo
|
|
75
|
-
const { isEmpty } = this.lib._
|
|
76
|
-
const result = await eachPlugins(handler, { glob: 'schema/*.*', prefix: this.
|
|
77
|
-
if (isEmpty(result)) this.log.warn('notFound%s', this.
|
|
85
|
+
const { isEmpty } = this.app.lib._
|
|
86
|
+
const result = await eachPlugins(handler, { glob: 'schema/*.*', prefix: this.ns })
|
|
87
|
+
if (isEmpty(result)) this.log.warn('notFound%s', this.t('schema'))
|
|
78
88
|
else await sanitizeSchema.call(this, result)
|
|
79
89
|
}
|
|
80
90
|
|
package/lib/exec-feature-hook.js
CHANGED
package/lib/exec-validation.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
async function execValidation ({ name, body, options, partial }) {
|
|
2
2
|
const { runHook } = this.app.bajo
|
|
3
|
-
const { keys, camelCase } = this.lib._
|
|
3
|
+
const { keys, camelCase } = this.app.lib._
|
|
4
4
|
const { noHook } = options
|
|
5
5
|
if (!noHook) {
|
|
6
|
-
await runHook(`${this.
|
|
7
|
-
await runHook(`${this.
|
|
6
|
+
await runHook(`${this.ns}:beforeRecordValidation`, name, body, options)
|
|
7
|
+
await runHook(`${this.ns}.${camelCase(name)}:beforeRecordValidation`, body, options)
|
|
8
8
|
}
|
|
9
9
|
const { validation = {} } = options
|
|
10
10
|
if (partial) {
|
|
@@ -12,8 +12,8 @@ async function execValidation ({ name, body, options, partial }) {
|
|
|
12
12
|
}
|
|
13
13
|
body = await this.validate(body, name, validation)
|
|
14
14
|
if (!noHook) {
|
|
15
|
-
await runHook(`${this.
|
|
16
|
-
await runHook(`${this.
|
|
15
|
+
await runHook(`${this.ns}:afterRecordValidation`, name, body, options)
|
|
16
|
+
await runHook(`${this.ns}.${camelCase(name)}:afterRecordValidation`, body, options)
|
|
17
17
|
}
|
|
18
18
|
return body
|
|
19
19
|
}
|
|
@@ -2,8 +2,9 @@ const indexTypes = ['default', 'unique', 'primary', 'fulltext']
|
|
|
2
2
|
|
|
3
3
|
async function genericPropSanitizer ({ prop, schema, driver }) {
|
|
4
4
|
const { join } = this.app.bajo
|
|
5
|
-
const { has, get, each } = this.lib._
|
|
6
|
-
const
|
|
5
|
+
const { has, get, each } = this.app.lib._
|
|
6
|
+
const { propType } = this.app.pluginClass.dobo
|
|
7
|
+
const def = propType[prop.type]
|
|
7
8
|
// detect from drivers
|
|
8
9
|
if (prop.type === 'string') {
|
|
9
10
|
def.minLength = prop.minLength ?? 0
|
|
@@ -13,14 +14,14 @@ async function genericPropSanitizer ({ prop, schema, driver }) {
|
|
|
13
14
|
if (def.minLength > 0) prop.required = true
|
|
14
15
|
}
|
|
15
16
|
if (prop.autoInc && !['smallint', 'integer'].includes(prop.type)) delete prop.autoInc
|
|
16
|
-
each(['minLength', 'maxLength', '
|
|
17
|
+
each(['minLength', 'maxLength', 'textType'], p => {
|
|
17
18
|
if (!has(def, p)) {
|
|
18
19
|
delete prop[p]
|
|
19
20
|
return undefined
|
|
20
21
|
}
|
|
21
22
|
prop[p] = get(prop, p, get(this.config, `default.property.${prop.type}.${p}`, def[p]))
|
|
22
|
-
if (def.
|
|
23
|
-
this.fatal('unsupportedAllowedChoices%s%s%s%s%s', p, prop[p], prop.name, schema.name, join(def.
|
|
23
|
+
if (def.values && !def.values.includes(prop[p])) {
|
|
24
|
+
this.fatal('unsupportedAllowedChoices%s%s%s%s%s', p, prop[p], prop.name, schema.name, join(def.values))
|
|
24
25
|
}
|
|
25
26
|
})
|
|
26
27
|
if (prop.index && !indexTypes.includes(prop.index.type)) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
async function handleAttachmentUpload ({ action, name, id, options = {} } = {}) {
|
|
2
2
|
const { getPluginDataDir } = this.app.bajo
|
|
3
|
-
const { fs } = this.lib
|
|
3
|
+
const { fs } = this.app.lib
|
|
4
4
|
const { req, mimeType, stats, setFile, setField } = options
|
|
5
5
|
|
|
6
6
|
name = this.attachmentPreCheck(name)
|
|
7
7
|
if (!name) return
|
|
8
8
|
if (action === 'remove') {
|
|
9
|
-
const dir = `${getPluginDataDir(this.
|
|
9
|
+
const dir = `${getPluginDataDir(this.ns)}/attachment/${name}/${id}`
|
|
10
10
|
await fs.remove(dir)
|
|
11
11
|
return
|
|
12
12
|
}
|
package/lib/index.js
ADDED
|
@@ -2,15 +2,15 @@ let saving = false
|
|
|
2
2
|
|
|
3
3
|
async function instantiate ({ connection, schemas, noRebuild }) {
|
|
4
4
|
const { getPluginDataDir } = this.app.bajo
|
|
5
|
-
const { fs } = this.lib
|
|
6
|
-
const { pick } = this.lib._
|
|
5
|
+
const { fs } = this.app.lib
|
|
6
|
+
const { pick } = this.app.lib._
|
|
7
7
|
this.memDb = this.memDb ?? {}
|
|
8
8
|
this.memDb.storage = this.memDb.storage ?? {}
|
|
9
9
|
this.memDb.instances = this.memDb.instances ?? []
|
|
10
10
|
const instance = pick(connection, ['name', 'type'])
|
|
11
11
|
this.memDb.instances.push(instance)
|
|
12
12
|
// if (noRebuild) return
|
|
13
|
-
const pdir = `${getPluginDataDir(this.
|
|
13
|
+
const pdir = `${getPluginDataDir(this.ns)}/memDb/data` // persistence dir
|
|
14
14
|
fs.ensureDirSync(pdir)
|
|
15
15
|
const persistence = []
|
|
16
16
|
for (const schema of schemas) {
|
|
@@ -35,7 +35,7 @@ async function instantiate ({ connection, schemas, noRebuild }) {
|
|
|
35
35
|
fs.writeFileSync(`${pdir}/${item}.json`, JSON.stringify(data), 'utf8')
|
|
36
36
|
}
|
|
37
37
|
saving = false
|
|
38
|
-
}, this.config.memDb.persistence.
|
|
38
|
+
}, this.config.memDb.persistence.syncPeriodDur)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export default instantiate
|
|
@@ -2,7 +2,7 @@ import { Query } from 'mingo'
|
|
|
2
2
|
|
|
3
3
|
async function find ({ schema, filter = {}, options = {} }) {
|
|
4
4
|
const { prepPagination } = this.app.dobo
|
|
5
|
-
const { omit } = this.lib._
|
|
5
|
+
const { omit } = this.app.lib._
|
|
6
6
|
const { limit, skip, sort, page } = await prepPagination(filter, schema)
|
|
7
7
|
const criteria = filter.query ?? {}
|
|
8
8
|
const q = new Query(criteria, { idKey: 'id' })
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
async function get ({ schema, id, options = {} }) {
|
|
2
2
|
const { thrownNotFound = true } = options
|
|
3
|
-
const { find } = this.lib._
|
|
3
|
+
const { find } = this.app.lib._
|
|
4
4
|
const result = find(this.memDb.storage[schema.name], { id })
|
|
5
5
|
if (!result && thrownNotFound) throw this.error('recordNotFound%s%s', id, schema.name, { statusCode: 404 })
|
|
6
6
|
return { data: result }
|
|
@@ -2,7 +2,7 @@ import getRecord from './get.js'
|
|
|
2
2
|
|
|
3
3
|
async function remove ({ schema, id, options = {} }) {
|
|
4
4
|
const { noResult } = options
|
|
5
|
-
const { findIndex, pullAt } = this.lib._
|
|
5
|
+
const { findIndex, pullAt } = this.app.lib._
|
|
6
6
|
const rec = noResult ? undefined : await getRecord.call(this, { schema, id })
|
|
7
7
|
const idx = findIndex(this.memDb.storage[schema.name], { id })
|
|
8
8
|
pullAt(this.memDb.storage[schema.name], [idx])
|
|
@@ -2,7 +2,7 @@ import getRecord from './get.js'
|
|
|
2
2
|
|
|
3
3
|
async function update ({ schema, id, body, options }) {
|
|
4
4
|
const { noResult } = options
|
|
5
|
-
const { findIndex, merge } = this.lib._
|
|
5
|
+
const { findIndex, merge } = this.app.lib._
|
|
6
6
|
const old = noResult ? undefined : await getRecord.call(this, { schema, id })
|
|
7
7
|
const idx = findIndex(this.memDb.storage[schema.name], { id })
|
|
8
8
|
const current = this.memDb.storage[schema.name][idx]
|
package/lib/mem-db/start.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import addFixtures from '../add-fixtures.js'
|
|
2
2
|
|
|
3
3
|
async function start () {
|
|
4
|
-
const { filter, map } = this.lib._
|
|
4
|
+
const { filter, map } = this.app.lib._
|
|
5
5
|
|
|
6
6
|
const conns = filter(this.connections, { type: 'dobo:memory' })
|
|
7
7
|
const schemas = filter(this.schemas, s => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
async function mergeAttachmentInfo (rec, source, { mimeType, stats, fullPath }) {
|
|
2
2
|
const { importPkg } = this.app.bajo
|
|
3
|
-
const { fs } = this.lib
|
|
4
|
-
const { pick } = this.lib._
|
|
3
|
+
const { fs } = this.app.lib
|
|
4
|
+
const { pick } = this.app.lib._
|
|
5
5
|
if (!this.app.waibu) return
|
|
6
6
|
const mime = await importPkg('waibu:mime')
|
|
7
7
|
|
package/lib/multi-rel-rows.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
async function multiRelRows ({ schema, records, options = {} }) {
|
|
2
|
-
const { isSet } = this.lib.aneka
|
|
3
|
-
const { uniq, find, map } = this.lib._
|
|
2
|
+
const { isSet } = this.app.lib.aneka
|
|
3
|
+
const { uniq, find, map } = this.app.lib._
|
|
4
4
|
const props = schema.properties.filter(p => isSet(p.rel) && !(options.hidden ?? []).includes(p.name))
|
|
5
5
|
// const props = schema.properties.filter(p => isSet(p.rel))
|
|
6
6
|
options.rels = options.rels ?? []
|
package/lib/resolve-method.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
async function resolveMethod (name, method, options = {}) {
|
|
2
2
|
const { importModule } = this.app.bajo
|
|
3
|
-
const { fs } = this.lib
|
|
4
|
-
const { camelCase } = this.lib._
|
|
3
|
+
const { fs } = this.app.lib
|
|
4
|
+
const { camelCase } = this.app.lib._
|
|
5
5
|
const { schema, driver, connection } = this.getInfo(name)
|
|
6
6
|
const [group, action] = method.split('-')
|
|
7
7
|
if (!options.force && (schema.disabled ?? []).includes(action)) throw this.error('methodIsDisabled%s%s', camelCase(method), name)
|
|
8
8
|
let file
|
|
9
9
|
if (connection.name === 'memory') file = `${this.app[driver.ns].dir.pkg}/lib/mem-db/method/${group}/${action}.js`
|
|
10
|
-
else file = `${this.app[driver.ns].dir.pkg}/${this.
|
|
10
|
+
else file = `${this.app[driver.ns].dir.pkg}/extend/${this.ns}/method/${group}/${action}.js`
|
|
11
11
|
if (!fs.existsSync(file)) throw this.error('methodUnsupported%s%s', camelCase(method), name)
|
|
12
12
|
const handler = await importModule(file)
|
|
13
13
|
return { handler, schema, driver, connection }
|
package/lib/sanitize-schema.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import genericPropSanitizer from './generic-prop-sanitizer.js'
|
|
2
2
|
|
|
3
3
|
async function sanitizeFeature (item) {
|
|
4
|
-
const { get, isPlainObject, mergeWith, isArray } = this.lib._
|
|
4
|
+
const { get, isPlainObject, mergeWith, isArray } = this.app.lib._
|
|
5
5
|
for (const f of item.feature) {
|
|
6
6
|
const feature = get(this.feature, f.name) // source from collectFeature
|
|
7
7
|
if (!feature) this.fatal('unknownFeature%s%s', f.name, item.name)
|
|
8
8
|
let [ns, path] = f.name.split('.')
|
|
9
|
-
if (!path) ns = this.
|
|
9
|
+
if (!path) ns = this.ns
|
|
10
10
|
const input = await feature.call(this.app[ns], f)
|
|
11
11
|
let props = input.properties
|
|
12
12
|
if (isPlainObject(props)) props = [props]
|
|
@@ -37,10 +37,11 @@ async function sanitizeFullText (item) {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
async function sanitizeSchema (items) {
|
|
40
|
-
const { defaultsDeep } = this.lib.aneka
|
|
40
|
+
const { defaultsDeep } = this.app.lib.aneka
|
|
41
41
|
const { freeze, fatal, importModule, join, breakNsPath, runHook } = this.app.bajo
|
|
42
|
-
const { isEmpty, orderBy, map, keys, findIndex, find, each, isString, get, isPlainObject, camelCase, uniq, filter } = this.lib._
|
|
43
|
-
const
|
|
42
|
+
const { isEmpty, orderBy, map, keys, findIndex, find, each, isString, get, isPlainObject, camelCase, uniq, filter } = this.app.lib._
|
|
43
|
+
const { propType } = this.app.pluginClass.dobo
|
|
44
|
+
const propTypes = keys(propType)
|
|
44
45
|
const schemas = []
|
|
45
46
|
this.log.debug('loadingDbSchemas')
|
|
46
47
|
for (const k in items) {
|
|
@@ -57,7 +58,7 @@ async function sanitizeSchema (items) {
|
|
|
57
58
|
if (isEmpty(type)) type = conn.type
|
|
58
59
|
const driver = find(this.drivers, { type, ns, driver: conn.driver })
|
|
59
60
|
if (driver.lowerCaseModel) item.name = item.name.toLowerCase()
|
|
60
|
-
let file = `${ns}
|
|
61
|
+
let file = `${ns}:/extend/${this.ns}/lib/${type}/prop-sanitizer.js`
|
|
61
62
|
let propSanitizer = await importModule(file)
|
|
62
63
|
if (!propSanitizer) propSanitizer = genericPropSanitizer
|
|
63
64
|
for (const idx in item.properties) {
|
|
@@ -128,7 +129,7 @@ async function sanitizeSchema (items) {
|
|
|
128
129
|
if (!all.includes(p.name)) all.push(p.name)
|
|
129
130
|
else fatal.call(this, 'Field \'%s@%s\' should be used only once', p.name, item.name)
|
|
130
131
|
})
|
|
131
|
-
file = `${ns}
|
|
132
|
+
file = `${ns}:/extend/${this.ns}/lib/${type}/schema-sanitizer.js`
|
|
132
133
|
const schemaSanitizer = await importModule(file)
|
|
133
134
|
if (schemaSanitizer) await schemaSanitizer.call(this, { schema: item, connection: conn, driver })
|
|
134
135
|
schemas.push(item)
|
package/lib/single-rel-rows.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
async function singleRelRows ({ schema, record, options = {} }) {
|
|
2
|
-
const { isSet } = this.lib.aneka
|
|
3
|
-
const { find } = this.lib._
|
|
2
|
+
const { isSet } = this.app.lib.aneka
|
|
3
|
+
const { find } = this.app.lib._
|
|
4
4
|
const props = schema.properties.filter(p => isSet(p.rel) && !(options.hidden ?? []).includes(p.name))
|
|
5
5
|
const rels = {}
|
|
6
6
|
options.rels = options.rels ?? []
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
|
|
3
3
|
async function copyUploaded (name, id, options = {}) {
|
|
4
|
-
const { fs } = this.lib
|
|
4
|
+
const { fs } = this.app.lib
|
|
5
5
|
const { req, setField, setFile, mimeType, stats, silent = true } = options
|
|
6
6
|
name = this.attachmentPreCheck(name)
|
|
7
7
|
if (!name) {
|
|
8
8
|
if (silent) return
|
|
9
|
-
throw this.error('isMissing%s', this.
|
|
9
|
+
throw this.error('isMissing%s', this.t('field.name'))
|
|
10
10
|
}
|
|
11
11
|
if (!this.app.waibu) {
|
|
12
12
|
if (silent) return
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import mergeAttachmentInfo from '../../lib/merge-attachment-info.js'
|
|
2
2
|
|
|
3
3
|
async function create (name, id, options = {}) {
|
|
4
|
-
const { fs } = this.lib
|
|
5
|
-
const { isEmpty } = this.lib._
|
|
4
|
+
const { fs } = this.app.lib
|
|
5
|
+
const { isEmpty } = this.app.lib._
|
|
6
6
|
name = this.attachmentPreCheck(name)
|
|
7
7
|
if (!name) return
|
|
8
8
|
const { source, field = 'file', file } = options
|
|
9
9
|
if (isEmpty(file)) return
|
|
10
|
-
if (!source) throw this.error('isMissing%s', this.
|
|
10
|
+
if (!source) throw this.error('isMissing%s', this.t('field.source'))
|
|
11
11
|
const baseDir = await this.attachmentGetPath(name, id, field, file, { dirOnly: true })
|
|
12
12
|
const { fullPath, stats, mimeType, req } = options
|
|
13
13
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import mergeAttachmentInfo from '../../lib/merge-attachment-info.js'
|
|
2
2
|
|
|
3
3
|
async function find (name, id, options = {}) {
|
|
4
|
-
const { fastGlob, fs } = this.lib
|
|
4
|
+
const { fastGlob, fs } = this.app.lib
|
|
5
5
|
const { getPluginDataDir } = this.app.bajo
|
|
6
6
|
name = this.attachmentPreCheck(name)
|
|
7
7
|
if (!name) return
|
|
8
|
-
const dir = `${getPluginDataDir(this.
|
|
8
|
+
const dir = `${getPluginDataDir(this.ns)}/attachment/${name}/${id}`
|
|
9
9
|
if (!fs.existsSync(dir)) return []
|
|
10
10
|
const files = await fastGlob(`${dir}/**/*`)
|
|
11
11
|
const { fullPath, stats, mimeType } = options
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
async function getPath (name, id, field, file, options = {}) {
|
|
2
2
|
const { getPluginDataDir } = this.app.bajo
|
|
3
|
-
const { pascalCase } = this.lib.aneka
|
|
4
|
-
const { fs } = this.lib
|
|
5
|
-
const dir = `${getPluginDataDir(this.
|
|
3
|
+
const { pascalCase } = this.app.lib.aneka
|
|
4
|
+
const { fs } = this.app.lib
|
|
5
|
+
const dir = `${getPluginDataDir(this.ns)}/attachment/${pascalCase(name)}/${id}`
|
|
6
6
|
if (options.dirOnly) return dir
|
|
7
7
|
const path = field ? `${dir}/${field}/${file}` : `${dir}/${file}`
|
|
8
8
|
if (!fs.existsSync(path)) throw this.error('notFound')
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
async function get (name, id, field, file, options = {}) {
|
|
2
2
|
name = this.attachmentPreCheck(name)
|
|
3
3
|
if (!name) return
|
|
4
|
-
const { find } = this.lib._
|
|
4
|
+
const { find } = this.app.lib._
|
|
5
5
|
const all = await this.attachmentFind(name, id, options)
|
|
6
6
|
if (field === 'null') field = null
|
|
7
7
|
const data = find(all, { field, file })
|
|
@@ -3,10 +3,10 @@ import execValidation from '../../lib/exec-validation.js'
|
|
|
3
3
|
import execFeatureHook from '../../lib/exec-feature-hook.js'
|
|
4
4
|
|
|
5
5
|
async function create (name, inputs, options) {
|
|
6
|
-
const { isSet } = this.lib.aneka
|
|
6
|
+
const { isSet } = this.app.lib.aneka
|
|
7
7
|
const { generateId, runHook } = this.app.bajo
|
|
8
8
|
const { clearModel } = this.cache ?? {}
|
|
9
|
-
const { find } = this.lib._
|
|
9
|
+
const { find } = this.app.lib._
|
|
10
10
|
options.dataOnly = options.dataOnly ?? true
|
|
11
11
|
options.truncateString = options.truncateString ?? true
|
|
12
12
|
const { noHook, noValidation } = options
|
|
@@ -20,8 +20,8 @@ async function create (name, inputs, options) {
|
|
|
20
20
|
if (!noValidation) b = await execValidation.call(this, { noHook, name, b, options })
|
|
21
21
|
}
|
|
22
22
|
if (!noHook) {
|
|
23
|
-
await runHook(`${this.
|
|
24
|
-
await runHook(`${this.
|
|
23
|
+
await runHook(`${this.ns}:beforeBulkCreate`, name, bodies, options)
|
|
24
|
+
await runHook(`${this.ns}.${name}:beforeBulkCreate`, bodies, options)
|
|
25
25
|
}
|
|
26
26
|
for (const idx in bodies) {
|
|
27
27
|
await execFeatureHook.call(this, 'beforeCreate', { schema, body: bodies[idx] })
|
|
@@ -37,8 +37,8 @@ async function create (name, inputs, options) {
|
|
|
37
37
|
await execFeatureHook.call(this, 'afterCreate', { schema, body: bodies[idx] })
|
|
38
38
|
}
|
|
39
39
|
if (!noHook) {
|
|
40
|
-
await runHook(`${this.
|
|
41
|
-
await runHook(`${this.
|
|
40
|
+
await runHook(`${this.ns}.${name}:afterBulkCreate`, bodies, options)
|
|
41
|
+
await runHook(`${this.ns}:afterBulkCreate`, name, bodies, options)
|
|
42
42
|
}
|
|
43
43
|
if (clearModel) await clearModel({ model: name })
|
|
44
44
|
}
|
|
@@ -2,19 +2,19 @@ import resolveMethod from '../../lib/resolve-method.js'
|
|
|
2
2
|
|
|
3
3
|
async function clear (name, options = {}) {
|
|
4
4
|
const { runHook } = this.app.bajo
|
|
5
|
-
const { camelCase } = this.lib._
|
|
5
|
+
const { camelCase } = this.app.lib._
|
|
6
6
|
|
|
7
7
|
await this.modelExists(name, true)
|
|
8
8
|
const { noHook } = options
|
|
9
9
|
const { handler, schema, driver } = await resolveMethod.call(this, name, 'model-clear', options)
|
|
10
10
|
if (!noHook) {
|
|
11
|
-
await runHook(`${this.
|
|
12
|
-
await runHook(`${this.
|
|
11
|
+
await runHook(`${this.ns}:beforeModelClear`, schema, options)
|
|
12
|
+
await runHook(`${this.ns}.${camelCase(name)}:beforeModelClear`, options)
|
|
13
13
|
}
|
|
14
14
|
const resp = await handler.call(this.app[driver.ns], { schema, options })
|
|
15
15
|
if (!noHook) {
|
|
16
|
-
await runHook(`${this.
|
|
17
|
-
await runHook(`${this.
|
|
16
|
+
await runHook(`${this.ns}.${camelCase(name)}:afterModelClear`, options, resp)
|
|
17
|
+
await runHook(`${this.ns}:afterModelClear`, schema, options, resp)
|
|
18
18
|
}
|
|
19
19
|
return resp
|
|
20
20
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import resolveMethod from '../../lib/resolve-method.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create a new model:
|
|
5
|
+
* - read corresponding schema
|
|
6
|
+
* - attempt to create table/database/collection accordingly
|
|
7
|
+
*
|
|
8
|
+
* @method
|
|
9
|
+
* @memberof Dobo
|
|
10
|
+
* @async
|
|
11
|
+
* @instance
|
|
12
|
+
* @name modelCreate
|
|
13
|
+
* @param {string} name - Model's name
|
|
14
|
+
* @param {Object} [options={}] - Options object
|
|
15
|
+
*/
|
|
16
|
+
async function create (name, options = {}) {
|
|
17
|
+
const { runHook } = this.app.bajo
|
|
18
|
+
const { camelCase } = this.app.lib._
|
|
19
|
+
|
|
20
|
+
const { handler, schema, driver } = await resolveMethod.call(this, name, 'model-create', options)
|
|
21
|
+
if (!options.noHook) {
|
|
22
|
+
await runHook(`${this.ns}:beforeModelCreate`, schema, options)
|
|
23
|
+
await runHook(`${this.ns}.${camelCase(name)}:beforeModelCreate`, options)
|
|
24
|
+
}
|
|
25
|
+
await handler.call(this.app[driver.ns], { schema, options })
|
|
26
|
+
if (!options.noHook) {
|
|
27
|
+
await runHook(`${this.ns}.${camelCase(name)}:afterModelCreate`, options)
|
|
28
|
+
await runHook(`${this.ns}:afterModelCreate`, schema, options)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default create
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import resolveMethod from '../../lib/resolve-method.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Drop database model
|
|
5
|
+
*
|
|
6
|
+
* @method
|
|
7
|
+
* @memberof Dobo
|
|
8
|
+
* @async
|
|
9
|
+
* @instance
|
|
10
|
+
* @name modelDrop
|
|
11
|
+
* @param {string} name - Model's name
|
|
12
|
+
* @param {Object} [options={}] - Options object
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
async function drop (name, options = {}) {
|
|
16
|
+
const { runHook } = this.app.bajo
|
|
17
|
+
const { camelCase } = this.app.lib._
|
|
18
|
+
const { handler, schema, driver } = await resolveMethod.call(this, name, 'model-drop', options)
|
|
19
|
+
|
|
20
|
+
if (!options.noHook) {
|
|
21
|
+
await runHook(`${this.ns}:beforeModelDrop`, schema, options)
|
|
22
|
+
await runHook(`${this.ns}.${camelCase(name)}:beforeModelDrop`, options)
|
|
23
|
+
}
|
|
24
|
+
await handler.call(this.app[driver.ns], { schema, options })
|
|
25
|
+
if (!options.noHook) {
|
|
26
|
+
await runHook(`${this.ns}.${camelCase(name)}:afterModelDrop`, options)
|
|
27
|
+
await runHook(`${this.ns}:afterModelDrop`, schema, options)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default drop
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import resolveMethod from '../../lib/resolve-method.js'
|
|
2
|
+
|
|
3
|
+
const cache = {}
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check if model exists already
|
|
7
|
+
*
|
|
8
|
+
* @method
|
|
9
|
+
* @memberof Dobo
|
|
10
|
+
* @async
|
|
11
|
+
* @instance
|
|
12
|
+
* @name modelExists
|
|
13
|
+
* @param {string} name - Model's name
|
|
14
|
+
* @param {boolean} [thrown=false] - If ```true``` throw error if not exists instead of just silent
|
|
15
|
+
* @param {Object} [options={}] - Options object
|
|
16
|
+
* @returns {boolean}
|
|
17
|
+
*/
|
|
18
|
+
async function exists (name, thrown, options = {}) {
|
|
19
|
+
if (cache[name]) return cache[name]
|
|
20
|
+
const { runHook } = this.app.bajo
|
|
21
|
+
const { camelCase } = this.app.lib._
|
|
22
|
+
const { handler, schema, driver } = await resolveMethod.call(this, name, 'model-exists', options)
|
|
23
|
+
if (!options.noHook) {
|
|
24
|
+
await runHook(`${this.ns}:beforeModelExists`, schema, options)
|
|
25
|
+
await runHook(`${this.ns}.${camelCase(name)}:beforeModelExists`, options)
|
|
26
|
+
}
|
|
27
|
+
const exist = await handler.call(this.app[driver.ns], { schema, options })
|
|
28
|
+
if (!options.noHook) {
|
|
29
|
+
await runHook(`${this.ns}.${camelCase(name)}:afterModelExists`, exist, options)
|
|
30
|
+
await runHook(`${this.ns}:afterModelExists`, schema, exist, options)
|
|
31
|
+
}
|
|
32
|
+
if (!exist && thrown) throw this.error('modelNotExists%s', name)
|
|
33
|
+
cache[name] = exist
|
|
34
|
+
return exist
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default exists
|
|
@@ -3,20 +3,20 @@ import resolveMethod from '../../lib/resolve-method.js'
|
|
|
3
3
|
async function clear (name, opts = {}) {
|
|
4
4
|
const { runHook } = this.app.bajo
|
|
5
5
|
await this.modelExists(name, true)
|
|
6
|
-
const { cloneDeep, camelCase, omit } = this.lib._
|
|
6
|
+
const { cloneDeep, camelCase, omit } = this.app.lib._
|
|
7
7
|
const options = cloneDeep(omit(opts, ['req', 'reply']))
|
|
8
8
|
options.req = opts.req
|
|
9
9
|
options.reply = opts.reply
|
|
10
10
|
const { noHook } = options
|
|
11
11
|
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-clear', options)
|
|
12
12
|
if (!noHook) {
|
|
13
|
-
await runHook(`${this.
|
|
14
|
-
await runHook(`${this.
|
|
13
|
+
await runHook(`${this.ns}:beforeRecordClear`, name, options)
|
|
14
|
+
await runHook(`${this.ns}.${camelCase(name)}:beforeRecordClear`, options)
|
|
15
15
|
}
|
|
16
16
|
const resp = await handler.call(this.app[driver.ns], { schema, options })
|
|
17
17
|
if (!noHook) {
|
|
18
|
-
await runHook(`${this.
|
|
19
|
-
await runHook(`${this.
|
|
18
|
+
await runHook(`${this.ns}.${camelCase(name)}:afterRecordClear`, options, resp)
|
|
19
|
+
await runHook(`${this.ns}:afterRecordClear`, name, options, resp)
|
|
20
20
|
}
|
|
21
21
|
return resp
|
|
22
22
|
}
|