dobo 1.0.1 → 1.0.3
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/README.md +1 -1
- package/bajo/.alias +1 -0
- package/bajo/config.json +12 -2
- package/bajo/init.js +14 -3
- package/bajo/method/attachment/create.js +1 -1
- package/bajo/method/attachment/get-path.js +1 -1
- package/bajo/method/attachment/get.js +1 -1
- package/bajo/method/attachment/remove.js +1 -1
- package/bajo/method/build-query.js +1 -0
- package/bajo/method/bulk/create.js +6 -6
- package/bajo/method/get-connection.js +6 -0
- package/bajo/method/get-info.js +2 -2
- package/bajo/method/get-schema.js +2 -2
- package/bajo/method/model/clear.js +7 -5
- package/bajo/method/model/create.js +10 -2
- package/bajo/method/model/drop.js +10 -2
- package/bajo/method/model/exists.js +9 -2
- package/bajo/method/pick-record.js +14 -8
- package/bajo/method/prep-pagination.js +5 -9
- package/bajo/method/record/clear.js +8 -7
- package/bajo/method/record/create.js +26 -28
- package/bajo/method/record/find-one.js +10 -9
- package/bajo/method/record/find.js +11 -9
- package/bajo/method/record/get.js +10 -9
- package/bajo/method/record/remove.js +13 -12
- package/bajo/method/record/update.js +22 -25
- package/bajo/method/record/upsert.js +4 -3
- package/bajo/method/sanitize/body.js +8 -9
- package/bajo/method/stat/aggregate.js +6 -6
- package/bajo/method/stat/histogram.js +5 -5
- package/bajo/method/validate.js +23 -20
- package/bajo/start.js +6 -2
- package/bajoCli/applet/connection.js +1 -1
- package/bajoCli/applet/lib/post-process.js +13 -13
- package/bajoCli/applet/model-clear.js +2 -2
- package/bajoCli/applet/model-rebuild.js +12 -9
- package/bajoCli/applet/record-create.js +2 -2
- package/bajoCli/applet/record-find.js +2 -2
- package/bajoCli/applet/record-get.js +2 -2
- package/bajoCli/applet/record-remove.js +2 -2
- package/bajoCli/applet/record-update.js +2 -2
- package/bajoCli/applet/schema.js +1 -1
- package/bajoCli/applet/stat-count.js +2 -2
- package/bajoI18N/resource/en-US.json +28 -27
- package/bajoI18N/resource/id.json +60 -27
- package/lib/add-fixtures.js +4 -4
- package/lib/check-unique.js +2 -2
- package/lib/collect-connections.js +3 -4
- package/lib/collect-drivers.js +11 -3
- package/lib/collect-feature.js +6 -5
- package/lib/collect-schemas.js +9 -7
- package/lib/exec-validation.js +8 -14
- package/lib/generic-prop-sanitizer.js +1 -1
- package/lib/mem-db/conn-sanitizer.js +8 -0
- package/lib/mem-db/instantiate.js +41 -0
- package/lib/mem-db/method/model/clear.js +6 -0
- package/lib/mem-db/method/model/create.js +5 -0
- package/lib/mem-db/method/model/drop.js +5 -0
- package/lib/mem-db/method/model/exists.js +5 -0
- package/lib/mem-db/method/record/create.js +12 -0
- package/lib/mem-db/method/record/find.js +20 -0
- package/lib/mem-db/method/record/get.js +9 -0
- package/lib/mem-db/method/record/remove.js +13 -0
- package/lib/mem-db/method/record/update.js +15 -0
- package/lib/mem-db/method/stat/count.js +11 -0
- package/lib/mem-db/start.js +25 -0
- package/lib/resolve-method.js +4 -3
- package/lib/sanitize-schema.js +21 -9
- package/package.json +5 -3
- package/bajo/hook/bajoI18N@before-init.js +0 -6
- package/bajoCli/applet/shell.js +0 -48
- /package/bajo/hook/{bajoI18N.db@before-resource-merge.js → bajo-i18n.db@before-resource-merge.js} +0 -0
package/README.md
CHANGED
package/bajo/.alias
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
db
|
package/bajo/config.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"alias": "db",
|
|
3
2
|
"connections": [],
|
|
4
3
|
"dependencies": [],
|
|
5
4
|
"mergeProps": ["connections"],
|
|
6
|
-
"
|
|
5
|
+
"validationParams": {
|
|
6
|
+
"abortEarly": false,
|
|
7
|
+
"convert": false,
|
|
8
|
+
"allowUnknown": true
|
|
9
|
+
},
|
|
10
|
+
"default": {
|
|
7
11
|
"property": {
|
|
8
12
|
"text": {
|
|
9
13
|
"kind": "text"
|
|
@@ -23,5 +27,11 @@
|
|
|
23
27
|
"required": true,
|
|
24
28
|
"index": { "type": "primary" }
|
|
25
29
|
}
|
|
30
|
+
},
|
|
31
|
+
"memDb": {
|
|
32
|
+
"createDefConnAtStart": true,
|
|
33
|
+
"persistence": {
|
|
34
|
+
"syncPeriod": 1
|
|
35
|
+
}
|
|
26
36
|
}
|
|
27
37
|
}
|
package/bajo/init.js
CHANGED
|
@@ -3,13 +3,24 @@ import collectDrivers from '../lib/collect-drivers.js'
|
|
|
3
3
|
import collectFeature from '../lib/collect-feature.js'
|
|
4
4
|
import collectSchemas from '../lib/collect-schemas.js'
|
|
5
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('There could only be one connection type \'%s\'', item.type)
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
async function init () {
|
|
7
13
|
const { buildCollections } = this.app.bajo
|
|
8
14
|
const { fs } = this.app.bajo.lib
|
|
9
|
-
|
|
10
|
-
fs.ensureDirSync(`${cfg.dir.data}/attachment`)
|
|
15
|
+
fs.ensureDirSync(`${this.dir.data}/attachment`)
|
|
11
16
|
await collectDrivers.call(this)
|
|
12
|
-
|
|
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] })
|
|
13
24
|
if (this.connections.length === 0) this.log.warn('No %s found!', this.print.write('connection'))
|
|
14
25
|
await collectFeature.call(this)
|
|
15
26
|
await collectSchemas.call(this)
|
|
@@ -20,7 +20,7 @@ async function create (name, id, options = {}) {
|
|
|
20
20
|
file
|
|
21
21
|
}
|
|
22
22
|
await mergeAttachmentInfo.call(this, rec, dest, { mimeType, fullPath, stats })
|
|
23
|
-
if (req && req.flash) req.flash('
|
|
23
|
+
if (req && req.flash) req.flash('notify', req.t('Attachment successfully uploaded'))
|
|
24
24
|
return rec
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -4,7 +4,7 @@ async function getPath (name, id, field, file, options = {}) {
|
|
|
4
4
|
const dir = `${getPluginDataDir(this.name)}/attachment/${pascalCase(name)}/${id}`
|
|
5
5
|
if (options.dirOnly) return dir
|
|
6
6
|
const path = field ? `${dir}/${field}/${file}` : `${dir}/${file}`
|
|
7
|
-
if (!fs.existsSync(path)) throw this.error('
|
|
7
|
+
if (!fs.existsSync(path)) throw this.error('notFound')
|
|
8
8
|
return path
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -5,7 +5,7 @@ async function get (name, id, field, file, options = {}) {
|
|
|
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 })
|
|
8
|
-
if (!data) throw this.error('
|
|
8
|
+
if (!data) throw this.error('notFound', { statusCode: 404 })
|
|
9
9
|
return data
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -5,7 +5,7 @@ async function remove (name, id, field, file, options = {}) {
|
|
|
5
5
|
const path = await this.attachmentGetPath(name, id, field, file)
|
|
6
6
|
const { req } = options
|
|
7
7
|
await fs.remove(path)
|
|
8
|
-
if (req && req.flash) req.flash('
|
|
8
|
+
if (req && req.flash) req.flash('notify', req.t('Attachment successfully removed'))
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export default remove
|
|
@@ -4,6 +4,7 @@ async function buildQuery ({ filter, schema, options = {} } = {}) {
|
|
|
4
4
|
const { trim, isString, isPlainObject } = this.app.bajo.lib._
|
|
5
5
|
let query = {}
|
|
6
6
|
if (isString(filter.query)) {
|
|
7
|
+
filter.oquery = filter.query
|
|
7
8
|
if (trim(filter.query).startsWith('{')) query = JSON.parse(filter.query)
|
|
8
9
|
else query = nql(filter.query).parse()
|
|
9
10
|
} else if (isPlainObject(filter.query)) query = filter.query
|
|
@@ -4,7 +4,7 @@ import execFeatureHook from '../../../lib/exec-feature-hook.js'
|
|
|
4
4
|
|
|
5
5
|
async function create (name, inputs, options) {
|
|
6
6
|
const { generateId, runHook, isSet } = this.app.bajo
|
|
7
|
-
const {
|
|
7
|
+
const { clearModel } = this.cache ?? {}
|
|
8
8
|
const { find } = this.app.bajo.lib._
|
|
9
9
|
options.dataOnly = options.dataOnly ?? true
|
|
10
10
|
options.truncateString = options.truncateString ?? true
|
|
@@ -19,8 +19,8 @@ async function create (name, inputs, options) {
|
|
|
19
19
|
if (!noValidation) b = await execValidation.call(this, { noHook, name, b, options })
|
|
20
20
|
}
|
|
21
21
|
if (!noHook) {
|
|
22
|
-
await runHook(`${this.name}:
|
|
23
|
-
await runHook(`${this.name}.${name}:
|
|
22
|
+
await runHook(`${this.name}:beforeBulkCreate`, name, bodies, options)
|
|
23
|
+
await runHook(`${this.name}.${name}:beforeBulkCreate`, bodies, options)
|
|
24
24
|
}
|
|
25
25
|
for (const idx in bodies) {
|
|
26
26
|
await execFeatureHook.call(this, 'beforeCreate', { schema, body: bodies[idx] })
|
|
@@ -36,10 +36,10 @@ async function create (name, inputs, options) {
|
|
|
36
36
|
await execFeatureHook.call(this, 'afterCreate', { schema, body: bodies[idx] })
|
|
37
37
|
}
|
|
38
38
|
if (!noHook) {
|
|
39
|
-
await runHook(`${this.name}.${name}:
|
|
40
|
-
await runHook(`${this.name}:
|
|
39
|
+
await runHook(`${this.name}.${name}:afterBulkCreate`, bodies, options)
|
|
40
|
+
await runHook(`${this.name}:afterBulkCreate`, name, bodies, options)
|
|
41
41
|
}
|
|
42
|
-
if (
|
|
42
|
+
if (clearModel) await clearModel({ model: name })
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
export default create
|
package/bajo/method/get-info.js
CHANGED
|
@@ -2,8 +2,8 @@ function getInfo (name) {
|
|
|
2
2
|
const { breakNsPath } = this.app.bajo
|
|
3
3
|
const { find, map } = this.app.bajo.lib._
|
|
4
4
|
const schema = this.getSchema(name)
|
|
5
|
-
const conn =
|
|
6
|
-
const
|
|
5
|
+
const conn = this.getConnection(schema.connection)
|
|
6
|
+
const { ns, path: type } = breakNsPath(conn.type)
|
|
7
7
|
const driver = find(this.drivers, { type, ns, driver: conn.driver })
|
|
8
8
|
const instance = find(this.app[driver.ns].instances, { name: schema.connection })
|
|
9
9
|
const opts = conn.type === 'mssql' ? { includeTriggerModifications: true } : undefined
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
function getSchema (input) {
|
|
1
|
+
function getSchema (input, cloned = true) {
|
|
2
2
|
const { find, isPlainObject, cloneDeep } = this.app.bajo.lib._
|
|
3
3
|
let name = isPlainObject(input) ? input.name : input
|
|
4
4
|
name = this.app.bajo.pascalCase(name)
|
|
5
5
|
const schema = find(this.schemas, { name })
|
|
6
6
|
if (!schema) throw this.error('Unknown model/schema \'%s\'', name)
|
|
7
|
-
return cloneDeep(schema)
|
|
7
|
+
return cloned ? cloneDeep(schema) : schema
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export default getSchema
|
|
@@ -2,17 +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.app.bajo.lib._
|
|
6
|
+
|
|
5
7
|
await this.modelExists(name, true)
|
|
6
8
|
const { noHook } = options
|
|
7
|
-
const { handler, schema } = await resolveMethod.call(this, name, 'model-clear')
|
|
9
|
+
const { handler, schema } = await resolveMethod.call(this, name, 'model-clear', options)
|
|
8
10
|
if (!noHook) {
|
|
9
|
-
await runHook(`${this.name}:
|
|
10
|
-
await runHook(`${this.name}.${name}:
|
|
11
|
+
await runHook(`${this.name}:beforeModelClear`, schema, options)
|
|
12
|
+
await runHook(`${this.name}.${camelCase(name)}:beforeModelClear`, options)
|
|
11
13
|
}
|
|
12
14
|
const resp = await handler.call(this, { schema, options })
|
|
13
15
|
if (!noHook) {
|
|
14
|
-
await runHook(`${this.name}.${name}:
|
|
15
|
-
await runHook(`${this.name}:
|
|
16
|
+
await runHook(`${this.name}.${camelCase(name)}:afterModelClear`, options, resp)
|
|
17
|
+
await runHook(`${this.name}:afterModelClear`, schema, options, resp)
|
|
16
18
|
}
|
|
17
19
|
return resp
|
|
18
20
|
}
|
|
@@ -2,10 +2,18 @@ import resolveMethod from '../../../lib/resolve-method.js'
|
|
|
2
2
|
|
|
3
3
|
async function create (name, options = {}) {
|
|
4
4
|
const { runHook } = this.app.bajo
|
|
5
|
+
const { camelCase } = this.app.bajo.lib._
|
|
6
|
+
|
|
5
7
|
const { handler, schema } = await resolveMethod.call(this, name, 'model-create', options)
|
|
6
|
-
|
|
8
|
+
if (!options.noHook) {
|
|
9
|
+
await runHook(`${this.name}:beforeModelCreate`, schema, options)
|
|
10
|
+
await runHook(`${this.name}.${camelCase(name)}:beforeModelCreate`, options)
|
|
11
|
+
}
|
|
7
12
|
await handler.call(this, { schema, options })
|
|
8
|
-
|
|
13
|
+
if (!options.noHook) {
|
|
14
|
+
await runHook(`${this.name}.${camelCase(name)}:afterModelCreate`, options)
|
|
15
|
+
await runHook(`${this.name}:afterModelCreate`, schema, options)
|
|
16
|
+
}
|
|
9
17
|
}
|
|
10
18
|
|
|
11
19
|
export default create
|
|
@@ -2,10 +2,18 @@ import resolveMethod from '../../../lib/resolve-method.js'
|
|
|
2
2
|
|
|
3
3
|
async function drop (name, options = {}) {
|
|
4
4
|
const { runHook } = this.app.bajo
|
|
5
|
+
const { camelCase } = this.app.bajo.lib._
|
|
5
6
|
const { handler, schema } = await resolveMethod.call(this, name, 'model-drop', options)
|
|
6
|
-
|
|
7
|
+
|
|
8
|
+
if (!options.noHook) {
|
|
9
|
+
await runHook(`${this.name}:beforeModelDrop`, schema, options)
|
|
10
|
+
await runHook(`${this.name}.${camelCase(name)}:beforeModelDrop`, options)
|
|
11
|
+
}
|
|
7
12
|
await handler.call(this, { schema, options })
|
|
8
|
-
|
|
13
|
+
if (!options.noHook) {
|
|
14
|
+
await runHook(`${this.name}.${camelCase(name)}:afterModelDrop`, options)
|
|
15
|
+
await runHook(`${this.name}:afterModelDrop`, schema, options)
|
|
16
|
+
}
|
|
9
17
|
}
|
|
10
18
|
|
|
11
19
|
export default drop
|
|
@@ -5,10 +5,17 @@ const cache = {}
|
|
|
5
5
|
async function exists (name, thrown, options = {}) {
|
|
6
6
|
if (cache[name]) return cache[name]
|
|
7
7
|
const { runHook } = this.app.bajo
|
|
8
|
+
const { camelCase } = this.app.bajo.lib._
|
|
8
9
|
const { handler, schema } = await resolveMethod.call(this, name, 'model-exists', options)
|
|
9
|
-
|
|
10
|
+
if (!options.noHook) {
|
|
11
|
+
await runHook(`${this.name}:beforeModelExists`, schema, options)
|
|
12
|
+
await runHook(`${this.name}.${camelCase(name)}:beforeModelExists`, options)
|
|
13
|
+
}
|
|
10
14
|
const exist = await handler.call(this, { schema, options })
|
|
11
|
-
|
|
15
|
+
if (!options.noHook) {
|
|
16
|
+
await runHook(`${this.name}.${camelCase(name)}:afterModelExists`, exist, options)
|
|
17
|
+
await runHook(`${this.name}:afterModelExists`, schema, exist, options)
|
|
18
|
+
}
|
|
12
19
|
if (!exist && thrown) throw this.error('Model doesn\'t exist yet. Please do model rebuild first')
|
|
13
20
|
cache[name] = exist
|
|
14
21
|
return exist
|
|
@@ -1,30 +1,36 @@
|
|
|
1
|
-
async function transform ({ record, schema, hidden = [] } = {}) {
|
|
2
|
-
const { dayjs } = this.app.bajo
|
|
1
|
+
async function transform ({ record, schema, hidden = [], forceNoHidden } = {}) {
|
|
2
|
+
const { dayjs } = this.app.bajo.lib
|
|
3
3
|
if (record._id) {
|
|
4
4
|
record.id = record._id
|
|
5
5
|
delete record._id
|
|
6
6
|
}
|
|
7
|
-
const
|
|
7
|
+
const defHidden = [...schema.hidden, ...hidden]
|
|
8
|
+
let result = {}
|
|
8
9
|
for (const p of schema.properties) {
|
|
9
|
-
if (
|
|
10
|
+
if (!forceNoHidden && defHidden.includes(p.name)) continue
|
|
10
11
|
result[p.name] = record[p.name] ?? null
|
|
11
12
|
if (record[p.name] === null) continue
|
|
12
13
|
switch (p.type) {
|
|
14
|
+
case 'boolean': result[p.name] = !!result[p.name]; break
|
|
13
15
|
case 'time': result[p.name] = dayjs(record[p.name]).format('HH:mm:ss'); break
|
|
14
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
|
|
15
18
|
}
|
|
16
19
|
}
|
|
17
|
-
|
|
20
|
+
result = await this.sanitizeBody({ body: result, schema, partial: true, ignoreNull: true })
|
|
21
|
+
if (record._rel) result._rel = record._rel
|
|
22
|
+
return result
|
|
18
23
|
}
|
|
19
24
|
|
|
20
|
-
async function pickRecord ({ record, fields, schema = {}, hidden = [] } = {}) {
|
|
25
|
+
async function pickRecord ({ record, fields, schema = {}, hidden = [], forceNoHidden } = {}) {
|
|
21
26
|
const { isArray, pick, clone, isEmpty, omit } = this.app.bajo.lib._
|
|
22
27
|
if (isEmpty(record)) return record
|
|
23
28
|
if (hidden.length > 0) record = omit(record, hidden)
|
|
24
|
-
if (!isArray(fields)) return await transform.call(this, { record, schema, hidden })
|
|
29
|
+
if (!isArray(fields)) return await transform.call(this, { record, schema, hidden, forceNoHidden })
|
|
25
30
|
const fl = clone(fields)
|
|
26
31
|
if (!fl.includes('id')) fl.unshift('id')
|
|
27
|
-
|
|
32
|
+
if (record._rel) fl.push('_rel')
|
|
33
|
+
return pick(await transform.call(this, { record, schema, hidden, forceNoHidden }), fl)
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
export default pickRecord
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
function buildPageSkipLimit (filter) {
|
|
2
|
-
let limit = parseInt(filter.limit) || this.config.
|
|
3
|
-
if (limit > this.config.
|
|
2
|
+
let limit = parseInt(filter.limit) || this.config.default.filter.limit
|
|
3
|
+
if (limit > this.config.default.filter.maxLimit) limit = this.config.default.filter.maxLimit
|
|
4
4
|
if (limit < 1) limit = 1
|
|
5
5
|
let page = parseInt(filter.page) || 1
|
|
6
6
|
if (page < 1) page = 1
|
|
@@ -14,11 +14,11 @@ function buildPageSkipLimit (filter) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
function buildSort (input, schema, allowSortUnindexed) {
|
|
17
|
-
const { isEmpty, map, each, isPlainObject, isString, trim,
|
|
17
|
+
const { isEmpty, map, each, isPlainObject, isString, trim, keys } = this.app.bajo.lib._
|
|
18
18
|
let sort
|
|
19
19
|
if (schema && isEmpty(input)) {
|
|
20
20
|
const columns = map(schema.properties, 'name')
|
|
21
|
-
each(this.config.
|
|
21
|
+
each(this.config.default.filter.sort, s => {
|
|
22
22
|
const [col] = s.split(':')
|
|
23
23
|
if (columns.includes(col)) {
|
|
24
24
|
input = s
|
|
@@ -39,13 +39,9 @@ function buildSort (input, schema, allowSortUnindexed) {
|
|
|
39
39
|
sort = item
|
|
40
40
|
}
|
|
41
41
|
if (schema) {
|
|
42
|
-
const indexes = map(filter(schema.properties, p => !!p.index), 'name')
|
|
43
|
-
each(schema.indexes, item => {
|
|
44
|
-
indexes.push(...item.fields)
|
|
45
|
-
})
|
|
46
42
|
const items = keys(sort)
|
|
47
43
|
each(items, i => {
|
|
48
|
-
if (!
|
|
44
|
+
if (!schema.sortables.includes(i) && !allowSortUnindexed) throw this.error('Sort on unindexed field: \'%s@%s\'', i, schema.name)
|
|
49
45
|
// if (schema.fullText.fields.includes(i)) throw this.error('Can\'t sort on full-text index: \'%s@%s\'', i, schema.name)
|
|
50
46
|
})
|
|
51
47
|
}
|
|
@@ -3,18 +3,19 @@ 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 } = this.app.bajo.lib._
|
|
7
|
-
const options = cloneDeep(opts)
|
|
6
|
+
const { cloneDeep, camelCase, omit } = this.app.bajo.lib._
|
|
7
|
+
const options = cloneDeep(omit(opts, ['req']))
|
|
8
|
+
options.req = opts.req
|
|
8
9
|
const { noHook } = options
|
|
9
|
-
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-clear')
|
|
10
|
+
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-clear', options)
|
|
10
11
|
if (!noHook) {
|
|
11
|
-
await runHook(`${this.name}:
|
|
12
|
-
await runHook(`${this.name}.${name}:
|
|
12
|
+
await runHook(`${this.name}:beforeRecordClear`, name, options)
|
|
13
|
+
await runHook(`${this.name}.${camelCase(name)}:beforeRecordClear`, options)
|
|
13
14
|
}
|
|
14
15
|
const resp = await handler.call(this.app[driver.ns], { schema, options })
|
|
15
16
|
if (!noHook) {
|
|
16
|
-
await runHook(`${this.name}.${name}:
|
|
17
|
-
await runHook(`${this.name}:
|
|
17
|
+
await runHook(`${this.name}.${camelCase(name)}:afterRecordClear`, options, resp)
|
|
18
|
+
await runHook(`${this.name}:afterRecordClear`, name, options, resp)
|
|
18
19
|
}
|
|
19
20
|
return resp
|
|
20
21
|
}
|
|
@@ -6,55 +6,53 @@ import execFeatureHook from '../../../lib/exec-feature-hook.js'
|
|
|
6
6
|
|
|
7
7
|
async function create (name, input, opts = {}) {
|
|
8
8
|
const { generateId, runHook, isSet } = this.app.bajo
|
|
9
|
-
const {
|
|
10
|
-
const {
|
|
11
|
-
const options = cloneDeep(opts)
|
|
9
|
+
const { clearModel } = this.cache ?? {}
|
|
10
|
+
const { find, forOwn, cloneDeep, camelCase, omit, get } = this.app.bajo.lib._
|
|
11
|
+
const options = cloneDeep(omit(opts, ['req']))
|
|
12
|
+
options.req = opts.req
|
|
12
13
|
options.dataOnly = options.dataOnly ?? true
|
|
13
14
|
input = cloneDeep(input)
|
|
14
|
-
const { fields, dataOnly, noHook, noValidation, noCheckUnique, noFeatureHook, noResult, noSanitize, hidden } = options
|
|
15
|
+
const { fields, dataOnly, noHook, noValidation, noCheckUnique, noFeatureHook, noResult, noSanitize, hidden, forceNoHidden } = options
|
|
15
16
|
options.truncateString = options.truncateString ?? true
|
|
16
17
|
options.dataOnly = false
|
|
17
18
|
await this.modelExists(name, true)
|
|
18
19
|
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-create', options)
|
|
19
20
|
const idField = find(schema.properties, { name: 'id' })
|
|
21
|
+
const extFields = get(options, 'validation.extFields', [])
|
|
20
22
|
if (!isSet(input.id)) {
|
|
21
23
|
if (idField.type === 'string') input.id = generateId()
|
|
22
24
|
else if (['integer', 'smallint'].includes(idField.type) && !idField.autoInc) input.id = generateId('int')
|
|
23
25
|
}
|
|
24
|
-
let body = noSanitize ? input : await this.sanitizeBody({ body: input, schema, strict: true })
|
|
26
|
+
let body = noSanitize ? input : await this.sanitizeBody({ body: input, schema, extFields, strict: true })
|
|
25
27
|
if (!noHook) {
|
|
26
|
-
await runHook(`${this.name}:
|
|
27
|
-
await runHook(`${this.name}.${name}:
|
|
28
|
+
await runHook(`${this.name}:beforeRecordCreate`, name, body, options)
|
|
29
|
+
await runHook(`${this.name}.${camelCase(name)}:beforeRecordCreate`, body, options)
|
|
28
30
|
}
|
|
29
31
|
if (!noFeatureHook) await execFeatureHook.call(this, 'beforeCreate', { schema, body })
|
|
30
|
-
if (!noValidation) body = await execValidation.call(this, {
|
|
32
|
+
if (!noValidation) body = await execValidation.call(this, { name, body, options })
|
|
31
33
|
if (isSet(body.id) && !noCheckUnique) await checkUnique.call(this, { schema, body })
|
|
32
34
|
let record = {}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
} catch (err) {
|
|
47
|
-
if (get(options, 'req.flash')) options.req.flash('dberr', err)
|
|
48
|
-
throw err
|
|
35
|
+
const nbody = {}
|
|
36
|
+
forOwn(body, (v, k) => {
|
|
37
|
+
if (v === undefined) return undefined
|
|
38
|
+
const prop = find(schema.properties, { name: k })
|
|
39
|
+
if (!prop) return undefined
|
|
40
|
+
if (options.truncateString && isSet(v) && ['string', 'text'].includes(prop.type)) v = v.slice(0, prop.maxLength)
|
|
41
|
+
nbody[k] = v
|
|
42
|
+
})
|
|
43
|
+
record = await handler.call(this.app[driver.ns], { schema, body: nbody, options })
|
|
44
|
+
if (options.req) {
|
|
45
|
+
if (options.req.file) await handleAttachmentUpload.call(this, { name: schema.name, id: body.id, body, options, action: 'create' })
|
|
46
|
+
if (options.req.flash && !options.noFlash) options.req.flash('notify', options.req.t('Record successfully created'))
|
|
49
47
|
}
|
|
50
48
|
if (!noFeatureHook) await execFeatureHook.call(this, 'afterCreate', { schema, body, record })
|
|
51
49
|
if (!noHook) {
|
|
52
|
-
await runHook(`${this.name}.${name}:
|
|
53
|
-
await runHook(`${this.name}:
|
|
50
|
+
await runHook(`${this.name}.${camelCase(name)}:afterRecordCreate`, body, options, record)
|
|
51
|
+
await runHook(`${this.name}:afterRecordCreate`, name, body, options, record)
|
|
54
52
|
}
|
|
55
|
-
if (
|
|
53
|
+
if (clearModel) await clearModel({ model: name, body, options, record })
|
|
56
54
|
if (noResult) return
|
|
57
|
-
record.data = await this.pickRecord({ record: record.data, fields, schema, hidden })
|
|
55
|
+
record.data = await this.pickRecord({ record: record.data, fields, schema, hidden, forceNoHidden })
|
|
58
56
|
return dataOnly ? record.data : record
|
|
59
57
|
}
|
|
60
58
|
|
|
@@ -4,18 +4,19 @@ import singleRelRows from '../../../lib/single-rel-rows.js'
|
|
|
4
4
|
async function findOne (name, filter = {}, opts = {}) {
|
|
5
5
|
const { runHook, isSet } = this.app.bajo
|
|
6
6
|
const { get, set } = this.cache ?? {}
|
|
7
|
-
const { cloneDeep } = this.app.bajo.lib._
|
|
8
|
-
const options = cloneDeep(opts)
|
|
7
|
+
const { cloneDeep, camelCase, omit } = this.app.bajo.lib._
|
|
8
|
+
const options = cloneDeep(omit(opts, ['req']))
|
|
9
|
+
options.req = opts.req
|
|
9
10
|
options.dataOnly = options.dataOnly ?? true
|
|
10
|
-
const { fields, dataOnly, noHook, noCache, hidden } = options
|
|
11
|
+
const { fields, dataOnly, noHook, noCache, hidden, forceNoHidden } = options
|
|
11
12
|
await this.modelExists(name, true)
|
|
12
13
|
filter.limit = 1
|
|
13
14
|
options.count = false
|
|
14
15
|
options.dataOnly = false
|
|
15
|
-
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-find')
|
|
16
|
+
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-find', options)
|
|
16
17
|
if (!noHook) {
|
|
17
|
-
await runHook(`${this.name}:
|
|
18
|
-
await runHook(`${this.name}.${name}:
|
|
18
|
+
await runHook(`${this.name}:beforeRecordFindOne`, name, filter, options)
|
|
19
|
+
await runHook(`${this.name}.${camelCase(name)}:beforeRecordFindOne`, filter, options)
|
|
19
20
|
}
|
|
20
21
|
if (get && !noCache) {
|
|
21
22
|
const cachedResult = await get({ model: name, filter, options })
|
|
@@ -27,10 +28,10 @@ async function findOne (name, filter = {}, opts = {}) {
|
|
|
27
28
|
const record = await handler.call(this.app[driver.ns], { schema, filter, options })
|
|
28
29
|
record.data = record.data[0]
|
|
29
30
|
if (!noHook) {
|
|
30
|
-
await runHook(`${this.name}.${name}:
|
|
31
|
-
await runHook(`${this.name}:
|
|
31
|
+
await runHook(`${this.name}.${camelCase(name)}:afterRecordFindOne`, filter, options, record)
|
|
32
|
+
await runHook(`${this.name}:afterRecordFindOne`, name, filter, options, record)
|
|
32
33
|
}
|
|
33
|
-
record.data = await this.pickRecord({ record: record.data, fields, schema, hidden })
|
|
34
|
+
record.data = await this.pickRecord({ record: record.data, fields, schema, hidden, forceNoHidden })
|
|
34
35
|
if (isSet(options.rels)) await singleRelRows.call(this, { schema, record: record.data, options })
|
|
35
36
|
if (set && !noCache) await set({ model: name, filter, options, record })
|
|
36
37
|
return dataOnly ? record.data : record
|
|
@@ -4,19 +4,21 @@ import multiRelRows from '../../../lib/multi-rel-rows.js'
|
|
|
4
4
|
async function find (name, filter = {}, opts = {}) {
|
|
5
5
|
const { runHook, isSet } = this.app.bajo
|
|
6
6
|
const { get, set } = this.cache ?? {}
|
|
7
|
-
const { cloneDeep } = this.app.bajo.lib._
|
|
8
|
-
const options = cloneDeep(opts)
|
|
7
|
+
const { cloneDeep, camelCase, omit } = this.app.bajo.lib._
|
|
8
|
+
const options = cloneDeep(omit(opts, ['req']))
|
|
9
|
+
options.req = opts.req
|
|
9
10
|
options.dataOnly = options.dataOnly ?? true
|
|
10
|
-
const { fields, dataOnly, noHook, noCache, hidden } = options
|
|
11
|
+
const { fields, dataOnly, noHook, noCache, hidden, forceNoHidden } = options
|
|
11
12
|
options.count = options.count ?? false
|
|
12
13
|
options.dataOnly = false
|
|
13
14
|
await this.modelExists(name, true)
|
|
14
|
-
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-find')
|
|
15
|
+
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-find', options)
|
|
15
16
|
filter.query = await this.buildQuery({ filter, schema, options }) ?? {}
|
|
17
|
+
if (options.queryHandler) filter.query = await options.queryHandler.call(opts.req ? this.app[opts.req.ns] : this, filter.query, opts.req)
|
|
16
18
|
filter.match = this.buildMatch({ input: filter.match, schema, options }) ?? {}
|
|
17
19
|
if (!noHook) {
|
|
18
|
-
await runHook(`${this.name}:
|
|
19
|
-
await runHook(`${this.name}.${name}:
|
|
20
|
+
await runHook(`${this.name}:beforeRecordFind`, name, filter, options)
|
|
21
|
+
await runHook(`${this.name}.${camelCase(name)}:beforeRecordFind`, filter, options)
|
|
20
22
|
}
|
|
21
23
|
if (get && !noCache) {
|
|
22
24
|
const cachedResult = await get({ model: name, filter, options })
|
|
@@ -27,11 +29,11 @@ async function find (name, filter = {}, opts = {}) {
|
|
|
27
29
|
}
|
|
28
30
|
const records = await handler.call(this.app[driver.ns], { schema, filter, options })
|
|
29
31
|
if (!noHook) {
|
|
30
|
-
await runHook(`${this.name}.${name}:
|
|
31
|
-
await runHook(`${this.name}:
|
|
32
|
+
await runHook(`${this.name}.${camelCase(name)}:afterRecordFind`, filter, options, records)
|
|
33
|
+
await runHook(`${this.name}:afterRecordFind`, name, filter, options, records)
|
|
32
34
|
}
|
|
33
35
|
for (const idx in records.data) {
|
|
34
|
-
records.data[idx] = await this.pickRecord({ record: records.data[idx], fields, schema, hidden })
|
|
36
|
+
records.data[idx] = await this.pickRecord({ record: records.data[idx], fields, schema, hidden, forceNoHidden })
|
|
35
37
|
}
|
|
36
38
|
if (isSet(options.rels)) await multiRelRows.call(this, { schema, records: records.data, options })
|
|
37
39
|
if (set && !noCache) await set({ model: name, filter, options, records })
|
|
@@ -4,17 +4,18 @@ import singleRelRows from '../../../lib/single-rel-rows.js'
|
|
|
4
4
|
async function get (name, id, opts = {}) {
|
|
5
5
|
const { runHook, isSet } = this.app.bajo
|
|
6
6
|
const { get, set } = this.cache ?? {}
|
|
7
|
-
const { cloneDeep } = this.app.bajo.lib._
|
|
8
|
-
const options = cloneDeep(opts)
|
|
7
|
+
const { cloneDeep, camelCase, omit } = this.app.bajo.lib._
|
|
8
|
+
const options = cloneDeep(omit(opts, ['req']))
|
|
9
|
+
options.req = opts.req
|
|
9
10
|
options.dataOnly = options.dataOnly ?? true
|
|
10
|
-
const { fields, dataOnly, noHook, noCache, hidden = [] } = options
|
|
11
|
+
const { fields, dataOnly, noHook, noCache, hidden = [], forceNoHidden } = options
|
|
11
12
|
await this.modelExists(name, true)
|
|
12
|
-
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-get')
|
|
13
|
+
const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-get', options)
|
|
13
14
|
id = this.sanitizeId(id, schema)
|
|
14
15
|
options.dataOnly = false
|
|
15
16
|
if (!noHook) {
|
|
16
|
-
await runHook(`${this.name}:
|
|
17
|
-
await runHook(`${this.name}.${name}:
|
|
17
|
+
await runHook(`${this.name}:beforeRecordGet`, name, id, options)
|
|
18
|
+
await runHook(`${this.name}.${camelCase(name)}:beforeRecordGet`, id, options)
|
|
18
19
|
}
|
|
19
20
|
if (get && !noCache) {
|
|
20
21
|
const cachedResult = await get({ model: name, id, options })
|
|
@@ -25,10 +26,10 @@ async function get (name, id, opts = {}) {
|
|
|
25
26
|
}
|
|
26
27
|
const record = await handler.call(this.app[driver.ns], { schema, id, options })
|
|
27
28
|
if (!noHook) {
|
|
28
|
-
await runHook(`${this.name}.${name}:
|
|
29
|
-
await runHook(`${this.name}:
|
|
29
|
+
await runHook(`${this.name}.${camelCase(name)}:afterRecordGet`, id, options, record)
|
|
30
|
+
await runHook(`${this.name}:afterRecordGet`, name, id, options, record)
|
|
30
31
|
}
|
|
31
|
-
record.data = await this.pickRecord({ record: record.data, fields, schema, hidden })
|
|
32
|
+
record.data = await this.pickRecord({ record: record.data, fields, schema, hidden, forceNoHidden })
|
|
32
33
|
if (isSet(options.rels)) await singleRelRows.call(this, { schema, record: record.data, options })
|
|
33
34
|
|
|
34
35
|
if (set && !noCache) await set({ model: name, id, options, record })
|