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.
Files changed (72) hide show
  1. package/README.md +1 -1
  2. package/bajo/.alias +1 -0
  3. package/bajo/config.json +12 -2
  4. package/bajo/init.js +14 -3
  5. package/bajo/method/attachment/create.js +1 -1
  6. package/bajo/method/attachment/get-path.js +1 -1
  7. package/bajo/method/attachment/get.js +1 -1
  8. package/bajo/method/attachment/remove.js +1 -1
  9. package/bajo/method/build-query.js +1 -0
  10. package/bajo/method/bulk/create.js +6 -6
  11. package/bajo/method/get-connection.js +6 -0
  12. package/bajo/method/get-info.js +2 -2
  13. package/bajo/method/get-schema.js +2 -2
  14. package/bajo/method/model/clear.js +7 -5
  15. package/bajo/method/model/create.js +10 -2
  16. package/bajo/method/model/drop.js +10 -2
  17. package/bajo/method/model/exists.js +9 -2
  18. package/bajo/method/pick-record.js +14 -8
  19. package/bajo/method/prep-pagination.js +5 -9
  20. package/bajo/method/record/clear.js +8 -7
  21. package/bajo/method/record/create.js +26 -28
  22. package/bajo/method/record/find-one.js +10 -9
  23. package/bajo/method/record/find.js +11 -9
  24. package/bajo/method/record/get.js +10 -9
  25. package/bajo/method/record/remove.js +13 -12
  26. package/bajo/method/record/update.js +22 -25
  27. package/bajo/method/record/upsert.js +4 -3
  28. package/bajo/method/sanitize/body.js +8 -9
  29. package/bajo/method/stat/aggregate.js +6 -6
  30. package/bajo/method/stat/histogram.js +5 -5
  31. package/bajo/method/validate.js +23 -20
  32. package/bajo/start.js +6 -2
  33. package/bajoCli/applet/connection.js +1 -1
  34. package/bajoCli/applet/lib/post-process.js +13 -13
  35. package/bajoCli/applet/model-clear.js +2 -2
  36. package/bajoCli/applet/model-rebuild.js +12 -9
  37. package/bajoCli/applet/record-create.js +2 -2
  38. package/bajoCli/applet/record-find.js +2 -2
  39. package/bajoCli/applet/record-get.js +2 -2
  40. package/bajoCli/applet/record-remove.js +2 -2
  41. package/bajoCli/applet/record-update.js +2 -2
  42. package/bajoCli/applet/schema.js +1 -1
  43. package/bajoCli/applet/stat-count.js +2 -2
  44. package/bajoI18N/resource/en-US.json +28 -27
  45. package/bajoI18N/resource/id.json +60 -27
  46. package/lib/add-fixtures.js +4 -4
  47. package/lib/check-unique.js +2 -2
  48. package/lib/collect-connections.js +3 -4
  49. package/lib/collect-drivers.js +11 -3
  50. package/lib/collect-feature.js +6 -5
  51. package/lib/collect-schemas.js +9 -7
  52. package/lib/exec-validation.js +8 -14
  53. package/lib/generic-prop-sanitizer.js +1 -1
  54. package/lib/mem-db/conn-sanitizer.js +8 -0
  55. package/lib/mem-db/instantiate.js +41 -0
  56. package/lib/mem-db/method/model/clear.js +6 -0
  57. package/lib/mem-db/method/model/create.js +5 -0
  58. package/lib/mem-db/method/model/drop.js +5 -0
  59. package/lib/mem-db/method/model/exists.js +5 -0
  60. package/lib/mem-db/method/record/create.js +12 -0
  61. package/lib/mem-db/method/record/find.js +20 -0
  62. package/lib/mem-db/method/record/get.js +9 -0
  63. package/lib/mem-db/method/record/remove.js +13 -0
  64. package/lib/mem-db/method/record/update.js +15 -0
  65. package/lib/mem-db/method/stat/count.js +11 -0
  66. package/lib/mem-db/start.js +25 -0
  67. package/lib/resolve-method.js +4 -3
  68. package/lib/sanitize-schema.js +21 -9
  69. package/package.json +5 -3
  70. package/bajo/hook/bajoI18N@before-init.js +0 -6
  71. package/bajoCli/applet/shell.js +0 -48
  72. /package/bajo/hook/{bajoI18N.db@before-resource-merge.js → bajo-i18n.db@before-resource-merge.js} +0 -0
@@ -3,31 +3,32 @@ import handleAttachmentUpload from '../../../lib/handle-attachment-upload.js'
3
3
 
4
4
  async function remove (name, id, opts = {}) {
5
5
  const { runHook } = this.app.bajo
6
- const { clearColl } = this.cache ?? {}
7
- const { cloneDeep } = this.app.bajo.lib._
8
- const options = cloneDeep(opts)
6
+ const { clearModel } = this.cache ?? {}
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, noResult, hidden } = options
11
+ const { fields, dataOnly, noHook, noResult, hidden, forceNoHidden } = options
11
12
  options.dataOnly = false
12
13
  await this.modelExists(name, true)
