dobo 1.2.10 → 2.0.1

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 (153) hide show
  1. package/.github/FUNDING.yml +13 -0
  2. package/.github/workflows/repo-lockdown.yml +24 -0
  3. package/.jsdoc.conf.json +45 -0
  4. package/LICENSE +1 -1
  5. package/README.md +38 -19
  6. package/docs/Dobo.html +26 -0
  7. package/docs/data/search.json +1 -0
  8. package/docs/fonts/Inconsolata-Regular.ttf +0 -0
  9. package/docs/fonts/OpenSans-Regular.ttf +0 -0
  10. package/docs/fonts/WorkSans-Bold.ttf +0 -0
  11. package/docs/global.html +7 -0
  12. package/docs/index.html +3 -0
  13. package/docs/index.js.html +578 -0
  14. package/docs/lib_collect-connections.js.html +39 -0
  15. package/docs/lib_collect-drivers.js.html +52 -0
  16. package/docs/lib_collect-features.js.html +36 -0
  17. package/docs/lib_collect-schemas.js.html +94 -0
  18. package/docs/lib_index.js.html +6 -0
  19. package/docs/method_model_create.js.html +35 -0
  20. package/docs/method_model_drop.js.html +34 -0
  21. package/docs/method_model_exists.js.html +40 -0
  22. package/docs/method_record_count.js.html +69 -0
  23. package/docs/method_record_create.js.html +114 -0
  24. package/docs/method_record_find-all.js.html +44 -0
  25. package/docs/method_record_find-one.js.html +73 -0
  26. package/docs/method_record_find.js.html +118 -0
  27. package/docs/method_record_get.js.html +92 -0
  28. package/docs/method_record_remove.js.html +75 -0
  29. package/docs/method_record_update.js.html +107 -0
  30. package/docs/method_record_upsert.js.html +54 -0
  31. package/docs/method_sanitize_body.js.html +88 -0
  32. package/docs/method_sanitize_date.js.html +30 -0
  33. package/docs/method_sanitize_id.js.html +20 -0
  34. package/docs/method_validate.js.html +249 -0
  35. package/docs/module-Lib.html +3 -0
  36. package/docs/scripts/core.js +726 -0
  37. package/docs/scripts/core.min.js +23 -0
  38. package/docs/scripts/resize.js +90 -0
  39. package/docs/scripts/search.js +265 -0
  40. package/docs/scripts/search.min.js +6 -0
  41. package/docs/scripts/third-party/Apache-License-2.0.txt +202 -0
  42. package/docs/scripts/third-party/fuse.js +9 -0
  43. package/docs/scripts/third-party/hljs-line-num-original.js +369 -0
  44. package/docs/scripts/third-party/hljs-line-num.js +1 -0
  45. package/docs/scripts/third-party/hljs-original.js +5171 -0
  46. package/docs/scripts/third-party/hljs.js +1 -0
  47. package/docs/scripts/third-party/popper.js +5 -0
  48. package/docs/scripts/third-party/tippy.js +1 -0
  49. package/docs/scripts/third-party/tocbot.js +672 -0
  50. package/docs/scripts/third-party/tocbot.min.js +1 -0
  51. package/docs/static/bitcoin.jpeg +0 -0
  52. package/docs/static/home.md +25 -0
  53. package/docs/static/logo-ecosystem.png +0 -0
  54. package/docs/static/logo.png +0 -0
  55. package/docs/styles/clean-jsdoc-theme-base.css +1159 -0
  56. package/docs/styles/clean-jsdoc-theme-dark.css +412 -0
  57. package/docs/styles/clean-jsdoc-theme-light.css +482 -0
  58. package/docs/styles/clean-jsdoc-theme-scrollbar.css +30 -0
  59. package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
  60. package/docs/styles/clean-jsdoc-theme.min.css +1 -0
  61. package/{bajo → extend/bajo}/intl/en-US.json +3 -2
  62. package/{bajo → extend/bajo}/intl/id.json +3 -2
  63. package/{bajoCli → extend/bajoCli}/applet/connection.js +5 -5
  64. package/extend/bajoCli/applet/lib/post-process.js +53 -0
  65. package/extend/bajoCli/applet/model-clear.js +11 -0
  66. package/{bajoCli → extend/bajoCli}/applet/model-rebuild.js +13 -13
  67. package/{bajoCli → extend/bajoCli}/applet/record-create.js +10 -8
  68. package/{bajoCli → extend/bajoCli}/applet/record-find.js +6 -5
  69. package/{bajoCli → extend/bajoCli}/applet/record-get.js +5 -5
  70. package/{bajoCli → extend/bajoCli}/applet/record-remove.js +5 -5
  71. package/{bajoCli → extend/bajoCli}/applet/record-update.js +9 -9
  72. package/{bajoCli → extend/bajoCli}/applet/schema.js +4 -4
  73. package/{bajoCli → extend/bajoCli}/applet/stat-count.js +4 -4
  74. package/{dobo → extend/dobo}/feature/created-at.js +1 -1
  75. package/{dobo → extend/dobo}/feature/removed-at.js +3 -3
  76. package/{dobo → extend/dobo}/feature/updated-at.js +2 -2
  77. package/{waibuMpa → extend/waibuMpa}/route/attachment/@model/@id/@field/@file.js +3 -3
  78. package/index.js +230 -72
  79. package/lib/add-fixtures.js +7 -6
  80. package/lib/build-bulk-action.js +2 -2
  81. package/lib/check-unique.js +2 -2
  82. package/lib/collect-connections.js +15 -4
  83. package/lib/collect-drivers.js +15 -6
  84. package/lib/{collect-feature.js → collect-features.js} +13 -4
  85. package/lib/collect-schemas.js +22 -12
  86. package/lib/exec-feature-hook.js +1 -1
  87. package/lib/exec-validation.js +5 -5
  88. package/lib/generic-prop-sanitizer.js +6 -5
  89. package/lib/handle-attachment-upload.js +2 -2
  90. package/lib/index.js +3 -0
  91. package/lib/mem-db/conn-sanitizer.js +1 -1
  92. package/lib/mem-db/instantiate.js +4 -4
  93. package/lib/mem-db/method/record/find.js +1 -1
  94. package/lib/mem-db/method/record/get.js +1 -1
  95. package/lib/mem-db/method/record/remove.js +1 -1
  96. package/lib/mem-db/method/record/update.js +1 -1
  97. package/lib/mem-db/start.js +1 -1
  98. package/lib/merge-attachment-info.js +2 -2
  99. package/lib/multi-rel-rows.js +2 -2
  100. package/lib/resolve-method.js +3 -3
  101. package/lib/sanitize-schema.js +8 -7
  102. package/lib/single-rel-rows.js +2 -2
  103. package/{plugin-method → method}/attachment/copy-uploaded.js +2 -2
  104. package/{plugin-method → method}/attachment/create.js +3 -3
  105. package/{plugin-method → method}/attachment/find.js +2 -2
  106. package/{plugin-method → method}/attachment/get-path.js +3 -3
  107. package/{plugin-method → method}/attachment/get.js +1 -1
  108. package/{plugin-method → method}/attachment/pre-check.js +1 -1
  109. package/{plugin-method → method}/attachment/remove.js +1 -1
  110. package/{plugin-method → method}/bulk/create.js +6 -6
  111. package/{plugin-method → method}/model/clear.js +5 -5
  112. package/method/model/create.js +32 -0
  113. package/method/model/drop.js +31 -0
  114. package/method/model/exists.js +37 -0
  115. package/{plugin-method → method}/record/clear.js +5 -5
  116. package/{plugin-method → method}/record/count.js +27 -5
  117. package/{plugin-method → method}/record/create.js +46 -6
  118. package/{plugin-method → method}/record/find-all.js +16 -0
  119. package/{plugin-method → method}/record/find-one.js +20 -6
  120. package/method/record/find.js +115 -0
  121. package/method/record/get.js +89 -0
  122. package/method/record/remove.js +72 -0
  123. package/{plugin-method → method}/record/update.js +47 -6
  124. package/{plugin-method → method}/record/upsert.js +18 -2
  125. package/{plugin-method → method}/sanitize/body.js +18 -3
  126. package/method/sanitize/date.js +27 -0
  127. package/{plugin-method → method}/sanitize/id.js +10 -0
  128. package/{plugin-method → method}/stat/aggregate.js +4 -4
  129. package/{plugin-method → method}/stat/histogram.js +4 -4
  130. package/{plugin-method → method}/validate.js +96 -7
  131. package/package.json +41 -36
  132. package/wiki/APPLETS.md +57 -0
  133. package/wiki/CONFIG.md +25 -0
  134. package/wiki/CONTRIBUTING.md +5 -0
  135. package/wiki/DEV-GUIDE.md +1 -0
  136. package/wiki/ECOSYSTEM.md +20 -0
  137. package/wiki/GETTING-STARTED.md +166 -0
  138. package/wiki/USER-GUIDE.md +1 -0
  139. package/bajoCli/applet/lib/post-process.js +0 -47
  140. package/bajoCli/applet/model-clear.js +0 -11
  141. package/plugin-method/model/create.js +0 -19
  142. package/plugin-method/model/drop.js +0 -19
  143. package/plugin-method/model/exists.js +0 -24
  144. package/plugin-method/record/find.js +0 -52
  145. package/plugin-method/record/get.js +0 -47
  146. package/plugin-method/record/remove.js +0 -41
  147. package/plugin-method/sanitize/date.js +0 -14
  148. /package/{bajoCli → extend/bajoCli}/applet.js +0 -0
  149. /package/{dobo → extend/dobo}/feature/dt.js +0 -0
  150. /package/{dobo → extend/dobo}/feature/int-id.js +0 -0
  151. /package/{waibuStatic → extend/waibuStatic}/virtual.json +0 -0
  152. /package/{plugin-method → method}/attachment/update.js +0 -0
  153. /package/{docs/query-language.md → wiki/QUERY-LANGUAGE.md} +0 -0
