dobo 2.0.0 → 2.2.0

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 (197) 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 +725 -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 +366 -0
  44. package/docs/scripts/third-party/hljs-line-num.js +1 -0
  45. package/docs/scripts/third-party/hljs-original.js +5164 -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 +671 -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/extend/bajo/intl/en-US.json +69 -30
  62. package/extend/bajo/intl/id.json +58 -29
  63. package/extend/bajoCli/applet/clear-record.js +22 -0
  64. package/extend/bajoCli/applet/connection.js +5 -5
  65. package/extend/bajoCli/applet/count-record.js +27 -0
  66. package/extend/bajoCli/applet/create-aggregate.js +33 -0
  67. package/extend/bajoCli/applet/create-histogram.js +33 -0
  68. package/extend/bajoCli/applet/create-record.js +39 -0
  69. package/extend/bajoCli/applet/find-record.js +27 -0
  70. package/extend/bajoCli/applet/get-record.js +27 -0
  71. package/extend/bajoCli/applet/lib/post-process.js +25 -26
  72. package/extend/bajoCli/applet/model.js +22 -0
  73. package/extend/bajoCli/applet/rebuild-model.js +91 -0
  74. package/extend/bajoCli/applet/remove-record.js +27 -0
  75. package/extend/bajoCli/applet/update-record.js +44 -0
  76. package/extend/bajoCli/applet.js +0 -0
  77. package/extend/dobo/driver/memory.js +170 -0
  78. package/extend/dobo/feature/created-at.js +10 -8
  79. package/extend/dobo/feature/dt.js +0 -0
  80. package/extend/dobo/feature/immutable.js +30 -0
  81. package/extend/dobo/feature/int-id.js +0 -0
  82. package/extend/dobo/feature/removed-at.js +35 -57
  83. package/extend/dobo/feature/updated-at.js +14 -12
  84. package/extend/waibuMpa/route/attachment/@model/@id/@field/@file.js +5 -9
  85. package/extend/waibuStatic/virtual.json +0 -0
  86. package/index.js +420 -337
  87. package/lib/collect-connections.js +60 -21
  88. package/lib/collect-drivers.js +29 -35
  89. package/lib/collect-features.js +40 -0
  90. package/lib/collect-models.js +319 -0
  91. package/lib/factory/action.js +161 -0
  92. package/lib/factory/connection.js +62 -0
  93. package/lib/factory/driver.js +358 -0
  94. package/lib/factory/feature.js +33 -0
  95. package/lib/factory/model/_util.js +402 -0
  96. package/lib/factory/model/build.js +15 -0
  97. package/lib/factory/model/clear-record.js +17 -0
  98. package/lib/factory/model/count-record.js +17 -0
  99. package/lib/factory/model/create-aggregate.js +17 -0
  100. package/lib/factory/model/create-attachment.js +29 -0
  101. package/lib/factory/model/create-histogram.js +17 -0
  102. package/lib/factory/model/create-record.js +35 -0
  103. package/lib/factory/model/drop.js +15 -0
  104. package/lib/factory/model/exists.js +21 -0
  105. package/lib/factory/model/find-all-record.js +71 -0
  106. package/lib/factory/model/find-attachment.js +29 -0
  107. package/lib/factory/model/find-one-record.js +19 -0
  108. package/lib/factory/model/find-record.js +103 -0
  109. package/lib/factory/model/get-attachment.js +15 -0
  110. package/lib/factory/model/get-record.js +79 -0
  111. package/lib/factory/model/list-attachment.js +37 -0
  112. package/lib/{add-fixtures.js → factory/model/load-fixtures.js} +69 -67
  113. package/lib/factory/model/remove-attachment.js +15 -0
  114. package/lib/factory/model/remove-record.js +59 -0
  115. package/lib/factory/model/sanitize-body.js +62 -0
  116. package/lib/factory/model/sanitize-id.js +7 -0
  117. package/lib/factory/model/sanitize-record.js +26 -0
  118. package/lib/factory/model/update-attachment.js +9 -0
  119. package/lib/factory/model/update-record.js +81 -0
  120. package/lib/factory/model/upsert-record.js +95 -0
  121. package/lib/factory/model/validate.js +232 -0
  122. package/lib/factory/model.js +150 -0
  123. package/lib/index.js +3 -0
  124. package/package.json +45 -36
  125. package/wiki/APPLETS.md +57 -0
  126. package/wiki/CHANGES.md +46 -0
  127. package/wiki/CONFIG.md +25 -0
  128. package/wiki/CONTRIBUTING.md +5 -0
  129. package/wiki/DEV-GUIDE.md +1 -0
  130. package/wiki/ECOSYSTEM.md +20 -0
  131. package/wiki/GETTING-STARTED.md +166 -0
  132. package/{docs/query-language.md → wiki/QUERY-LANGUAGE.md} +0 -0
  133. package/wiki/USER-GUIDE.md +1 -0
  134. package/extend/bajoCli/applet/model-clear.js +0 -11
  135. package/extend/bajoCli/applet/model-rebuild.js +0 -101
  136. package/extend/bajoCli/applet/record-create.js +0 -41
  137. package/extend/bajoCli/applet/record-find.js +0 -27
  138. package/extend/bajoCli/applet/record-get.js +0 -24
  139. package/extend/bajoCli/applet/record-remove.js +0 -24
  140. package/extend/bajoCli/applet/record-update.js +0 -47
  141. package/extend/bajoCli/applet/schema.js +0 -22
  142. package/extend/bajoCli/applet/stat-count.js +0 -24
  143. package/lib/build-bulk-action.js +0 -12
  144. package/lib/check-unique.js +0 -39
  145. package/lib/collect-feature.js +0 -25
  146. package/lib/collect-schemas.js +0 -83
  147. package/lib/exec-feature-hook.js +0 -13
  148. package/lib/exec-validation.js +0 -21
  149. package/lib/generic-prop-sanitizer.js +0 -31
  150. package/lib/handle-attachment-upload.js +0 -16
  151. package/lib/mem-db/conn-sanitizer.js +0 -8
  152. package/lib/mem-db/instantiate.js +0 -41
  153. package/lib/mem-db/method/model/clear.js +0 -6
  154. package/lib/mem-db/method/model/create.js +0 -5
  155. package/lib/mem-db/method/model/drop.js +0 -5
  156. package/lib/mem-db/method/model/exists.js +0 -5
  157. package/lib/mem-db/method/record/create.js +0 -12
  158. package/lib/mem-db/method/record/find.js +0 -20
  159. package/lib/mem-db/method/record/get.js +0 -9
  160. package/lib/mem-db/method/record/remove.js +0 -13
  161. package/lib/mem-db/method/record/update.js +0 -15
  162. package/lib/mem-db/method/stat/count.js +0 -11
  163. package/lib/mem-db/start.js +0 -25
  164. package/lib/merge-attachment-info.js +0 -16
  165. package/lib/multi-rel-rows.js +0 -42
  166. package/lib/resolve-method.js +0 -16
  167. package/lib/sanitize-schema.js +0 -197
  168. package/lib/single-rel-rows.js +0 -38
  169. package/method/attachment/copy-uploaded.js +0 -34
  170. package/method/attachment/create.js +0 -29
  171. package/method/attachment/find.js +0 -27
  172. package/method/attachment/get-path.js +0 -12
  173. package/method/attachment/get.js +0 -12
  174. package/method/attachment/pre-check.js +0 -9
  175. package/method/attachment/remove.js +0 -11
  176. package/method/attachment/update.js +0 -7
  177. package/method/bulk/create.js +0 -46
  178. package/method/model/clear.js +0 -22
  179. package/method/model/create.js +0 -19
  180. package/method/model/drop.js +0 -19
  181. package/method/model/exists.js +0 -24
  182. package/method/record/clear.js +0 -24
  183. package/method/record/count.js +0 -44
  184. package/method/record/create.js +0 -71
  185. package/method/record/find-all.js +0 -25
  186. package/method/record/find-one.js +0 -56
  187. package/method/record/find.js +0 -52
  188. package/method/record/get.js +0 -47
  189. package/method/record/remove.js +0 -41
  190. package/method/record/update.js +0 -63
  191. package/method/record/upsert.js +0 -35
  192. package/method/sanitize/body.js +0 -70
  193. package/method/sanitize/date.js +0 -14
  194. package/method/sanitize/id.js +0 -7
  195. package/method/stat/aggregate.js +0 -23
  196. package/method/stat/histogram.js +0 -26
  197. package/method/validate.js +0 -157
