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
package/index.js CHANGED
@@ -1,22 +1,153 @@
1
1
  import collectConnections from './lib/collect-connections.js'
2
2
  import collectDrivers from './lib/collect-drivers.js'
3
- import collectFeature from './lib/collect-feature.js'
3
+ import collectFeatures from './lib/collect-features.js'
4
4
  import collectSchemas from './lib/collect-schemas.js'
5
5
  import memDbStart from './lib/mem-db/start.js'
6
6
  import memDbInstantiate from './lib/mem-db/instantiate.js'
7
7
  import nql from '@tryghost/nql'
8
8
  import path from 'path'
9
9
 
10
+ /**
11
+ * @typedef {string} TRecordSortKey
12
+ */
13
+
14
+ /**
15
+ * Key value pairs used as sort information:
16
+ * - Key represent model's field name
17
+ * - value represent its sort order: ```1``` for ascending order, and ```-1``` for descending order
18
+ *
19
+ * Example: to sort by firstName (ascending) and lastName (descending)
20
+ * ```javascript
21
+ * const sort = {
22
+ * firstName: 1,
23
+ * lastName: -1
24
+ * }
25
+ * ```
26
+ *
27
+ * @typedef {Object.<string, TRecordSortKey>} TRecordSort
28
+ */
29
+
30
+ /**
31
+ * @typedef {Object} TRecordPagination
32
+ * @property {number} limit - Number of records per page
33
+ * @property {number} page - Page number
34
+ * @property {number} skip - Records to skip
35
+ * @property {TRecordSort} sort - Sort order
36
+ */
37
+
38
+ /**
39
+ * @typedef {Object} TPropType
40
+ * @property {Object} integer
41
+ * @property {string} [integer.validator=number]
42
+ * @property {Object} smallint
43
+ * @property {string} [smallint.validator=number]
44
+ * @property {Object} text
45
+ * @property {string} [text.validator=string]
46
+ * @property {string} [text.textType=string]
47
+ * @property {string[]} [text.values=['text', 'mediumtext', 'longtext']]
48
+ * @property {Object} string
49
+ * @property {string} [string.validator=string]
50
+ * @property {maxLength} [string.maxLength=255]
51
+ * @property {minLength} [string.minLength=0]
52
+ * @property {Object} float
53
+ * @property {string} [float.validator=number]
54
+ * @property {Object} double
55
+ * @property {string} [double.validator=number]
56
+ * @property {Object} boolean
57
+ * @property {string} [boolean.validator=boolean]
58
+ * @property {Object} datetime
59
+ * @property {string} [datetime.validator=date]
60
+ * @property {Object} date
61
+ * @property {string} [date.validator=date]
62
+ * @property {Object} time
63
+ * @property {string} [time.validator=date]
64
+ * @property {Object} timestamp
65
+ * @property {string} [timestamp.validator=timestamp]
66
+ * @property {Object} object={}
67
+ * @property {Object} array={}
68
+ */
69
+ const propType = {
70
+ integer: {
71
+ validator: 'number'
72
+ },
73
+ smallint: {
74
+ validator: 'number'
75
+ },
76
+ text: {
77
+ validator: 'string',
78
+ textType: 'text',
79
+ values: ['text', 'mediumtext', 'longtext']
80
+ },
81
+ string: {
82
+ validator: 'string',
83
+ maxLength: 255,
84
+ minLength: 0
85
+ },
86
+ float: {
87
+ validator: 'number'
88
+ },
89
+ double: {
90
+ validator: 'number'
91
+ },
92
+ boolean: {
93
+ validator: 'boolean'
94
+ },
95
+ date: {
96
+ validator: 'date'
97
+ },
98
+ datetime: {
99
+ validator: 'date'
100
+ },
101
+ time: {
102
+ validator: 'date'
103
+ },
104
+ timestamp: {
105
+ validator: 'timestamp'
106
+ },
107
+ object: {},
108
+ array: {}
109
+ }
110
+
111
+ /**
112
+ * Plugin factory
113
+ *
114
+ * @param {string} pkgName - NPM package name
115
+ * @returns {class}
116
+ */
10
117
  async function factory (pkgName) {
11
118
  const me = this
12
119
 
13
- return class Dobo extends this.lib.BajoPlugin {
120
+ /**
121
+ * Dobo Database Framework for {@link https://github.com/ardhi/bajo|Bajo}.
122
+ *
123
+ * See {@tutorial ecosystem} for available drivers & tools
124
+ *
125
+ * @class
126
+ */
127
+ class Dobo extends this.app.pluginClass.base {
128
+ /**
129
+ * @constant {string}
130
+ * @memberof Dobo
131
+ * @default 'db'
132
+ */
133
+ static alias = 'db'
134
+
135
+ /**
136
+ * @constant {string[]}
137
+ * @memberof Dobo
138
+ * @default ['count', 'avg', 'min', 'max', 'sum']
139
+ */
140
+ static aggregateTypes = ['count', 'avg', 'min', 'max', 'sum']
141
+ /**
142
+ * @constant {TPropType}
143
+ * @memberof Dobo
144
+ */
145
+ static propType = propType
146
+
14
147
  constructor () {
15
148
  super(pkgName, me.app)
16
- this.alias = 'db'
17
149
  this.config = {
18
150
  connections: [],
19
- mergeProps: ['connections'],
20
151
  validationParams: {
21
152
  abortEarly: false,
22
153
  convert: false,
@@ -25,7 +156,7 @@ async function factory (pkgName) {
25
156
  default: {
26
157
  property: {
27
158
  text: {
28
- kind: 'text'
159
+ textType: 'text'
29
160
  },
30
161
  string: {
31
162
  length: 50
@@ -47,59 +178,49 @@ async function factory (pkgName) {
47
178
  memDb: {
48
179
  createDefConnAtStart: true,
49
180
  persistence: {
50
- syncPeriod: 1
181
+ syncPeriodDur: '1s'
51
182
  }
52
- }
53
- }
54
- this.aggregateTypes = ['count', 'avg', 'min', 'max', 'sum']
55
- this.propType = {
56
- integer: {
57
- validator: 'number'
58
- },
59
- smallint: {
60
- validator: 'number'
61
- },
62
- text: {
63
- validator: 'string',
64
- kind: 'text',
65
- choices: ['text', 'mediumtext', 'longtext']
66
- },
67
- string: {
68
- validator: 'string',
69
- maxLength: 255,
70
- minLength: 0
71
- },
72
- float: {
73
- validator: 'number'
74
183
  },
75
- double: {
76
- validator: 'number'
77
- },
78
- boolean: {
79
- validator: 'boolean'
80
- },
81
- date: {
82
- validator: 'date'
83
- },
84
- datetime: {
85
- validator: 'date'
86
- },
87
- time: {
88
- validator: 'date'
89
- },
90
- timestamp: {
91
- validator: 'timestamp'
92
- },
93
- object: {},
94
- array: {}
184
+ applet: {
185
+ confirmation: false
186
+ }
95
187
  }
188
+
189
+ /**
190
+ * @type {Object[]}
191
+ */
192
+ this.drivers = []
193
+
194
+ /**
195
+ * @type {Object[]}
196
+ */
197
+ this.connections = []
198
+
199
+ /**
200
+ * @type {Object[]}
201
+ */
202
+ this.features = []
203
+
204
+ /**
205
+ * @type {Object[]}
206
+ */
207
+ this.schemas = []
96
208
  }
97
209
 
210
+ /**
211
+ * Initialize plugin and performing the following tasks:
212
+ * - {@link module:Lib.collectDrivers|Collecting all drivers}
213
+ * - {@link module:Lib.collectConnections|Collecting all connections}
214
+ * - {@link module:Lib.collectFeatures|Collecting all features}
215
+ * - {@link module:Lib.collectSchemas|Collecting all schemas}
216
+ * @method
217
+ * @async
218
+ */
98
219
  init = async () => {
99
220
  const { buildCollections } = this.app.bajo
100
- const { fs } = this.lib
221
+ const { fs } = this.app.lib
101
222
  const checkType = async (item, items) => {
102
- const { filter } = this.lib._
223
+ const { filter } = this.app.lib._
103
224
  const existing = filter(items, { type: 'dobo:memory' })
104
225
  if (existing.length > 1) this.fatal('onlyOneConnType%s', item.type)
105
226
  }
@@ -112,31 +233,52 @@ async function factory (pkgName) {
112
233
  name: 'memory'
113
234
  })
114
235
  }
115
- this.connections = await buildCollections({ ns: this.name, container: 'connections', handler: collectConnections, dupChecks: ['name', checkType] })
116
- if (this.connections.length === 0) this.log.warn('notFound%s', this.print.write('connection'))
117
- await collectFeature.call(this)
236
+ this.connections = await buildCollections({ ns: this.ns, container: 'connections', handler: collectConnections, dupChecks: ['name', checkType] })
237
+ if (this.connections.length === 0) this.log.warn('notFound%s', this.t('connection'))
238
+ await collectFeatures.call(this)
118
239
  await collectSchemas.call(this)
119
240
  }
120
241
 
242
+ /**
243
+ * Start plugin
244
+ *
245
+ * @method
246
+ * @async
247
+ * @param {(string|Array)} [conns=all] - Which connections should be run on start
248
+ * @param {boolean} [noRebuild=false] - Set ```true``` to ALWAYS rebuild model on start. Yes, only set it to ```true``` if you REALLY know what you're doing!!!
249
+ */
121
250
  start = async (conns = 'all', noRebuild = true) => {
122
251
  const { importModule, breakNsPath } = this.app.bajo
123
- const { find, filter, isString, map } = this.lib._
252
+ const { find, filter, isString, map } = this.app.lib._
124
253
  if (conns === 'all') conns = this.connections
125
254
  else if (isString(conns)) conns = filter(this.connections, { name: conns })
126
255
  else conns = map(conns, c => find(this.connections, { name: c }))
127
256
  for (const c of conns) {
128
257
  const { ns } = breakNsPath(c.type)
129
258
  const schemas = filter(this.schemas, { connection: c.name })
130
- const mod = c.type === 'dobo:memory' ? memDbInstantiate : await importModule(`${ns}:/${this.name}/boot/instantiate.js`)
259
+ const mod = c.type === 'dobo:memory' ? memDbInstantiate : await importModule(`${ns}:/extend/${this.ns}/boot/instantiate.js`)
131
260
  await mod.call(this.app[ns], { connection: c, noRebuild, schemas })
132
261
  this.log.trace('driverInstantiated%s%s', c.driver, c.name)
133
262
  }
134
263
  await memDbStart.call(this)
135
264
  }
136
265
 
266
+ /**
267
+ * Pick only fields defined from a record
268
+ *
269
+ * @method
270
+ * @async
271
+ * @param {Object} [options={}] - Options object
272
+ * @param {Object} options.record - Record to pick fields from
273
+ * @param {Array} options.fields - Array of field names to be picked
274
+ * @param {Object} options.schema - Associated record's schema
275
+ * @param {Object} [options.hidden=[]] - Additional fields to be hidden in addition the one defined in schema
276
+ * @param {boolean} [options.forceNoHidden] - Force ALL fields to be picked, thus ignoring hidden fields
277
+ * @returns {Object}
278
+ */
137
279
  pickRecord = async ({ record, fields, schema = {}, hidden = [], forceNoHidden } = {}) => {
138
- const { isArray, pick, clone, isEmpty, omit } = this.lib._
139
- const { dayjs } = this.lib
280
+ const { isArray, pick, clone, isEmpty, omit } = this.app.lib._
281
+ const { dayjs } = this.app.lib
140
282
 
141
283
  const transform = async ({ record, schema, hidden = [], forceNoHidden } = {}) => {
142
284
  if (record._id) {
@@ -170,6 +312,20 @@ async function factory (pkgName) {
170
312
  return pick(await transform.call(this, { record, schema, hidden, forceNoHidden }), fl)
171
313
  }
172
314
 
315
+ /**
316
+ * Prepare records pagination:
317
+ * - making sure records limit is obeyed
318
+ * - making sure page is a positive value
319
+ * - if skip is given, recalculate limit to use skip instead of page number
320
+ * - Build sort info
321
+ *
322
+ * @method
323
+ * @async
324
+ * @param {Object} [filter={}] - Filter object
325
+ * @param {Object} schema - Model's schema
326
+ * @param {Object} options - Options
327
+ * @returns {TRecordPagination}
328
+ */
173
329
  prepPagination = async (filter = {}, schema, options = {}) => {
174
330
  const buildPageSkipLimit = (filter) => {
175
331
  let limit = parseInt(filter.limit) || this.config.default.filter.limit
@@ -188,7 +344,7 @@ async function factory (pkgName) {
188
344
  }
189
345
 
190
346
  const buildSort = (input, schema, allowSortUnindexed) => {
191
- const { isEmpty, map, each, isPlainObject, isString, trim, keys } = this.lib._
347
+ const { isEmpty, map, each, isPlainObject, isString, trim, keys } = this.app.lib._
192
348
  let sort
193
349
  if (schema && isEmpty(input)) {
194
350
  const columns = map(schema.properties, 'name')
@@ -233,7 +389,7 @@ async function factory (pkgName) {
233
389
  }
234
390
 
235
391
  buildMatch = ({ input = '', schema, options }) => {
236
- const { isPlainObject, trim } = this.lib._
392
+ const { isPlainObject, trim } = this.app.lib._
237
393
  if (isPlainObject(input)) return input
238
394
  const split = (value, schema) => {
239
395
  let [field, val] = value.split(':').map(i => i.trim())
@@ -266,7 +422,7 @@ async function factory (pkgName) {
266
422
  }
267
423
 
268
424
  buildQuery = ({ filter, schema, options = {} } = {}) => {
269
- const { trim, find, isString, isPlainObject } = this.lib._
425
+ const { trim, find, isString, isPlainObject } = this.app.lib._
270
426
  let query = {}
271
427
  if (isString(filter.query)) {
272
428
  try {
@@ -295,9 +451,9 @@ async function factory (pkgName) {
295
451
  }
296
452
 
297
453
  sanitizeQuery = (query, schema, parent) => {
298
- const { cloneDeep, isPlainObject, isArray, find } = this.lib._
299
- const { isSet } = this.lib.aneka
300
- const { dayjs } = this.lib
454
+ const { cloneDeep, isPlainObject, isArray, find } = this.app.lib._
455
+ const { isSet } = this.app.lib.aneka
456
+ const { dayjs } = this.app.lib
301
457
  const obj = cloneDeep(query)
302
458
  const keys = Object.keys(obj)
303
459
  const sanitize = (key, val, p) => {
@@ -336,13 +492,13 @@ async function factory (pkgName) {
336
492
  }
337
493
 
338
494
  getConnection = (name) => {
339
- const { find } = this.lib._
495
+ const { find } = this.app.lib._
340
496
  return find(this.connections, { name })
341
497
  }
342
498
 
343
499
  getInfo = (name) => {
344
500
  const { breakNsPath } = this.app.bajo
345
- const { find, map, isEmpty } = this.lib._
501
+ const { find, map, isEmpty } = this.app.lib._
346
502
  const schema = this.getSchema(name)
347
503
  const conn = this.getConnection(schema.connection)
348
504
  let { ns, path: type } = breakNsPath(conn.type)
@@ -355,8 +511,8 @@ async function factory (pkgName) {
355
511
  }
356
512
 
357
513
  getSchema = (input, cloned = true) => {
358
- const { find, isPlainObject, cloneDeep } = this.lib._
359
- const { pascalCase } = this.lib.aneka
514
+ const { find, isPlainObject, cloneDeep } = this.app.lib._
515
+ const { pascalCase } = this.app.lib.aneka
360
516
  let name = isPlainObject(input) ? input.name : input
361
517
  name = pascalCase(name)
362
518
  const schema = find(this.schemas, { name })
@@ -366,7 +522,7 @@ async function factory (pkgName) {
366
522
 
367
523
  getField = (name, model) => {
368
524
  const { getInfo } = this.app.dobo
369
- const { find } = this.lib._
525
+ const { find } = this.app.lib._
370
526
  const { schema } = getInfo(model)
371
527
 
372
528
  return find(schema.properties, { name })
@@ -377,18 +533,18 @@ async function factory (pkgName) {
377
533
  }
378
534
 
379
535
  getMemdbStorage = (name, fields = []) => {
380
- const { map, pick } = this.lib._
536
+ const { map, pick } = this.app.lib._
381
537
  const all = this.memDb.storage[name] ?? []
382
538
  if (fields.length === 0) return all
383
539
  return map(all, item => pick(item, fields))
384
540
  }
385
541
 
386
542
  listAttachments = async ({ model, id = '*', field = '*', file = '*' } = {}, { uriEncoded = true } = {}) => {
387
- const { map, kebabCase } = this.lib._
388
- const { pascalCase } = this.lib.aneka
543
+ const { map, kebabCase } = this.app.lib._
544
+ const { pascalCase } = this.app.lib.aneka
389
545
  const { importPkg, getPluginDataDir } = this.app.bajo
390
546
  const mime = await importPkg('waibu:mime')
391
- const { fastGlob } = this.lib
547
+ const { fastGlob } = this.app.lib
392
548
  const root = `${getPluginDataDir('dobo')}/attachment`
393
549
  model = pascalCase(model)
394
550
  let pattern = `${root}/${model}/${id}/${field}/${file}`
@@ -412,6 +568,8 @@ async function factory (pkgName) {
412
568
  })
413
569
  }
414
570
  }
571
+
572
+ return Dobo
415
573
  }
416
574
 
417
575
  export default factory
@@ -2,8 +2,8 @@ import path from 'path'
2
2
 
3
3
  async function addFixture (name, { spinner } = {}) {
4
4
  const { resolvePath, readConfig, eachPlugins, getPluginDataDir } = this.app.bajo
5
- const { isEmpty, isArray, isString } = this.lib._
6
- const { fs } = this.lib
5
+ const { isEmpty, isArray, isString } = this.app.lib._
6
+ const { fs } = this.app.lib
7
7
  const { schema, connection } = this.getInfo(name)
8
8
  if (connection.proxy) {
9
9
  this.log.warn('proxiedConnBound%s', schema.name)
@@ -16,12 +16,13 @@ async function addFixture (name, { spinner } = {}) {
16
16
  let items = await readConfig(pattern, { ns: schema.ns, ignoreError: true })
17
17
  if (isEmpty(items)) items = []
18
18
  // override
19
- const overrides = await readConfig(`${this.app.main.dir.pkg}/dobo/override/${schema.ns}/fixture/${base}.*`, { ns: this.name, ignoreError: true })
19
+ const overrides = await readConfig(`${this.app.main.dir.pkg}/extend/dobo/override/${schema.ns}/fixture/${base}.*`, { ns: this.ns, ignoreError: true })
20
20
 
21
21
  if (isArray(overrides) && !isEmpty(overrides)) items = overrides
22
22
  // extend
23
- await eachPlugins(async function ({ dir, ns }) {
24
- const extend = await readConfig(`${dir}/dobo/extend/${schema.ns}/fixture/${base}.*`, { ns, ignoreError: true })
23
+ await eachPlugins(async function ({ dir }) {
24
+ const { ns } = this
25
+ const extend = await readConfig(`${dir}/extend/dobo/extend/${schema.ns}/fixture/${base}.*`, { ns, ignoreError: true })
25
26
  if (isArray(extend) && !isEmpty(extend)) items.push(...extend)
26
27
  })
27
28
  if (isEmpty(items)) return result
@@ -56,7 +57,7 @@ async function addFixture (name, { spinner } = {}) {
56
57
  } catch (err) {
57
58
  console.log(err)
58
59
  err.model = schema.name
59
- if (this.app.bajo.applet) this.print.fail(this.validationErrorMessage(err))
60
+ if (this.app.applet) this.print.fail(this.validationErrorMessage(err))
60
61
  result.failed++
61
62
  }
62
63
  }
@@ -1,9 +1,9 @@
1
1
  async function buildBulkAction (name, action, options = {}) {
2
2
  const { fs, importModule } = this.app.bajo
3
- const { camelCase } = this.lib._
3
+ const { camelCase } = this.app.lib._
4
4
  const { schema, driver, connection } = await this.getInfo(name)
5
5
  if (!options.force && (schema.disabled ?? []).includes(action)) throw this.error('methodIsDisabled%s%s', camelCase('bulk ' + action), name)
6
- const file = `${driver.plugin}:/${this.name}/method/bulk/${action}.js`
6
+ const file = `${driver.plugin}:/extend/${this.ns}/method/bulk/${action}.js`
7
7
  if (!fs.existsSync(file)) throw this.error('methodUnsupported%s%s', camelCase('bulk ' + action), name)
8
8
  const handler = await importModule(file)
9
9
  return { handler, schema, driver, connection }
@@ -1,6 +1,6 @@
1
1
  async function checkUnique ({ schema, body, id }) {
2
- const { isSet } = this.lib.aneka
3
- const { filter, map, set } = this.lib._
2
+ const { isSet } = this.app.lib.aneka
3
+ const { filter, map, set } = this.app.lib._
4
4
  const singles = map(filter(schema.properties, p => (p.index ?? {}).type === 'unique'), 'name')
5
5
  const opts = { noHook: true, noCache: true, thrownNotFound: false, forceNoHidden: true }
6
6
  let old = {}
@@ -2,18 +2,29 @@ async function defSanitizer (item) {
2
2
  return item
3
3
  }
4
4
 
5
- async function collectConnections ({ item, index, options }) {
5
+ /**
6
+ * Collect all database connections from {@tutorial config}.
7
+ *
8
+ * @name collectConnections
9
+ * @memberof module:Lib
10
+ * @async
11
+ * @see Dobo#init
12
+ * @param {Object} [options={}]
13
+ * @param {Object} [options.item={}]
14
+ * @returns {Object}
15
+ */
16
+ async function collectConnections ({ item }) {
6
17
  const conn = item
7
18
  const { importModule, breakNsPath } = this.app.bajo
8
- const { has, find, isEmpty } = this.lib._
19
+ const { has, find, isEmpty } = this.app.lib._
9
20
  if (!has(conn, 'type')) this.fatal('mustValidDbType')
10
21
  let { ns, path: type } = breakNsPath(conn.type)
11
22
  if (isEmpty(type)) type = conn.type
12
23
  const driver = find(this.drivers, { ns, type })
13
24
  if (!driver) this.fatal('unsupportedDbType%s', conn.type)
14
- let file = `${ns}:/${this.name}/lib/${type}/conn-sanitizer.js`
25
+ let file = `${ns}:/extend/${this.ns}/lib/${type}/conn-sanitizer.js`
15
26
  if (conn.type === 'dobo:memory') file = `${ns}:/lib/mem-db/conn-sanitizer.js`
16
- if (driver.provider) file = `${driver.provider}:/${ns}/lib/${type}/conn-sanitizer.js`
27
+ if (driver.provider) file = `${driver.provider}:/extend/${ns}/lib/${type}/conn-sanitizer.js`
17
28
  let sanitizer = await importModule(file)
18
29
  if (!sanitizer) sanitizer = defSanitizer
19
30
  const result = await sanitizer.call(this, conn)
@@ -1,18 +1,27 @@
1
+ /**
2
+ * Collect all database drivers from loaded plugins
3
+ *
4
+ * @name collectDrivers
5
+ * @memberof module:Lib
6
+ * @async
7
+ * @see Dobo#init
8
+ */
1
9
  async function collectDrivers () {
2
10
  const { eachPlugins, readConfig, runHook } = this.app.bajo
3
- const { isString, find, pick, merge, cloneDeep } = this.lib._
11
+ const { isString, find, pick, merge, cloneDeep } = this.app.lib._
4
12
  const me = this
5
13
  me.drivers = []
6
14
  // built-in memory driver
7
15
  me.drivers.push({
8
16
  type: 'memory',
9
- ns: me.name,
17
+ ns: me.ns,
10
18
  driver: 'memory',
11
19
  idField: merge(cloneDeep(me.config.default.idField), { name: 'id' })
12
20
  })
13
21
  // others
14
- await runHook(`${this.name}:beforeCollectDrivers`)
15
- await eachPlugins(async function ({ file, ns }) {
22
+ await runHook(`${this.ns}:beforeCollectDrivers`)
23
+ await eachPlugins(async function ({ file }) {
24
+ const { ns } = this
16
25
  const info = await readConfig(file, { ns })
17
26
  if (!info.type) this.fatal('driverMustProvideDbType')
18
27
  if (!info.driver) this.fatal('driverMustHaveName')
@@ -33,8 +42,8 @@ async function collectDrivers () {
33
42
  }
34
43
  me.drivers.push(merge(ext, driver))
35
44
  }
36
- }, { glob: 'boot/driver.*', prefix: this.name })
37
- await runHook(`${this.name}:afterCollectDrivers`)
45
+ }, { glob: 'boot/driver.*', prefix: this.ns })
46
+ await runHook(`${this.ns}:afterCollectDrivers`)
38
47
  }
39
48
 
40
49
  export default collectDrivers
@@ -1,23 +1,32 @@
1
1
  import path from 'path'
2
2
 
3
- async function handler ({ file, alias, ns }) {
3
+ async function handler ({ file }) {
4
+ const { ns } = this
4
5
  const { importModule } = this.app.bajo
5
- const { camelCase, isFunction } = this.lib._
6
+ const { camelCase, isFunction } = this.app.lib._
6
7
  const me = this.app.dobo
7
8
 
8
9
  let name = camelCase(path.basename(file, '.js'))
9
- if (ns !== me.name) name = `${ns}.${name}`
10
+ if (ns !== me.ns) name = `${ns}.${name}`
10
11
  const mod = await importModule(file)
11
12
  if (!isFunction(mod)) this.fatal('featureNotAsync%s', name)
12
13
  me.feature[name] = mod
13
14
  me.log.trace('- %s', name)
14
15
  }
15
16
 
17
+ /**
18
+ * Collect all database features from all loaded plugins
19
+ *
20
+ * @name collectFeatures
21
+ * @memberof module:Lib
22
+ * @async
23
+ * @see Dobo#init
24
+ */
16
25
  async function collectFeature () {
17
26
  const { eachPlugins } = this.app.bajo
18
27
  this.feature = {}
19
28
  this.log.trace('loadingDbFeature')
20
- await eachPlugins(handler, { glob: 'feature/*.js', prefix: this.name })
29
+ await eachPlugins(handler, { glob: 'feature/*.js', prefix: this.ns })
21
30
  this.log.debug('totalLoadedFeatures%d', Object.keys(this.feature).length)
22
31
  }
23
32