13
- const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-remove')
14
+ const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-remove', options)
14
15
  id = this.sanitizeId(id, schema)
15
16
  if (!noHook) {
16
- await runHook(`${this.name}:onBeforeRecordRemove`, name, id, options)
17
- await runHook(`${this.name}.${name}:onBeforeRecordRemove`, id, options)
17
+ await runHook(`${this.name}:beforeRecordRemove`, name, id, options)
18
+ await runHook(`${this.name}.${camelCase(name)}:beforeRecordRemove`, id, options)
18
19
  }
19
20
  const record = await handler.call(this.app[driver.ns], { schema, id, options })
20
21
  if (options.req) {
21
22
  if (options.req.file) await handleAttachmentUpload.call(this, { name: schema.name, id, options, action: 'remove' })
22
- if (options.req.flash) options.req.flash('dbsuccess', { message: this.print.write('Record successfully removed'), record })
23
+ if (options.req.flash && !options.noFlash) options.req.flash('notify', options.req.t('Record successfully removed'))
23
24
  }
24
25
  if (!noHook) {
25
- await runHook(`${this.name}.${name}:onAfterRecordRemove`, id, options, record)
26
- await runHook(`${this.name}:onAfterRecordRemove`, name, id, options, record)
26
+ await runHook(`${this.name}.${camelCase(name)}:afterRecordRemove`, id, options, record)
27
+ await runHook(`${this.name}:afterRecordRemove`, name, id, options, record)
27
28
  }
28
- if (clearColl) await clearColl({ model: name, id, options, record })
29
+ if (clearModel) await clearModel({ model: name, id, options, record })
29
30
  if (noResult) return
30
- record.oldData = await this.pickRecord({ record: record.oldData, fields, schema, hidden })
31
+ record.oldData = await this.pickRecord({ record: record.oldData, fields, schema, hidden, forceNoHidden })
31
32
  return dataOnly ? record.oldData : record
32
33
  }
33
34
 
@@ -6,54 +6,51 @@ import execFeatureHook from '../../../lib/exec-feature-hook.js'
6
6
 