@@ -1,24 +0,0 @@
1
- import postProcess from './lib/post-process.js'
2
-
3
- async function statCount (path, ...args) {
4
- const { importPkg } = this.app.bajo
5
- const { isEmpty, map } = this.lib._
6
- const [select, input] = await importPkg('bajoCli:@inquirer/select', 'bajoCli:@inquirer/input')
7
- if (isEmpty(this.schemas)) return this.print.fail('notFound%s', this.print.write('field.schema'), { exit: this.app.bajo.applet })
8
- let [schema, query] = args
9
- if (isEmpty(schema)) {
10
- schema = await select({
11
- message: this.print.write('selectSchema'),
12
- choices: map(this.schemas, s => ({ value: s.name }))
13
- })
14
- }
15
- if (isEmpty(query)) {
16
- query = await input({
17
- message: this.print.write('enterQueryIfAny')
18
- })
19
- }
20
- const filter = { query }
21
- await postProcess.call(this, { noConfirmation: true, handler: 'statCount', params: [schema, filter], path, processMsg: 'Counting record(s)' })
22
- }
23
-
24
- export default statCount
@@ -1,12 +0,0 @@
1
- async function buildBulkAction (name, action, options = {}) {
2
- const { fs, importModule } = this.app.bajo
3
- const { camelCase } = this.lib._
4
- const { schema, driver, connection } = await this.getInfo(name)
5
- if (!options.force && (schema.disabled ?? []).includes(action)) throw this.error('methodIsDisabled%s%s', camelCase('bulk ' + action), name)
6
- const file = `${driver.plugin}:/extend/${this.name}/method/bulk/${action}.js`
7
- if (!fs.existsSync(file)) throw this.error('methodUnsupported%s%s', camelCase('bulk ' + action), name)
8
- const handler = await importModule(file)
9
- return { handler, schema, driver, connection }
10
- }
11
-
12
- export default buildBulkAction
@@ -1,39 +0,0 @@
1
- async function checkUnique ({ schema, body, id }) {
2
- const { isSet } = this.lib.aneka
3
- const { filter, map, set } = this.lib._
4
- const singles = map(filter(schema.properties, p => (p.index ?? {}).type === 'unique'), 'name')
5
- const opts = { noHook: true, noCache: true, thrownNotFound: false, forceNoHidden: true }
6
- let old = {}
7
- if (id) old = (await this.recordGet(schema.name, id, opts)) ?? {}
8
- for (const s of singles) {
9
- if (!isSet(body[s])) continue
10
- if (id && body[s] === old[s]) continue
11
- const query = set({}, s, body[s])
12
- const resp = await this.recordFind(schema.name, { query, limit: 1 }, opts)
13
- if (resp.length !== 0) {
14
- const details = [{ field: s, error: 'uniqueConstraintError', value: id }]
15
- throw this.error('uniqueConstraintError', { details, body })
16
- }
17
- }
18
- const multis = filter(schema.indexes, i => i.type === 'unique')
19
- for (const m of multis) {
20
- const query = {}
21
- let empty = true
22
- let same = true
23
- for (const f of m.fields) {
24
- if (body[f]) empty = false
25
- if (body[f] !== old[f]) same = false
26
- query[f] = body[f]
27
- }
28
- if (empty || same) continue
29
- const resp = await this.recordFind(schema.name, { query, limit: 1 }, { noHook: true, noCache: true, forceNoHidden: true })
30
- if (resp.length !== 0) {
31
- const details = map(m.fields, f => {
32
- return { field: f, error: 'Unique constraint error' }
33
- })
34
- throw this.error('Unique constraint error', { details, body })
35
- }
36
- }
37
- }
38
-
39
- export default checkUnique
@@ -1,25 +0,0 @@
1
- import path from 'path'
2
-
3
- async function handler ({ file }) {
4
- const { name: ns } = this
5
- const { importModule } = this.app.bajo
6
- const { camelCase, isFunction } = this.lib._
7
- const me = this.app.dobo
8
-
9
- let name = camelCase(path.basename(file, '.js'))
10
- if (ns !== me.name) name = `${ns}.${name}`
11
- const mod = await importModule(file)
12
- if (!isFunction(mod)) this.fatal('featureNotAsync%s', name)
13
- me.feature[name] = mod
14
- me.log.trace('- %s', name)
15
- }
16
-
17
- async function collectFeature () {
18
- const { eachPlugins } = this.app.bajo
19
- this.feature = {}
20
- this.log.trace('loadingDbFeature')
21
- await eachPlugins(handler, { glob: 'feature/*.js', prefix: this.name })
22
- this.log.debug('totalLoadedFeatures%d', Object.keys(this.feature).length)
23
- }
24
-
25
- export default collectFeature
@@ -1,83 +0,0 @@
1
- import path from 'path'
2
- import sanitizeSchema from './sanitize-schema.js'
3
-
4
- async function handler ({ file }) {
5
- const { name: ns, alias } = this
6
- const { readConfig, eachPlugins } = this.app.bajo
7
- const { pascalCase } = this.lib.aneka
8
- const { get, isPlainObject, each, find, has, isArray, forOwn, isString, merge } = this.lib._
9
- const { fastGlob } = this.lib
10
-
11
- const base = path.basename(file, path.extname(file))
12
- const defName = pascalCase(`${alias} ${base}`)
13
- const mod = await readConfig(file, { ns, ignoreError: true })
14
- if (!isPlainObject(mod)) this.fatal('invalidSchema%s', defName)
15
- const forcedConn = get(this, `app.${ns}.config.dobo.schemaConnection.${base}`)
16
- if (forcedConn) mod.connection = forcedConn
17
- if (!mod.connection) mod.connection = 'default'
18
- mod.name = mod.name ?? defName
19
- mod.file = file
20
- mod.ns = ns
21
- mod.attachment = mod.attachment ?? true
22
- mod.feature = mod.feature ?? []
23
- mod.buildLevel = mod.buildLevel ?? 999
24
- const feats = []
25
- if (isArray(mod.feature)) {
26
- each(mod.feature, f => {
27
- if (isString(f)) feats.push({ name: f })
28
- else if (isPlainObject(f)) feats.push(f)
29
- })
30
- } else if (isPlainObject(mod.feature)) {
31
- forOwn(mod.feature, (v, k) => {
32
- feats.push(merge({}, v, { name: k }))
33
- })
34
- }
35
- mod.feature = feats
36
- mod.properties = mod.properties ?? []
37
- // if ((mod.properties ?? []).length === 0) this.fatal('noPropsFoundOnSchema%s', mod.name)
38
- // schema extender
39
- await eachPlugins(async function ({ dir }) {
40
- const { name: ns } = this
41
- const glob = `${dir}/extend/dobo/extend/${mod.ns}/schema/${base}.*`
42
- const files = await fastGlob(glob)
43
- for (const file of files) {
44
- const extender = await readConfig(file, { ns, ignoreError: true })
45
- if (!isPlainObject(extender)) return undefined
46
- each(extender.properties ?? [], p => {
47
- if (isString(p) && mod.properties.includes(p)) return undefined
48
- else if (find(mod.properties, { name: p.name })) return undefined
49
- mod.properties.push(p)
50
- })
51
- const feats = []
52
- if (isArray(extender.feature)) {
53
- each(extender.feature, f => {
54
- if (isString(f)) feats.push({ name: f })
55
- else if (isPlainObject(f)) feats.push(f)
56
- })
57
- } else if (isPlainObject(extender.feature)) {
58
- forOwn(extender.feature, (v, k) => {
59
- feats.push(merge({}, v, { name: k }))
60
- })
61
- }
62
- if (feats.length > 0) mod.feature.push(...feats)
63
- if (ns === this.app.bajo.mainNs) {
64
- each(['connection', 'name'], i => {
65
- if (has(extender, i)) mod[i] = extender[i]
66
- })
67
- }
68
- mod.extender = mod.extender ?? []
69
- mod.extender.push(ns)
70
- }
71
- })
72
- return mod
73
- }
74
-
75
- async function collectSchemas () {
76
- const { eachPlugins } = this.app.bajo
77
- const { isEmpty } = this.lib._
78
- const result = await eachPlugins(handler, { glob: 'schema/*.*', prefix: this.name })
79
- if (isEmpty(result)) this.log.warn('notFound%s', this.print.write('schema'))
80
- else await sanitizeSchema.call(this, result)
81
- }
82
-
83
- export default collectSchemas
@@ -1,13 +0,0 @@
1
- async function execFeatureHook (name, params = {}) {
2
- const { get } = this.lib._
3
- const { schema } = params
4
- for (const f of schema.feature) {
5
- const fn = get(this.feature, f.name)
6
- if (!fn) continue
7
- const input = await fn.call(this, f)
8
- const hook = get(input, 'hook.' + name)
9
- if (hook) await hook.call(this, params)
10
- }
11
- }
12
-
13
- export default execFeatureHook
@@ -1,21 +0,0 @@
1
- async function execValidation ({ name, body, options, partial }) {
2
- const { runHook } = this.app.bajo
3
- const { keys, camelCase } = this.lib._
4
- const { noHook } = options
5
- if (!noHook) {
6
- await runHook(`${this.name}:beforeRecordValidation`, name, body, options)
7
- await runHook(`${this.name}.${camelCase(name)}:beforeRecordValidation`, body, options)
8
- }
9
- const { validation = {} } = options
10
- if (partial) {
11
- validation.fields = keys(body)
12
- }
13
- body = await this.validate(body, name, validation)
14
- if (!noHook) {
15
- await runHook(`${this.name}:afterRecordValidation`, name, body, options)
16
- await runHook(`${this.name}.${camelCase(name)}:afterRecordValidation`, body, options)
17
- }
18
- return body
19
- }
20
-
21
- export default execValidation
@@ -1,31 +0,0 @@
1
- const indexTypes = ['default', 'unique', 'primary', 'fulltext']
2
-
3
- async function genericPropSanitizer ({ prop, schema, driver }) {
4
- const { join } = this.app.bajo
5
- const { has, get, each } = this.lib._
6
- const def = this.propType[prop.type]
7
- // detect from drivers
8
- if (prop.type === 'string') {
9
- def.minLength = prop.minLength ?? 0
10
- def.maxLength = prop.maxLength ?? 255
11
- if (has(prop, 'length')) def.maxLength = prop.length
12
- if (prop.required && def.minLength === 0) def.minLength = 1
13
- if (def.minLength > 0) prop.required = true
14
- }
15
- if (prop.autoInc && !['smallint', 'integer'].includes(prop.type)) delete prop.autoInc
16
- each(['minLength', 'maxLength', 'kind'], p => {
17
- if (!has(def, p)) {
18
- delete prop[p]
19
- return undefined
20
- }
21
- 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))
24
- }
25
- })
26
- if (prop.index && !indexTypes.includes(prop.index.type)) {
27
- this.fatal('unsupportedIndexType%s%s%s%s', prop.index.type, prop.name, schema.name, join(indexTypes))
28
- }
29
- }
30
-
31
- export default genericPropSanitizer
@@ -1,16 +0,0 @@
1
- async function handleAttachmentUpload ({ action, name, id, options = {} } = {}) {
2
- const { getPluginDataDir } = this.app.bajo
3
- const { fs } = this.lib
4
- const { req, mimeType, stats, setFile, setField } = options
5
-
6
- name = this.attachmentPreCheck(name)
7
- if (!name) return
8
- if (action === 'remove') {
9
- const dir = `${getPluginDataDir(this.name)}/attachment/${name}/${id}`
10
- await fs.remove(dir)
11
- return
12
- }
13
- return this.attachmentCopyUploaded(name, id, { req, mimeType, stats, setFile, setField })
14
- }
15
-
16
- export default handleAttachmentUpload
@@ -1,8 +0,0 @@
1
- async function connSanitizer (connection) {
2
- const { pick } = this.lib._
3
- const result = pick(connection, ['type', 'name', 'driver'])
4
- result.memory = true
5
- return result
6
- }
7
-
8
- export default connSanitizer
@@ -1,41 +0,0 @@
1
- let saving = false
2
-
3
- async function instantiate ({ connection, schemas, noRebuild }) {
4
- const { getPluginDataDir } = this.app.bajo
5
- const { fs } = this.lib
6
- const { pick } = this.lib._
7
- this.memDb = this.memDb ?? {}
8
- this.memDb.storage = this.memDb.storage ?? {}
9
- this.memDb.instances = this.memDb.instances ?? []
10
- const instance = pick(connection, ['name', 'type'])
11
- this.memDb.instances.push(instance)
12
- // if (noRebuild) return
13
- const pdir = `${getPluginDataDir(this.name)}/memDb/data` // persistence dir
14
- fs.ensureDirSync(pdir)
15
- const persistence = []
16
- for (const schema of schemas) {
17
- this.memDb.storage[schema.name] = this.memDb.storage[schema.name] ?? [] // init empty model
18
- if (!schema.persistence) continue
19
- persistence.push(schema.name)
20
- // load if persistence
21
- const file = `${pdir}/${schema.name}.json`
22
- if (!fs.existsSync(file)) continue
23
- try {
24
- const data = fs.readFileSync(file, 'utf8')
25
- this.memDb.storage[schema.name] = JSON.parse(data)
26
- } catch (err) {
27
- this.fatal('cantLoad%s%s', schema.name, err.message)
28
- }
29
- }
30
- setInterval(() => {
31
- if (saving) return
32
- saving = true
33
- for (const item of persistence) {
34
- const data = this.memDb.storage[item]
35
- fs.writeFileSync(`${pdir}/${item}.json`, JSON.stringify(data), 'utf8')
36
- }
37
- saving = false
38
- }, this.config.memDb.persistence.syncPeriod * 1000)
39
- }
40
-
41
- export default instantiate
@@ -1,6 +0,0 @@
1
- async function clear ({ schema, options = {} }) {
2
- this.memDb.storage[schema.name].splice(0)
3
- return true
4
- }
5
-
6
- export default clear
@@ -1,5 +0,0 @@
1
- async function exists ({ schema, options = {} }) {
2
- this.memDb.storage[schema.name] = []
3
- }
4
-
5
- export default exists
@@ -1,5 +0,0 @@
1
- async function exists ({ schema, options = {} }) {
2
- this.memDb.storage[schema.name].splice(0)
3
- }
4
-
5
- export default exists
@@ -1,5 +0,0 @@
1
- async function exists ({ schema, options = {} }) {
2
- return true
3
- }
4
-
5
- export default exists
@@ -1,12 +0,0 @@
1
- import getRecord from './get.js'
2
-
3
- async function create ({ schema, body, options = {} }) {
4
- const { noResult } = options
5
- const exist = await getRecord.call(this, { schema, id: body.id, options: { thrownNotFound: false } })
6
- if (exist.data) throw this.error('recordExists%s%s', body.id, schema.name)
7
- this.memDb.storage[schema.name].push(body)
8
- if (noResult) return
9
- return { data: body }
10
- }
11
-
12
- export default create
@@ -1,20 +0,0 @@
1
- import { Query } from 'mingo'
2
-
3
- async function find ({ schema, filter = {}, options = {} }) {
4
- const { prepPagination } = this.app.dobo
5
- const { omit } = this.lib._
6
- const { limit, skip, sort, page } = await prepPagination(filter, schema)
7
- const criteria = filter.query ?? {}
8
- const q = new Query(criteria, { idKey: 'id' })
9
- let cursor = q.find(this.memDb.storage[schema.name])
10
- let count = 0
11
- if (options.count && !options.dataOnly) count = cursor.count()
12
- cursor = q.find(this.memDb.storage[schema.name])
13
- if (sort) cursor.sort(sort)
14
- if (!options.noLimit) cursor.skip(skip).limit(limit)
15
- let result = { data: cursor.all(), page, limit, count, pages: Math.ceil(count / limit) }
16
- if (!options.count) result = omit(result, ['count', 'pages'])
17
- return result
18
- }
19
-
20
- export default find
@@ -1,9 +0,0 @@
1
- async function get ({ schema, id, options = {} }) {
2
- const { thrownNotFound = true } = options
3
- const { find } = this.lib._
4
- const result = find(this.memDb.storage[schema.name], { id })
5
- if (!result && thrownNotFound) throw this.error('recordNotFound%s%s', id, schema.name, { statusCode: 404 })
6
- return { data: result }
7
- }
8
-
9
- export default get
@@ -1,13 +0,0 @@
1
- import getRecord from './get.js'
2
-
3
- async function remove ({ schema, id, options = {} }) {
4
- const { noResult } = options
5
- const { findIndex, pullAt } = this.lib._
6
- const rec = noResult ? undefined : await getRecord.call(this, { schema, id })
7
- const idx = findIndex(this.memDb.storage[schema.name], { id })
8
- pullAt(this.memDb.storage[schema.name], [idx])
9
- if (noResult) return
10
- return { oldData: rec.data }
11
- }
12
-
13
- export default remove
@@ -1,15 +0,0 @@
1
- import getRecord from './get.js'
2
-
3
- async function update ({ schema, id, body, options }) {
4
- const { noResult } = options
5
- const { findIndex, merge } = this.lib._
6
- const old = noResult ? undefined : await getRecord.call(this, { schema, id })
7
- const idx = findIndex(this.memDb.storage[schema.name], { id })
8
- const current = this.memDb.storage[schema.name][idx]
9
- this.memDb.storage[schema.name][idx] = merge(current, body)
10
- if (noResult) return
11
- const result = this.memDb.storage[schema.name][idx]
12
- return { oldData: old.data, data: result }
13
- }
14
-
15
- export default update
@@ -1,11 +0,0 @@
1
- import { Query } from 'mingo'
2
-
3
- async function count ({ schema, filter = {}, options = {} }) {
4
- const criteria = filter.query ?? {}
5
- const q = new Query(criteria, { idKey: 'id' })
6
- const cursor = q.find(this.memDb.storage[schema.name])
7
- const count = cursor.count()
8
- return { data: count }
9
- }
10
-
11
- export default count
@@ -1,25 +0,0 @@
1
- import addFixtures from '../add-fixtures.js'
2
-
3
- async function start () {
4
- const { filter, map } = this.lib._
5
-
6
- const conns = filter(this.connections, { type: 'dobo:memory' })
7
- const schemas = filter(this.schemas, s => {
8
- const names = map(conns, 'name')
9
- return names.includes(s.connection)
10
- })
11
- if (schemas.length === 0) return
12
- this.log.debug('addingFixtureToMemDb')
13
- for (const schema of schemas) {
14
- if (schema.persistence) {
15
- this.log.warn('addingMemoryPersistenceIgnored', schema.name)
16
- continue
17
- }
18
- let { success, error } = await addFixtures.call(this, schema.name)
19
- success = success ?? 0
20
- error = error ?? 0
21
- this.log.trace('- %s@%s (%d/%d)', schema.name, schema.connection, success, success + error)
22
- }
23
- }
24
-
25
- export default start
@@ -1,16 +0,0 @@
1
- async function mergeAttachmentInfo (rec, source, { mimeType, stats, fullPath }) {
2
- const { importPkg } = this.app.bajo
3
- const { fs } = this.lib
4
- const { pick } = this.lib._
5
- if (!this.app.waibu) return
6
- const mime = await importPkg('waibu:mime')
7
-
8
- if (mimeType) rec.mimeType = mime.getType(rec.file)
9
- if (fullPath) rec.fullPath = source
10
- if (stats) {
11
- const s = fs.statSync(source)
12
- rec.stats = pick(s, ['size', 'atime', 'ctime', 'mtime'])
13
- }
14
- }
15
-
16
- export default mergeAttachmentInfo
@@ -1,42 +0,0 @@
1
- async function multiRelRows ({ schema, records, options = {} }) {
2
- const { isSet } = this.lib.aneka
3
- const { uniq, find, map } = this.lib._
4
- const props = schema.properties.filter(p => isSet(p.rel) && !(options.hidden ?? []).includes(p.name))
5
- // const props = schema.properties.filter(p => isSet(p.rel))
6
- options.rels = options.rels ?? []
7
- if (props.length > 0) {
8
- for (const prop of props) {
9
- for (const key in prop.rel) {
10
- if (!((typeof options.rels === 'string' && ['*', 'all'].includes(options.rels)) || options.rels.includes(key))) continue
11
- const val = prop.rel[key]
12
- if (val.fields.length === 0) continue
13
- if (val.type !== 'one-to-one') continue
14
- const relschema = this.getSchema(val.schema)
15
- const matches = uniq(map(records, r => {
16
- let v = r[prop.name]
17
- if (val.propName === 'id') {
18
- const idField = find(relschema.properties, { name: 'id' })
19
- if (idField.type === 'integer') v = parseInt(v)
20
- }
21
- return v
22
- }))
23
- const query = {}
24
- query[val.propName] = { $in: matches }
25
- const relFilter = { query, limit: matches.length }
26
- const relOptions = { dataOnly: true, rels: [] }
27
- const results = await this.recordFind(relschema.name, relFilter, relOptions)
28
- const fields = [...val.fields]
29
- if (!fields.includes(prop.name)) fields.push(prop.name)
30
- for (const i in records) {
31
- records[i]._rel = records[i]._rel ?? {}
32
- const rec = records[i]
33
- const res = results.find(r => (r[val.propName] + '') === rec[prop.name] + '')
34
- if (res) records[i]._rel[key] = await this.pickRecord({ record: res, fields, schema: relschema })
35
- else records[i]._rel[key] = {}
36
- }
37
- }
38
- }
39
- }
40
- }
41
-
42
- export default multiRelRows
@@ -1,16 +0,0 @@
1
- async function resolveMethod (name, method, options = {}) {
2
- const { importModule } = this.app.bajo
3
- const { fs } = this.lib
4
- const { camelCase } = this.lib._
5
- const { schema, driver, connection } = this.getInfo(name)
6
- const [group, action] = method.split('-')
7
- if (!options.force && (schema.disabled ?? []).includes(action)) throw this.error('methodIsDisabled%s%s', camelCase(method), name)
8
- let file
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}/extend/${this.name}/method/${group}/${action}.js`
11
- if (!fs.existsSync(file)) throw this.error('methodUnsupported%s%s', camelCase(method), name)
12
- const handler = await importModule(file)
13
- return { handler, schema, driver, connection }
14
- }
15
-
16
- export default resolveMethod