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.
Files changed (75) hide show
  1. package/bajo/intl/en-US.json +5 -1
  2. package/bajo/intl/id.json +0 -1
  3. package/bajoCli/applet/connection.js +1 -1
  4. package/bajoCli/applet/lib/post-process.js +1 -1
  5. package/bajoCli/applet/model-clear.js +1 -1
  6. package/bajoCli/applet/model-rebuild.js +27 -7
  7. package/bajoCli/applet/record-create.js +1 -1
  8. package/bajoCli/applet/record-find.js +1 -1
  9. package/bajoCli/applet/record-get.js +1 -1
  10. package/bajoCli/applet/record-remove.js +1 -1
  11. package/bajoCli/applet/record-update.js +1 -1
  12. package/bajoCli/applet/schema.js +1 -1
  13. package/bajoCli/applet/stat-count.js +1 -1
  14. package/dobo/feature/removed-at.js +85 -0
  15. package/lib/add-fixtures.js +1 -1
  16. package/lib/build-bulk-action.js +1 -1
  17. package/lib/check-unique.js +5 -5
  18. package/lib/collect-connections.js +1 -1
  19. package/lib/collect-drivers.js +1 -1
  20. package/lib/collect-feature.js +1 -1
  21. package/lib/collect-schemas.js +3 -3
  22. package/lib/exec-feature-hook.js +4 -3
  23. package/lib/exec-validation.js +1 -1
  24. package/lib/generic-prop-sanitizer.js +1 -1
  25. package/lib/handle-attachment-upload.js +1 -1
  26. package/lib/mem-db/conn-sanitizer.js +1 -1
  27. package/lib/mem-db/instantiate.js +2 -2
  28. package/lib/mem-db/method/record/find.js +1 -1
  29. package/lib/mem-db/method/record/get.js +1 -1
  30. package/lib/mem-db/method/record/remove.js +1 -1
  31. package/lib/mem-db/method/record/update.js +1 -1
  32. package/lib/mem-db/start.js +1 -1
  33. package/lib/merge-attachment-info.js +2 -2
  34. package/lib/resolve-method.js +2 -2
  35. package/lib/sanitize-schema.js +3 -3
  36. package/package.json +1 -1
  37. package/plugin/factory.js +324 -0
  38. package/plugin/method/attachment/copy-uploaded.js +1 -1
  39. package/plugin/method/attachment/create.js +1 -1
  40. package/plugin/method/attachment/find.js +1 -1
  41. package/plugin/method/attachment/get-path.js +1 -1
  42. package/plugin/method/attachment/get.js +1 -1
  43. package/plugin/method/attachment/remove.js +1 -1
  44. package/plugin/method/bulk/create.js +1 -1
  45. package/plugin/method/model/clear.js +1 -1
  46. package/plugin/method/model/create.js +1 -1
  47. package/plugin/method/model/drop.js +1 -1
  48. package/plugin/method/model/exists.js +1 -1
  49. package/plugin/method/record/clear.js +1 -1
  50. package/plugin/method/record/count.js +13 -8
  51. package/plugin/method/record/create.js +9 -8
  52. package/plugin/method/record/find-one.js +11 -4
  53. package/plugin/method/record/find.js +10 -4
  54. package/plugin/method/record/get.js +10 -4
  55. package/plugin/method/record/remove.js +9 -4
  56. package/plugin/method/record/update.js +6 -4
  57. package/plugin/method/record/upsert.js +20 -6
  58. package/plugin/method/sanitize/body.js +1 -1
  59. package/plugin/method/sanitize/date.js +1 -1
  60. package/plugin/method/validate.js +2 -2
  61. package/waibuMpa/route/attachment/@model/@id/@field/@file.js +9 -2
  62. package/plugin/.alias +0 -1
  63. package/plugin/config.json +0 -36
  64. package/plugin/init.js +0 -29
  65. package/plugin/method/aggregate-types.js +0 -1
  66. package/plugin/method/build-match.js +0 -34
  67. package/plugin/method/build-query.js +0 -14
  68. package/plugin/method/get-connection.js +0 -6
  69. package/plugin/method/get-info.js +0 -14
  70. package/plugin/method/get-schema.js +0 -10
  71. package/plugin/method/pick-record.js +0 -36
  72. package/plugin/method/prep-pagination.js +0 -63
  73. package/plugin/method/prop-type.js +0 -43
  74. package/plugin/method/validation-error-message.js +0 -12
  75. 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.app.bajo.lib._
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 (get && !noCache) {
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.app.bajo.lib._
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
- const record = await handler.call(this.app[driver.ns], { schema, id, options })
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.app.bajo.lib._
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
- const record = await handler.call(this.app[driver.ns], { schema, id, body: nbody, options })
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.app.bajo.lib._
4
- const { cloneDeep, omit } = this.app.bajo.lib._
5
- const options = cloneDeep(omit(opts, ['req', 'reply']))
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
- const old = await this.recordGet(name, id, { thrownNotFound: false, dataOnly: true, noHook: true, noCache: true, force: true, hidden: options.hidden, forceNoHidden: options.forceNoHidden })
17
- if (old) return await this.recordUpdate(name, id, input, options)
18
- return await this.recordCreate(name, input, options)
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.app.bajo.lib._
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
@@ -1,5 +1,5 @@
1
1
  function sanitizeDate (value, { input, output, silent = true } = {}) {
2
- const { dayjs } = this.app.bajo.lib
2
+ const { dayjs } = this.lib
3
3
  if (value === 0) return null
4
4
  if (!output) output = input
5
5
  const dt = dayjs(value, input)
@@ -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.app.bajo.lib._
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.app.bajo.lib._
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.app.bajo.lib
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
@@ -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,6 +0,0 @@
1
- function getConnection (name) {
2
- const { find } = this.app.bajo.lib._
3
- return find(this.connections, { name })
4
- }
5
-
6
- export default getConnection
@@ -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