dobo 1.0.0 → 1.0.2
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/README.md +23 -1
- package/bajo/config.json +27 -0
- package/bajo/hook/bajoI18N.db@before-resource-merge.js +10 -0
- package/bajo/hook/bajoI18N@before-init.js +6 -0
- package/bajo/init.js +18 -0
- package/bajo/method/aggregate-types.js +1 -0
- package/bajo/method/attachment/copy-uploaded.js +32 -0
- package/bajo/method/attachment/create.js +27 -0
- package/bajo/method/attachment/find.js +27 -0
- package/bajo/method/attachment/get-path.js +11 -0
- package/bajo/method/attachment/get.js +12 -0
- package/bajo/method/attachment/pre-check.js +8 -0
- package/bajo/method/attachment/remove.js +11 -0
- package/bajo/method/attachment/update.js +7 -0
- package/bajo/method/build-match.js +34 -0
- package/bajo/method/build-query.js +13 -0
- package/bajo/method/bulk/create.js +45 -0
- package/bajo/method/get-info.js +14 -0
- package/bajo/method/get-schema.js +10 -0
- package/bajo/method/model/clear.js +20 -0
- package/bajo/method/model/create.js +11 -0
- package/bajo/method/model/drop.js +11 -0
- package/bajo/method/model/exists.js +17 -0
- package/bajo/method/pick-record.js +30 -0
- package/bajo/method/prep-pagination.js +66 -0
- package/bajo/method/prop-type.js +43 -0
- package/bajo/method/record/clear.js +22 -0
- package/bajo/method/record/create.js +61 -0
- package/bajo/method/record/find-all.js +15 -0
- package/bajo/method/record/find-one.js +39 -0
- package/bajo/method/record/find.js +41 -0
- package/bajo/method/record/get.js +38 -0
- package/bajo/method/record/remove.js +34 -0
- package/bajo/method/record/update.js +60 -0
- package/bajo/method/record/upsert.js +19 -0
- package/bajo/method/sanitize/body.js +67 -0
- package/bajo/method/sanitize/date.js +14 -0
- package/bajo/method/sanitize/id.js +7 -0
- package/bajo/method/stat/aggregate.js +23 -0
- package/bajo/method/stat/histogram.js +26 -0
- package/bajo/method/validate.js +154 -0
- package/bajo/method/validation-error-message.js +12 -0
- package/bajo/start.js +16 -0
- package/bajoCli/applet/connection.js +22 -0
- package/bajoCli/applet/lib/post-process.js +47 -0
- package/bajoCli/applet/model-clear.js +11 -0
- package/bajoCli/applet/model-rebuild.js +77 -0
- package/bajoCli/applet/record-create.js +41 -0
- package/bajoCli/applet/record-find.js +27 -0
- package/bajoCli/applet/record-get.js +24 -0
- package/bajoCli/applet/record-remove.js +24 -0
- package/bajoCli/applet/record-update.js +47 -0
- package/bajoCli/applet/schema.js +22 -0
- package/bajoCli/applet/shell.js +48 -0
- package/bajoCli/applet/stat-count.js +24 -0
- package/bajoCli/applet.js +1 -0
- package/bajoI18N/resource/en-US.json +82 -0
- package/bajoI18N/resource/id.json +143 -0
- package/dobo/feature/created-at.js +18 -0
- package/dobo/feature/dt.js +13 -0
- package/dobo/feature/int-id.js +13 -0
- package/dobo/feature/updated-at.js +23 -0
- package/lib/add-fixtures.js +53 -0
- package/lib/build-bulk-action.js +12 -0
- package/lib/check-unique.js +39 -0
- package/lib/collect-connections.js +25 -0
- package/lib/collect-drivers.js +32 -0
- package/lib/collect-feature.js +23 -0
- package/lib/collect-schemas.js +77 -0
- package/lib/exec-feature-hook.js +12 -0
- package/lib/exec-validation.js +27 -0
- package/lib/generic-prop-sanitizer.js +38 -0
- package/lib/handle-attachment-upload.js +16 -0
- package/lib/merge-attachment-info.js +16 -0
- package/lib/multi-rel-rows.js +34 -0
- package/lib/resolve-method.js +15 -0
- package/lib/sanitize-schema.js +180 -0
- package/lib/single-rel-rows.js +32 -0
- package/package.json +2 -1
- package/waibuStatic/virtual.json +4 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import addFixtures from '../../lib/add-fixtures.js'
|
|
2
|
+
|
|
3
|
+
async function modelRebuild ({ path, args }) {
|
|
4
|
+
const { importPkg, outmatch } = this.app.bajo
|
|
5
|
+
const { isEmpty, map, trim } = this.app.bajo.lib._
|
|
6
|
+
const spinner = this.print.spinner
|
|
7
|
+
const [input, confirm, boxen] = await importPkg('bajoCli:@inquirer/input',
|
|
8
|
+
'bajoCli:@inquirer/confirm', 'bajoCli:boxen')
|
|
9
|
+
const schemas = map(this.schemas, 'name')
|
|
10
|
+
let names = args.join(' ')
|
|
11
|
+
if (isEmpty(schemas)) return this.print.fail('No schema found!', { exit: this.app.bajo.applet })
|
|
12
|
+
if (isEmpty(names)) {
|
|
13
|
+
names = await input({
|
|
14
|
+
message: this.print.write('Enter schema name(s), separated by space:'),
|
|
15
|
+
default: '*'
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
const isMatch = outmatch(map(names.split(' '), m => trim(m)))
|
|
19
|
+
names = schemas.filter(isMatch)
|
|
20
|
+
if (names.length === 0) return this.print.fail('No schema matched', true, { exit: this.app.bajo.applet })
|
|
21
|
+
names = names.sort()
|
|
22
|
+
console.log(boxen(names.join(' '), { title: this.print.write('Schema (%d)', names.length), padding: 0.5, borderStyle: 'round' }))
|
|
23
|
+
const answer = await confirm({
|
|
24
|
+
message: this.print.write('The above mentioned schema(s) will be rebuilt as model. Continue?'),
|
|
25
|
+
default: false
|
|
26
|
+
})
|
|
27
|
+
if (!answer) return this.print.fail('Aborted!', { exit: this.app.bajo.applet })
|
|
28
|
+
const conns = []
|
|
29
|
+
for (const s of names) {
|
|
30
|
+
const { connection } = this.getInfo(s)
|
|
31
|
+
if (!conns.includes(connection.name)) conns.push(connection.name)
|
|
32
|
+
}
|
|
33
|
+
await this.start(conns)
|
|
34
|
+
const result = { succed: 0, failed: 0, skipped: 0 }
|
|
35
|
+
for (const s of names) {
|
|
36
|
+
const { schema, instance, connection } = this.getInfo(s)
|
|
37
|
+
const spin = spinner({ showCounter: true }).start('Rebuilding \'%s\'...', schema.name)
|
|
38
|
+
if (!instance) {
|
|
39
|
+
spin.warn('Client instance not connected \'%s@%s\'. Skipped!', schema.connection, schema.name)
|
|
40
|
+
result.skipped++
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
const exists = await this.modelExists(schema, false, spinner)
|
|
44
|
+
if (exists) {
|
|
45
|
+
if (this.app.bajo.config.force) {
|
|
46
|
+
try {
|
|
47
|
+
await this.modelDrop(schema, spinner)
|
|
48
|
+
spin.setText('Model \'%s\' successfully dropped', schema.name)
|
|
49
|
+
} catch (err) {
|
|
50
|
+
spin.fail('Error on dropping model \'%s\': %s', schema.name, err.message)
|
|
51
|
+
result.failed++
|
|
52
|
+
continue
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
spin.fail('Model \'%s\' exists. Won\'t rebuild without --force', schema.name)
|
|
56
|
+
result.failed++
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
await this.modelCreate(schema, spinner)
|
|
62
|
+
if (connection.memory) spin.succeed('Model \'%s\' successfully created', schema.name)
|
|
63
|
+
else {
|
|
64
|
+
const fixture = await addFixtures.call(this, schema, spin)
|
|
65
|
+
spin.succeed('Model \'%s\' successfully created, with fixture: added %d, rejected: %s', schema.name, fixture.success, fixture.failed)
|
|
66
|
+
}
|
|
67
|
+
result.succed++
|
|
68
|
+
} catch (err) {
|
|
69
|
+
if (this.app.bajo.config.log.applet && this.app.bajo.config.log.level === 'trace') console.error(err)
|
|
70
|
+
spin.fail('Error on creating \'%s\': %s', schema.name, err.message)
|
|
71
|
+
result.failed++
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
this.print.info('Done! Succeded: %d, failed: %s, skipped: %d', result.succed, result.failed, result.skipped)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export default modelRebuild
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import postProcess from './lib/post-process.js'
|
|
2
|
+
|
|
3
|
+
async function createRecord ({ path, args, options }) {
|
|
4
|
+
const { importPkg } = this.app.bajo
|
|
5
|
+
const { isEmpty, map, isPlainObject } = this.app.bajo.lib._
|
|
6
|
+
const [input, select, boxen] = await importPkg('bajoCli:@inquirer/input',
|
|
7
|
+
'bajoCli:@inquirer/select', 'bajoCli:boxen')
|
|
8
|
+
if (isEmpty(this.schemas)) return this.print.fail('No schema found!', { exit: this.app.bajo.applet })
|
|
9
|
+
let [schema, body] = args
|
|
10
|
+
if (isEmpty(schema)) {
|
|
11
|
+
schema = await select({
|
|
12
|
+
message: this.print.write('Please select a schema:'),
|
|
13
|
+
choices: map(this.schemas, s => ({ value: s.name }))
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
if (isEmpty(body)) {
|
|
17
|
+
body = await input({
|
|
18
|
+
message: this.print.write('Enter JSON payload:'),
|
|
19
|
+
validate: text => {
|
|
20
|
+
if (isEmpty(text)) return this.print.write('Payload is required')
|
|
21
|
+
try {
|
|
22
|
+
const parsed = JSON.parse(text)
|
|
23
|
+
if (!isPlainObject(parsed)) throw new Error()
|
|
24
|
+
} catch (err) {
|
|
25
|
+
return this.print.write('Payload must be a valid JSON object')
|
|
26
|
+
}
|
|
27
|
+
return true
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
let payload
|
|
32
|
+
try {
|
|
33
|
+
payload = JSON.parse(body)
|
|
34
|
+
} catch (err) {
|
|
35
|
+
return this.print.fail('Invalid payload syntax', { exit: this.app.bajo.applet })
|
|
36
|
+
}
|
|
37
|
+
console.log(boxen(JSON.stringify(payload, null, 2), { title: schema, padding: 0.5, borderStyle: 'round' }))
|
|
38
|
+
await postProcess.call(this, { handler: 'recordCreate', params: [schema, payload], path, processMsg: 'Creating record', options })
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default createRecord
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import postProcess from './lib/post-process.js'
|
|
2
|
+
|
|
3
|
+
async function findRecord ({ path, args, options }) {
|
|
4
|
+
const { importPkg } = this.app.bajo
|
|
5
|
+
const { isEmpty, map, pick } = this.app.bajo.lib._
|
|
6
|
+
const [select, input] = await importPkg('bajoCli:@inquirer/select', 'bajoCli:@inquirer/input')
|
|
7
|
+
if (isEmpty(this.schemas)) return this.print.fail('No schema found!', { exit: this.app.bajo.applet })
|
|
8
|
+
let [schema, query] = args
|
|
9
|
+
if (isEmpty(schema)) {
|
|
10
|
+
schema = await select({
|
|
11
|
+
message: this.print.write('Please select a schema:'),
|
|
12
|
+
choices: map(this.schemas, s => ({ value: s.name }))
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
if (isEmpty(query)) {
|
|
16
|
+
query = await input({
|
|
17
|
+
message: this.print.write('Please enter a query (if any):')
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
if (isEmpty(query)) query = {}
|
|
21
|
+
const filter = pick(this.app.bajo.config, ['page', 'offset', 'pageSize', 'sort', 'limit'])
|
|
22
|
+
filter.pageSize = filter.pageSize ?? filter.limit
|
|
23
|
+
filter.query = query
|
|
24
|
+
await postProcess.call(this, { noConfirmation: true, handler: 'recordFind', params: [schema, filter], path, processMsg: 'Finding record(s)', options })
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default findRecord
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import postProcess from './lib/post-process.js'
|
|
2
|
+
|
|
3
|
+
async function getRecord ({ path, args, options }) {
|
|
4
|
+
const { importPkg } = this.app.bajo
|
|
5
|
+
const { isEmpty, map } = this.app.bajo.lib._
|
|
6
|
+
const [input, select] = await importPkg('bajoCli:@inquirer/input', 'bajoCli:@inquirer/select')
|
|
7
|
+
if (isEmpty(this.schemas)) return this.print.fail('No schema found!', { exit: this.app.bajo.applet })
|
|
8
|
+
let [schema, id] = args
|
|
9
|
+
if (isEmpty(schema)) {
|
|
10
|
+
schema = await select({
|
|
11
|
+
message: this.print.write('Please select a schema:'),
|
|
12
|
+
choices: map(this.schemas, s => ({ value: s.name }))
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
if (isEmpty(id)) {
|
|
16
|
+
id = await input({
|
|
17
|
+
message: this.print.write('Enter record ID:'),
|
|
18
|
+
validate: text => isEmpty(text) ? this.print.write('ID is required') : true
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
await postProcess.call(this, { noConfirmation: true, handler: 'recordGet', params: [schema, id], path, processMsg: 'Getting record', options })
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default getRecord
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import postProcess from './lib/post-process.js'
|
|
2
|
+
|
|
3
|
+
async function removeRecord ({ path, args, options }) {
|
|
4
|
+
const { importPkg } = this.app.bajo
|
|
5
|
+
const { isEmpty, map } = this.app.bajo.lib._
|
|
6
|
+
const [input, select] = await importPkg('bajoCli:@inquirer/input', 'bajoCli:@inquirer/select')
|
|
7
|
+
if (isEmpty(this.schemas)) return this.print.fail('No schema found!', { exit: this.app.bajo.applet })
|
|
8
|
+
let [schema, id] = args
|
|
9
|
+
if (isEmpty(schema)) {
|
|
10
|
+
schema = await select({
|
|
11
|
+
message: this.print.write('Please select a schema:'),
|
|
12
|
+
choices: map(this.schemas, s => ({ value: s.name }))
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
if (isEmpty(id)) {
|
|
16
|
+
id = await input({
|
|
17
|
+
message: this.print.write('Enter record ID:'),
|
|
18
|
+
validate: text => isEmpty(text) ? this.print.write('ID is required') : true
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
await postProcess.call(this, { handler: 'recordRemove', params: [schema, id], path, processMsg: 'Removing record', options })
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default removeRecord
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import postProcess from './lib/post-process.js'
|
|
2
|
+
|
|
3
|
+
async function updateRecord ({ path, args, options }) {
|
|
4
|
+
const { importPkg } = this.app.bajo
|
|
5
|
+
const { isEmpty, map, isPlainObject } = this.app.bajo.lib._
|
|
6
|
+
const [input, select, boxen] = await importPkg('bajoCli:@inquirer/input',
|
|
7
|
+
'bajoCli:@inquirer/select', 'bajoCli:boxen')
|
|
8
|
+
if (isEmpty(this.schemas)) return this.print.fail('No schema found!', { exit: this.app.bajo.applet })
|
|
9
|
+
let [schema, id, body] = args
|
|
10
|
+
if (isEmpty(schema)) {
|
|
11
|
+
schema = await select({
|
|
12
|
+
message: this.print.write('Please select a schema:'),
|
|
13
|
+
choices: map(this.schemas, s => ({ value: s.name }))
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
if (isEmpty(id)) {
|
|
17
|
+
id = await input({
|
|
18
|
+
message: this.print.write('Enter record ID:'),
|
|
19
|
+
validate: text => isEmpty(text) ? this.print.write('ID is required') : true
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
if (isEmpty(body)) {
|
|
23
|
+
body = await input({
|
|
24
|
+
message: this.print.write('Enter JSON payload:'),
|
|
25
|
+
validate: text => {
|
|
26
|
+
if (isEmpty(text)) return this.print.write('Payload is required')
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(text)
|
|
29
|
+
if (!isPlainObject(parsed)) throw new Error()
|
|
30
|
+
} catch (err) {
|
|
31
|
+
return this.print.write('Payload must be a valid JSON object')
|
|
32
|
+
}
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
let payload
|
|
38
|
+
try {
|
|
39
|
+
payload = JSON.parse(body)
|
|
40
|
+
} catch (err) {
|
|
41
|
+
return this.print.fail('Invalid payload syntax', { exit: this.app.bajo.applet })
|
|
42
|
+
}
|
|
43
|
+
console.log(boxen(JSON.stringify(payload, null, 2), { title: schema, padding: 0.5, borderStyle: 'round' }))
|
|
44
|
+
await postProcess.call(this, { handler: 'recordUpdate', params: [schema, id, payload], path, processMsg: 'Updating record', options })
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default updateRecord
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
async function schema ({ path, args }) {
|
|
2
|
+
const { importPkg } = this.app.bajo
|
|
3
|
+
const { isEmpty, map, find } = this.app.bajo.lib._
|
|
4
|
+
const { getOutputFormat, writeOutput } = this.app.bajoCli
|
|
5
|
+
const select = await importPkg('bajoCli:@inquirer/select')
|
|
6
|
+
const format = getOutputFormat()
|
|
7
|
+
if (isEmpty(this.schemas)) return this.print.fail('No schema found!', { exit: this.app.bajo.applet })
|
|
8
|
+
let name = args[0]
|
|
9
|
+
if (isEmpty(name)) {
|
|
10
|
+
const choices = map(this.schemas, s => ({ value: s.name }))
|
|
11
|
+
name = await select({
|
|
12
|
+
message: this.print.write('Please choose a schema:'),
|
|
13
|
+
choices
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
const result = find(this.schemas, { name })
|
|
17
|
+
if (!result) return this.print.fail('Can\'t find %s named \'%s\'', this.print.write('schema'), name, { exit: this.app.bajo.applet })
|
|
18
|
+
this.print.info('Done!')
|
|
19
|
+
await writeOutput(result, path, format)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default schema
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const mods = [
|
|
2
|
+
{ method: 'recordFind' },
|
|
3
|
+
{ method: 'recordGet' },
|
|
4
|
+
{ method: 'recordCreate' },
|
|
5
|
+
{ method: 'recordUpdate' },
|
|
6
|
+
{ method: 'recordRemove' },
|
|
7
|
+
'-',
|
|
8
|
+
{ method: 'modelRebuild' },
|
|
9
|
+
'-',
|
|
10
|
+
{ method: 'schema' },
|
|
11
|
+
{ method: 'connection' },
|
|
12
|
+
'-',
|
|
13
|
+
{ method: 'quit' },
|
|
14
|
+
'-'
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
async function shell ({ path, args, options }) {
|
|
18
|
+
const { importPkg, importModule, resolvePath, currentLoc } = this.app.bajo
|
|
19
|
+
const prompts = await importPkg('bajoCli:@inquirer/prompts')
|
|
20
|
+
const { map, find, repeat, kebabCase } = this.app.bajo.lib._
|
|
21
|
+
const { select, Separator, confirm } = prompts
|
|
22
|
+
const choices = map(mods, m => m === '-' ? new Separator() : ({ value: m.method }))
|
|
23
|
+
const dir = currentLoc(import.meta).dir
|
|
24
|
+
for (;;) {
|
|
25
|
+
const method = await select({
|
|
26
|
+
message: this.print.write('Select method:'),
|
|
27
|
+
choices
|
|
28
|
+
})
|
|
29
|
+
if (method === 'quit') {
|
|
30
|
+
const answer = await confirm({
|
|
31
|
+
message: this.print.write('Are you sure to quit?')
|
|
32
|
+
})
|
|
33
|
+
if (!answer) continue
|
|
34
|
+
this.print.info('Quitting now, have a nice day!')
|
|
35
|
+
process.kill(process.pid, 'SIGINT')
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
console.log(repeat('-', 80))
|
|
39
|
+
this.print.info('Running: %s', method)
|
|
40
|
+
const mod = find(mods, { method })
|
|
41
|
+
const file = `${dir}/${kebabCase(mod.method)}.js`
|
|
42
|
+
const instance = await importModule(resolvePath(file))
|
|
43
|
+
await instance.call(this, method, [])
|
|
44
|
+
console.log(repeat('-', 80))
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default shell
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import postProcess from './lib/post-process.js'
|
|
2
|
+
|
|
3
|
+
async function statCount ({ path, args, options }) {
|
|
4
|
+
const { importPkg } = this.app.bajo
|
|
5
|
+
const { isEmpty, map } = this.app.bajo.lib._
|
|
6
|
+
const [select, input] = await importPkg('bajoCli:@inquirer/select', 'bajoCli:@inquirer/input')
|
|
7
|
+
if (isEmpty(this.schemas)) return this.print.fail('No schema found!', { exit: this.app.bajo.applet })
|
|
8
|
+
let [schema, query] = args
|
|
9
|
+
if (isEmpty(schema)) {
|
|
10
|
+
schema = await select({
|
|
11
|
+
message: this.print.write('Please select a schema:'),
|
|
12
|
+
choices: map(this.schemas, s => ({ value: s.name }))
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
if (isEmpty(query)) {
|
|
16
|
+
query = await input({
|
|
17
|
+
message: this.print.write('Please enter a query (if any):')
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
const filter = { query }
|
|
21
|
+
await postProcess.call(this, { noConfirmation: true, handler: 'statCount', params: [schema, filter], path, processMsg: 'Counting record(s)', options })
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default statCount
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default 'default'
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"field": {
|
|
3
|
+
"id": "ID",
|
|
4
|
+
"name": "Name",
|
|
5
|
+
"dt": "Date/Time",
|
|
6
|
+
"createdAt": "Created At",
|
|
7
|
+
"updatedAt": "Updated At",
|
|
8
|
+
"title": "Title",
|
|
9
|
+
"description": "Description",
|
|
10
|
+
"subTitle": "Sub Title",
|
|
11
|
+
"plugin": "Plugin",
|
|
12
|
+
"author": "Author",
|
|
13
|
+
"dir": "Directory",
|
|
14
|
+
"file": "File",
|
|
15
|
+
"meta": "Meta Info",
|
|
16
|
+
"level": "Level",
|
|
17
|
+
"ref": "Reference",
|
|
18
|
+
"section": "Section",
|
|
19
|
+
"asset": "Asset",
|
|
20
|
+
"category": "Category",
|
|
21
|
+
"categoryId": "Category ID",
|
|
22
|
+
"username": "Username",
|
|
23
|
+
"password": "Password",
|
|
24
|
+
"password2": "Repeat Password",
|
|
25
|
+
"firstName": "First Name",
|
|
26
|
+
"lastName": "Last Name",
|
|
27
|
+
"address1": "Address 1",
|
|
28
|
+
"address2": "Address 2",
|
|
29
|
+
"city": "City Name",
|
|
30
|
+
"zipCode": "Zip Code",
|
|
31
|
+
"provinceState": "State",
|
|
32
|
+
"country": "Country",
|
|
33
|
+
"phone": "Phone",
|
|
34
|
+
"email": "Email",
|
|
35
|
+
"key": "Key",
|
|
36
|
+
"status": "Status",
|
|
37
|
+
"orgName": "Organization",
|
|
38
|
+
"picName": "PIC Name",
|
|
39
|
+
"picRole": "PIC Role",
|
|
40
|
+
"picPhone": "PIC Phone",
|
|
41
|
+
"picEmail": "PIC Email",
|
|
42
|
+
"website": "Website",
|
|
43
|
+
"alias": "Alias",
|
|
44
|
+
"twitter": "Twitter",
|
|
45
|
+
"instagram": "Instagram",
|
|
46
|
+
"linkedIn": "Linked In",
|
|
47
|
+
"facebook": "Faceboook",
|
|
48
|
+
"userId": "User ID",
|
|
49
|
+
"siteId": "Site ID",
|
|
50
|
+
"theme": "Theme",
|
|
51
|
+
"token": "Token",
|
|
52
|
+
"field": "Field"
|
|
53
|
+
},
|
|
54
|
+
"validation": {
|
|
55
|
+
"any.required": "Harus diisi",
|
|
56
|
+
"any.only": "Harus sesuai dengan {{ref}}",
|
|
57
|
+
"string.alphanum": "Harus berupa alfa numerik karakter saja",
|
|
58
|
+
"string.base": "Harus berupa string",
|
|
59
|
+
"string.base64": "Harus berupa string base64 yang valid",
|
|
60
|
+
"string.creditCard": "Harus berupa nomor kartu kredit",
|
|
61
|
+
"string.dataUri": "Harus berupa string dataUri yang valid",
|
|
62
|
+
"string.domain": "Harus mengandung nama domain yang valid",
|
|
63
|
+
"string.email": "Harus berupa surel yang valid",
|
|
64
|
+
"string.empty": "Tidak boleh dibiarkan kosong",
|
|
65
|
+
"string.guid": "Harus berupa GUID yang valid",
|
|
66
|
+
"string.hex": "Harus mengandung hexadesimal karakter yang valid saja",
|
|
67
|
+
"string.hexAlign": "Representasi hex yang terdekode harus byte aligned",
|
|
68
|
+
"string.hostname": "Harus berupa nama host yang valid",
|
|
69
|
+
"string.ip": "Harus berupa alamat ip yang valid dengan CIDR {{cidr}}",
|
|
70
|
+
"string.ipVersion": "Harus berupa alamat ip yang valid dengan versi {{version}} dan CIDR {{cidr}}",
|
|
71
|
+
"string.isoDate": "Harus dalam format ISO",
|
|
72
|
+
"string.isoDuration": "Harus berupa durasi ISO 8601 yang valid",
|
|
73
|
+
"string.length": "Panjang harus pas {{limit}} karakter",
|
|
74
|
+
"string.lowercase": "Hanya boleh mengandung huruf kecil saja",
|
|
75
|
+
"string.max": "Panjang karakter harus lebih kecil atau sama dengan {{limit}} karakter",
|
|
76
|
+
"string.min": "Panjang karakter harus setidaknya {{limit}} karakter",
|
|
77
|
+
"string.token": "Hanya boleh terdiri atas karakter alfanumerik dan garis bawah saja",
|
|
78
|
+
"string.trim": "Tidak boleh memiliki spasi didepan atau dibelakang",
|
|
79
|
+
"string.uri": "Harus berupa URI yang valid",
|
|
80
|
+
"string.uppercase": "Hanya boleh mengandung huruf besar saja"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
{
|
|
2
|
+
"[%s] '%s' is connected": "[%s] '%s' telah tersambung",
|
|
3
|
+
"[%s] Error on '%s': %s": "[%s] Kesalahan pada '%s': %s",
|
|
4
|
+
"[%s] '%s' is destroyed": "[%s] '%s' telah dimusnahkan",
|
|
5
|
+
"[%s] Loaded schemas: %s": "[%s] Skema termuat: %s",
|
|
6
|
+
"[%s] Load schema: %s (%d)": "[%s] Muat skema: %s (%d)",
|
|
7
|
+
"[%s] Loaded connections: %s": "[%s] Koneksi termuat: %s",
|
|
8
|
+
"Unsupported property type '%s' in '%s'": "Tipe properti '%s' di '%s' tidak didukung",
|
|
9
|
+
"No schema found!": "Tidak ditemukan skema!",
|
|
10
|
+
"Enter schema name(s), separated by space:": "Masukkan nama skema, dipisah dengan spasi:",
|
|
11
|
+
"No schema matched": "Tidak ditemukan skema yang cocok",
|
|
12
|
+
"Schema (%d)": "Skema (%d)",
|
|
13
|
+
"The above mentioned schema(s) will be rebuilt & modeled. Continue?": "Semua skema tersebut diatas akan dibuat ulang sebagai model. Anda yakin?",
|
|
14
|
+
"Rebuilding '%s'...": "Pembuatan ulang '%s'...",
|
|
15
|
+
"No database connection '%s' for '%s'. Aborted!'": "Tidak ada koneksi database '%s' untuk '%s'. Batalkan!",
|
|
16
|
+
"Error on dropping model '%s': %s": "Gagal menghapus model '%s': %s",
|
|
17
|
+
"Model '%s' exists. Won't rebuild without --force": "Model '%s' telah ada. Tidak dilakukan pembuatan ulang tanpa --force",
|
|
18
|
+
"Model '%s' successfully created": "Model '%s' sukses dibuat",
|
|
19
|
+
"Error on creating model '%s': %s": "Gagal membuat model '%s': %s",
|
|
20
|
+
"Model '%s' successfully dropped": "Model '%s' sukses dihapus",
|
|
21
|
+
"Db '%s' for '%s' is a memory database, skipped": "Db '%s' untuk '%s' adalah database memori, lewati",
|
|
22
|
+
"[%s] Model '%s@%s' successfully built on the fly": "[%s] Model '%s@%s' sukses dibuat ulang on the fly",
|
|
23
|
+
"Unable to build model '%s@%s': %s": "Gagal membuat ulang model '%s' di '%s': %s",
|
|
24
|
+
"Unknown schema '%s'": "Skema '%s' tidak dikenal",
|
|
25
|
+
"Payload must be a valid JSON object": "Data harus berupa obyek JSON yang valid",
|
|
26
|
+
"Please select a schema:": "Silahkan masukkan sebuah skema:",
|
|
27
|
+
"Enter JSON payload:": "Masukkan data JSON:",
|
|
28
|
+
"Payload is required": "Data harus diisi",
|
|
29
|
+
"Invalid payload syntax": "Sintak data tidak valid",
|
|
30
|
+
"Creating record": "Pembuatan data",
|
|
31
|
+
"Enter record ID:": "Masukkan ID data:",
|
|
32
|
+
"ID is required": "ID harus diisi",
|
|
33
|
+
"Getting record": "Mengambil data",
|
|
34
|
+
"Removing record": "Menghapus data",
|
|
35
|
+
"Can't find schema named %s": "Tidak bisa menemukan skema dengan nama %s",
|
|
36
|
+
"Record '%s@%s' not found!": "Data '%s@%s' tidak ditemukan",
|
|
37
|
+
"Invalid schema '%s'": "Skema '%s' tidak valid",
|
|
38
|
+
"Schema '%s' doesn't have properties at all": "Skema '%s' tidak memiliki properti sama sekali",
|
|
39
|
+
"Field 'id@%s' is a reserved field and should not be added manually": "Kolom 'id@%s' adalah kolom ter-reservasi dan seharusnya tidak ditambahkan secara manual",
|
|
40
|
+
"Missing property type for '%s@%s'": "Tipe properti untuk '%s@%s' tidak ditemukan",
|
|
41
|
+
"Unsupported property type '%s@%s' in '%s'": "Tipe properti '%s@%s' di '%s' tidak didukung",
|
|
42
|
+
"Unknown connection '%s@%s'": "Koneksi '%s@%s' tidak dikenal",
|
|
43
|
+
"Field '%s@%s' is required": "Kolom '%s@%s' harus diisi",
|
|
44
|
+
"'%s' key is required": "Kunci '%s' harus diisi",
|
|
45
|
+
"Please enter a query (if any):": "Silahkan masukkan kueri (jika ada):",
|
|
46
|
+
"Finding record(s)": "Temukan data",
|
|
47
|
+
"Record '%s@%s' exists already!": "Data '%s@%s' sudah ada",
|
|
48
|
+
"Field to group aggregate is missing": "Field to group aggregate is missing",
|
|
49
|
+
"Field to calculate aggregate is missing": "Field to calculate aggregate is missing",
|
|
50
|
+
"Base field for histogram must be provided": "Base field for histogram must be provided",
|
|
51
|
+
"Unknown base field for histogram '%s'": "Unknown base field for histogram '%s'",
|
|
52
|
+
"Field type '%s@%s' must be a datetime field": "Field type '%s@%s' must be a datetime field",
|
|
53
|
+
"Group field to aggregate is missing": "Group field to aggregate is missing",
|
|
54
|
+
"Unknown group field '%s@%s'": "Unknown group field '%s@%s'",
|
|
55
|
+
"Group field must be of type integer, smallint or float": "Group field must be of type integer, smallint or float",
|
|
56
|
+
"Unsupported aggregate type: '%s'": "Unsupported aggregate type: '%s'",
|
|
57
|
+
"'%s@%s' key is required": "'%s@%s' key is required",
|
|
58
|
+
"Full text index need integer type primary id in '%s@%s'": "Full text index need integer type primary id in '%s@%s'",
|
|
59
|
+
"Unsupported aggregate '%s'": "Unsupported aggregate '%s'",
|
|
60
|
+
"Unsupported %s '%s' for '%s@%s'. Allowed choices: %s": "Unsupported %s '%s' for '%s@%s'. Allowed choices: %s",
|
|
61
|
+
"Method '%s@%s' is disabled": "Metode '%s@%s' dinonaktifkan",
|
|
62
|
+
"field": {
|
|
63
|
+
"id": "ID",
|
|
64
|
+
"name": "Nama",
|
|
65
|
+
"dt": "Tgl/Jam",
|
|
66
|
+
"createdAt": "Dibuat Pada",
|
|
67
|
+
"updatedAt": "Diubah Pada",
|
|
68
|
+
"title": "Judul",
|
|
69
|
+
"description": "Keterangan",
|
|
70
|
+
"subTitle": "Sub Judul",
|
|
71
|
+
"plugin": "Plugin",
|
|
72
|
+
"author": "Penulis",
|
|
73
|
+
"dir": "Direktori",
|
|
74
|
+
"file": "Berkas",
|
|
75
|
+
"meta": "Info Meta",
|
|
76
|
+
"level": "Tingkat",
|
|
77
|
+
"ref": "Referensi",
|
|
78
|
+
"section": "Bagian",
|
|
79
|
+
"asset": "Aset",
|
|
80
|
+
"category": "Kategori",
|
|
81
|
+
"categoryId": "ID Kategori",
|
|
82
|
+
"username": "Nama Pengguna",
|
|
83
|
+
"password": "Kata Sandi",
|
|
84
|
+
"password2": "Ulangi Kata Sandi",
|
|
85
|
+
"firstName": "Nama Depan",
|
|
86
|
+
"lastName": "Nama Belakang",
|
|
87
|
+
"address1": "Alamat 1",
|
|
88
|
+
"address2": "Alamat 2",
|
|
89
|
+
"city": "Nama Kota",
|
|
90
|
+
"zipCode": "Kode Pos",
|
|
91
|
+
"provinceState": "Propinsi",
|
|
92
|
+
"country": "Negara",
|
|
93
|
+
"phone": "Telepon",
|
|
94
|
+
"email": "Surel",
|
|
95
|
+
"key": "Kunci",
|
|
96
|
+
"status": "Status",
|
|
97
|
+
"orgName": "Organisasi",
|
|
98
|
+
"picName": "Nama PJ",
|
|
99
|
+
"picRole": "Peran PJ",
|
|
100
|
+
"picPhone": "Telpon PJ",
|
|
101
|
+
"picEmail": "Surel PJ",
|
|
102
|
+
"website": "Alamat Situs",
|
|
103
|
+
"alias": "Alias",
|
|
104
|
+
"twitter": "Twitter",
|
|
105
|
+
"instagram": "Instagram",
|
|
106
|
+
"linkedIn": "Linked In",
|
|
107
|
+
"facebook": "Faceboook",
|
|
108
|
+
"userId": "ID Pengguna",
|
|
109
|
+
"siteId": "ID Situs",
|
|
110
|
+
"theme": "Tema",
|
|
111
|
+
"token": "Token",
|
|
112
|
+
"field": "Field"
|
|
113
|
+
},
|
|
114
|
+
"Validation Error": "Kesalahan Validasi",
|
|
115
|
+
"validation": {
|
|
116
|
+
"any.required": "Harus diisi",
|
|
117
|
+
"any.only": "Harus sesuai dengan {{ref}}",
|
|
118
|
+
"string.alphanum": "Harus berupa alfa numerik karakter saja",
|
|
119
|
+
"string.base": "Harus berupa string",
|
|
120
|
+
"string.base64": "Harus berupa string base64 yang valid",
|
|
121
|
+
"string.creditCard": "Harus berupa nomor kartu kredit",
|
|
122
|
+
"string.dataUri": "Harus berupa string dataUri yang valid",
|
|
123
|
+
"string.domain": "Harus mengandung nama domain yang valid",
|
|
124
|
+
"string.email": "Harus berupa surel yang valid",
|
|
125
|
+
"string.empty": "Tidak boleh dibiarkan kosong",
|
|
126
|
+
"string.guid": "Harus berupa GUID yang valid",
|
|
127
|
+
"string.hex": "Harus mengandung hexadesimal karakter yang valid saja",
|
|
128
|
+
"string.hexAlign": "Representasi hex yang terdekode harus byte aligned",
|
|
129
|
+
"string.hostname": "Harus berupa nama host yang valid",
|
|
130
|
+
"string.ip": "Harus berupa alamat ip yang valid dengan CIDR {{cidr}}",
|
|
131
|
+
"string.ipVersion": "Harus berupa alamat ip yang valid dengan versi {{version}} dan CIDR {{cidr}}",
|
|
132
|
+
"string.isoDate": "Harus dalam format ISO",
|
|
133
|
+
"string.isoDuration": "Harus berupa durasi ISO 8601 yang valid",
|
|
134
|
+
"string.length": "Panjang harus pas {{limit}} karakter",
|
|
135
|
+
"string.lowercase": "Hanya boleh mengandung huruf kecil saja",
|
|
136
|
+
"string.max": "Panjang karakter harus lebih kecil atau sama dengan {{limit}} karakter",
|
|
137
|
+
"string.min": "Panjang karakter harus setidaknya {{limit}} karakter",
|
|
138
|
+
"string.token": "Hanya boleh terdiri atas karakter alfanumerik dan garis bawah saja",
|
|
139
|
+
"string.trim": "Tidak boleh memiliki spasi didepan atau dibelakang",
|
|
140
|
+
"string.uri": "Harus berupa URI yang valid",
|
|
141
|
+
"string.uppercase": "Hanya boleh mengandung huruf besar saja"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
async function createdAt (opts = {}) {
|
|
2
|
+
opts.fieldName = opts.fieldName ?? 'createdAt'
|
|
3
|
+
return {
|
|
4
|
+
properties: {
|
|
5
|
+
name: opts.fieldName,
|
|
6
|
+
type: 'datetime',
|
|
7
|
+
index: true
|
|
8
|
+
},
|
|
9
|
+
hook: {
|
|
10
|
+
beforeCreate: async function ({ body }) {
|
|
11
|
+
const now = new Date()
|
|
12
|
+
if (opts.overwrite || !this.app.bajo.isSet(body[opts.fieldName])) body[opts.fieldName] = now
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default createdAt
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
async function dt (opts = {}) {
|
|
2
|
+
opts.fieldName = opts.fieldName ?? 'dt'
|
|
3
|
+
return {
|
|
4
|
+
properties: [{
|
|
5
|
+
name: opts.fieldName ?? 'dt',
|
|
6
|
+
type: 'datetime',
|
|
7
|
+
required: opts.required ?? true,
|
|
8
|
+
index: opts.index ?? true
|
|
9
|
+
}]
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default dt
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
async function updatedAt (opts = {}) {
|
|
2
|
+
opts.fieldName = opts.fieldName ?? 'updatedAt'
|
|
3
|
+
opts.overwrite = opts.overwrite ?? true
|
|
4
|
+
return {
|
|
5
|
+
properties: {
|
|
6
|
+
name: opts.fieldName,
|
|
7
|
+
type: 'datetime',
|
|
8
|
+
index: true
|
|
9
|
+
},
|
|
10
|
+
hook: {
|
|
11
|
+
beforeCreate: async function ({ body }) {
|
|
12
|
+
const now = new Date()
|
|
13
|
+
if (opts.overwrite || !this.app.bajo.isSet(body[opts.fieldName])) body[opts.fieldName] = now
|
|
14
|
+
},
|
|
15
|
+
beforeUpdate: async function ({ body }) {
|
|
16
|
+
const now = new Date()
|
|
17
|
+
if (opts.overwrite || !this.app.bajo.isSet(body[opts.fieldName])) body[opts.fieldName] = now
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default updatedAt
|