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.
- package/.github/FUNDING.yml +13 -0
- package/.github/workflows/repo-lockdown.yml +24 -0
- package/.jsdoc.conf.json +45 -0
- package/LICENSE +1 -1
- package/README.md +38 -19
- package/docs/Dobo.html +26 -0
- package/docs/data/search.json +1 -0
- package/docs/fonts/Inconsolata-Regular.ttf +0 -0
- package/docs/fonts/OpenSans-Regular.ttf +0 -0
- package/docs/fonts/WorkSans-Bold.ttf +0 -0
- package/docs/global.html +7 -0
- package/docs/index.html +3 -0
- package/docs/index.js.html +578 -0
- package/docs/lib_collect-connections.js.html +39 -0
- package/docs/lib_collect-drivers.js.html +52 -0
- package/docs/lib_collect-features.js.html +36 -0
- package/docs/lib_collect-schemas.js.html +94 -0
- package/docs/lib_index.js.html +6 -0
- package/docs/method_model_create.js.html +35 -0
- package/docs/method_model_drop.js.html +34 -0
- package/docs/method_model_exists.js.html +40 -0
- package/docs/method_record_count.js.html +69 -0
- package/docs/method_record_create.js.html +114 -0
- package/docs/method_record_find-all.js.html +44 -0
- package/docs/method_record_find-one.js.html +73 -0
- package/docs/method_record_find.js.html +118 -0
- package/docs/method_record_get.js.html +92 -0
- package/docs/method_record_remove.js.html +75 -0
- package/docs/method_record_update.js.html +107 -0
- package/docs/method_record_upsert.js.html +54 -0
- package/docs/method_sanitize_body.js.html +88 -0
- package/docs/method_sanitize_date.js.html +30 -0
- package/docs/method_sanitize_id.js.html +20 -0
- package/docs/method_validate.js.html +249 -0
- package/docs/module-Lib.html +3 -0
- package/docs/scripts/core.js +726 -0
- package/docs/scripts/core.min.js +23 -0
- package/docs/scripts/resize.js +90 -0
- package/docs/scripts/search.js +265 -0
- package/docs/scripts/search.min.js +6 -0
- package/docs/scripts/third-party/Apache-License-2.0.txt +202 -0
- package/docs/scripts/third-party/fuse.js +9 -0
- package/docs/scripts/third-party/hljs-line-num-original.js +369 -0
- package/docs/scripts/third-party/hljs-line-num.js +1 -0
- package/docs/scripts/third-party/hljs-original.js +5171 -0
- package/docs/scripts/third-party/hljs.js +1 -0
- package/docs/scripts/third-party/popper.js +5 -0
- package/docs/scripts/third-party/tippy.js +1 -0
- package/docs/scripts/third-party/tocbot.js +672 -0
- package/docs/scripts/third-party/tocbot.min.js +1 -0
- package/docs/static/bitcoin.jpeg +0 -0
- package/docs/static/home.md +25 -0
- package/docs/static/logo-ecosystem.png +0 -0
- package/docs/static/logo.png +0 -0
- package/docs/styles/clean-jsdoc-theme-base.css +1159 -0
- package/docs/styles/clean-jsdoc-theme-dark.css +412 -0
- package/docs/styles/clean-jsdoc-theme-light.css +482 -0
- package/docs/styles/clean-jsdoc-theme-scrollbar.css +30 -0
- package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
- package/docs/styles/clean-jsdoc-theme.min.css +1 -0
- package/{bajo → extend/bajo}/intl/en-US.json +3 -2
- package/{bajo → extend/bajo}/intl/id.json +3 -2
- package/{bajoCli → extend/bajoCli}/applet/connection.js +5 -5
- package/extend/bajoCli/applet/lib/post-process.js +53 -0
- package/extend/bajoCli/applet/model-clear.js +11 -0
- package/{bajoCli → extend/bajoCli}/applet/model-rebuild.js +13 -13
- package/{bajoCli → extend/bajoCli}/applet/record-create.js +10 -8
- package/{bajoCli → extend/bajoCli}/applet/record-find.js +6 -5
- package/{bajoCli → extend/bajoCli}/applet/record-get.js +5 -5
- package/{bajoCli → extend/bajoCli}/applet/record-remove.js +5 -5
- package/{bajoCli → extend/bajoCli}/applet/record-update.js +9 -9
- package/{bajoCli → extend/bajoCli}/applet/schema.js +4 -4
- package/{bajoCli → extend/bajoCli}/applet/stat-count.js +4 -4
- package/{dobo → extend/dobo}/feature/created-at.js +1 -1
- package/{dobo → extend/dobo}/feature/removed-at.js +3 -3
- package/{dobo → extend/dobo}/feature/updated-at.js +2 -2
- package/{waibuMpa → extend/waibuMpa}/route/attachment/@model/@id/@field/@file.js +3 -3
- package/index.js +230 -72
- package/lib/add-fixtures.js +7 -6
- package/lib/build-bulk-action.js +2 -2
- package/lib/check-unique.js +2 -2
- package/lib/collect-connections.js +15 -4
- package/lib/collect-drivers.js +15 -6
- package/lib/{collect-feature.js → collect-features.js} +13 -4
- package/lib/collect-schemas.js +22 -12
- package/lib/exec-feature-hook.js +1 -1
- package/lib/exec-validation.js +5 -5
- package/lib/generic-prop-sanitizer.js +6 -5
- package/lib/handle-attachment-upload.js +2 -2
- package/lib/index.js +3 -0
- package/lib/mem-db/conn-sanitizer.js +1 -1
- package/lib/mem-db/instantiate.js +4 -4
- package/lib/mem-db/method/record/find.js +1 -1
- package/lib/mem-db/method/record/get.js +1 -1
- package/lib/mem-db/method/record/remove.js +1 -1
- package/lib/mem-db/method/record/update.js +1 -1
- package/lib/mem-db/start.js +1 -1
- package/lib/merge-attachment-info.js +2 -2
- package/lib/multi-rel-rows.js +2 -2
- package/lib/resolve-method.js +3 -3
- package/lib/sanitize-schema.js +8 -7
- package/lib/single-rel-rows.js +2 -2
- package/{plugin-method → method}/attachment/copy-uploaded.js +2 -2
- package/{plugin-method → method}/attachment/create.js +3 -3
- package/{plugin-method → method}/attachment/find.js +2 -2
- package/{plugin-method → method}/attachment/get-path.js +3 -3
- package/{plugin-method → method}/attachment/get.js +1 -1
- package/{plugin-method → method}/attachment/pre-check.js +1 -1
- package/{plugin-method → method}/attachment/remove.js +1 -1
- package/{plugin-method → method}/bulk/create.js +6 -6
- package/{plugin-method → method}/model/clear.js +5 -5
- package/method/model/create.js +32 -0
- package/method/model/drop.js +31 -0
- package/method/model/exists.js +37 -0
- package/{plugin-method → method}/record/clear.js +5 -5
- package/{plugin-method → method}/record/count.js +27 -5
- package/{plugin-method → method}/record/create.js +46 -6
- package/{plugin-method → method}/record/find-all.js +16 -0
- package/{plugin-method → method}/record/find-one.js +20 -6
- package/method/record/find.js +115 -0
- package/method/record/get.js +89 -0
- package/method/record/remove.js +72 -0
- package/{plugin-method → method}/record/update.js +47 -6
- package/{plugin-method → method}/record/upsert.js +18 -2
- package/{plugin-method → method}/sanitize/body.js +18 -3
- package/method/sanitize/date.js +27 -0
- package/{plugin-method → method}/sanitize/id.js +10 -0
- package/{plugin-method → method}/stat/aggregate.js +4 -4
- package/{plugin-method → method}/stat/histogram.js +4 -4
- package/{plugin-method → method}/validate.js +96 -7
- package/package.json +41 -36
- package/wiki/APPLETS.md +57 -0
- package/wiki/CONFIG.md +25 -0
- package/wiki/CONTRIBUTING.md +5 -0
- package/wiki/DEV-GUIDE.md +1 -0
- package/wiki/ECOSYSTEM.md +20 -0
- package/wiki/GETTING-STARTED.md +166 -0
- package/wiki/USER-GUIDE.md +1 -0
- package/bajoCli/applet/lib/post-process.js +0 -47
- package/bajoCli/applet/model-clear.js +0 -11
- package/plugin-method/model/create.js +0 -19
- package/plugin-method/model/drop.js +0 -19
- package/plugin-method/model/exists.js +0 -24
- package/plugin-method/record/find.js +0 -52
- package/plugin-method/record/get.js +0 -47
- package/plugin-method/record/remove.js +0 -41
- package/plugin-method/sanitize/date.js +0 -14
- /package/{bajoCli → extend/bajoCli}/applet.js +0 -0
- /package/{dobo → extend/dobo}/feature/dt.js +0 -0
- /package/{dobo → extend/dobo}/feature/int-id.js +0 -0
- /package/{waibuStatic → extend/waibuStatic}/virtual.json +0 -0
- /package/{plugin-method → method}/attachment/update.js +0 -0
- /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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
76
|
-
|
|
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.
|
|
116
|
-
if (this.connections.length === 0) this.log.warn('notFound%s', this.
|
|
117
|
-
await
|
|
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}
|
|
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
|
package/lib/add-fixtures.js
CHANGED
|
@@ -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.
|
|
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
|
|
24
|
-
const
|
|
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.
|
|
60
|
+
if (this.app.applet) this.print.fail(this.validationErrorMessage(err))
|
|
60
61
|
result.failed++
|
|
61
62
|
}
|
|
62
63
|
}
|
package/lib/build-bulk-action.js
CHANGED
|
@@ -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}
|
|
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 }
|
package/lib/check-unique.js
CHANGED
|
@@ -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
|
-
|
|
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}
|
|
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}
|
|
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)
|
package/lib/collect-drivers.js
CHANGED
|
@@ -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.
|
|
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.
|
|
15
|
-
await eachPlugins(async function ({ file
|
|
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.
|
|
37
|
-
await runHook(`${this.
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|