@@ -1,11 +1,12 @@
1
1
  import path from 'path'
2
2
  import sanitizeSchema from './sanitize-schema.js'
3
3
 
4
- async function handler ({ file, alias, ns }) {
4
+ async function handler ({ file }) {
5
+ const { ns, alias } = this
5
6
  const { readConfig, eachPlugins } = this.app.bajo
6
- const { pascalCase } = this.lib.aneka
7
- const { get, isPlainObject, each, find, has, isArray, forOwn, isString, merge } = this.lib._
8
- const { fastGlob } = this.lib
7
+ const { pascalCase } = this.app.lib.aneka
8
+ const { get, isPlainObject, each, find, has, isArray, forOwn, isString, merge } = this.app.lib._
9
+ const { fastGlob } = this.app.lib
9
10
 
10
11
  const base = path.basename(file, path.extname(file))
11
12
  const defName = pascalCase(`${alias} ${base}`)
@@ -35,11 +36,12 @@ async function handler ({ file, alias, ns }) {
35
36
  mod.properties = mod.properties ?? []
36
37
  // if ((mod.properties ?? []).length === 0) this.fatal('noPropsFoundOnSchema%s', mod.name)
37
38
  // schema extender
38
- await eachPlugins(async function (opts) {
39
- const glob = `${opts.dir}/dobo/extend/${mod.ns}/schema/${base}.*`
39
+ await eachPlugins(async function ({ dir }) {
40
+ const { ns } = this
41
+ const glob = `${dir}/extend/dobo/extend/${mod.ns}/schema/${base}.*`
40
42
  const files = await fastGlob(glob)
41
43
  for (const file of files) {
42
- const extender = await readConfig(file, { ns: opts.ns, ignoreError: true })
44
+ const extender = await readConfig(file, { ns, ignoreError: true })
43
45
  if (!isPlainObject(extender)) return undefined
44
46
  each(extender.properties ?? [], p => {
45
47
  if (isString(p) && mod.properties.includes(p)) return undefined
@@ -58,23 +60,31 @@ async function handler ({ file, alias, ns }) {
58
60
  })
59
61
  }
60
62
  if (feats.length > 0) mod.feature.push(...feats)
61
- if (opts.plugin === this.app.bajo.mainNs) {
63
+ if (ns === this.app.mainNs) {
62
64
  each(['connection', 'name'], i => {
63
65
  if (has(extender, i)) mod[i] = extender[i]
64
66
  })
65
67
  }
66
68
  mod.extender = mod.extender ?? []
67
- mod.extender.push(opts.plugin)
69
+ mod.extender.push(ns)
68
70
  }
69
71
  })
70
72
  return mod
71
73
  }
72
74
 
75
+ /**
76
+ * Collect all database schemas from loaded plugins
77
+ *
78
+ * @name collectSchemas
79
+ * @memberof module:Lib
80
+ * @async
81
+ * @see Dobo#init
82
+ */
73
83
  async function collectSchemas () {
74
84
  const { eachPlugins } = this.app.bajo
75
- const { isEmpty } = this.lib._
76
- const result = await eachPlugins(handler, { glob: 'schema/*.*', prefix: this.name })
77
- if (isEmpty(result)) this.log.warn('notFound%s', this.print.write('schema'))
85
+ const { isEmpty } = this.app.lib._
86
+ const result = await eachPlugins(handler, { glob: 'schema/*.*', prefix: this.ns })
87
+ if (isEmpty(result)) this.log.warn('notFound%s', this.t('schema'))
78
88
  else await sanitizeSchema.call(this, result)
79
89
  }
80
90
 
@@ -1,5 +1,5 @@
1
1
  async function execFeatureHook (name, params = {}) {
2
- const { get } = this.lib._
2
+ const { get } = this.app.lib._
3
3
  const { schema } = params
4
4
  for (const f of schema.feature) {
5
5
  const fn = get(this.feature, f.name)
@@ -1,10 +1,10 @@
1
1
  async function execValidation ({ name, body, options, partial }) {
2
2
  const { runHook } = this.app.bajo
3
- const { keys, camelCase } = this.lib._
3
+ const { keys, camelCase } = this.app.lib._
4
4
  const { noHook } = options
5
5
  if (!noHook) {
6
- await runHook(`${this.name}:beforeRecordValidation`, name, body, options)
7
- await runHook(`${this.name}.${camelCase(name)}:beforeRecordValidation`, body, options)
6
+ await runHook(`${this.ns}:beforeRecordValidation`, name, body, options)
7
+ await runHook(`${this.ns}.${camelCase(name)}:beforeRecordValidation`, body, options)
8
8
  }
9
9
  const { validation = {} } = options
10
10
  if (partial) {
@@ -12,8 +12,8 @@ async function execValidation ({ name, body, options, partial }) {
12
12
  }
13
13
  body = await this.validate(body, name, validation)
14
14
  if (!noHook) {
15
- await runHook(`${this.name}:afterRecordValidation`, name, body, options)
16
- await runHook(`${this.name}.${camelCase(name)}:afterRecordValidation`, body, options)
15
+ await runHook(`${this.ns}:afterRecordValidation`, name, body, options)
16
+ await runHook(`${this.ns}.${camelCase(name)}:afterRecordValidation`, body, options)
17
17
  }
18
18
  return body
19
19
  }
@@ -2,8 +2,9 @@ const indexTypes = ['default', 'unique', 'primary', 'fulltext']
2
2
 
3
3
  async function genericPropSanitizer ({ prop, schema, driver }) {
4
4
  const { join } = this.app.bajo
5
- const { has, get, each } = this.lib._
6
- const def = this.propType[prop.type]
5
+ const { has, get, each } = this.app.lib._
6
+ const { propType } = this.app.pluginClass.dobo
7
+ const def = propType[prop.type]
7
8
  // detect from drivers
8
9
  if (prop.type === 'string') {
9
10
  def.minLength = prop.minLength ?? 0
@@ -13,14 +14,14 @@ async function genericPropSanitizer ({ prop, schema, driver }) {
13
14
  if (def.minLength > 0) prop.required = true
14
15
  }
15
16
  if (prop.autoInc && !['smallint', 'integer'].includes(prop.type)) delete prop.autoInc
16
- each(['minLength', 'maxLength', 'kind'], p => {
17
+ each(['minLength', 'maxLength', 'textType'], p => {
17
18
  if (!has(def, p)) {
18
19
  delete prop[p]
19
20
  return undefined
20
21
  }
21
22
  prop[p] = get(prop, p, get(this.config, `default.property.${prop.type}.${p}`, def[p]))
22
- if (def.choices && !def.choices.includes(prop[p])) {
23
- this.fatal('unsupportedAllowedChoices%s%s%s%s%s', p, prop[p], prop.name, schema.name, join(def.choices))
23
+ if (def.values && !def.values.includes(prop[p])) {
24
+ this.fatal('unsupportedAllowedChoices%s%s%s%s%s', p, prop[p], prop.name, schema.name, join(def.values))
24
25
  }
25
26
  })
26
27
  if (prop.index && !indexTypes.includes(prop.index.type)) {
@@ -1,12 +1,12 @@
1
1
  async function handleAttachmentUpload ({ action, name, id, options = {} } = {}) {
2
2
  const { getPluginDataDir } = this.app.bajo
3
- const { fs } = this.lib
3
+ const { fs } = this.app.lib
4
4
  const { req, mimeType, stats, setFile, setField } = options
5
5
 
6
6
  name = this.attachmentPreCheck(name)
7
7
  if (!name) return
8
8
  if (action === 'remove') {
9
- const dir = `${getPluginDataDir(this.name)}/attachment/${name}/${id}`
9
+ const dir = `${getPluginDataDir(this.ns)}/attachment/${name}/${id}`
10
10
  await fs.remove(dir)
11
11
  return
12
12
  }
package/lib/index.js ADDED
@@ -0,0 +1,3 @@
1
+ /**
2
+ * @module Lib
3
+ */
@@ -1,5 +1,5 @@
1
1
  async function connSanitizer (connection) {
2
- const { pick } = this.lib._
2
+ const { pick } = this.app.lib._
3
3
  const result = pick(connection, ['type', 'name', 'driver'])
4
4
  result.memory = true
5
5
  return result
@@ -2,15 +2,15 @@ let saving = false
2
2
 
3
3
  async function instantiate ({ connection, schemas, noRebuild }) {
4
4
  const { getPluginDataDir } = this.app.bajo
5
- const { fs } = this.lib
6
- const { pick } = this.lib._
5
+ const { fs } = this.app.lib
6
+ const { pick } = this.app.lib._
7
7
  this.memDb = this.memDb ?? {}
8
8
  this.memDb.storage = this.memDb.storage ?? {}
9
9
  this.memDb.instances = this.memDb.instances ?? []
10
10
  const instance = pick(connection, ['name', 'type'])
11
11
  this.memDb.instances.push(instance)
12
12
  // if (noRebuild) return
13
- const pdir = `${getPluginDataDir(this.name)}/memDb/data` // persistence dir
13
+ const pdir = `${getPluginDataDir(this.ns)}/memDb/data` // persistence dir
14
14
  fs.ensureDirSync(pdir)
15
15
  const persistence = []
16
16
  for (const schema of schemas) {
@@ -35,7 +35,7 @@ async function instantiate ({ connection, schemas, noRebuild }) {
35
35
  fs.writeFileSync(`${pdir}/${item}.json`, JSON.stringify(data), 'utf8')
36
36
  }
37
37
  saving = false
38
- }, this.config.memDb.persistence.syncPeriod * 1000)
38
+ }, this.config.memDb.persistence.syncPeriodDur)
39
39
  }
40
40
 
41
41
  export default instantiate
@@ -2,7 +2,7 @@ import { Query } from 'mingo'
2
2
 
3
3
  async function find ({ schema, filter = {}, options = {} }) {
4
4
  const { prepPagination } = this.app.dobo
5
- const { omit } = this.lib._
5
+ const { omit } = this.app.lib._
6
6
  const { limit, skip, sort, page } = await prepPagination(filter, schema)
7
7
  const criteria = filter.query ?? {}
8
8
  const q = new Query(criteria, { idKey: 'id' })
@@ -1,6 +1,6 @@
1
1
  async function get ({ schema, id, options = {} }) {
2
2
  const { thrownNotFound = true } = options
3
- const { find } = this.lib._
3
+ const { find } = this.app.lib._
4
4
  const result = find(this.memDb.storage[schema.name], { id })
5
5
  if (!result && thrownNotFound) throw this.error('recordNotFound%s%s', id, schema.name, { statusCode: 404 })
6
6
  return { data: result }
@@ -2,7 +2,7 @@ import getRecord from './get.js'
2
2
 
3
3
  async function remove ({ schema, id, options = {} }) {
4
4
  const { noResult } = options
5
- const { findIndex, pullAt } = this.lib._
5
+ const { findIndex, pullAt } = this.app.lib._
6
6
  const rec = noResult ? undefined : await getRecord.call(this, { schema, id })
7
7
  const idx = findIndex(this.memDb.storage[schema.name], { id })
8
8
  pullAt(this.memDb.storage[schema.name], [idx])
@@ -2,7 +2,7 @@ import getRecord from './get.js'
2
2
 
3
3
  async function update ({ schema, id, body, options }) {
4
4
  const { noResult } = options
5
- const { findIndex, merge } = this.lib._
5
+ const { findIndex, merge } = this.app.lib._
6
6
  const old = noResult ? undefined : await getRecord.call(this, { schema, id })
7
7
  const idx = findIndex(this.memDb.storage[schema.name], { id })
8
8
  const current = this.memDb.storage[schema.name][idx]
@@ -1,7 +1,7 @@
1
1
  import addFixtures from '../add-fixtures.js'
2
2
 
3
3
  async function start () {
4
- const { filter, map } = this.lib._
4
+ const { filter, map } = this.app.lib._
5
5
 
6
6
  const conns = filter(this.connections, { type: 'dobo:memory' })
7
7
  const schemas = filter(this.schemas, s => {
@@ -1,7 +1,7 @@
1
1
  async function mergeAttachmentInfo (rec, source, { mimeType, stats, fullPath }) {
2
2
  const { importPkg } = this.app.bajo
3
- const { fs } = this.lib
4
- const { pick } = this.lib._
3
+ const { fs } = this.app.lib
4
+ const { pick } = this.app.lib._
5
5
  if (!this.app.waibu) return
6
6
  const mime = await importPkg('waibu:mime')
7
7
 
@@ -1,6 +1,6 @@
1
1
  async function multiRelRows ({ schema, records, options = {} }) {
2
- const { isSet } = this.lib.aneka
3
- const { uniq, find, map } = this.lib._
2
+ const { isSet } = this.app.lib.aneka
3
+ const { uniq, find, map } = this.app.lib._
4
4
  const props = schema.properties.filter(p => isSet(p.rel) && !(options.hidden ?? []).includes(p.name))
5
5
  // const props = schema.properties.filter(p => isSet(p.rel))
6
6
  options.rels = options.rels ?? []
@@ -1,13 +1,13 @@
1
1
  async function resolveMethod (name, method, options = {}) {
2
2
  const { importModule } = this.app.bajo
3
- const { fs } = this.lib
4
- const { camelCase } = this.lib._
3
+ const { fs } = this.app.lib
4
+ const { camelCase } = this.app.lib._
5
5
  const { schema, driver, connection } = this.getInfo(name)
6
6
  const [group, action] = method.split('-')
7
7
  if (!options.force && (schema.disabled ?? []).includes(action)) throw this.error('methodIsDisabled%s%s', camelCase(method), name)
8
8
  let file
9
9
  if (connection.name === 'memory') file = `${this.app[driver.ns].dir.pkg}/lib/mem-db/method/${group}/${action}.js`
10
- else file = `${this.app[driver.ns].dir.pkg}/${this.name}/method/${group}/${action}.js`
10
+ else file = `${this.app[driver.ns].dir.pkg}/extend/${this.ns}/method/${group}/${action}.js`
11
11
  if (!fs.existsSync(file)) throw this.error('methodUnsupported%s%s', camelCase(method), name)
12
12
  const handler = await importModule(file)
13
13
  return { handler, schema, driver, connection }
@@ -1,12 +1,12 @@
1
1
  import genericPropSanitizer from './generic-prop-sanitizer.js'
2
2
 
3
3
  async function sanitizeFeature (item) {
4
- const { get, isPlainObject, mergeWith, isArray } = this.lib._
4
+ const { get, isPlainObject, mergeWith, isArray } = this.app.lib._
5
5
  for (const f of item.feature) {
6
6
  const feature = get(this.feature, f.name) // source from collectFeature
7
7
  if (!feature) this.fatal('unknownFeature%s%s', f.name, item.name)
8
8
  let [ns, path] = f.name.split('.')
9
- if (!path) ns = this.name
9
+ if (!path) ns = this.ns
10
10
  const input = await feature.call(this.app[ns], f)
11
11
  let props = input.properties
12
12
  if (isPlainObject(props)) props = [props]
@@ -37,10 +37,11 @@ async function sanitizeFullText (item) {
37
37
  }
38
38
 
39
39
  async function sanitizeSchema (items) {
40
- const { defaultsDeep } = this.lib.aneka
40
+ const { defaultsDeep } = this.app.lib.aneka
41
41
  const { freeze, fatal, importModule, join, breakNsPath, runHook } = this.app.bajo
42
- const { isEmpty, orderBy, map, keys, findIndex, find, each, isString, get, isPlainObject, camelCase, uniq, filter } = this.lib._
43
- const propTypes = keys(this.propType)
42
+ const { isEmpty, orderBy, map, keys, findIndex, find, each, isString, get, isPlainObject, camelCase, uniq, filter } = this.app.lib._
43
+ const { propType } = this.app.pluginClass.dobo
44
+ const propTypes = keys(propType)
44
45
  const schemas = []
45
46
  this.log.debug('loadingDbSchemas')
46
47
  for (const k in items) {
@@ -57,7 +58,7 @@ async function sanitizeSchema (items) {
57
58
  if (isEmpty(type)) type = conn.type
58
59
  const driver = find(this.drivers, { type, ns, driver: conn.driver })
59
60
  if (driver.lowerCaseModel) item.name = item.name.toLowerCase()
60
- let file = `${ns}:/${this.name}/lib/${type}/prop-sanitizer.js`
61
+ let file = `${ns}:/extend/${this.ns}/lib/${type}/prop-sanitizer.js`
61
62
  let propSanitizer = await importModule(file)
62
63
  if (!propSanitizer) propSanitizer = genericPropSanitizer
63
64
  for (const idx in item.properties) {
@@ -128,7 +129,7 @@ async function sanitizeSchema (items) {
128
129
  if (!all.includes(p.name)) all.push(p.name)
129
130
  else fatal.call(this, 'Field \'%s@%s\' should be used only once', p.name, item.name)
130
131
  })
131
- file = `${ns}:/${this.name}/lib/${type}/schema-sanitizer.js`
132
+ file = `${ns}:/extend/${this.ns}/lib/${type}/schema-sanitizer.js`
132
133
  const schemaSanitizer = await importModule(file)
133
134
  if (schemaSanitizer) await schemaSanitizer.call(this, { schema: item, connection: conn, driver })
134
135
  schemas.push(item)
@@ -1,6 +1,6 @@
1
1
  async function singleRelRows ({ schema, record, options = {} }) {
2
- const { isSet } = this.lib.aneka
3
- const { find } = this.lib._
2
+ const { isSet } = this.app.lib.aneka
3
+ const { find } = this.app.lib._
4
4
  const props = schema.properties.filter(p => isSet(p.rel) && !(options.hidden ?? []).includes(p.name))
5
5
  const rels = {}
6
6
  options.rels = options.rels ?? []
@@ -1,12 +1,12 @@
1
1
  import path from 'path'
2
2
 
3
3
  async function copyUploaded (name, id, options = {}) {
4
- const { fs } = this.lib
4
+ const { fs } = this.app.lib
5
5
  const { req, setField, setFile, mimeType, stats, silent = true } = options
6
6
  name = this.attachmentPreCheck(name)
7
7
  if (!name) {
8
8
  if (silent) return
9
- throw this.error('isMissing%s', this.print.write('field.name'))
9
+ throw this.error('isMissing%s', this.t('field.name'))
10
10
  }
11
11
  if (!this.app.waibu) {
12
12
  if (silent) return
@@ -1,13 +1,13 @@
1
1
  import mergeAttachmentInfo from '../../lib/merge-attachment-info.js'
2
2
 
3
3
  async function create (name, id, options = {}) {
4
- const { fs } = this.lib
5
- const { isEmpty } = this.lib._
4
+ const { fs } = this.app.lib
5
+ const { isEmpty } = this.app.lib._
6
6
  name = this.attachmentPreCheck(name)
7
7
  if (!name) return
8
8
  const { source, field = 'file', file } = options
9
9
  if (isEmpty(file)) return
10
- if (!source) throw this.error('isMissing%s', this.print.write('field.source'))
10
+ if (!source) throw this.error('isMissing%s', this.t('field.source'))
11
11
  const baseDir = await this.attachmentGetPath(name, id, field, file, { dirOnly: true })
12
12
  const { fullPath, stats, mimeType, req } = options
13
13
 
@@ -1,11 +1,11 @@
1
1
  import mergeAttachmentInfo from '../../lib/merge-attachment-info.js'
2
2
 
3
3
  async function find (name, id, options = {}) {
4
- const { fastGlob, fs } = this.lib
4
+ const { fastGlob, fs } = this.app.lib
5
5
  const { getPluginDataDir } = this.app.bajo
6
6
  name = this.attachmentPreCheck(name)
7
7
  if (!name) return
8
- const dir = `${getPluginDataDir(this.name)}/attachment/${name}/${id}`
8
+ const dir = `${getPluginDataDir(this.ns)}/attachment/${name}/${id}`
9
9
  if (!fs.existsSync(dir)) return []
10
10
  const files = await fastGlob(`${dir}/**/*`)
11
11
  const { fullPath, stats, mimeType } = options
@@ -1,8 +1,8 @@
1
1
  async function getPath (name, id, field, file, options = {}) {
2
2
  const { getPluginDataDir } = this.app.bajo
3
- const { pascalCase } = this.lib.aneka
4
- const { fs } = this.lib
5
- const dir = `${getPluginDataDir(this.name)}/attachment/${pascalCase(name)}/${id}`
3
+ const { pascalCase } = this.app.lib.aneka
4
+ const { fs } = this.app.lib
5
+ const dir = `${getPluginDataDir(this.ns)}/attachment/${pascalCase(name)}/${id}`
6
6
  if (options.dirOnly) return dir
7
7
  const path = field ? `${dir}/${field}/${file}` : `${dir}/${file}`
8
8
  if (!fs.existsSync(path)) throw this.error('notFound')
@@ -1,7 +1,7 @@
1
1
  async function get (name, id, field, file, options = {}) {
2
2
  name = this.attachmentPreCheck(name)
3
3
  if (!name) return
4
- const { find } = this.lib._
4
+ const { find } = this.app.lib._
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 })
@@ -1,5 +1,5 @@
1
1
  function preCheck (name) {
2
- const { pascalCase } = this.lib.aneka
2
+ const { pascalCase } = this.app.lib.aneka
3
3
  name = pascalCase(name)
4
4
  const schema = this.getSchema(name)
5
5
  if (!schema.attachment) return false
@@ -1,5 +1,5 @@
1
1
  async function remove (name, id, field, file, options = {}) {
2
- const { fs } = this.lib
2
+ const { fs } = this.app.lib
3
3
  name = this.attachmentPreCheck(name)
4
4
  if (!name) return
5
5
  const path = await this.attachmentGetPath(name, id, field, file)
@@ -3,10 +3,10 @@ import execValidation from '../../lib/exec-validation.js'
3
3
  import execFeatureHook from '../../lib/exec-feature-hook.js'
4
4
 
5
5
  async function create (name, inputs, options) {
6
- const { isSet } = this.lib.aneka
6
+ const { isSet } = this.app.lib.aneka
7
7
  const { generateId, runHook } = this.app.bajo
8
8
  const { clearModel } = this.cache ?? {}
9
- const { find } = this.lib._
9
+ const { find } = this.app.lib._
10
10
  options.dataOnly = options.dataOnly ?? true
11
11
  options.truncateString = options.truncateString ?? true
12
12
  const { noHook, noValidation } = options
@@ -20,8 +20,8 @@ async function create (name, inputs, options) {
20
20
  if (!noValidation) b = await execValidation.call(this, { noHook, name, b, options })
21
21
  }
22
22
  if (!noHook) {
23
- await runHook(`${this.name}:beforeBulkCreate`, name, bodies, options)
24
- await runHook(`${this.name}.${name}:beforeBulkCreate`, bodies, options)
23
+ await runHook(`${this.ns}:beforeBulkCreate`, name, bodies, options)
24
+ await runHook(`${this.ns}.${name}:beforeBulkCreate`, bodies, options)
25
25
  }
26
26
  for (const idx in bodies) {
27
27
  await execFeatureHook.call(this, 'beforeCreate', { schema, body: bodies[idx] })
@@ -37,8 +37,8 @@ async function create (name, inputs, options) {
37
37
  await execFeatureHook.call(this, 'afterCreate', { schema, body: bodies[idx] })
38
38
  }
39
39
  if (!noHook) {
40
- await runHook(`${this.name}.${name}:afterBulkCreate`, bodies, options)
41
- await runHook(`${this.name}:afterBulkCreate`, name, bodies, options)
40
+ await runHook(`${this.ns}.${name}:afterBulkCreate`, bodies, options)
41
+ await runHook(`${this.ns}:afterBulkCreate`, name, bodies, options)
42
42
  }
43
43
  if (clearModel) await clearModel({ model: name })
44
44
  }
@@ -2,19 +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.lib._
5
+ const { camelCase } = this.app.lib._
6
6
 
7
7
  await this.modelExists(name, true)
8
8
  const { noHook } = options
9
9
  const { handler, schema, driver } = await resolveMethod.call(this, name, 'model-clear', options)
10
10
  if (!noHook) {
11
- await runHook(`${this.name}:beforeModelClear`, schema, options)
12
- await runHook(`${this.name}.${camelCase(name)}:beforeModelClear`, options)
11
+ await runHook(`${this.ns}:beforeModelClear`, schema, options)
12
+ await runHook(`${this.ns}.${camelCase(name)}:beforeModelClear`, options)
13
13
  }
14
14
  const resp = await handler.call(this.app[driver.ns], { schema, options })
15
15
  if (!noHook) {
16
- await runHook(`${this.name}.${camelCase(name)}:afterModelClear`, options, resp)
17
- await runHook(`${this.name}:afterModelClear`, schema, options, resp)
16
+ await runHook(`${this.ns}.${camelCase(name)}:afterModelClear`, options, resp)
17
+ await runHook(`${this.ns}:afterModelClear`, schema, options, resp)
18
18
  }
19
19
  return resp
20
20
  }
@@ -0,0 +1,32 @@
1
+ import resolveMethod from '../../lib/resolve-method.js'
2
+
3
+ /**
4
+ * Create a new model:
5
+ * - read corresponding schema
6
+ * - attempt to create table/database/collection accordingly
7
+ *
8
+ * @method
9
+ * @memberof Dobo
10
+ * @async
11
+ * @instance
12
+ * @name modelCreate
13
+ * @param {string} name - Model's name
14
+ * @param {Object} [options={}] - Options object
15
+ */
16
+ async function create (name, options = {}) {
17
+ const { runHook } = this.app.bajo
18
+ const { camelCase } = this.app.lib._
19
+
20
+ const { handler, schema, driver } = await resolveMethod.call(this, name, 'model-create', options)
21
+ if (!options.noHook) {
22
+ await runHook(`${this.ns}:beforeModelCreate`, schema, options)
23
+ await runHook(`${this.ns}.${camelCase(name)}:beforeModelCreate`, options)
24
+ }
25
+ await handler.call(this.app[driver.ns], { schema, options })
26
+ if (!options.noHook) {
27
+ await runHook(`${this.ns}.${camelCase(name)}:afterModelCreate`, options)
28
+ await runHook(`${this.ns}:afterModelCreate`, schema, options)
29
+ }
30
+ }
31
+
32
+ export default create
@@ -0,0 +1,31 @@
1
+ import resolveMethod from '../../lib/resolve-method.js'
2
+
3
+ /**
4
+ * Drop database model
5
+ *
6
+ * @method
7
+ * @memberof Dobo
8
+ * @async
9
+ * @instance
10
+ * @name modelDrop
11
+ * @param {string} name - Model's name
12
+ * @param {Object} [options={}] - Options object
13
+ */
14
+
15
+ async function drop (name, options = {}) {
16
+ const { runHook } = this.app.bajo
17
+ const { camelCase } = this.app.lib._
18
+ const { handler, schema, driver } = await resolveMethod.call(this, name, 'model-drop', options)
19
+
20
+ if (!options.noHook) {
21
+ await runHook(`${this.ns}:beforeModelDrop`, schema, options)
22
+ await runHook(`${this.ns}.${camelCase(name)}:beforeModelDrop`, options)
23
+ }
24
+ await handler.call(this.app[driver.ns], { schema, options })
25
+ if (!options.noHook) {
26
+ await runHook(`${this.ns}.${camelCase(name)}:afterModelDrop`, options)
27
+ await runHook(`${this.ns}:afterModelDrop`, schema, options)
28
+ }
29
+ }
30
+
31
+ export default drop
@@ -0,0 +1,37 @@
1
+ import resolveMethod from '../../lib/resolve-method.js'
2
+
3
+ const cache = {}
4
+
5
+ /**
6
+ * Check if model exists already
7
+ *
8
+ * @method
9
+ * @memberof Dobo
10
+ * @async
11
+ * @instance
12
+ * @name modelExists
13
+ * @param {string} name - Model's name
14
+ * @param {boolean} [thrown=false] - If ```true``` throw error if not exists instead of just silent
15
+ * @param {Object} [options={}] - Options object
16
+ * @returns {boolean}
17
+ */
18
+ async function exists (name, thrown, options = {}) {
19
+ if (cache[name]) return cache[name]
20
+ const { runHook } = this.app.bajo
21
+ const { camelCase } = this.app.lib._
22
+ const { handler, schema, driver } = await resolveMethod.call(this, name, 'model-exists', options)
23
+ if (!options.noHook) {
24
+ await runHook(`${this.ns}:beforeModelExists`, schema, options)
25
+ await runHook(`${this.ns}.${camelCase(name)}:beforeModelExists`, options)
26
+ }
27
+ const exist = await handler.call(this.app[driver.ns], { schema, options })
28
+ if (!options.noHook) {
29
+ await runHook(`${this.ns}.${camelCase(name)}:afterModelExists`, exist, options)
30
+ await runHook(`${this.ns}:afterModelExists`, schema, exist, options)
31
+ }
32
+ if (!exist && thrown) throw this.error('modelNotExists%s', name)
33
+ cache[name] = exist
34
+ return exist
35
+ }
36
+
37
+ export default exists
@@ -3,20 +3,20 @@ 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, camelCase, omit } = this.lib._
6
+ const { cloneDeep, camelCase, omit } = this.app.lib._
7
7
  const options = cloneDeep(omit(opts, ['req', 'reply']))
8
8
  options.req = opts.req
9
9
  options.reply = opts.reply
10
10
  const { noHook } = options
11
11
  const { handler, schema, driver } = await resolveMethod.call(this, name, 'record-clear', options)
12
12
  if (!noHook) {
13
- await runHook(`${this.name}:beforeRecordClear`, name, options)
14
- await runHook(`${this.name}.${camelCase(name)}:beforeRecordClear`, options)
13
+ await runHook(`${this.ns}:beforeRecordClear`, name, options)
14
+ await runHook(`${this.ns}.${camelCase(name)}:beforeRecordClear`, options)
15
15
  }
16
16
  const resp = await handler.call(this.app[driver.ns], { schema, options })
17
17
  if (!noHook) {
18
- await runHook(`${this.name}.${camelCase(name)}:afterRecordClear`, options, resp)
19
- await runHook(`${this.name}:afterRecordClear`, name, options, resp)
18
+ await runHook(`${this.ns}.${camelCase(name)}:afterRecordClear`, options, resp)
19
+ await runHook(`${this.ns}:afterRecordClear`, name, options, resp)
20
20
  }
21
21
  return resp
22
22
  }