dobo 1.1.0 → 1.1.2
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/bajo/intl/en-US.json +5 -1
- package/bajo/intl/id.json +0 -1
- package/bajoCli/applet/connection.js +1 -1
- package/bajoCli/applet/lib/post-process.js +1 -1
- package/bajoCli/applet/model-clear.js +1 -1
- package/bajoCli/applet/model-rebuild.js +27 -7
- package/bajoCli/applet/record-create.js +1 -1
- package/bajoCli/applet/record-find.js +1 -1
- package/bajoCli/applet/record-get.js +1 -1
- package/bajoCli/applet/record-remove.js +1 -1
- package/bajoCli/applet/record-update.js +1 -1
- package/bajoCli/applet/schema.js +1 -1
- package/bajoCli/applet/stat-count.js +1 -1
- package/dobo/feature/removed-at.js +85 -0
- package/lib/add-fixtures.js +1 -1
- package/lib/build-bulk-action.js +1 -1
- package/lib/check-unique.js +5 -5
- package/lib/collect-connections.js +1 -1
- package/lib/collect-drivers.js +1 -1
- package/lib/collect-feature.js +1 -1
- package/lib/collect-schemas.js +3 -3
- package/lib/exec-feature-hook.js +4 -3
- package/lib/exec-validation.js +1 -1
- package/lib/generic-prop-sanitizer.js +1 -1
- package/lib/handle-attachment-upload.js +1 -1
- package/lib/mem-db/conn-sanitizer.js +1 -1
- package/lib/mem-db/instantiate.js +2 -2
- 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/resolve-method.js +2 -2
- package/lib/sanitize-schema.js +3 -3
- package/package.json +1 -1
- package/plugin/factory.js +324 -0
- package/plugin/method/attachment/copy-uploaded.js +1 -1
- package/plugin/method/attachment/create.js +1 -1
- package/plugin/method/attachment/find.js +1 -1
- package/plugin/method/attachment/get-path.js +1 -1
- package/plugin/method/attachment/get.js +1 -1
- package/plugin/method/attachment/remove.js +1 -1
- package/plugin/method/bulk/create.js +1 -1
- package/plugin/method/model/clear.js +1 -1
- package/plugin/method/model/create.js +1 -1
- package/plugin/method/model/drop.js +1 -1
- package/plugin/method/model/exists.js +1 -1
- package/plugin/method/record/clear.js +1 -1
- package/plugin/method/record/count.js +13 -8
- package/plugin/method/record/create.js +9 -8
- package/plugin/method/record/find-one.js +11 -4
- package/plugin/method/record/find.js +10 -4
- package/plugin/method/record/get.js +10 -4
- package/plugin/method/record/remove.js +9 -4
- package/plugin/method/record/update.js +6 -4
- package/plugin/method/record/upsert.js +20 -6
- package/plugin/method/sanitize/body.js +1 -1
- package/plugin/method/sanitize/date.js +1 -1
- package/plugin/method/validate.js +2 -2
- package/waibuMpa/route/attachment/@model/@id/@field/@file.js +9 -2
- package/plugin/.alias +0 -1
- package/plugin/config.json +0 -36
- package/plugin/init.js +0 -29
- package/plugin/method/aggregate-types.js +0 -1
- package/plugin/method/build-match.js +0 -34
- package/plugin/method/build-query.js +0 -14
- package/plugin/method/get-connection.js +0 -6
- package/plugin/method/get-info.js +0 -14
- package/plugin/method/get-schema.js +0 -10
- package/plugin/method/pick-record.js +0 -36
- package/plugin/method/prep-pagination.js +0 -63
- package/plugin/method/prop-type.js +0 -43
- package/plugin/method/validation-error-message.js +0 -12
- package/plugin/start.js +0 -20
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import resolveMethod from '../../../lib/resolve-method.js'
|
|
2
2
|
import singleRelRows from '../../../lib/single-rel-rows.js'
|
|
3
|
+
import execFeatureHook from '../../../lib/exec-feature-hook.js'
|
|
3
4
|
|
|
4
5
|
async function get (name, id, opts = {}) {
|
|
5
6
|
const { runHook, isSet } = this.app.bajo
|
|
6
7
|
const { get, set } = this.cache ?? {}
|
|
7
|
-
const { cloneDeep, camelCase, omit } = this.
|
|
8
|
+
const { cloneDeep, camelCase, omit } = this.lib._
|
|
9
|
+
delete opts.record
|
|
8
10
|
const options = cloneDeep(omit(opts, ['req', 'reply']))
|
|
9
11
|
options.req = opts.req
|
|
10
12
|
options.reply = opts.reply
|
|
11
13
|
options.dataOnly = options.dataOnly ?? true
|
|
12
|
-
let { fields, dataOnly, noHook, noCache, hidden = [], forceNoHidden } = options
|
|
14
|
+
let { fields, dataOnly, noHook, noCache, noFeatureHook, hidden = [], forceNoHidden } = options
|
|
13
15
|
await this.modelExists(name, true)
|
|
14
16
|
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-get', options)
|
|
15
17
|
if (!schema.cacheable) noCache = true
|
|
@@ -19,14 +21,17 @@ async function get (name, id, opts = {}) {
|
|
|
19
21
|
await runHook(`${this.name}:beforeRecordGet`, name, id, options)
|
|
20
22
|
await runHook(`${this.name}.${camelCase(name)}:beforeRecordGet`, id, options)
|
|
21
23
|
}
|
|
22
|
-
if (
|
|
24
|
+
if (!noFeatureHook) await execFeatureHook.call(this, 'beforeGet', { schema, id, options })
|
|
25
|
+
if (get && !noCache && !options.record) {
|
|
23
26
|
const cachedResult = await get({ model: name, id, options })
|
|
24
27
|
if (cachedResult) {
|
|
25
28
|
cachedResult.cached = true
|
|
29
|
+
if (!noFeatureHook) await execFeatureHook.call(this, 'afterGet', { schema, id, options, record: cachedResult })
|
|
26
30
|
return dataOnly ? cachedResult.data : cachedResult
|
|
27
31
|
}
|
|
28
32
|
}
|
|
29
|
-
const record = await handler.call(this.app[driver.ns], { schema, id, options })
|
|
33
|
+
const record = options.record ?? (await handler.call(this.app[driver.ns], { schema, id, options }))
|
|
34
|
+
delete options.record
|
|
30
35
|
if (isSet(options.rels)) await singleRelRows.call(this, { schema, record: record.data, options })
|
|
31
36
|
if (!noHook) {
|
|
32
37
|
await runHook(`${this.name}.${camelCase(name)}:afterRecordGet`, id, options, record)
|
|
@@ -35,6 +40,7 @@ async function get (name, id, opts = {}) {
|
|
|
35
40
|
record.data = await this.pickRecord({ record: record.data, fields, schema, hidden, forceNoHidden })
|
|
36
41
|
|
|
37
42
|
if (set && !noCache) await set({ model: name, id, options, record })
|
|
43
|
+
if (!noFeatureHook) await execFeatureHook.call(this, 'afterGet', { schema, id, options, record })
|
|
38
44
|
return dataOnly ? record.data : record
|
|
39
45
|
}
|
|
40
46
|
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import resolveMethod from '../../../lib/resolve-method.js'
|
|
2
2
|
import handleAttachmentUpload from '../../../lib/handle-attachment-upload.js'
|
|
3
|
+
import execFeatureHook from '../../../lib/exec-feature-hook.js'
|
|
3
4
|
|
|
4
5
|
async function remove (name, id, opts = {}) {
|
|
5
6
|
const { runHook } = this.app.bajo
|
|
6
7
|
const { clearModel } = this.cache ?? {}
|
|
7
|
-
const { cloneDeep, camelCase, omit } = this.
|
|
8
|
+
const { cloneDeep, camelCase, omit } = this.lib._
|
|
9
|
+
delete opts.record
|
|
8
10
|
const options = cloneDeep(omit(opts, ['req', 'reply']))
|
|
9
11
|
options.req = opts.req
|
|
10
12
|
options.reply = opts.reply
|
|
11
13
|
options.dataOnly = options.dataOnly ?? true
|
|
12
|
-
const { fields, dataOnly, noHook, noResult, hidden, forceNoHidden } = options
|
|
14
|
+
const { fields, dataOnly, noHook, noResult, noFeatureHook, hidden, forceNoHidden } = options
|
|
13
15
|
options.dataOnly = false
|
|
14
16
|
await this.modelExists(name, true)
|
|
15
17
|
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-remove', options)
|
|
@@ -18,7 +20,9 @@ async function remove (name, id, opts = {}) {
|
|
|
18
20
|
await runHook(`${this.name}:beforeRecordRemove`, name, id, options)
|
|
19
21
|
await runHook(`${this.name}.${camelCase(name)}:beforeRecordRemove`, id, options)
|
|
20
22
|
}
|
|
21
|
-
|
|
23
|
+
if (!noFeatureHook) await execFeatureHook.call(this, 'beforeRemove', { schema, id, options })
|
|
24
|
+
const record = options.record ?? (await handler.call(this.app[driver.ns], { schema, id, options }))
|
|
25
|
+
delete options.record
|
|
22
26
|
if (options.req) {
|
|
23
27
|
if (options.req.file) await handleAttachmentUpload.call(this, { name: schema.name, id, options, action: 'remove' })
|
|
24
28
|
if (options.req.flash && !options.noFlash) options.req.flash('notify', options.req.t('recordRemoved'))
|
|
@@ -29,7 +33,8 @@ async function remove (name, id, opts = {}) {
|
|
|
29
33
|
}
|
|
30
34
|
if (clearModel) await clearModel({ model: name, id, options, record })
|
|
31
35
|
if (noResult) return
|
|
32
|
-
record.oldData = await this.pickRecord({ record: record.oldData, fields, schema, hidden, forceNoHidden })
|
|
36
|
+
record.oldData = options.record ? options.record.oldData : (await this.pickRecord({ record: record.oldData, fields, schema, hidden, forceNoHidden }))
|
|
37
|
+
if (!noFeatureHook) await execFeatureHook.call(this, 'afterRemove', { schema, id, options, record })
|
|
33
38
|
return dataOnly ? record.oldData : record
|
|
34
39
|
}
|
|
35
40
|
|
|
@@ -8,7 +8,8 @@ import singleRelRows from '../../../lib/single-rel-rows.js'
|
|
|
8
8
|
async function update (name, id, input, opts = {}) {
|
|
9
9
|
const { runHook, isSet } = this.app.bajo
|
|
10
10
|
const { clearModel } = this.cache ?? {}
|
|
11
|
-
const { forOwn, find, cloneDeep, camelCase, omit, get } = this.
|
|
11
|
+
const { forOwn, find, cloneDeep, camelCase, omit, get } = this.lib._
|
|
12
|
+
delete opts.record
|
|
12
13
|
const options = cloneDeep(omit(opts, ['req', 'reply']))
|
|
13
14
|
options.req = opts.req
|
|
14
15
|
options.reply = opts.reply
|
|
@@ -27,7 +28,6 @@ async function update (name, id, input, opts = {}) {
|
|
|
27
28
|
await runHook(`${this.name}:beforeRecordUpdate`, name, id, body, options)
|
|
28
29
|
await runHook(`${this.name}.${camelCase(name)}:beforeRecordUpdate`, id, body, options)
|
|
29
30
|
}
|
|
30
|
-
if (!noFeatureHook) await execFeatureHook.call(this, 'beforeUpdate', { schema, body })
|
|
31
31
|
if (!noValidation) body = await execValidation.call(this, { name, body, options, partial })
|
|
32
32
|
if (!noCheckUnique) await checkUnique.call(this, { schema, body, id })
|
|
33
33
|
const nbody = {}
|
|
@@ -39,13 +39,14 @@ async function update (name, id, input, opts = {}) {
|
|
|
39
39
|
nbody[k] = v
|
|
40
40
|
})
|
|
41
41
|
delete nbody.id
|
|
42
|
-
|
|
42
|
+
if (!noFeatureHook) await execFeatureHook.call(this, 'beforeUpdate', { schema, body: nbody, options })
|
|
43
|
+
const record = options.record ?? (await handler.call(this.app[driver.ns], { schema, id, body: nbody, options }))
|
|
44
|
+
delete options.record
|
|
43
45
|
if (isSet(options.rels)) await singleRelRows.call(this, { schema, record: record.data, options })
|
|
44
46
|
if (options.req) {
|
|
45
47
|
if (options.req.file) await handleAttachmentUpload.call(this, { name: schema.name, id, body, options, action: 'update' })
|
|
46
48
|
if (options.req.flash && !options.noFlash) options.req.flash('notify', options.req.t('recordUpdated'))
|
|
47
49
|
}
|
|
48
|
-
if (!noFeatureHook) await execFeatureHook.call(this, 'afterUpdate', { schema, body: nbody, record })
|
|
49
50
|
if (!noHook) {
|
|
50
51
|
await runHook(`${this.name}.${camelCase(name)}:afterRecordUpdate`, id, nbody, options, record)
|
|
51
52
|
await runHook(`${this.name}:afterRecordUpdate`, name, id, nbody, options, record)
|
|
@@ -54,6 +55,7 @@ async function update (name, id, input, opts = {}) {
|
|
|
54
55
|
if (noResult) return
|
|
55
56
|
record.oldData = await this.pickRecord({ record: record.oldData, fields, schema, hidden, forceNoHidden })
|
|
56
57
|
record.data = await this.pickRecord({ record: record.data, fields, schema, hidden, forceNoHidden })
|
|
58
|
+
if (!noFeatureHook) await execFeatureHook.call(this, 'afterUpdate', { schema, body: nbody, record })
|
|
57
59
|
return dataOnly ? record.data : record
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
async function upsert (name, input, opts = {}) {
|
|
2
2
|
const { generateId } = this.app.bajo
|
|
3
|
-
const { find } = this.
|
|
4
|
-
const { cloneDeep, omit } = this.
|
|
5
|
-
const
|
|
3
|
+
const { find } = this.lib._
|
|
4
|
+
const { cloneDeep, omit, merge } = this.lib._
|
|
5
|
+
const { query, omitOnUpdate = [], omitOnCreate = [] } = opts
|
|
6
|
+
const options = cloneDeep(omit(opts, ['req', 'reply', 'query', 'omitOnUpdate', 'omitOnCreate']))
|
|
6
7
|
options.req = opts.req
|
|
7
8
|
options.reply = opts.reply
|
|
8
9
|
options.dataOnly = options.dataOnly ?? true
|
|
@@ -13,9 +14,22 @@ async function upsert (name, input, opts = {}) {
|
|
|
13
14
|
if (idField.type === 'string') id = input.id ?? generateId()
|
|
14
15
|
else if (idField.type === 'integer') id = input.id ?? generateId('int')
|
|
15
16
|
id = this.sanitizeId(id, schema)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
let old
|
|
18
|
+
let body
|
|
19
|
+
const o = { dataOnly: true, noHook: true, noCache: true, hidden: options.hidden, forceNoHidden: options.forceNoHidden }
|
|
20
|
+
if (query) {
|
|
21
|
+
old = await this.recordFindOne(name, { query }, o)
|
|
22
|
+
} else {
|
|
23
|
+
o.thrownNotFound = false
|
|
24
|
+
old = await this.recordGet(name, id, o)
|
|
25
|
+
}
|
|
26
|
+
if (old) {
|
|
27
|
+
body = merge(omit(old, ['id', 'createdAt', 'updatedAt', 'removedAt']), omit(input, omitOnUpdate))
|
|
28
|
+
return await this.recordUpdate(name, old.id, body, options)
|
|
29
|
+
}
|
|
30
|
+
if (!query) input.id = id
|
|
31
|
+
body = omit(input, omitOnCreate)
|
|
32
|
+
return await this.recordCreate(name, body, options)
|
|
19
33
|
}
|
|
20
34
|
|
|
21
35
|
export default upsert
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
async function sanitizeBody ({ body = {}, schema = {}, partial, strict, extFields = [] }) {
|
|
2
2
|
const { isSet, dayjs, callHandler } = this.app.bajo
|
|
3
|
-
const { has, isString, isNumber, concat } = this.
|
|
3
|
+
const { has, isString, isNumber, concat } = this.lib._
|
|
4
4
|
const result = {}
|
|
5
5
|
for (const p of concat(schema.properties, extFields)) {
|
|
6
6
|
if (partial && !has(body, p.name)) continue
|
|
@@ -20,7 +20,7 @@ function buildFromDbSchema (schema, { fields = [], rule = {}, extFields = [] } =
|
|
|
20
20
|
const {
|
|
21
21
|
isPlainObject, get, each, isEmpty, isString, forOwn, keys,
|
|
22
22
|
find, isArray, has, cloneDeep, concat, without
|
|
23
|
-
} = this.
|
|
23
|
+
} = this.lib._
|
|
24
24
|
const obj = {}
|
|
25
25
|
const me = this
|
|
26
26
|
const refs = []
|
|
@@ -127,7 +127,7 @@ function buildFromDbSchema (schema, { fields = [], rule = {}, extFields = [] } =
|
|
|
127
127
|
|
|
128
128
|
async function validate (value, joiSchema, { ns, fields, extFields, params } = {}) {
|
|
129
129
|
const { defaultsDeep, isSet } = this.app.bajo
|
|
130
|
-
const { isString, forOwn, find } = this.
|
|
130
|
+
const { isString, forOwn, find } = this.lib._
|
|
131
131
|
|
|
132
132
|
ns = ns ?? [this.name]
|
|
133
133
|
params = defaultsDeep(params, this.config.validationParams)
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
|
|
3
3
|
async function attachment (req, reply) {
|
|
4
|
+
const { isString } = this.lib._
|
|
4
5
|
const { importPkg, getPluginDataDir, pascalCase } = this.app.bajo
|
|
6
|
+
const { routePath } = this.app.waibu
|
|
5
7
|
const mime = await importPkg('waibu:mime')
|
|
6
|
-
const { fs } = this.
|
|
8
|
+
const { fs } = this.lib
|
|
7
9
|
const file = `${getPluginDataDir('dobo')}/attachment/${pascalCase(req.params.model)}/${req.params.id}/${req.params.field}/${req.params.file}`
|
|
8
|
-
if (!fs.existsSync(file)) throw this.error('_notFound', { noView: true })
|
|
9
10
|
const mimeType = mime.getType(path.extname(file))
|
|
11
|
+
if (!fs.existsSync(file)) {
|
|
12
|
+
if (!req.query.notfound) throw this.error('_notFound', { noView: true })
|
|
13
|
+
const [, ext] = mimeType.split('/')
|
|
14
|
+
const replacer = isString(req.query.notfound) ? req.query.notfound : `waibuStatic.asset:/not-found.${ext}`
|
|
15
|
+
return reply.redirectTo(routePath(replacer))
|
|
16
|
+
}
|
|
10
17
|
reply.header('Content-Type', mimeType)
|
|
11
18
|
const stream = fs.createReadStream(file)
|
|
12
19
|
reply.send(stream)
|
package/plugin/.alias
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
db
|
package/plugin/config.json
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"connections": [],
|
|
3
|
-
"mergeProps": ["connections"],
|
|
4
|
-
"validationParams": {
|
|
5
|
-
"abortEarly": false,
|
|
6
|
-
"convert": false,
|
|
7
|
-
"allowUnknown": true
|
|
8
|
-
},
|
|
9
|
-
"default": {
|
|
10
|
-
"property": {
|
|
11
|
-
"text": {
|
|
12
|
-
"kind": "text"
|
|
13
|
-
},
|
|
14
|
-
"string": {
|
|
15
|
-
"length": 50
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
"filter": {
|
|
19
|
-
"limit": 25,
|
|
20
|
-
"maxLimit": 200,
|
|
21
|
-
"sort": ["dt:-1", "updatedAt:-1", "updated_at:-1", "createdAt:-1", "createdAt:-1", "ts:-1", "username", "name"]
|
|
22
|
-
},
|
|
23
|
-
"idField": {
|
|
24
|
-
"type": "string",
|
|
25
|
-
"maxLength": 50,
|
|
26
|
-
"required": true,
|
|
27
|
-
"index": { "type": "primary" }
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
"memDb": {
|
|
31
|
-
"createDefConnAtStart": true,
|
|
32
|
-
"persistence": {
|
|
33
|
-
"syncPeriod": 1
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
package/plugin/init.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import collectConnections from '../lib/collect-connections.js'
|
|
2
|
-
import collectDrivers from '../lib/collect-drivers.js'
|
|
3
|
-
import collectFeature from '../lib/collect-feature.js'
|
|
4
|
-
import collectSchemas from '../lib/collect-schemas.js'
|
|
5
|
-
|
|
6
|
-
async function checkType (item, items) {
|
|
7
|
-
const { filter } = this.app.bajo.lib._
|
|
8
|
-
const existing = filter(items, { type: 'dobo:memory' })
|
|
9
|
-
if (existing.length > 1) this.fatal('onlyOneConnType%s', item.type)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
async function init () {
|
|
13
|
-
const { buildCollections } = this.app.bajo
|
|
14
|
-
const { fs } = this.app.bajo.lib
|
|
15
|
-
fs.ensureDirSync(`${this.dir.data}/attachment`)
|
|
16
|
-
await collectDrivers.call(this)
|
|
17
|
-
if (this.config.memDb.createDefConnAtStart) {
|
|
18
|
-
this.config.connections.push({
|
|
19
|
-
type: 'dobo:memory',
|
|
20
|
-
name: 'memory'
|
|
21
|
-
})
|
|
22
|
-
}
|
|
23
|
-
this.connections = await buildCollections({ ns: this.name, container: 'connections', handler: collectConnections, dupChecks: ['name', checkType] })
|
|
24
|
-
if (this.connections.length === 0) this.log.warn('notFound%s', this.print.write('connection'))
|
|
25
|
-
await collectFeature.call(this)
|
|
26
|
-
await collectSchemas.call(this)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export default init
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default ['count', 'avg', 'min', 'max', 'sum']
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
function split (value, schema) {
|
|
2
|
-
let [field, val] = value.split(':').map(i => i.trim())
|
|
3
|
-
if (!val) {
|
|
4
|
-
val = field
|
|
5
|
-
field = '*'
|
|
6
|
-
}
|
|
7
|
-
return { field, value: val }
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function buildMatch ({ input = '', schema, options }) {
|
|
11
|
-
const { isPlainObject, trim } = this.app.bajo.lib._
|
|
12
|
-
input = trim(input)
|
|
13
|
-
let items = {}
|
|
14
|
-
if (isPlainObject(input)) items = input
|
|
15
|
-
else if (input[0] === '{') items = JSON.parse(input)
|
|
16
|
-
else {
|
|
17
|
-
for (const item of input.split('+').map(i => i.trim())) {
|
|
18
|
-
const part = split.call(this, item, schema)
|
|
19
|
-
if (!items[part.field]) items[part.field] = []
|
|
20
|
-
items[part.field].push(...part.value.split(' ').filter(v => ![''].includes(v)))
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
const matcher = {}
|
|
24
|
-
for (const f of schema.fullText.fields) {
|
|
25
|
-
const value = []
|
|
26
|
-
if (typeof items[f] === 'string') items[f] = [items[f]]
|
|
27
|
-
if (Object.prototype.hasOwnProperty.call(items, f)) value.push(...items[f])
|
|
28
|
-
matcher[f] = value
|
|
29
|
-
}
|
|
30
|
-
if (Object.prototype.hasOwnProperty.call(items, '*')) matcher['*'] = items['*']
|
|
31
|
-
return matcher
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export default buildMatch
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import nql from '@tryghost/nql'
|
|
2
|
-
|
|
3
|
-
async function buildQuery ({ filter, schema, options = {} } = {}) {
|
|
4
|
-
const { trim, isString, isPlainObject } = this.app.bajo.lib._
|
|
5
|
-
let query = {}
|
|
6
|
-
if (isString(filter.query)) {
|
|
7
|
-
filter.oquery = filter.query
|
|
8
|
-
if (trim(filter.query).startsWith('{')) query = JSON.parse(filter.query)
|
|
9
|
-
else query = nql(filter.query).parse()
|
|
10
|
-
} else if (isPlainObject(filter.query)) query = filter.query
|
|
11
|
-
return query
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export default buildQuery
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
function getInfo (name) {
|
|
2
|
-
const { breakNsPath } = this.app.bajo
|
|
3
|
-
const { find, map } = this.app.bajo.lib._
|
|
4
|
-
const schema = this.getSchema(name)
|
|
5
|
-
const conn = this.getConnection(schema.connection)
|
|
6
|
-
const { ns, path: type } = breakNsPath(conn.type)
|
|
7
|
-
const driver = find(this.drivers, { type, ns, driver: conn.driver })
|
|
8
|
-
const instance = find(this.app[driver.ns].instances, { name: schema.connection })
|
|
9
|
-
const opts = conn.type === 'mssql' ? { includeTriggerModifications: true } : undefined
|
|
10
|
-
const returning = [map(schema.properties, 'name'), opts]
|
|
11
|
-
return { instance, driver, connection: conn, returning, schema }
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export default getInfo
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
function getSchema (input, cloned = true) {
|
|
2
|
-
const { find, isPlainObject, cloneDeep } = this.app.bajo.lib._
|
|
3
|
-
let name = isPlainObject(input) ? input.name : input
|
|
4
|
-
name = this.app.bajo.pascalCase(name)
|
|
5
|
-
const schema = find(this.schemas, { name })
|
|
6
|
-
if (!schema) throw this.error('unknownModelSchema%s', name)
|
|
7
|
-
return cloned ? cloneDeep(schema) : schema
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export default getSchema
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
async function transform ({ record, schema, hidden = [], forceNoHidden } = {}) {
|
|
2
|
-
const { dayjs } = this.app.bajo.lib
|
|
3
|
-
if (record._id) {
|
|
4
|
-
record.id = record._id
|
|
5
|
-
delete record._id
|
|
6
|
-
}
|
|
7
|
-
const defHidden = [...schema.hidden, ...hidden]
|
|
8
|
-
let result = {}
|
|
9
|
-
for (const p of schema.properties) {
|
|
10
|
-
if (!forceNoHidden && defHidden.includes(p.name)) continue
|
|
11
|
-
result[p.name] = record[p.name] ?? null
|
|
12
|
-
if (record[p.name] === null) continue
|
|
13
|
-
switch (p.type) {
|
|
14
|
-
case 'boolean': result[p.name] = !!result[p.name]; break
|
|
15
|
-
case 'time': result[p.name] = dayjs(record[p.name]).format('HH:mm:ss'); break
|
|
16
|
-
case 'date': result[p.name] = dayjs(record[p.name]).format('YYYY-MM-DD'); break
|
|
17
|
-
case 'datetime': result[p.name] = dayjs(record[p.name]).toISOString(); break
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
result = await this.sanitizeBody({ body: result, schema, partial: true, ignoreNull: true })
|
|
21
|
-
if (record._rel) result._rel = record._rel
|
|
22
|
-
return result
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async function pickRecord ({ record, fields, schema = {}, hidden = [], forceNoHidden } = {}) {
|
|
26
|
-
const { isArray, pick, clone, isEmpty, omit } = this.app.bajo.lib._
|
|
27
|
-
if (isEmpty(record)) return record
|
|
28
|
-
if (hidden.length > 0) record = omit(record, hidden)
|
|
29
|
-
if (!isArray(fields)) return await transform.call(this, { record, schema, hidden, forceNoHidden })
|
|
30
|
-
const fl = clone(fields)
|
|
31
|
-
if (!fl.includes('id')) fl.unshift('id')
|
|
32
|
-
if (record._rel) fl.push('_rel')
|
|
33
|
-
return pick(await transform.call(this, { record, schema, hidden, forceNoHidden }), fl)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export default pickRecord
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
function buildPageSkipLimit (filter) {
|
|
2
|
-
let limit = parseInt(filter.limit) || this.config.default.filter.limit
|
|
3
|
-
if (limit === -1) limit = this.config.default.filter.maxLimit
|
|
4
|
-
if (limit > this.config.default.filter.maxLimit) limit = this.config.default.filter.maxLimit
|
|
5
|
-
if (limit < 1) limit = 1
|
|
6
|
-
let page = parseInt(filter.page) || 1
|
|
7
|
-
if (page < 1) page = 1
|
|
8
|
-
let skip = (page - 1) * limit
|
|
9
|
-
if (filter.skip) {
|
|
10
|
-
skip = parseInt(filter.skip) || skip
|
|
11
|
-
page = undefined
|
|
12
|
-
}
|
|
13
|
-
if (skip < 0) skip = 0
|
|
14
|
-
return { page, skip, limit }
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function buildSort (input, schema, allowSortUnindexed) {
|
|
18
|
-
const { isEmpty, map, each, isPlainObject, isString, trim, keys } = this.app.bajo.lib._
|
|
19
|
-
let sort
|
|
20
|
-
if (schema && isEmpty(input)) {
|
|
21
|
-
const columns = map(schema.properties, 'name')
|
|
22
|
-
each(this.config.default.filter.sort, s => {
|
|
23
|
-
const [col] = s.split(':')
|
|
24
|
-
if (columns.includes(col)) {
|
|
25
|
-
input = s
|
|
26
|
-
return false
|
|
27
|
-
}
|
|
28
|
-
})
|
|
29
|
-
}
|
|
30
|
-
if (!isEmpty(input)) {
|
|
31
|
-
if (isPlainObject(input)) sort = input
|
|
32
|
-
else if (isString(input)) {
|
|
33
|
-
const item = {}
|
|
34
|
-
each(input.split('+'), text => {
|
|
35
|
-
let [col, dir] = map(trim(text).split(':'), i => trim(i))
|
|
36
|
-
dir = (dir ?? '').toUpperCase()
|
|
37
|
-
dir = dir === 'DESC' ? -1 : parseInt(dir) || 1
|
|
38
|
-
item[col] = dir / Math.abs(dir)
|
|
39
|
-
})
|
|
40
|
-
sort = item
|
|
41
|
-
}
|
|
42
|
-
if (schema) {
|
|
43
|
-
const items = keys(sort)
|
|
44
|
-
each(items, i => {
|
|
45
|
-
if (!schema.sortables.includes(i) && !allowSortUnindexed) throw this.error('sortOnUnindexedField%s%s', i, schema.name)
|
|
46
|
-
// if (schema.fullText.fields.includes(i)) throw this.error('Can\'t sort on full-text index: \'%s@%s\'', i, schema.name)
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return sort
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function prepPagination (filter = {}, schema, options = {}) {
|
|
54
|
-
const { page, skip, limit } = buildPageSkipLimit.call(this, filter)
|
|
55
|
-
let sortInput = filter.sort
|
|
56
|
-
try {
|
|
57
|
-
sortInput = JSON.parse(sortInput)
|
|
58
|
-
} catch (err) {}
|
|
59
|
-
const sort = buildSort.call(this, sortInput, schema, options.allowSortUnindexed)
|
|
60
|
-
return { limit, page, skip, sort }
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export default prepPagination
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
const propType = {
|
|
2
|
-
integer: {
|
|
3
|
-
validator: 'number'
|
|
4
|
-
},
|
|
5
|
-
smallint: {
|
|
6
|
-
validator: 'number'
|
|
7
|
-
},
|
|
8
|
-
text: {
|
|
9
|
-
validator: 'string',
|
|
10
|
-
kind: 'text',
|
|
11
|
-
choices: ['text', 'mediumtext', 'longtext']
|
|
12
|
-
},
|
|
13
|
-
string: {
|
|
14
|
-
validator: 'string',
|
|
15
|
-
maxLength: 255,
|
|
16
|
-
minLength: 0
|
|
17
|
-
},
|
|
18
|
-
float: {
|
|
19
|
-
validator: 'number'
|
|
20
|
-
},
|
|
21
|
-
double: {
|
|
22
|
-
validator: 'number'
|
|
23
|
-
},
|
|
24
|
-
boolean: {
|
|
25
|
-
validator: 'boolean'
|
|
26
|
-
},
|
|
27
|
-
date: {
|
|
28
|
-
validator: 'date'
|
|
29
|
-
},
|
|
30
|
-
datetime: {
|
|
31
|
-
validator: 'date'
|
|
32
|
-
},
|
|
33
|
-
time: {
|
|
34
|
-
validator: 'date'
|
|
35
|
-
},
|
|
36
|
-
timestamp: {
|
|
37
|
-
validator: 'timestamp'
|
|
38
|
-
},
|
|
39
|
-
object: {},
|
|
40
|
-
array: {}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export default propType
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
function validationErrorMessage (err) {
|
|
2
|
-
let text = err.message
|
|
3
|
-
if (err.details) {
|
|
4
|
-
text += ' -> '
|
|
5
|
-
text += this.app.bajo.join(err.details.map((d, idx) => {
|
|
6
|
-
return `${d.field}@${err.model}: ${d.error} (${d.value})`
|
|
7
|
-
}))
|
|
8
|
-
}
|
|
9
|
-
return text
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export default validationErrorMessage
|
package/plugin/start.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import memDbStart from '../lib/mem-db/start.js'
|
|
2
|
-
import memDbInstantiate from '../lib/mem-db/instantiate.js'
|
|
3
|
-
|
|
4
|
-
async function start (conns = 'all', noRebuild = true) {
|
|
5
|
-
const { importModule, breakNsPath } = this.app.bajo
|
|
6
|
-
const { find, filter, isString, map } = this.app.bajo.lib._
|
|
7
|
-
if (conns === 'all') conns = this.connections
|
|
8
|
-
else if (isString(conns)) conns = filter(this.connections, { name: conns })
|
|
9
|
-
else conns = map(conns, c => find(this.connections, { name: c }))
|
|
10
|
-
for (const c of conns) {
|
|
11
|
-
const { ns } = breakNsPath(c.type)
|
|
12
|
-
const schemas = filter(this.schemas, { connection: c.name })
|
|
13
|
-
const mod = c.type === 'dobo:memory' ? memDbInstantiate : await importModule(`${ns}:/${this.name}/boot/instantiate.js`)
|
|
14
|
-
await mod.call(this.app[ns], { connection: c, noRebuild, schemas })
|
|
15
|
-
this.log.trace('driverInstantiated%s%s', c.driver, c.name)
|
|
16
|
-
}
|
|
17
|
-
await memDbStart.call(this)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export default start
|