7
7
  async function update (name, id, input, opts = {}) {
8
8
  const { runHook, isSet } = this.app.bajo
9
- const { clearColl } = this.cache ?? {}
10
- const { get, forOwn, find, cloneDeep } = this.app.bajo.lib._
11
- const options = cloneDeep(opts)
9
+ const { clearModel } = this.cache ?? {}
10
+ const { forOwn, find, 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, partial = true, hidden } = options
15
+ const { fields, dataOnly, noHook, noValidation, noCheckUnique, noFeatureHook, noResult, noSanitize, partial = true, hidden, forceNoHidden } = options
15
16
  options.dataOnly = true
16
17
  options.truncateString = options.truncateString ?? true
17
18
  await this.modelExists(name, true)
18
- const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-update')
19
+ const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-update', options)
19
20
  id = this.sanitizeId(id, schema)
20
- let body = noSanitize ? input : await this.sanitizeBody({ body: input, schema, partial, strict: true })
21
+ const extFields = get(options, 'validation.extFields', [])
22
+ let body = noSanitize ? input : await this.sanitizeBody({ body: input, schema, partial, strict: true, extFields })
21
23
  delete body.id
22
24
  if (!noHook) {
23
- await runHook(`${this.name}:onBeforeRecordUpdate`, name, id, body, options)
24
- await runHook(`${this.name}.${name}:onBeforeRecordUpdate`, id, body, options)
25
+ await runHook(`${this.name}:beforeRecordUpdate`, name, id, body, options)
26
+ await runHook(`${this.name}.${camelCase(name)}:beforeRecordUpdate`, id, body, options)
25
27
  }
26
28
  if (!noFeatureHook) await execFeatureHook.call(this, 'beforeUpdate', { schema, body })
27
- if (!noValidation) body = await execValidation.call(this, { noHook, name, body, options, partial })
29
+ if (!noValidation) body = await execValidation.call(this, { name, body, options, partial })
28
30
  if (!noCheckUnique) await checkUnique.call(this, { schema, body, id })
29
- let record
30
31
  const nbody = {}
31
32
  forOwn(body, (v, k) => {
32
33
  if (v === undefined) return undefined
33
34
  const prop = find(schema.properties, { name: k })
34
- if (options.truncateString && isSet(v) && prop && ['string', 'text'].includes(prop.type)) v = v.slice(0, prop.maxLength)
35
+ if (!prop) return undefined
36
+ if (options.truncateString && isSet(v) && ['string', 'text'].includes(prop.type)) v = v.slice(0, prop.maxLength)
35
37
  nbody[k] = v
36
38
  })
37
39
  delete nbody.id
38
- try {
39
- record = await handler.call(this.app[driver.ns], { schema, id, body: nbody, options })
40
- if (options.req) {
41
- if (options.req.file) await handleAttachmentUpload.call(this, { name: schema.name, id, body, options, action: 'update' })
42
- if (options.req.flash) options.req.flash('dbsuccess', { message: this.print.write('Record successfully updated'), record })
43
- }
44
- } catch (err) {
45
- if (get(options, 'req.flash')) options.req.flash('dberr', err)
46
- throw err
40
+ const record = await handler.call(this.app[driver.ns], { schema, id, body: nbody, options })
41
+ if (options.req) {
42
+ if (options.req.file) await handleAttachmentUpload.call(this, { name: schema.name, id, body, options, action: 'update' })
43
+ if (options.req.flash && !options.noFlash) options.req.flash('notify', options.req.t('Record successfully updated'))
47
44
  }
48
45
  if (!noFeatureHook) await execFeatureHook.call(this, 'afterUpdate', { schema, body: nbody, record })
49
46
  if (!noHook) {
50
- await runHook(`${this.name}.${name}:onAfterRecordUpdate`, id, nbody, options, record)
51
- await runHook(`${this.name}:onAfterRecordUpdate`, name, id, nbody, options, record)
47
+ await runHook(`${this.name}.${camelCase(name)}:afterRecordUpdate`, id, nbody, options, record)
48
+ await runHook(`${this.name}:afterRecordUpdate`, name, id, nbody, options, record)
52
49
  }
53
- if (clearColl) await clearColl({ model: name, id, body: nbody, options, record })
50
+ if (clearModel) await clearModel({ model: name, id, body: nbody, options, record })
54
51
  if (noResult) return
55
- record.oldData = await this.pickRecord({ record: record.oldData, fields, schema, hidden })
56
- record.data = await this.pickRecord({ record: record.data, fields, schema, hidden })
52
+ record.oldData = await this.pickRecord({ record: record.oldData, fields, schema, hidden, forceNoHidden })
53
+ record.data = await this.pickRecord({ record: record.data, fields, schema, hidden, forceNoHidden })
57
54
  return dataOnly ? record.data : record
58
55
  }
59
56
 
@@ -1,8 +1,9 @@
1
1
  async function upsert (name, input, opts = {}) {
2
2
  const { generateId } = this.app.bajo
3
3
  const { find } = this.app.bajo.lib._
4
- const { cloneDeep } = this.app.bajo.lib._
5
- const options = cloneDeep(opts)
4
+ const { cloneDeep, omit } = this.app.bajo.lib._
5
+ const options = cloneDeep(omit(opts, ['req']))
6
+ options.req = opts.req
6
7
  options.dataOnly = options.dataOnly ?? true
7
8
  await this.modelExists(name, true)
8
9
  const { schema } = this.getInfo(name)
@@ -11,7 +12,7 @@ async function upsert (name, input, opts = {}) {
11
12
  if (idField.type === 'string') id = input.id ?? generateId()
12
13
  else if (idField.type === 'integer') id = input.id ?? generateId('int')
13
14
  id = this.sanitizeId(id, schema)
14
- const old = await this.recordGet(name, id, { thrownNotFound: false, dataOnly: true, noHook: true, noCache: true })
15
+ const old = await this.recordGet(name, id, { thrownNotFound: false, dataOnly: true, noHook: true, noCache: true, force: true, hidden: options.hidden, forceNoHidden: options.forceNoHidden })
15
16
  if (old) return await this.recordUpdate(name, id, input, options)
16
17
  return await this.recordCreate(name, input, options)
17
18
  }
@@ -1,8 +1,8 @@
1
- async function sanitizeBody ({ body = {}, schema = {}, partial, strict }) {
2
- const { isSet, dayjs } = this.app.bajo
3
- const { has, get, isString, isNumber } = this.app.bajo.lib._
1
+ async function sanitizeBody ({ body = {}, schema = {}, partial, strict, extFields = [] }) {
2
+ const { isSet, dayjs, callHandler } = this.app.bajo
3
+ const { has, isString, isNumber, concat } = this.app.bajo.lib._
4
4
  const result = {}
5
- for (const p of schema.properties) {
5
+ for (const p of concat(schema.properties, extFields)) {
6
6
  if (partial && !has(body, p.name)) continue
7
7
  if (['object', 'array'].includes(p.type)) {
8
8
  if (isString(body[p.name])) {
@@ -18,7 +18,7 @@ async function sanitizeBody ({ body = {}, schema = {}, partial, strict }) {
18
18
  }
19
19
  } else result[p.name] = body[p.name]
20
20
  if (isSet(body[p.name])) {
21
- if (p.type === 'boolean') result[p.name] = result[p.name] === null ? null : (!!result[p.name])
21
+ if (p.type === 'boolean') result[p.name] = result[p.name] === null ? null : (['true', true].includes(result[p.name]))
22
22
  if (['float', 'double'].includes(p.type)) {
23
23
  if (isNumber(body[p.name])) result[p.name] = body[p.name]
24
24
  else if (strict) {
@@ -50,10 +50,9 @@ async function sanitizeBody ({ body = {}, schema = {}, partial, strict }) {
50
50
  } else {
51
51
  if (p.default) {
52
52
  result[p.name] = p.default
53
- if (isString(p.default) && p.default.startsWith('helper:')) {
54
- const helper = p.default.split(':')[1]
55
- const method = get(this, helper)
56
- if (method) result[p.name] = await this[method]()
53
+ if (isString(p.default) && p.default.startsWith('handler:')) {
54
+ const [, ...args] = p.default.split(':')
55
+ if (args.length > 0) result[p.name] = await callHandler(args.join(':'))
57
56
  } else {
58
57
  if (['float', 'double'].includes(p.type)) result[p.name] = parseFloat(result[p.name]) || null
59
58
  if (['integer', 'smallint'].includes(p.type)) result[p.name] = parseInt(result[p.name]) || null
@@ -5,17 +5,17 @@ async function aggregate (name, filter = {}, options = {}) {
5
5
  const { dataOnly = true, noHook, aggregate } = options
6
6
  options.dataOnly = false
7
7
  await this.modelExists(name, true)
8
- const { handler, schema, driver } = await resolveMethod.call(this, name, 'stat-aggregate')
8
+ const { handler, schema, driver } = await resolveMethod.call(this, name, 'stat-aggregate', options)
9
9
  if (!noHook) {
10
- await runHook(`${this.name}:onBeforeStatAggregate`, name, aggregate, filter, options)
11
- await runHook(`${this.name}.${name}:onBeforeStatAggregate`, aggregate, filter, options)
10
+ await runHook(`${this.name}:beforeStatAggregate`, name, aggregate, filter, options)
11
+ await runHook(`${this.name}.${name}:beforeStatAggregate`, aggregate, filter, options)
12
12
  }
13
- const rec = await handler.call(this.app[driver.ns], { schema, filter, options })
14
13
  filter.query = await this.buildQuery({ filter, schema, options }) ?? {}
15
14
  filter.match = this.buildMatch({ input: filter.match, schema, options }) ?? {}
15
+ const rec = await handler.call(this.app[driver.ns], { schema, filter, options })
16
16
  if (!noHook) {
17
- await runHook(`${this.name}.${name}:onAfterStatAggregate`, aggregate, filter, options, rec)
18
- await runHook(`${this.name}:onAfterStatAggregate`, name, aggregate, filter, options, rec)
17
+ await runHook(`${this.name}.${name}:afterStatAggregate`, aggregate, filter, options, rec)
18
+ await runHook(`${this.name}:afterStatAggregate`, name, aggregate, filter, options, rec)
19
19
  }
20
20
  return dataOnly ? rec.data : rec
21
21
  }
@@ -8,17 +8,17 @@ async function histogram (name, filter = {}, options = {}) {
8
8
  options.dataOnly = false
9
9
  if (!types.includes(type)) throw this.error('Histogram type must be one of these: %s', join(types))
10
10
  await this.modelExists(name, true)
11
- const { handler, schema, driver } = await resolveMethod.call(this, name, 'stat-histogram')
11
+ const { handler, schema, driver } = await resolveMethod.call(this, name, 'stat-histogram', options)
12
12
  filter.query = await this.buildQuery({ filter, schema, options }) ?? {}
13
13
  filter.match = this.buildMatch({ input: filter.match, schema, options }) ?? {}
14
14
  if (!noHook) {
15
- await runHook(`${this.name}:onBeforeStatHistogram`, name, type, filter, options)
16
- await runHook(`${this.name}.${name}:onBeforeStatHistogram`, type, filter, options)
15
+ await runHook(`${this.name}:beforeStatHistogram`, name, type, filter, options)
16
+ await runHook(`${this.name}.${name}:beforeStatHistogram`, type, filter, options)
17
17
  }
18
18
  const rec = await handler.call(this.app[driver.ns], { schema, type, filter, options })
19
19
  if (!noHook) {
20
- await runHook(`${this.name}.${name}:onAfterStatHistogram`, type, filter, options, rec)
21
- await runHook(`${this.name}:onAfterStatHistogram`, name, type, filter, options, rec)
20
+ await runHook(`${this.name}.${name}:afterStatHistogram`, type, filter, options, rec)
21
+ await runHook(`${this.name}:afterStatHistogram`, name, type, filter, options, rec)
22
22
  }
23
23
  return dataOnly ? rec.data : rec
24
24
  }
@@ -15,25 +15,26 @@ const validator = {
15
15
  timestamp: ['timestamp']
16
16
  }
17
17
 
18
- function buildFromDbSchema (schema, { fields = [], rule = {}, extProperties = [] } = {}) {
18
+ function buildFromDbSchema (schema, { fields = [], rule = {}, extFields = [] } = {}) {
19
19
  // if (schema.validation) return schema.validation
20
20
  const {
21
21
  isPlainObject, get, each, isEmpty, isString, forOwn, keys,
22
- find, isArray, has, cloneDeep, concat
22
+ find, isArray, has, cloneDeep, concat, without
23
23
  } = this.app.bajo.lib._
24
24
  const obj = {}
25
25
  const me = this
26
+ const refs = []
26
27
 
27
- function getRuleKv (rule) {
28
+ function getRuleKv (kvRule) {
28
29
  let key
29
30
  let value
30
31
  let columns
31
- if (isPlainObject(rule)) {
32
- key = rule.rule
33
- value = rule.params
34
- columns = rule.fields
35
- } else if (isString(rule)) {
36
- [key, value, columns] = rule.split(':')
32
+ if (isPlainObject(kvRule)) {
33
+ key = kvRule.rule
34
+ value = kvRule.params
35
+ columns = kvRule.fields
36
+ } else if (isString(kvRule)) {
37
+ [key, value, columns] = kvRule.split(':')
37
38
  }
38
39
  return { key, value, columns }
39
40
  }
@@ -42,30 +43,31 @@ function buildFromDbSchema (schema, { fields = [], rule = {}, extProperties = []
42
43
  const minMax = { min: false, max: false }
43
44
  const rules = get(rule, prop.name, prop.rules ?? [])
44
45
  if (!isArray(rules)) return rules
45
- let isRef
46
46
  each(rules, r => {
47
47
  const types = validator[me.propType[prop.type].validator]
48
48
  const { key, value } = getRuleKv(r)
49
+ if (keys(minMax).includes(key)) minMax[key] = true
49
50
  if (key === 'ref') {
50
- isRef = true
51
+ refs.push(prop.name)
51
52
  obj = joi.ref(value)
52
53
  return undefined
53
54
  }
54
55
  if (!key || !types.includes(key)) return undefined
55
- if (keys(minMax).includes(key)) minMax[key] = true
56
56
  obj = obj[key](value)
57
57
  })
58
- if (!isRef && ['string', 'text'].includes(prop.type)) {
58
+ if (refs.includes(prop.name)) return obj
59
+ if (['string', 'text'].includes(prop.type)) {
59
60
  forOwn(minMax, (v, k) => {
60
61
  if (v) return undefined
61
62
  if (has(prop, `${k}Length`)) obj = obj[k](prop[`${k}Length`])
62
63
  })
63
64
  }
64
- if (!isRef && !['id'].includes(prop.name) && prop.required) obj = obj.required()
65
+ if (isArray(prop.values)) obj = obj.valid(...prop.values)
66
+ if (!['id'].includes(prop.name) && prop.required) obj = obj.required()
65
67
  return obj
66
68
  }
67
69
 
68
- const props = concat(cloneDeep(schema.properties), extProperties)
70
+ const props = concat(cloneDeep(schema.properties), extFields)
69
71
 
70
72
  for (const p of props) {
71
73
  if (excludedTypes.includes(p.type) || excludedNames.includes(p.name)) continue
@@ -105,7 +107,7 @@ function buildFromDbSchema (schema, { fields = [], rule = {}, extProperties = []
105
107
  }
106
108
  if (isEmpty(obj)) return false
107
109
  each(get(schema, 'globalRules', []), r => {
108
- each(keys(obj), k => {
110
+ each(without(keys(obj), ...refs), k => {
109
111
  const prop = find(props, { name: k })
110
112
  if (!prop) return undefined
111
113
  const types = validator[me.propType[prop.type].validator]
@@ -123,13 +125,14 @@ function buildFromDbSchema (schema, { fields = [], rule = {}, extProperties = []
123
125
  return result
124
126
  }
125
127
 
126
- async function validate (value, joiSchema, { ns, fields, extProperties, params } = {}) {
128
+ async function validate (value, joiSchema, { ns, fields, extFields, params } = {}) {
127
129
  const { defaultsDeep, isSet } = this.app.bajo
128
130
  const { isString, forOwn, find } = this.app.bajo.lib._
129
131
 
130
132
  ns = ns ?? [this.name]
131
- params = defaultsDeep(params, { abortEarly: false, convert: false, rule: undefined, allowUnknown: true })
132
- const { rule } = params
133
+ params = defaultsDeep(params, this.config.validationParams)
134
+ const { rule = {} } = params
135
+ delete params.rule
133
136
  if (isString(joiSchema)) {
134
137
  const { schema } = this.getInfo(joiSchema)
135
138
  forOwn(value, (v, k) => {
@@ -141,7 +144,7 @@ async function validate (value, joiSchema, { ns, fields, extProperties, params }
141
144
  if (p.type === type) value[k] = this.sanitizeDate(value[k], { input, output: 'native' })
142
145
  }
143
146
  })
144
- joiSchema = buildFromDbSchema.call(this, schema, { fields, rule, extProperties })
147
+ joiSchema = buildFromDbSchema.call(this, schema, { fields, rule, extFields })
145
148
  }
146
149
  if (!joiSchema) return value
147
150
  try {
package/bajo/start.js CHANGED
@@ -1,3 +1,6 @@
1
+ import memDbStart from '../lib/mem-db/start.js'
2
+ import memDbInstantiate from '../lib/mem-db/instantiate.js'
3
+
1
4
  async function start (conns = 'all', noRebuild = true) {
2
5
  const { importModule, breakNsPath } = this.app.bajo
3
6
  const { find, filter, isString, map } = this.app.bajo.lib._
@@ -5,12 +8,13 @@ async function start (conns = 'all', noRebuild = true) {
5
8
  else if (isString(conns)) conns = filter(this.connections, { name: conns })
6
9
  else conns = map(conns, c => find(this.connections, { name: c }))
7
10
  for (const c of conns) {
8
- const [ns] = breakNsPath(c.type)
11
+ const { ns } = breakNsPath(c.type)
9
12
  const schemas = filter(this.schemas, { connection: c.name })
10
- const mod = await importModule(`${ns}:/${this.name}/boot/instantiate.js`)
13
+ const mod = c.type === 'dobo:memory' ? memDbInstantiate : await importModule(`${ns}:/${this.name}/boot/instantiate.js`)
11
14
  await mod.call(this.app[ns], { connection: c, noRebuild, schemas })
12
15
  this.log.trace('- Driver \'%s:%s\' instantiated', c.driver, c.name)
13
16
  }
17
+ await memDbStart.call(this)
14
18
  }
15
19
 
16
20
  export default start
@@ -1,4 +1,4 @@
1
- async function connection ({ path, args }) {
1
+ async function connection (path, ...args) {
2
2
  const { importPkg } = this.app.bajo
3
3
  const { isEmpty, map, find } = this.app.bajo.lib._
4
4
  const select = await importPkg('bajoCli:@inquirer/select')
@@ -1,26 +1,25 @@
1
1
  const conns = []
2
2
 
3
- async function postProcess ({ handler, params, path, processMsg, noConfirmation, options = {} } = {}) {
4
- const { print, getConfig, saveAsDownload, importPkg, spinner } = this.app.bajo
3
+ async function postProcess ({ handler, params, path, processMsg, noConfirmation } = {}) {
4
+ const { saveAsDownload, importPkg } = this.app.bajo
5
5
  const { prettyPrint } = this.app.bajoCli.helper
6
6
  const { find, get } = this.app.bajo.lib._
7
7
  const [stripAnsi, confirm] = await importPkg('bajoCli:strip-ansi', 'bajoCli:@inquirer/confirm')
8
- const config = getConfig()
9
- if (!noConfirmation && config.confirmation === false) noConfirmation = true
10
- params.push({ fields: config.fields, dataOnly: !config.full })
8
+ if (!noConfirmation && this.config.confirmation === false) noConfirmation = true
9
+ params.push({ fields: this.config.fields, dataOnly: !this.config.full })
11
10
 
12
11
  const schema = find(this.schemas, { name: params[0] })
13
- if (!schema) return print.fail('No schema found!', { exit: config.tool })
12
+ if (!schema) return this.print.fatal('No schema found!')
14
13
  let cont = true
15
14
  if (!noConfirmation) {
16
- const answer = await confirm({ message: print.write('Are you sure to continue?'), default: false })
15
+ const answer = await confirm({ message: this.print.write('Are you sure to continue?'), default: false })
17
16
  if (!answer) {
18
- print.fail('Aborted!')
17
+ this.print.fail('Aborted!')
19
18
  cont = false
20
19
  }
21
20
  }
22
21
  if (!cont) return
23
- const spin = spinner().start(`${processMsg}...`)
22
+ const spin = this.print.spinner().start(`${processMsg}...`)
24
23
  const { connection } = this.getInfo(schema)
25
24
  if (!conns.includes(connection.name)) {
26
25
  await this.start(connection.name)
@@ -29,19 +28,20 @@ async function postProcess ({ handler, params, path, processMsg, noConfirmation,
29
28
  try {
30
29
  const resp = await this[handler](...params)
31
30
  spin.succeed('Done!')
32
- const result = config.pretty ? (await prettyPrint(resp)) : JSON.stringify(resp, null, 2)
33
- if (config.save) {
31
+ const result = this.config.pretty ? (await prettyPrint(resp)) : JSON.stringify(resp, null, 2)
32
+ if (this.config.save) {
34
33
  const id = resp.id ?? get(resp, 'data.id') ?? get(resp, 'oldData.id')
35
34
  const base = path === 'recordFind' ? params[0] : (params[0] + '/' + id)
36
- const file = `/${path}/${base}.${config.pretty ? 'txt' : 'json'}`
35
+ const file = `/${path}/${base}.${this.config.pretty ? 'txt' : 'json'}`
37
36
  await saveAsDownload(file, stripAnsi(result))
38
37
  } else console.log(result)
39
38
  } catch (err) {
40
- if (config.log.tool) {
39
+ if (this.config.log.applet) {
41
40
  spin.stop()
42
41
  console.error(err)
43
42
  } else spin.fail('Error: %s', err.message)
44
43
  }
44
+ process.exit()
45
45
  }
46
46
 
47
47
  export default postProcess
@@ -1,11 +1,11 @@
1
1
  import postProcess from './lib/post-process.js'
2
2
 
3
- async function modelClear ({ path, args, options }) {
3
+ async function modelClear (...args) {
4
4
  const { print } = this.app.bajo
5
5
  const { isEmpty } = this.app.bajo.lib._
6
6
  if (isEmpty(this.schemas)) return print.fail('No schema found!', { exit: this.app.bajo.applet })
7
7
  const [schema] = args
8
- await postProcess.call(this, { handler: 'modelClear', params: [schema], path, processMsg: 'Clear records', options })
8
+ await postProcess.call(this, { handler: 'modelClear', params: [schema], path: 'modelClear', processMsg: 'Clear records' })
9
9
  }
10
10
 
11
11
  export default modelClear
@@ -1,9 +1,9 @@
1
1
  import addFixtures from '../../lib/add-fixtures.js'
2
2
 
3
- async function modelRebuild ({ path, args }) {
4
- const { importPkg, outmatch } = this.app.bajo
3
+ async function modelRebuild (...args) {
4
+ const { importPkg } = this.app.bajo
5
+ const { outmatch } = this.app.bajo.lib
5
6
  const { isEmpty, map, trim } = this.app.bajo.lib._
6
- const spinner = this.print.spinner
7
7
  const [input, confirm, boxen] = await importPkg('bajoCli:@inquirer/input',
8
8
  'bajoCli:@inquirer/confirm', 'bajoCli:boxen')
9
9
  const schemas = map(this.schemas, 'name')
@@ -25,26 +25,28 @@ async function modelRebuild ({ path, args }) {
25
25
  default: false
26
26
  })
27
27
  if (!answer) return this.print.fail('Aborted!', { exit: this.app.bajo.applet })
28
+ /*
28
29
  const conns = []
29
30
  for (const s of names) {
30
31
  const { connection } = this.getInfo(s)
31
32
  if (!conns.includes(connection.name)) conns.push(connection.name)
32
33
  }
33
- await this.start(conns)
34
+ */
35
+ await this.start('all')
34
36
  const result = { succed: 0, failed: 0, skipped: 0 }
35
37
  for (const s of names) {
36
38
  const { schema, instance, connection } = this.getInfo(s)
37
- const spin = spinner({ showCounter: true }).start('Rebuilding \'%s\'...', schema.name)
39
+ const spin = this.print.spinner({ showCounter: true }).start('Rebuilding \'%s\'...', schema.name)
38
40
  if (!instance) {
39
41
  spin.warn('Client instance not connected \'%s@%s\'. Skipped!', schema.connection, schema.name)
40
42
  result.skipped++
41
43
  continue
42
44
  }
43
- const exists = await this.modelExists(schema, false, spinner)
45
+ const exists = await this.modelExists(schema.name, false, { spinner: spin })
44
46
  if (exists) {
45
47
  if (this.app.bajo.config.force) {
46
48
  try {
47
- await this.modelDrop(schema, spinner)
49
+ await this.modelDrop(schema.name, { spinner: spin })
48
50
  spin.setText('Model \'%s\' successfully dropped', schema.name)
49
51
  } catch (err) {
50
52
  spin.fail('Error on dropping model \'%s\': %s', schema.name, err.message)
@@ -58,10 +60,10 @@ async function modelRebuild ({ path, args }) {
58
60
  }
59
61
  }
60
62
  try {
61
- await this.modelCreate(schema, spinner)
63
+ await this.modelCreate(schema.name, { spinner: spin })
62
64
  if (connection.memory) spin.succeed('Model \'%s\' successfully created', schema.name)
63
65
  else {
64
- const fixture = await addFixtures.call(this, schema, spin)
66
+ const fixture = await addFixtures.call(this, schema.name, { spinner: spin })
65
67
  spin.succeed('Model \'%s\' successfully created, with fixture: added %d, rejected: %s', schema.name, fixture.success, fixture.failed)
66
68
  }
67
69
  result.succed++
@@ -72,6 +74,7 @@ async function modelRebuild ({ path, args }) {
72
74
  }
73
75
  }
74
76
  this.print.info('Done! Succeded: %d, failed: %s, skipped: %d', result.succed, result.failed, result.skipped)
77
+ process.exit()
75
78
  }
76
79
 
77
80
  export default modelRebuild
@@ -1,6 +1,6 @@
1
1
  import postProcess from './lib/post-process.js'
2
2
 
3
- async function createRecord ({ path, args, options }) {
3
+ async function createRecord (path, ...args) {
4
4
  const { importPkg } = this.app.bajo
5
5
  const { isEmpty, map, isPlainObject } = this.app.bajo.lib._
6
6
  const [input, select, boxen] = await importPkg('bajoCli:@inquirer/input',
@@ -35,7 +35,7 @@ async function createRecord ({ path, args, options }) {
35
35
  return this.print.fail('Invalid payload syntax', { exit: this.app.bajo.applet })
36
36
  }
37
37
  console.log(boxen(JSON.stringify(payload, null, 2), { title: schema, padding: 0.5, borderStyle: 'round' }))
38
- await postProcess.call(this, { handler: 'recordCreate', params: [schema, payload], path, processMsg: 'Creating record', options })
38
+ await postProcess.call(this, { handler: 'recordCreate', params: [schema, payload], path, processMsg: 'Creating record' })
39
39
  }
40
40
 
41
41
  export default createRecord
@@ -1,6 +1,6 @@
1
1
  import postProcess from './lib/post-process.js'
2
2
 
3
- async function findRecord ({ path, args, options }) {
3
+ async function findRecord (path, ...args) {
4
4
  const { importPkg } = this.app.bajo
5
5
  const { isEmpty, map, pick } = this.app.bajo.lib._
6
6
  const [select, input] = await importPkg('bajoCli:@inquirer/select', 'bajoCli:@inquirer/input')
@@ -21,7 +21,7 @@ async function findRecord ({ path, args, options }) {
21
21
  const filter = pick(this.app.bajo.config, ['page', 'offset', 'pageSize', 'sort', 'limit'])
22
22
  filter.pageSize = filter.pageSize ?? filter.limit
23
23
  filter.query = query
24
- await postProcess.call(this, { noConfirmation: true, handler: 'recordFind', params: [schema, filter], path, processMsg: 'Finding record(s)', options })
24
+ await postProcess.call(this, { noConfirmation: true, handler: 'recordFind', params: [schema, filter], path, processMsg: 'Finding record(s)' })
25
25
  }
26
26
 
27
27
  export default findRecord
@@ -1,6 +1,6 @@
1
1
  import postProcess from './lib/post-process.js'
2
2
 
3
- async function getRecord ({ path, args, options }) {
3
+ async function getRecord (path, ...args) {
4
4
  const { importPkg } = this.app.bajo
5
5
  const { isEmpty, map } = this.app.bajo.lib._
6
6
  const [input, select] = await importPkg('bajoCli:@inquirer/input', 'bajoCli:@inquirer/select')
@@ -18,7 +18,7 @@ async function getRecord ({ path, args, options }) {
18
18
  validate: text => isEmpty(text) ? this.print.write('ID is required') : true
19
19
  })
20
20
  }
21
- await postProcess.call(this, { noConfirmation: true, handler: 'recordGet', params: [schema, id], path, processMsg: 'Getting record', options })
21
+ await postProcess.call(this, { noConfirmation: true, handler: 'recordGet', params: [schema, id], path, processMsg: 'Getting record' })
22
22
  }
23
23
 
24
24
  export default getRecord
@@ -1,6 +1,6 @@
1
1
  import postProcess from './lib/post-process.js'
2
2
 
3
- async function removeRecord ({ path, args, options }) {
3
+ async function removeRecord (path, ...args) {
4
4
  const { importPkg } = this.app.bajo
5
5
  const { isEmpty, map } = this.app.bajo.lib._
6
6
  const [input, select] = await importPkg('bajoCli:@inquirer/input', 'bajoCli:@inquirer/select')
@@ -18,7 +18,7 @@ async function removeRecord ({ path, args, options }) {
18
18
  validate: text => isEmpty(text) ? this.print.write('ID is required') : true
19
19
  })
20
20
  }
21
- await postProcess.call(this, { handler: 'recordRemove', params: [schema, id], path, processMsg: 'Removing record', options })
21
+ await postProcess.call(this, { handler: 'recordRemove', params: [schema, id], path, processMsg: 'Removing record' })
22
22
  }
23
23
 
24
24
  export default removeRecord
@@ -1,6 +1,6 @@
1
1
  import postProcess from './lib/post-process.js'
2
2
 
3
- async function updateRecord ({ path, args, options }) {
3
+ async function updateRecord (path, ...args) {
4
4
  const { importPkg } = this.app.bajo
5
5
  const { isEmpty, map, isPlainObject } = this.app.bajo.lib._
6
6
  const [input, select, boxen] = await importPkg('bajoCli:@inquirer/input',
@@ -41,7 +41,7 @@ async function updateRecord ({ path, args, options }) {
41
41
  return this.print.fail('Invalid payload syntax', { exit: this.app.bajo.applet })
42
42
  }
43
43
  console.log(boxen(JSON.stringify(payload, null, 2), { title: schema, padding: 0.5, borderStyle: 'round' }))
44
- await postProcess.call(this, { handler: 'recordUpdate', params: [schema, id, payload], path, processMsg: 'Updating record', options })
44
+ await postProcess.call(this, { handler: 'recordUpdate', params: [schema, id, payload], path, processMsg: 'Updating record' })
45
45
  }
46
46
 
47
47
  export default updateRecord
@@ -1,4 +1,4 @@
1
- async function schema ({ path, args }) {
1
+ async function schema (path, ...args) {
2
2
  const { importPkg } = this.app.bajo
3
3
  const { isEmpty, map, find } = this.app.bajo.lib._
4
4
  const { getOutputFormat, writeOutput } = this.app.bajoCli
@@ -1,6 +1,6 @@
1
1
  import postProcess from './lib/post-process.js'
2
2
 
3
- async function statCount ({ path, args, options }) {
3
+ async function statCount (path, ...args) {
4
4
  const { importPkg } = this.app.bajo
5
5
  const { isEmpty, map } = this.app.bajo.lib._
6
6
  const [select, input] = await importPkg('bajoCli:@inquirer/select', 'bajoCli:@inquirer/input')
@@ -18,7 +18,7 @@ async function statCount ({ path, args, options }) {
18
18
  })
19
19
  }
20
20
  const filter = { query }
21
- await postProcess.call(this, { noConfirmation: true, handler: 'statCount', params: [schema, filter], path, processMsg: 'Counting record(s)', options })
21
+ await postProcess.call(this, { noConfirmation: true, handler: 'statCount', params: [schema, filter], path, processMsg: 'Counting record(s)' })
22
22
  }
23
23
 
24
24
  export default statCount