dobo 2.0.0 → 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 +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 +725 -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 +366 -0
- package/docs/scripts/third-party/hljs-line-num.js +1 -0
- package/docs/scripts/third-party/hljs-original.js +5164 -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 +671 -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/extend/bajo/intl/en-US.json +69 -30
- package/extend/bajo/intl/id.json +58 -29
- package/extend/bajoCli/applet/clear-record.js +22 -0
- package/extend/bajoCli/applet/connection.js +5 -5
- 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 +25 -26
- 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 +10 -8
- 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 +35 -57
- package/extend/dobo/feature/updated-at.js +14 -12
- package/extend/waibuMpa/route/attachment/@model/@id/@field/@file.js +5 -9
- package/extend/waibuStatic/virtual.json +0 -0
- package/index.js +420 -337
- package/lib/collect-connections.js +60 -21
- package/lib/collect-drivers.js +29 -35
- package/lib/collect-features.js +40 -0
- 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/lib/factory/model/find-record.js +103 -0
- 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/lib/factory/model/validate.js +232 -0
- package/lib/factory/model.js +150 -0
- package/lib/index.js +3 -0
- package/package.json +45 -36
- package/wiki/APPLETS.md +57 -0
- package/wiki/CHANGES.md +46 -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/{docs/query-language.md → wiki/QUERY-LANGUAGE.md} +0 -0
- package/wiki/USER-GUIDE.md +1 -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 -41
- package/extend/bajoCli/applet/record-find.js +0 -27
- 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-feature.js +0 -25
- package/lib/collect-schemas.js +0 -83
- package/lib/exec-feature-hook.js +0 -13
- package/lib/exec-validation.js +0 -21
- package/lib/generic-prop-sanitizer.js +0 -31
- 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 -197
- 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 -19
- package/method/model/drop.js +0 -19
- package/method/model/exists.js +0 -24
- package/method/record/clear.js +0 -24
- package/method/record/count.js +0 -44
- package/method/record/create.js +0 -71
- package/method/record/find-all.js +0 -25
- package/method/record/find-one.js +0 -56
- package/method/record/find.js +0 -52
- package/method/record/get.js +0 -47
- package/method/record/remove.js +0 -41
- package/method/record/update.js +0 -63
- package/method/record/upsert.js +0 -35
- package/method/sanitize/body.js +0 -70
- package/method/sanitize/date.js +0 -14
- package/method/sanitize/id.js +0 -7
- package/method/stat/aggregate.js +0 -23
- package/method/stat/histogram.js +0 -26
- package/method/validate.js +0 -157
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import postProcess from './lib/post-process.js'
|
|
2
|
-
|
|
3
|
-
async function statCount (path, ...args) {
|
|
4
|
-
const { importPkg } = this.app.bajo
|
|
5
|
-
const { isEmpty, map } = this.lib._
|
|
6
|
-
const [select, input] = await importPkg('bajoCli:@inquirer/select', 'bajoCli:@inquirer/input')
|
|
7
|
-
if (isEmpty(this.schemas)) return this.print.fail('notFound%s', this.print.write('field.schema'), { exit: this.app.bajo.applet })
|
|
8
|
-
let [schema, query] = args
|
|
9
|
-
if (isEmpty(schema)) {
|
|
10
|
-
schema = await select({
|
|
11
|
-
message: this.print.write('selectSchema'),
|
|
12
|
-
choices: map(this.schemas, s => ({ value: s.name }))
|
|
13
|
-
})
|
|
14
|
-
}
|
|
15
|
-
if (isEmpty(query)) {
|
|
16
|
-
query = await input({
|
|
17
|
-
message: this.print.write('enterQueryIfAny')
|
|
18
|
-
})
|
|
19
|
-
}
|
|
20
|
-
const filter = { query }
|
|
21
|
-
await postProcess.call(this, { noConfirmation: true, handler: 'statCount', params: [schema, filter], path, processMsg: 'Counting record(s)' })
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export default statCount
|
package/lib/build-bulk-action.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
async function buildBulkAction (name, action, options = {}) {
|
|
2
|
-
const { fs, importModule } = this.app.bajo
|
|
3
|
-
const { camelCase } = this.lib._
|
|
4
|
-
const { schema, driver, connection } = await this.getInfo(name)
|
|
5
|
-
if (!options.force && (schema.disabled ?? []).includes(action)) throw this.error('methodIsDisabled%s%s', camelCase('bulk ' + action), name)
|
|
6
|
-
const file = `${driver.plugin}:/extend/${this.name}/method/bulk/${action}.js`
|
|
7
|
-
if (!fs.existsSync(file)) throw this.error('methodUnsupported%s%s', camelCase('bulk ' + action), name)
|
|
8
|
-
const handler = await importModule(file)
|
|
9
|
-
return { handler, schema, driver, connection }
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export default buildBulkAction
|
package/lib/check-unique.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
async function checkUnique ({ schema, body, id }) {
|
|
2
|
-
const { isSet } = this.lib.aneka
|
|
3
|
-
const { filter, map, set } = this.lib._
|
|
4
|
-
const singles = map(filter(schema.properties, p => (p.index ?? {}).type === 'unique'), 'name')
|
|
5
|
-
const opts = { noHook: true, noCache: true, thrownNotFound: false, forceNoHidden: true }
|
|
6
|
-
let old = {}
|
|
7
|
-
if (id) old = (await this.recordGet(schema.name, id, opts)) ?? {}
|
|
8
|
-
for (const s of singles) {
|
|
9
|
-
if (!isSet(body[s])) continue
|
|
10
|
-
if (id && body[s] === old[s]) continue
|
|
11
|
-
const query = set({}, s, body[s])
|
|
12
|
-
const resp = await this.recordFind(schema.name, { query, limit: 1 }, opts)
|
|
13
|
-
if (resp.length !== 0) {
|
|
14
|
-
const details = [{ field: s, error: 'uniqueConstraintError', value: id }]
|
|
15
|
-
throw this.error('uniqueConstraintError', { details, body })
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
const multis = filter(schema.indexes, i => i.type === 'unique')
|
|
19
|
-
for (const m of multis) {
|
|
20
|
-
const query = {}
|
|
21
|
-
let empty = true
|
|
22
|
-
let same = true
|
|
23
|
-
for (const f of m.fields) {
|
|
24
|
-
if (body[f]) empty = false
|
|
25
|
-
if (body[f] !== old[f]) same = false
|
|
26
|
-
query[f] = body[f]
|
|
27
|
-
}
|
|
28
|
-
if (empty || same) continue
|
|
29
|
-
const resp = await this.recordFind(schema.name, { query, limit: 1 }, { noHook: true, noCache: true, forceNoHidden: true })
|
|
30
|
-
if (resp.length !== 0) {
|
|
31
|
-
const details = map(m.fields, f => {
|
|
32
|
-
return { field: f, error: 'Unique constraint error' }
|
|
33
|
-
})
|
|
34
|
-
throw this.error('Unique constraint error', { details, body })
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export default checkUnique
|
package/lib/collect-feature.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
|
|
3
|
-
async function handler ({ file }) {
|
|
4
|
-
const { name: ns } = this
|
|
5
|
-
const { importModule } = this.app.bajo
|
|
6
|
-
const { camelCase, isFunction } = this.lib._
|
|
7
|
-
const me = this.app.dobo
|
|
8
|
-
|
|
9
|
-
let name = camelCase(path.basename(file, '.js'))
|
|
10
|
-
if (ns !== me.name) name = `${ns}.${name}`
|
|
11
|
-
const mod = await importModule(file)
|
|
12
|
-
if (!isFunction(mod)) this.fatal('featureNotAsync%s', name)
|
|
13
|
-
me.feature[name] = mod
|
|
14
|
-
me.log.trace('- %s', name)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async function collectFeature () {
|
|
18
|
-
const { eachPlugins } = this.app.bajo
|
|
19
|
-
this.feature = {}
|
|
20
|
-
this.log.trace('loadingDbFeature')
|
|
21
|
-
await eachPlugins(handler, { glob: 'feature/*.js', prefix: this.name })
|
|
22
|
-
this.log.debug('totalLoadedFeatures%d', Object.keys(this.feature).length)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export default collectFeature
|
package/lib/collect-schemas.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import sanitizeSchema from './sanitize-schema.js'
|
|
3
|
-
|
|
4
|
-
async function handler ({ file }) {
|
|
5
|
-
const { name: ns, alias } = this
|
|
6
|
-
const { readConfig, eachPlugins } = this.app.bajo
|
|
7
|
-
const { pascalCase } = this.lib.aneka
|
|
8
|
-
const { get, isPlainObject, each, find, has, isArray, forOwn, isString, merge } = this.lib._
|
|
9
|
-
const { fastGlob } = this.lib
|
|
10
|
-
|
|
11
|
-
const base = path.basename(file, path.extname(file))
|
|
12
|
-
const defName = pascalCase(`${alias} ${base}`)
|
|
13
|
-
const mod = await readConfig(file, { ns, ignoreError: true })
|
|
14
|
-
if (!isPlainObject(mod)) this.fatal('invalidSchema%s', defName)
|
|
15
|
-
const forcedConn = get(this, `app.${ns}.config.dobo.schemaConnection.${base}`)
|
|
16
|
-
if (forcedConn) mod.connection = forcedConn
|
|
17
|
-
if (!mod.connection) mod.connection = 'default'
|
|
18
|
-
mod.name = mod.name ?? defName
|
|
19
|
-
mod.file = file
|
|
20
|
-
mod.ns = ns
|
|
21
|
-
mod.attachment = mod.attachment ?? true
|
|
22
|
-
mod.feature = mod.feature ?? []
|
|
23
|
-
mod.buildLevel = mod.buildLevel ?? 999
|
|
24
|
-
const feats = []
|
|
25
|
-
if (isArray(mod.feature)) {
|
|
26
|
-
each(mod.feature, f => {
|
|
27
|
-
if (isString(f)) feats.push({ name: f })
|
|
28
|
-
else if (isPlainObject(f)) feats.push(f)
|
|
29
|
-
})
|
|
30
|
-
} else if (isPlainObject(mod.feature)) {
|
|
31
|
-
forOwn(mod.feature, (v, k) => {
|
|
32
|
-
feats.push(merge({}, v, { name: k }))
|
|
33
|
-
})
|
|
34
|
-
}
|
|
35
|
-
mod.feature = feats
|
|
36
|
-
mod.properties = mod.properties ?? []
|
|
37
|
-
// if ((mod.properties ?? []).length === 0) this.fatal('noPropsFoundOnSchema%s', mod.name)
|
|
38
|
-
// schema extender
|
|
39
|
-
await eachPlugins(async function ({ dir }) {
|
|
40
|
-
const { name: ns } = this
|
|
41
|
-
const glob = `${dir}/extend/dobo/extend/${mod.ns}/schema/${base}.*`
|
|
42
|
-
const files = await fastGlob(glob)
|
|
43
|
-
for (const file of files) {
|
|
44
|
-
const extender = await readConfig(file, { ns, ignoreError: true })
|
|
45
|
-
if (!isPlainObject(extender)) return undefined
|
|
46
|
-
each(extender.properties ?? [], p => {
|
|
47
|
-
if (isString(p) && mod.properties.includes(p)) return undefined
|
|
48
|
-
else if (find(mod.properties, { name: p.name })) return undefined
|
|
49
|
-
mod.properties.push(p)
|
|
50
|
-
})
|
|
51
|
-
const feats = []
|
|
52
|
-
if (isArray(extender.feature)) {
|
|
53
|
-
each(extender.feature, f => {
|
|
54
|
-
if (isString(f)) feats.push({ name: f })
|
|
55
|
-
else if (isPlainObject(f)) feats.push(f)
|
|
56
|
-
})
|
|
57
|
-
} else if (isPlainObject(extender.feature)) {
|
|
58
|
-
forOwn(extender.feature, (v, k) => {
|
|
59
|
-
feats.push(merge({}, v, { name: k }))
|
|
60
|
-
})
|
|
61
|
-
}
|
|
62
|
-
if (feats.length > 0) mod.feature.push(...feats)
|
|
63
|
-
if (ns === this.app.bajo.mainNs) {
|
|
64
|
-
each(['connection', 'name'], i => {
|
|
65
|
-
if (has(extender, i)) mod[i] = extender[i]
|
|
66
|
-
})
|
|
67
|
-
}
|
|
68
|
-
mod.extender = mod.extender ?? []
|
|
69
|
-
mod.extender.push(ns)
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
return mod
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function collectSchemas () {
|
|
76
|
-
const { eachPlugins } = this.app.bajo
|
|
77
|
-
const { isEmpty } = this.lib._
|
|
78
|
-
const result = await eachPlugins(handler, { glob: 'schema/*.*', prefix: this.name })
|
|
79
|
-
if (isEmpty(result)) this.log.warn('notFound%s', this.print.write('schema'))
|
|
80
|
-
else await sanitizeSchema.call(this, result)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export default collectSchemas
|
package/lib/exec-feature-hook.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
async function execFeatureHook (name, params = {}) {
|
|
2
|
-
const { get } = this.lib._
|
|
3
|
-
const { schema } = params
|
|
4
|
-
for (const f of schema.feature) {
|
|
5
|
-
const fn = get(this.feature, f.name)
|
|
6
|
-
if (!fn) continue
|
|
7
|
-
const input = await fn.call(this, f)
|
|
8
|
-
const hook = get(input, 'hook.' + name)
|
|
9
|
-
if (hook) await hook.call(this, params)
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default execFeatureHook
|
package/lib/exec-validation.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
async function execValidation ({ name, body, options, partial }) {
|
|
2
|
-
const { runHook } = this.app.bajo
|
|
3
|
-
const { keys, camelCase } = this.lib._
|
|
4
|
-
const { noHook } = options
|
|
5
|
-
if (!noHook) {
|
|
6
|
-
await runHook(`${this.name}:beforeRecordValidation`, name, body, options)
|
|
7
|
-
await runHook(`${this.name}.${camelCase(name)}:beforeRecordValidation`, body, options)
|
|
8
|
-
}
|
|
9
|
-
const { validation = {} } = options
|
|
10
|
-
if (partial) {
|
|
11
|
-
validation.fields = keys(body)
|
|
12
|
-
}
|
|
13
|
-
body = await this.validate(body, name, validation)
|
|
14
|
-
if (!noHook) {
|
|
15
|
-
await runHook(`${this.name}:afterRecordValidation`, name, body, options)
|
|
16
|
-
await runHook(`${this.name}.${camelCase(name)}:afterRecordValidation`, body, options)
|
|
17
|
-
}
|
|
18
|
-
return body
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export default execValidation
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
const indexTypes = ['default', 'unique', 'primary', 'fulltext']
|
|
2
|
-
|
|
3
|
-
async function genericPropSanitizer ({ prop, schema, driver }) {
|
|
4
|
-
const { join } = this.app.bajo
|
|
5
|
-
const { has, get, each } = this.lib._
|
|
6
|
-
const def = this.propType[prop.type]
|
|
7
|
-
// detect from drivers
|
|
8
|
-
if (prop.type === 'string') {
|
|
9
|
-
def.minLength = prop.minLength ?? 0
|
|
10
|
-
def.maxLength = prop.maxLength ?? 255
|
|
11
|
-
if (has(prop, 'length')) def.maxLength = prop.length
|
|
12
|
-
if (prop.required && def.minLength === 0) def.minLength = 1
|
|
13
|
-
if (def.minLength > 0) prop.required = true
|
|
14
|
-
}
|
|
15
|
-
if (prop.autoInc && !['smallint', 'integer'].includes(prop.type)) delete prop.autoInc
|
|
16
|
-
each(['minLength', 'maxLength', 'kind'], p => {
|
|
17
|
-
if (!has(def, p)) {
|
|
18
|
-
delete prop[p]
|
|
19
|
-
return undefined
|
|
20
|
-
}
|
|
21
|
-
prop[p] = get(prop, p, get(this.config, `default.property.${prop.type}.${p}`, def[p]))
|
|
22
|
-
if (def.choices && !def.choices.includes(prop[p])) {
|
|
23
|
-
this.fatal('unsupportedAllowedChoices%s%s%s%s%s', p, prop[p], prop.name, schema.name, join(def.choices))
|
|
24
|
-
}
|
|
25
|
-
})
|
|
26
|
-
if (prop.index && !indexTypes.includes(prop.index.type)) {
|
|
27
|
-
this.fatal('unsupportedIndexType%s%s%s%s', prop.index.type, prop.name, schema.name, join(indexTypes))
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export default genericPropSanitizer
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
async function handleAttachmentUpload ({ action, name, id, options = {} } = {}) {
|
|
2
|
-
const { getPluginDataDir } = this.app.bajo
|
|
3
|
-
const { fs } = this.lib
|
|
4
|
-
const { req, mimeType, stats, setFile, setField } = options
|
|
5
|
-
|
|
6
|
-
name = this.attachmentPreCheck(name)
|
|
7
|
-
if (!name) return
|
|
8
|
-
if (action === 'remove') {
|
|
9
|
-
const dir = `${getPluginDataDir(this.name)}/attachment/${name}/${id}`
|
|
10
|
-
await fs.remove(dir)
|
|
11
|
-
return
|
|
12
|
-
}
|
|
13
|
-
return this.attachmentCopyUploaded(name, id, { req, mimeType, stats, setFile, setField })
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export default handleAttachmentUpload
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
let saving = false
|
|
2
|
-
|
|
3
|
-
async function instantiate ({ connection, schemas, noRebuild }) {
|
|
4
|
-
const { getPluginDataDir } = this.app.bajo
|
|
5
|
-
const { fs } = this.lib
|
|
6
|
-
const { pick } = this.lib._
|
|
7
|
-
this.memDb = this.memDb ?? {}
|
|
8
|
-
this.memDb.storage = this.memDb.storage ?? {}
|
|
9
|
-
this.memDb.instances = this.memDb.instances ?? []
|
|
10
|
-
const instance = pick(connection, ['name', 'type'])
|
|
11
|
-
this.memDb.instances.push(instance)
|
|
12
|
-
// if (noRebuild) return
|
|
13
|
-
const pdir = `${getPluginDataDir(this.name)}/memDb/data` // persistence dir
|
|
14
|
-
fs.ensureDirSync(pdir)
|
|
15
|
-
const persistence = []
|
|
16
|
-
for (const schema of schemas) {
|
|
17
|
-
this.memDb.storage[schema.name] = this.memDb.storage[schema.name] ?? [] // init empty model
|
|
18
|
-
if (!schema.persistence) continue
|
|
19
|
-
persistence.push(schema.name)
|
|
20
|
-
// load if persistence
|
|
21
|
-
const file = `${pdir}/${schema.name}.json`
|
|
22
|
-
if (!fs.existsSync(file)) continue
|
|
23
|
-
try {
|
|
24
|
-
const data = fs.readFileSync(file, 'utf8')
|
|
25
|
-
this.memDb.storage[schema.name] = JSON.parse(data)
|
|
26
|
-
} catch (err) {
|
|
27
|
-
this.fatal('cantLoad%s%s', schema.name, err.message)
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
setInterval(() => {
|
|
31
|
-
if (saving) return
|
|
32
|
-
saving = true
|
|
33
|
-
for (const item of persistence) {
|
|
34
|
-
const data = this.memDb.storage[item]
|
|
35
|
-
fs.writeFileSync(`${pdir}/${item}.json`, JSON.stringify(data), 'utf8')
|
|
36
|
-
}
|
|
37
|
-
saving = false
|
|
38
|
-
}, this.config.memDb.persistence.syncPeriod * 1000)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export default instantiate
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import getRecord from './get.js'
|
|
2
|
-
|
|
3
|
-
async function create ({ schema, body, options = {} }) {
|
|
4
|
-
const { noResult } = options
|
|
5
|
-
const exist = await getRecord.call(this, { schema, id: body.id, options: { thrownNotFound: false } })
|
|
6
|
-
if (exist.data) throw this.error('recordExists%s%s', body.id, schema.name)
|
|
7
|
-
this.memDb.storage[schema.name].push(body)
|
|
8
|
-
if (noResult) return
|
|
9
|
-
return { data: body }
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export default create
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Query } from 'mingo'
|
|
2
|
-
|
|
3
|
-
async function find ({ schema, filter = {}, options = {} }) {
|
|
4
|
-
const { prepPagination } = this.app.dobo
|
|
5
|
-
const { omit } = this.lib._
|
|
6
|
-
const { limit, skip, sort, page } = await prepPagination(filter, schema)
|
|
7
|
-
const criteria = filter.query ?? {}
|
|
8
|
-
const q = new Query(criteria, { idKey: 'id' })
|
|
9
|
-
let cursor = q.find(this.memDb.storage[schema.name])
|
|
10
|
-
let count = 0
|
|
11
|
-
if (options.count && !options.dataOnly) count = cursor.count()
|
|
12
|
-
cursor = q.find(this.memDb.storage[schema.name])
|
|
13
|
-
if (sort) cursor.sort(sort)
|
|
14
|
-
if (!options.noLimit) cursor.skip(skip).limit(limit)
|
|
15
|
-
let result = { data: cursor.all(), page, limit, count, pages: Math.ceil(count / limit) }
|
|
16
|
-
if (!options.count) result = omit(result, ['count', 'pages'])
|
|
17
|
-
return result
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export default find
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
async function get ({ schema, id, options = {} }) {
|
|
2
|
-
const { thrownNotFound = true } = options
|
|
3
|
-
const { find } = this.lib._
|
|
4
|
-
const result = find(this.memDb.storage[schema.name], { id })
|
|
5
|
-
if (!result && thrownNotFound) throw this.error('recordNotFound%s%s', id, schema.name, { statusCode: 404 })
|
|
6
|
-
return { data: result }
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export default get
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import getRecord from './get.js'
|
|
2
|
-
|
|
3
|
-
async function remove ({ schema, id, options = {} }) {
|
|
4
|
-
const { noResult } = options
|
|
5
|
-
const { findIndex, pullAt } = this.lib._
|
|
6
|
-
const rec = noResult ? undefined : await getRecord.call(this, { schema, id })
|
|
7
|
-
const idx = findIndex(this.memDb.storage[schema.name], { id })
|
|
8
|
-
pullAt(this.memDb.storage[schema.name], [idx])
|
|
9
|
-
if (noResult) return
|
|
10
|
-
return { oldData: rec.data }
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default remove
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import getRecord from './get.js'
|
|
2
|
-
|
|
3
|
-
async function update ({ schema, id, body, options }) {
|
|
4
|
-
const { noResult } = options
|
|
5
|
-
const { findIndex, merge } = this.lib._
|
|
6
|
-
const old = noResult ? undefined : await getRecord.call(this, { schema, id })
|
|
7
|
-
const idx = findIndex(this.memDb.storage[schema.name], { id })
|
|
8
|
-
const current = this.memDb.storage[schema.name][idx]
|
|
9
|
-
this.memDb.storage[schema.name][idx] = merge(current, body)
|
|
10
|
-
if (noResult) return
|
|
11
|
-
const result = this.memDb.storage[schema.name][idx]
|
|
12
|
-
return { oldData: old.data, data: result }
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export default update
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Query } from 'mingo'
|
|
2
|
-
|
|
3
|
-
async function count ({ schema, filter = {}, options = {} }) {
|
|
4
|
-
const criteria = filter.query ?? {}
|
|
5
|
-
const q = new Query(criteria, { idKey: 'id' })
|
|
6
|
-
const cursor = q.find(this.memDb.storage[schema.name])
|
|
7
|
-
const count = cursor.count()
|
|
8
|
-
return { data: count }
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export default count
|
package/lib/mem-db/start.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import addFixtures from '../add-fixtures.js'
|
|
2
|
-
|
|
3
|
-
async function start () {
|
|
4
|
-
const { filter, map } = this.lib._
|
|
5
|
-
|
|
6
|
-
const conns = filter(this.connections, { type: 'dobo:memory' })
|
|
7
|
-
const schemas = filter(this.schemas, s => {
|
|
8
|
-
const names = map(conns, 'name')
|
|
9
|
-
return names.includes(s.connection)
|
|
10
|
-
})
|
|
11
|
-
if (schemas.length === 0) return
|
|
12
|
-
this.log.debug('addingFixtureToMemDb')
|
|
13
|
-
for (const schema of schemas) {
|
|
14
|
-
if (schema.persistence) {
|
|
15
|
-
this.log.warn('addingMemoryPersistenceIgnored', schema.name)
|
|
16
|
-
continue
|
|
17
|
-
}
|
|
18
|
-
let { success, error } = await addFixtures.call(this, schema.name)
|
|
19
|
-
success = success ?? 0
|
|
20
|
-
error = error ?? 0
|
|
21
|
-
this.log.trace('- %s@%s (%d/%d)', schema.name, schema.connection, success, success + error)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export default start
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
async function mergeAttachmentInfo (rec, source, { mimeType, stats, fullPath }) {
|
|
2
|
-
const { importPkg } = this.app.bajo
|
|
3
|
-
const { fs } = this.lib
|
|
4
|
-
const { pick } = this.lib._
|
|
5
|
-
if (!this.app.waibu) return
|
|
6
|
-
const mime = await importPkg('waibu:mime')
|
|
7
|
-
|
|
8
|
-
if (mimeType) rec.mimeType = mime.getType(rec.file)
|
|
9
|
-
if (fullPath) rec.fullPath = source
|
|
10
|
-
if (stats) {
|
|
11
|
-
const s = fs.statSync(source)
|
|
12
|
-
rec.stats = pick(s, ['size', 'atime', 'ctime', 'mtime'])
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export default mergeAttachmentInfo
|
package/lib/multi-rel-rows.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
async function multiRelRows ({ schema, records, options = {} }) {
|
|
2
|
-
const { isSet } = this.lib.aneka
|
|
3
|
-
const { uniq, find, map } = this.lib._
|
|
4
|
-
const props = schema.properties.filter(p => isSet(p.rel) && !(options.hidden ?? []).includes(p.name))
|
|
5
|
-
// const props = schema.properties.filter(p => isSet(p.rel))
|
|
6
|
-
options.rels = options.rels ?? []
|
|
7
|
-
if (props.length > 0) {
|
|
8
|
-
for (const prop of props) {
|
|
9
|
-
for (const key in prop.rel) {
|
|
10
|
-
if (!((typeof options.rels === 'string' && ['*', 'all'].includes(options.rels)) || options.rels.includes(key))) continue
|
|
11
|
-
const val = prop.rel[key]
|
|
12
|
-
if (val.fields.length === 0) continue
|
|
13
|
-
if (val.type !== 'one-to-one') continue
|
|
14
|
-
const relschema = this.getSchema(val.schema)
|
|
15
|
-
const matches = uniq(map(records, r => {
|
|
16
|
-
let v = r[prop.name]
|
|
17
|
-
if (val.propName === 'id') {
|
|
18
|
-
const idField = find(relschema.properties, { name: 'id' })
|
|
19
|
-
if (idField.type === 'integer') v = parseInt(v)
|
|
20
|
-
}
|
|
21
|
-
return v
|
|
22
|
-
}))
|
|
23
|
-
const query = {}
|
|
24
|
-
query[val.propName] = { $in: matches }
|
|
25
|
-
const relFilter = { query, limit: matches.length }
|
|
26
|
-
const relOptions = { dataOnly: true, rels: [] }
|
|
27
|
-
const results = await this.recordFind(relschema.name, relFilter, relOptions)
|
|
28
|
-
const fields = [...val.fields]
|
|
29
|
-
if (!fields.includes(prop.name)) fields.push(prop.name)
|
|
30
|
-
for (const i in records) {
|
|
31
|
-
records[i]._rel = records[i]._rel ?? {}
|
|
32
|
-
const rec = records[i]
|
|
33
|
-
const res = results.find(r => (r[val.propName] + '') === rec[prop.name] + '')
|
|
34
|
-
if (res) records[i]._rel[key] = await this.pickRecord({ record: res, fields, schema: relschema })
|
|
35
|
-
else records[i]._rel[key] = {}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export default multiRelRows
|
package/lib/resolve-method.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
async function resolveMethod (name, method, options = {}) {
|
|
2
|
-
const { importModule } = this.app.bajo
|
|
3
|
-
const { fs } = this.lib
|
|
4
|
-
const { camelCase } = this.lib._
|
|
5
|
-
const { schema, driver, connection } = this.getInfo(name)
|
|
6
|
-
const [group, action] = method.split('-')
|
|
7
|
-
if (!options.force && (schema.disabled ?? []).includes(action)) throw this.error('methodIsDisabled%s%s', camelCase(method), name)
|
|
8
|
-
let file
|
|
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}/extend/${this.name}/method/${group}/${action}.js`
|
|
11
|
-
if (!fs.existsSync(file)) throw this.error('methodUnsupported%s%s', camelCase(method), name)
|
|
12
|
-
const handler = await importModule(file)
|
|
13
|
-
return { handler, schema, driver, connection }
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export default resolveMethod
|