dobo 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +725 -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 +366 -0
- package/docs/scripts/third-party/hljs-line-num.js +1 -0
- package/docs/scripts/third-party/hljs-original.js +5164 -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 +671 -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/extend/bajo/intl/en-US.json +69 -30
- package/extend/bajo/intl/id.json +58 -29
- package/extend/bajoCli/applet/clear-record.js +22 -0
- package/extend/bajoCli/applet/connection.js +5 -5
- package/extend/bajoCli/applet/count-record.js +27 -0
- package/extend/bajoCli/applet/create-aggregate.js +33 -0
- package/extend/bajoCli/applet/create-histogram.js +33 -0
- package/extend/bajoCli/applet/create-record.js +39 -0
- package/extend/bajoCli/applet/find-record.js +27 -0
- package/extend/bajoCli/applet/get-record.js +27 -0
- package/extend/bajoCli/applet/lib/post-process.js +25 -26
- package/extend/bajoCli/applet/model.js +22 -0
- package/extend/bajoCli/applet/rebuild-model.js +91 -0
- package/extend/bajoCli/applet/remove-record.js +27 -0
- package/extend/bajoCli/applet/update-record.js +44 -0
- package/extend/bajoCli/applet.js +0 -0
- package/extend/dobo/driver/memory.js +170 -0
- package/extend/dobo/feature/created-at.js +10 -8
- package/extend/dobo/feature/dt.js +0 -0
- package/extend/dobo/feature/immutable.js +30 -0
- package/extend/dobo/feature/int-id.js +0 -0
- package/extend/dobo/feature/removed-at.js +35 -57
- package/extend/dobo/feature/updated-at.js +14 -12
- package/extend/waibuMpa/route/attachment/@model/@id/@field/@file.js +5 -9
- package/extend/waibuStatic/virtual.json +0 -0
- package/index.js +420 -337
- package/lib/collect-connections.js +60 -21
- package/lib/collect-drivers.js +29 -35
- package/lib/collect-features.js +40 -0
- package/lib/collect-models.js +319 -0
- package/lib/factory/action.js +161 -0
- package/lib/factory/connection.js +62 -0
- package/lib/factory/driver.js +358 -0
- package/lib/factory/feature.js +33 -0
- package/lib/factory/model/_util.js +402 -0
- package/lib/factory/model/build.js +15 -0
- package/lib/factory/model/clear-record.js +17 -0
- package/lib/factory/model/count-record.js +17 -0
- package/lib/factory/model/create-aggregate.js +17 -0
- package/lib/factory/model/create-attachment.js +29 -0
- package/lib/factory/model/create-histogram.js +17 -0
- package/lib/factory/model/create-record.js +35 -0
- package/lib/factory/model/drop.js +15 -0
- package/lib/factory/model/exists.js +21 -0
- package/lib/factory/model/find-all-record.js +71 -0
- package/lib/factory/model/find-attachment.js +29 -0
- package/lib/factory/model/find-one-record.js +19 -0
- package/lib/factory/model/find-record.js +103 -0
- package/lib/factory/model/get-attachment.js +15 -0
- package/lib/factory/model/get-record.js +79 -0
- package/lib/factory/model/list-attachment.js +37 -0
- package/lib/{add-fixtures.js → factory/model/load-fixtures.js} +69 -67
- package/lib/factory/model/remove-attachment.js +15 -0
- package/lib/factory/model/remove-record.js +59 -0
- package/lib/factory/model/sanitize-body.js +62 -0
- package/lib/factory/model/sanitize-id.js +7 -0
- package/lib/factory/model/sanitize-record.js +26 -0
- package/lib/factory/model/update-attachment.js +9 -0
- package/lib/factory/model/update-record.js +81 -0
- package/lib/factory/model/upsert-record.js +95 -0
- package/lib/factory/model/validate.js +232 -0
- package/lib/factory/model.js +150 -0
- package/lib/index.js +3 -0
- package/package.json +45 -36
- package/wiki/APPLETS.md +57 -0
- package/wiki/CHANGES.md +46 -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/{docs/query-language.md → wiki/QUERY-LANGUAGE.md} +0 -0
- package/wiki/USER-GUIDE.md +1 -0
- package/extend/bajoCli/applet/model-clear.js +0 -11
- package/extend/bajoCli/applet/model-rebuild.js +0 -101
- package/extend/bajoCli/applet/record-create.js +0 -41
- package/extend/bajoCli/applet/record-find.js +0 -27
- package/extend/bajoCli/applet/record-get.js +0 -24
- package/extend/bajoCli/applet/record-remove.js +0 -24
- package/extend/bajoCli/applet/record-update.js +0 -47
- package/extend/bajoCli/applet/schema.js +0 -22
- package/extend/bajoCli/applet/stat-count.js +0 -24
- package/lib/build-bulk-action.js +0 -12
- package/lib/check-unique.js +0 -39
- package/lib/collect-feature.js +0 -25
- package/lib/collect-schemas.js +0 -83
- package/lib/exec-feature-hook.js +0 -13
- package/lib/exec-validation.js +0 -21
- package/lib/generic-prop-sanitizer.js +0 -31
- package/lib/handle-attachment-upload.js +0 -16
- package/lib/mem-db/conn-sanitizer.js +0 -8
- package/lib/mem-db/instantiate.js +0 -41
- package/lib/mem-db/method/model/clear.js +0 -6
- package/lib/mem-db/method/model/create.js +0 -5
- package/lib/mem-db/method/model/drop.js +0 -5
- package/lib/mem-db/method/model/exists.js +0 -5
- package/lib/mem-db/method/record/create.js +0 -12
- package/lib/mem-db/method/record/find.js +0 -20
- package/lib/mem-db/method/record/get.js +0 -9
- package/lib/mem-db/method/record/remove.js +0 -13
- package/lib/mem-db/method/record/update.js +0 -15
- package/lib/mem-db/method/stat/count.js +0 -11
- package/lib/mem-db/start.js +0 -25
- package/lib/merge-attachment-info.js +0 -16
- package/lib/multi-rel-rows.js +0 -42
- package/lib/resolve-method.js +0 -16
- package/lib/sanitize-schema.js +0 -197
- package/lib/single-rel-rows.js +0 -38
- package/method/attachment/copy-uploaded.js +0 -34
- package/method/attachment/create.js +0 -29
- package/method/attachment/find.js +0 -27
- package/method/attachment/get-path.js +0 -12
- package/method/attachment/get.js +0 -12
- package/method/attachment/pre-check.js +0 -9
- package/method/attachment/remove.js +0 -11
- package/method/attachment/update.js +0 -7
- package/method/bulk/create.js +0 -46
- package/method/model/clear.js +0 -22
- package/method/model/create.js +0 -19
- package/method/model/drop.js +0 -19
- package/method/model/exists.js +0 -24
- package/method/record/clear.js +0 -24
- package/method/record/count.js +0 -44
- package/method/record/create.js +0 -71
- package/method/record/find-all.js +0 -25
- package/method/record/find-one.js +0 -56
- package/method/record/find.js +0 -52
- package/method/record/get.js +0 -47
- package/method/record/remove.js +0 -41
- package/method/record/update.js +0 -63
- package/method/record/upsert.js +0 -35
- package/method/sanitize/body.js +0 -70
- package/method/sanitize/date.js +0 -14
- package/method/sanitize/id.js +0 -7
- package/method/stat/aggregate.js +0 -23
- package/method/stat/histogram.js +0 -26
- package/method/validate.js +0 -157
package/wiki/APPLETS.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Applet
|
|
2
|
+
|
|
3
|
+
## connection
|
|
4
|
+
|
|
5
|
+
Gunakan applet ini untuk menampilkan koneksi database yang Anda miliki
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
$ node index.js -a dobo:connection # Masuk ke mode interaktif
|
|
9
|
+
$ node index.js -a dobo:connection default # Tampilkan koneksi dengan nama 'default'
|
|
10
|
+
$ node index.js -a dobo:connection default --format=json # Tampilkan dalam format 'json'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## modelClear
|
|
14
|
+
|
|
15
|
+
Hapus tabel yang Anda inginkan. **Perhatian**: tabel akan dihapus dari database BESERTA isinya. Jadi pastikan bahwa Anda telah membackup tabel Anda terlebih dahulu sebelum Anda memanggil applet ini.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
$ node index.js -a dobo:modelRebuild # Masuk ke mode interaktif
|
|
19
|
+
$ node index.js -a dobo:modelRebuild 'Cdb*' # Hapus model dengan awalan 'Cdb'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## modelRebuild
|
|
23
|
+
|
|
24
|
+
Pada saat pertama kali sebuah plugin dimuat dan plugin meng-extend Dobo, Anda perlu memanggil applet ini untuk membuat tabel sesuai dengan skema yang telah ditentukan.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
$ node index.js -a dobo:modelRebuild # Gunakan mode interaktif
|
|
28
|
+
$ node index.js -a dobo:modelRebuild CdbCountry Sumba # Masukkan satu persatu nama modelnya
|
|
29
|
+
$ node index.js -a dobo:modelRebuild 'Cdb*' # List semua model dengan awalan 'Cdb'
|
|
30
|
+
```
|
|
31
|
+
Setelah tabel sukses dibuat, maka jika model dilengkapi dengan fixture, fixture tersebut akan dimuat didalam tabel yang bersangkutan.
|
|
32
|
+
|
|
33
|
+
Jika tabel telah ada di database, Anda harus menggunakan switch ```--force``` untuk memaksa model bisa di hapus kemudian dibuat ulang kembali.
|
|
34
|
+
|
|
35
|
+
## recordCreate
|
|
36
|
+
|
|
37
|
+
Gunakan applet ini untuk membuat rekord:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
$ node index.js -a dobo:recordCreate CdbCountry
|
|
41
|
+
ℹ App is running as applet...
|
|
42
|
+
✔ Enter JSON payload: { "id": "XX", "name": "My Country" }
|
|
43
|
+
╭ CdbCountry ─────────────╮
|
|
44
|
+
│ { │
|
|
45
|
+
│ "id": "XX", │
|
|
46
|
+
│ "name": "My Country" │
|
|
47
|
+
│ } │
|
|
48
|
+
╰─────────────────────────╯
|
|
49
|
+
? Are you sure to continue? (y/N)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## recordFind
|
|
53
|
+
|
|
54
|
+
Mencari rekord yang sesuai dengan kriteria pemilihan Anda. Jika kriteria tidak dimasukkan (filter kosong), maka akan diberikan semua rekord yang ada.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
|
package/wiki/CHANGES.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Changes
|
|
2
|
+
|
|
3
|
+
## 2026-01-11
|
|
4
|
+
|
|
5
|
+
- [2.2.0] Any driver that support memory DB can now declare itself as in-memory DB and be handled as such
|
|
6
|
+
- [2.2.0] ```driver.init()``` is removed, and driver should solely use ```driver.createClient()``` instead
|
|
7
|
+
- [2.2.0] Bug fixes
|
|
8
|
+
|
|
9
|
+
## 2026-01-07
|
|
10
|
+
|
|
11
|
+
- [2.2.0] Add ```immutable``` feature
|
|
12
|
+
- [2.2.0] Lots of bug fixes
|
|
13
|
+
|
|
14
|
+
## 2025-12-28
|
|
15
|
+
|
|
16
|
+
- [2.2.0] Add ```calcAggregate()``` & ```calcHistogram()``` for array of data objects
|
|
17
|
+
- [2.2.0] Implement ```createAggregate()``` & ```createHistogram()``` to the built-in memory database driver
|
|
18
|
+
- [2.2.0] If no ```default``` connection found, all models automatically bound to ```memory``` connection
|
|
19
|
+
|
|
20
|
+
## 2025-12-22
|
|
21
|
+
|
|
22
|
+
- [2.2.0] Introduce Action class that enables you to work on models with chainable methods
|
|
23
|
+
- [2.2.0] All base class definitions moved now to ```this.baseClass``` instead of ```this.lib```
|
|
24
|
+
|
|
25
|
+
## 2025-12-16
|
|
26
|
+
|
|
27
|
+
- [2.2.0] Upgrade mingo to 7.1.0
|
|
28
|
+
|
|
29
|
+
## 2025-12-14
|
|
30
|
+
|
|
31
|
+
- [2.2.0] Drop Model class, replace as Model class
|
|
32
|
+
|
|
33
|
+
## 2025-12-10
|
|
34
|
+
|
|
35
|
+
- [2.2.0] Rewrite the whole thing into class based modules: Connection, Driver, Feature, Model. Dobo will solely serve as DB Manager in the future
|
|
36
|
+
|
|
37
|
+
## 2025-12-05
|
|
38
|
+
- [2.2.0] Connection now saved in ```this.connections``` as ```Connection``` instance
|
|
39
|
+
|
|
40
|
+
## 2025-12-03
|
|
41
|
+
|
|
42
|
+
- [2.1.0] Upgrade joi to 18.0.2
|
|
43
|
+
- [2.1.0] Upgrade mingo to 7.0.2
|
|
44
|
+
- [2.1.0] Feature now saved in ```this.features``` as ```Feature``` instance
|
|
45
|
+
- [2.1.0] Driver now saved in ```this.drivers``` as ```Driver``` instance
|
|
46
|
+
- [2.1.0] Add ```this.getDriver()```. Accept short name or NsPath format
|
package/wiki/CONFIG.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Config Object
|
|
2
|
+
|
|
3
|
+
| Key Name | Type | Default | Description |
|
|
4
|
+
| ------- | ---- | ----- | ----------- |
|
|
5
|
+
| ```connections``` | ```array``` | ```[]``` | Connection object |
|
|
6
|
+
| ```validationParams``` | ```object``` | | Defaults to [Joi validate's](https://joi.dev/api/?v=17.13.3#anyvalidateasyncvalue-options) options |
|
|
7
|
+
| ```abortEarly``` | ```boolean``` | ```false``` | |
|
|
8
|
+
| ```convert``` | ```boolean``` | ```false``` | |
|
|
9
|
+
| ```allowUnknown``` | ```boolean``` | ```true``` | |
|
|
10
|
+
| ```default``` | ```object``` | | default values |
|
|
11
|
+
| ```property``` | ```object``` | | |
|
|
12
|
+
| ```text``` | ```object``` | | |
|
|
13
|
+
| ```textType``` | ```string``` | ```text``` | Allowed values: ```text```, ```mediumtext```, or ```longtext``` |
|
|
14
|
+
| ```string``` | ```object``` | | |
|
|
15
|
+
| ```length``` | ```number``` | ```50``` | |
|
|
16
|
+
| ```filter``` | ```object``` | | |
|
|
17
|
+
| ```limit``` | ```number``` | ```25``` | Rows returned in one page |
|
|
18
|
+
| ```maxLimit``` | ```number``` | ```200``` | Max rows returned in one page |
|
|
19
|
+
| ```hardLimit``` | ```number``` | ```10000``` | Max rows returned on dataset export |
|
|
20
|
+
| ```sort``` | ```array``` | | |
|
|
21
|
+
| ```idField``` | ```object``` | | |
|
|
22
|
+
| ```memDb``` | ```object``` | | |
|
|
23
|
+
| ```createDefConnAtStart``` | ```boolean``` | ```true``` | |
|
|
24
|
+
| ```persistence``` | ```object``` | | |
|
|
25
|
+
| ```syncPeriodDur``` | ```string | number``` | ```1s``` | |
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks very much to everyone who wants to join as a contributor, but I have committed to devoting 100% of my time to this project. Therefore, I'm currently unable to accept pull requests from anyone until the project is large enough for me to manage it independently.
|
|
4
|
+
|
|
5
|
+
However, I am available if you encounter any bugs that require immediate fixes. Please report your issues in a GitHub issue, and I'll try to address them promptly. I'm also open to criticism and suggestions for improvements or requests for new features.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Developer Guide
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Ecosystem
|
|
2
|
+
|
|
3
|
+
## Drivers
|
|
4
|
+
|
|
5
|
+
| Package | Docs | NS | Alias | Description |
|
|
6
|
+
| ------- | ---- | -- | ----- | ----------- |
|
|
7
|
+
| [dobo-couchdb](https://github.com/ardhi/dobo-couchdb) | [Docs](https://ardhi.github.io/dobo-couchdb) | doboCouchdb | dbcouch | CouchDB Driver |
|
|
8
|
+
| [dobo-elasticsearch](https://github.com/ardhi/dobo-elasticsearch) | [Docs](https://ardhi.github.io/dobo-elasticsearch) | doboElasticsearch | dbes | Elasticsearch Driver |
|
|
9
|
+
| [dobo-knex](https://github.com/ardhi/dobo-knex) | [Docs](https://ardhi.github.io/dobo-knex) | doboKnex | dbknex | Knex/SQL Driver |
|
|
10
|
+
| [dobo-mongodb](https://github.com/ardhi/dobo-mongodb) | [Docs](https://ardhi.github.io/dobo-mongodb) | doboMongodb | dbmongo | MongoDB Driver |
|
|
11
|
+
| [dobo-redis](https://github.com/ardhi/dobo-redis) | [Docs](https://ardhi.github.io/dobo-redis) | doboRedis | dbredis | Redis Driver |
|
|
12
|
+
| [dobo-restproxy](https://github.com/ardhi/dobo-restproxy) | [Docs](https://ardhi.github.io/dobo-restproxy) | doboRestproxy | dbrpx | Restproxy Driver |
|
|
13
|
+
| [dobo-restproxy-jsonserver](https://github.com/ardhi/dobo-restproxy-jsonserver) | [Docs](https://ardhi.github.io/dobo-restproxy-jsonserver) | doboResporoxyJsonserver | dbrpxjs |JsonServer Support for doboRestproxy |
|
|
14
|
+
| [dobo-restproxy-ndut](https://github.com/ardhi/dobo-restproxy-ndut) | [Docs](https://ardhi.github.io/dobo-restproxy-ndut) | doboRestproxyNdut | dbrpxndut | NDUT Support for doboRestproxy |
|
|
15
|
+
|
|
16
|
+
## Misc
|
|
17
|
+
|
|
18
|
+
| Package | Docs | NS | Alias | Description |
|
|
19
|
+
| ------- | ---- | -- | ----- | ----------- |
|
|
20
|
+
| [dobo-extra](https://github.com/ardhi/dobo-extra) | [Docs](https://ardhi.github.io/dobo-extra) | doboExtra | dbx | Dobo Extra Tools/Utility |
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
> If you're new to the [Dobo DBMS](https://ardhi.github.io/dobo), we recommend you to read and follow along with [Bajo Tutorial](https://ardhi.github.io/bajo/tutorial-01-getting-started.html) first, as this document is the continuation of it
|
|
4
|
+
|
|
5
|
+
**Dobo** is the Bajo sub-framework developed specifically to handle database management. In this tutorial, we'll go over how to install the necessary packages and interact with them.
|
|
6
|
+
|
|
7
|
+
Here is some basic knowledge about Dobo you need to be familiar with:
|
|
8
|
+
|
|
9
|
+
- All record-related actions mimic REST API methods: *find* records, *get* a particular record by its ID, *create* a new record, *update* an existing record by ID and payload, and *remove* an existing record by its ID.
|
|
10
|
+
- A Dobo model requires a predefined model. Even if you use a NoSQL database, you still need to write a model.
|
|
11
|
+
- There are two main groups of methods to be familiar with:
|
|
12
|
+
- ```dobo.model{Action}``` methods manage everything related to model management, such as table creation or deletion.
|
|
13
|
+
- ```dobo.record{Action}``` methods handle record manipulation.
|
|
14
|
+
- A record in Bajo always needs to have an ID. The ID can be alphanumeric characters or an integer, and it is defined by the underlying driver used by the model.
|
|
15
|
+
|
|
16
|
+
For more info about Dobo, please [click here](https://ardhi.github.io/dobo).
|
|
17
|
+
|
|
18
|
+
### Installation
|
|
19
|
+
|
|
20
|
+
As you might have guessed, Dobo and its drivers are normal Bajo plugins. Although [many drivers](https://github.com/ardhi/dobo/tutorials/drivers.md) exist, for this tutorial, we'll only use SQLite 3, which is provided by the dobo-knex driver.
|
|
21
|
+
|
|
22
|
+
Now, please install the required plugins and SQLite drivers first:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
$ npm install dobo dobo-knex sqlite3
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Don't forget to add ```dobo``` and ```dobo-knex``` to the ```data/config/.plugins``` file.
|
|
29
|
+
|
|
30
|
+
### Model
|
|
31
|
+
|
|
32
|
+
Let's pretend we're building an address book with fields like name, age, phone, etc. This entity needs to be modeled with a model and then "connected" to a database:
|
|
33
|
+
|
|
34
|
+
1. Create ```main/extend/dobo/model/address-book.json``` file.
|
|
35
|
+
2. Enter the following model:
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"properties": [{
|
|
39
|
+
"name": "firstName",
|
|
40
|
+
"type": "string",
|
|
41
|
+
"maxLength": 20,
|
|
42
|
+
"required": true,
|
|
43
|
+
"index": true
|
|
44
|
+
},
|
|
45
|
+
"lastName::20:true:true",
|
|
46
|
+
"age:smallint",
|
|
47
|
+
"phone::20:true:true",
|
|
48
|
+
"email::50:true"
|
|
49
|
+
],
|
|
50
|
+
"feature": {
|
|
51
|
+
"createdAt": true,
|
|
52
|
+
"updatedAt": true
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
You should notice here that in properties you can use either the verbose, full-object syntax or the string-based one. Please visit the Dobo documentation to learn more.
|
|
57
|
+
|
|
58
|
+
3. Create ```main/extend/dobo/fixture/address-book.json``` file. Fixtures allow you to quickly fill your database with predefined records. It's not required, but it helps a lot with prototyping.
|
|
59
|
+
```json
|
|
60
|
+
[{
|
|
61
|
+
"firstName": "James",
|
|
62
|
+
"lastName": "Bond",
|
|
63
|
+
"phone": "+44-007"
|
|
64
|
+
}, {
|
|
65
|
+
"firstName": "Felix",
|
|
66
|
+
"lastName": "Leiter",
|
|
67
|
+
"age": 50,
|
|
68
|
+
"phone": "+1-0000001"
|
|
69
|
+
}]
|
|
70
|
+
```
|
|
71
|
+
4. By default, all models are connected to a database connection named ```default```. Now let's create this connection by creating ```data/config/dobo.json``` file:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"connections": [{
|
|
76
|
+
"name": "default",
|
|
77
|
+
"type": "knex:sqlite3",
|
|
78
|
+
"connection": {
|
|
79
|
+
"filename": "my-project.sqlite3"
|
|
80
|
+
}
|
|
81
|
+
}]
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
5. That's all there is to it. Now you need to build this model like this:
|
|
85
|
+
```
|
|
86
|
+
$ node index.js -a dobo:modelRebuild MainAddressBook
|
|
87
|
+
ℹ App runs in applet mode
|
|
88
|
+
╭ Model (1) ──────╮
|
|
89
|
+
│ MainAddressBook │
|
|
90
|
+
╰──────────────────╯
|
|
91
|
+
✔ The above mentioned model(s) will be rebuilt as model. Continue? Yes
|
|
92
|
+
✔ Model 'MainAddressBook' successfully created
|
|
93
|
+
ℹ Done! Succeded: 1, failed: 0, skipped: 0
|
|
94
|
+
✔ Fixture on 'MainAddressBook': added 2, rejected: 0
|
|
95
|
+
```
|
|
96
|
+
6. Done!
|
|
97
|
+
|
|
98
|
+
Note: Although you can use YAML or TOML for models/fixtures, it's recommended to stick with JSON because it's always supported and doesn't require an extra plugin.
|
|
99
|
+
|
|
100
|
+
Dobo models are by default always named with ```{Alias}{ModelName}```, which is a pascal-cased plugin alias and base name from your model file. For field names, Dobo use camel-cased names as a convention. You can change this behavior to match your needs, but it is suggested that you're keeping these conventions at least for this tutorial.
|
|
101
|
+
|
|
102
|
+
### Applets
|
|
103
|
+
|
|
104
|
+
Dobo provides you with a number of applets that will help you manipulate models and records directly. This means you don't have to touch your tables and databases directly through SQL statements or NoSQL procedures ever again. Everything can be managed through one common syntax provided by Dobo, regardless of your backend type.
|
|
105
|
+
|
|
106
|
+
First, let's try to list records:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
$ node index.js -a dobo:recordFind MainAddressBook
|
|
110
|
+
ℹ App runs in applet mode
|
|
111
|
+
✔ Please enter your query (if any):
|
|
112
|
+
✔ Done
|
|
113
|
+
┌────┬───────────┬──────────┬─────┬────────────┬───────┬──────────────────────────┬──────────────────────────┐
|
|
114
|
+
│ id │ firstName │ lastName │ age │ phone │ email │ createdAt │ updatedAt │
|
|
115
|
+
├────┼───────────┼──────────┼─────┼────────────┼───────┼──────────────────────────┼──────────────────────────┤
|
|
116
|
+
│ 2 │ Felix │ Leiter │ 50 │ +1-0000001 │ │ 2025-09-18T13:47:29.296Z │ 2025-09-18T13:47:29.296Z │
|
|
117
|
+
├────┼───────────┼──────────┼─────┼────────────┼───────┼──────────────────────────┼──────────────────────────┤
|
|
118
|
+
│ 1 │ James │ Bond │ │ +44-007 │ │ 2025-09-18T13:47:29.280Z │ 2025-09-18T13:47:29.280Z │
|
|
119
|
+
└────┴───────────┴──────────┴─────┴────────────┴───────┴──────────────────────────┴──────────────────────────┘
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Now, add a new record:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
$ node index.js -a dobo:recordCreate MainAddressBook
|
|
126
|
+
ℹ App runs in applet mode
|
|
127
|
+
✔ Enter JSON payload: { "firstName": "Miss", "lastName": "Moneypenny" }
|
|
128
|
+
╭ MainAddressBook ────────────╮
|
|
129
|
+
│ { │
|
|
130
|
+
│ "firstName": "Miss", │
|
|
131
|
+
│ "lastName": "Moneypenny" │
|
|
132
|
+
│ } │
|
|
133
|
+
╰─────────────────────────────╯
|
|
134
|
+
✖ Error: Validation Error
|
|
135
|
+
✔ Enter JSON payload: { "firstName": "Miss", "lastName": "Moneypenny", "phone": "+44-111" }
|
|
136
|
+
╭ MainAddressBook ─────────────╮
|
|
137
|
+
│ { │
|
|
138
|
+
│ "firstName": "Miss", │
|
|
139
|
+
│ "lastName": "Moneypenny", │
|
|
140
|
+
│ "phone": "+44-111" │
|
|
141
|
+
│ } │
|
|
142
|
+
╰──────────────────────────────╯
|
|
143
|
+
✔ Done
|
|
144
|
+
┌───────────┬──────────────────────────┐
|
|
145
|
+
│ id │ 3 │
|
|
146
|
+
├───────────┼──────────────────────────┤
|
|
147
|
+
│ firstName │ Miss │
|
|
148
|
+
├───────────┼──────────────────────────┤
|
|
149
|
+
│ lastName │ Moneypenny │
|
|
150
|
+
├───────────┼──────────────────────────┤
|
|
151
|
+
│ age │ │
|
|
152
|
+
├───────────┼──────────────────────────┤
|
|
153
|
+
│ phone │ +44-111 │
|
|
154
|
+
├───────────┼──────────────────────────┤
|
|
155
|
+
│ email │ │
|
|
156
|
+
├───────────┼──────────────────────────┤
|
|
157
|
+
│ createdAt │ 2025-09-18T14:38:11.933Z │
|
|
158
|
+
├───────────┼──────────────────────────┤
|
|
159
|
+
│ updatedAt │ 2025-09-18T14:38:11.933Z │
|
|
160
|
+
└───────────┴──────────────────────────┘
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
As you can see, Dobo is smart enough to reject any payload that isn't right. In this case, we forgot to include the phone number since according to the model, this field is defined as required.
|
|
164
|
+
|
|
165
|
+
You can now try all of Dobo's other applets. [This page](https://github.com/ardhi/dobo/tutorials/applets) provides its complete list.
|
|
166
|
+
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# User Guide
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import postProcess from './lib/post-process.js'
|
|
2
|
-
|
|
3
|
-
async function modelClear (...args) {
|
|
4
|
-
const { print } = this.app.bajo
|
|
5
|
-
const { isEmpty } = this.lib._
|
|
6
|
-
if (isEmpty(this.schemas)) return print.fail('notFound%s', 'schema', { exit: this.app.bajo.applet })
|
|
7
|
-
const [schema] = args
|
|
8
|
-
await postProcess.call(this, { handler: 'modelClear', params: [schema], path: 'modelClear', processMsg: 'Clear records' })
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export default modelClear
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import addFixtures from '../../lib/add-fixtures.js'
|
|
2
|
-
|
|
3
|
-
async function modelRebuild (...args) {
|
|
4
|
-
const { importPkg } = this.app.bajo
|
|
5
|
-
const { outmatch } = this.lib
|
|
6
|
-
const { isEmpty, map, trim, without } = this.lib._
|
|
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('notFound%s', 'schema', { exit: this.app.bajo.applet })
|
|
12
|
-
if (isEmpty(names)) {
|
|
13
|
-
names = await input({
|
|
14
|
-
message: this.print.write('enterSchemaName'),
|
|
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
|
-
console.log(boxen(names.join(' '), { title: this.print.write('schema%d', names.length), padding: 0.5, borderStyle: 'round' }))
|
|
22
|
-
const answer = await confirm({
|
|
23
|
-
message: this.print.write('schemasWillBeRebuiltContinue'),
|
|
24
|
-
default: false
|
|
25
|
-
})
|
|
26
|
-
if (!answer) return this.print.fail('aborted', { exit: this.app.bajo.applet })
|
|
27
|
-
/*
|
|
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
|
-
*/
|
|
34
|
-
await this.start('all')
|
|
35
|
-
const result = { succed: 0, failed: 0, skipped: 0 }
|
|
36
|
-
const skipped = []
|
|
37
|
-
for (const s of names) {
|
|
38
|
-
const { schema, instance } = this.getInfo(s)
|
|
39
|
-
const spin = this.print.spinner({ showCounter: true }).start('rebuilding%s', schema.name)
|
|
40
|
-
if (!instance) {
|
|
41
|
-
spin.warn('clientInstanceNotConnected%s', schema.connection, schema.name)
|
|
42
|
-
skipped.push(schema.name)
|
|
43
|
-
result.skipped++
|
|
44
|
-
continue
|
|
45
|
-
}
|
|
46
|
-
/*
|
|
47
|
-
if (connection.memory) {
|
|
48
|
-
spin.warn('memoryDbSkipped%s', schema.name)
|
|
49
|
-
continue
|
|
50
|
-
}
|
|
51
|
-
*/
|
|
52
|
-
const exists = await this.modelExists(schema.name, false, { spinner: spin })
|
|
53
|
-
if (exists) {
|
|
54
|
-
if (this.app.bajo.config.force) {
|
|
55
|
-
try {
|
|
56
|
-
await this.modelDrop(schema.name, { spinner: spin })
|
|
57
|
-
spin.setText('modelDropped%s', schema.name)
|
|
58
|
-
} catch (err) {
|
|
59
|
-
spin.fail('errorDroppingModel%s%s', schema.name, err.message)
|
|
60
|
-
result.failed++
|
|
61
|
-
continue
|
|
62
|
-
}
|
|
63
|
-
} else {
|
|
64
|
-
spin.fail('modelExistsNeedForce%s', schema.name)
|
|
65
|
-
result.failed++
|
|
66
|
-
continue
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
try {
|
|
70
|
-
await this.modelCreate(schema.name, { spinner: spin })
|
|
71
|
-
spin.succeed('modelCreated%s', schema.name)
|
|
72
|
-
result.succed++
|
|
73
|
-
} catch (err) {
|
|
74
|
-
if (this.app.bajo.config.log.applet && this.app.bajo.config.log.level === 'trace') console.error(err)
|
|
75
|
-
spin.fail('errorCreatingModel%s%s', schema.name, err.message)
|
|
76
|
-
result.failed++
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
this.print.info('succeedFailSkip%d%d%d', result.succed, result.failed, result.skipped)
|
|
80
|
-
if (result.failed > 0) this.print.fatal('cantContinueAddFixture')
|
|
81
|
-
for (const s of without(names, ...skipped)) {
|
|
82
|
-
const { schema, connection } = this.getInfo(s)
|
|
83
|
-
const spin = this.print.spinner({ showCounter: true }).start('addingFixture%s', schema.name)
|
|
84
|
-
if (connection.memory) {
|
|
85
|
-
spin.warn('memoryDbSkipped%s', schema.name)
|
|
86
|
-
continue
|
|
87
|
-
}
|
|
88
|
-
try {
|
|
89
|
-
const fixture = await addFixtures.call(this, schema.name, { spinner: spin })
|
|
90
|
-
spin.succeed('fixtureAdded%s%s%s', schema.name, fixture.success, fixture.failed)
|
|
91
|
-
result.succed++
|
|
92
|
-
} catch (err) {
|
|
93
|
-
if (this.app.bajo.config.log.applet && this.app.bajo.config.log.level === 'trace') console.error(err)
|
|
94
|
-
spin.fail('errorAddingFixture%s%s', schema.name, err.message)
|
|
95
|
-
result.failed++
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
process.exit()
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export default modelRebuild
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import postProcess from './lib/post-process.js'
|
|
2
|
-
|
|
3
|
-
async function createRecord (path, ...args) {
|
|
4
|
-
const { importPkg } = this.app.bajo
|
|
5
|
-
const { isEmpty, map, isPlainObject } = this.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('notFound%s', this.print.write('field.schema'), { exit: this.app.bajo.applet })
|
|
9
|
-
let [schema, body] = args
|
|
10
|
-
if (isEmpty(schema)) {
|
|
11
|
-
schema = await select({
|
|
12
|
-
message: this.print.write('selectSchema'),
|
|
13
|
-
choices: map(this.schemas, s => ({ value: s.name }))
|
|
14
|
-
})
|
|
15
|
-
}
|
|
16
|
-
if (isEmpty(body)) {
|
|
17
|
-
body = await input({
|
|
18
|
-
message: this.print.write('enterJsonPayload'),
|
|
19
|
-
validate: text => {
|
|
20
|
-
if (isEmpty(text)) return this.print.write('payloadRequired')
|
|
21
|
-
try {
|
|
22
|
-
const parsed = JSON.parse(text)
|
|
23
|
-
if (!isPlainObject(parsed)) throw new Error()
|
|
24
|
-
} catch (err) {
|
|
25
|
-
return this.print.write('payloadMustBeJson')
|
|
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('invalidPayloadSyntax', { 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' })
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export default createRecord
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import postProcess from './lib/post-process.js'
|
|
2
|
-
|
|
3
|
-
async function findRecord (path, ...args) {
|
|
4
|
-
const { importPkg } = this.app.bajo
|
|
5
|
-
const { isEmpty, map, pick } = this.lib._
|
|
6
|
-
const [select, input] = await importPkg('bajoCli:@inquirer/select', 'bajoCli:@inquirer/input')
|
|
7
|
-
if (isEmpty(this.schemas)) return this.print.fail('notFound%s', this.print.write('field.schema'), { exit: this.app.bajo.applet })
|
|
8
|
-
let [schema, query] = args
|
|
9
|
-
if (isEmpty(schema)) {
|
|
10
|
-
schema = await select({
|
|
11
|
-
message: this.print.write('selectSchema'),
|
|
12
|
-
choices: map(this.schemas, s => ({ value: s.name }))
|
|
13
|
-
})
|
|
14
|
-
}
|
|
15
|
-
if (isEmpty(query)) {
|
|
16
|
-
query = await input({
|
|
17
|
-
message: this.print.write('enterQueryIfAny')
|
|
18
|
-
})
|
|
19
|
-
}
|
|
20
|
-
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)' })
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export default findRecord
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import postProcess from './lib/post-process.js'
|
|
2
|
-
|
|
3
|
-
async function getRecord (path, ...args) {
|
|
4
|
-
const { importPkg } = this.app.bajo
|
|
5
|
-
const { isEmpty, map } = this.lib._
|
|
6
|
-
const [input, select] = await importPkg('bajoCli:@inquirer/input', 'bajoCli:@inquirer/select')
|
|
7
|
-
if (isEmpty(this.schemas)) return this.print.fail('notFound%s', this.print.write('field.schema'), { 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' })
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export default getRecord
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import postProcess from './lib/post-process.js'
|
|
2
|
-
|
|
3
|
-
async function removeRecord (path, ...args) {
|
|
4
|
-
const { importPkg } = this.app.bajo
|
|
5
|
-
const { isEmpty, map } = this.lib._
|
|
6
|
-
const [input, select] = await importPkg('bajoCli:@inquirer/input', 'bajoCli:@inquirer/select')
|
|
7
|
-
if (isEmpty(this.schemas)) return this.print.fail('notFound%s', this.print.write('field.schema'), { 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' })
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export default removeRecord
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import postProcess from './lib/post-process.js'
|
|
2
|
-
|
|
3
|
-
async function updateRecord (path, ...args) {
|
|
4
|
-
const { importPkg } = this.app.bajo
|
|
5
|
-
const { isEmpty, map, isPlainObject } = this.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('notFound%s', this.print.write('field.schema'), { exit: this.app.bajo.applet })
|
|
9
|
-
let [schema, id, body] = args
|
|
10
|
-
if (isEmpty(schema)) {
|
|
11
|
-
schema = await select({
|
|
12
|
-
message: this.print.write('selectSchema'),
|
|
13
|
-
choices: map(this.schemas, s => ({ value: s.name }))
|
|
14
|
-
})
|
|
15
|
-
}
|
|
16
|
-
if (isEmpty(id)) {
|
|
17
|
-
id = await input({
|
|
18
|
-
message: this.print.write('enterRecordId'),
|
|
19
|
-
validate: text => isEmpty(text) ? this.print.write('idIsRequired') : true
|
|
20
|
-
})
|
|
21
|
-
}
|
|
22
|
-
if (isEmpty(body)) {
|
|
23
|
-
body = await input({
|
|
24
|
-
message: this.print.write('enterJsonPayload'),
|
|
25
|
-
validate: text => {
|
|
26
|
-
if (isEmpty(text)) return this.print.write('payloadRequired')
|
|
27
|
-
try {
|
|
28
|
-
const parsed = JSON.parse(text)
|
|
29
|
-
if (!isPlainObject(parsed)) throw new Error()
|
|
30
|
-
} catch (err) {
|
|
31
|
-
return this.print.write('payloadMustBeJson')
|
|
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('invalidPayloadSyntax', { 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' })
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export default updateRecord
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
async function schema (path, ...args) {
|
|
2
|
-
const { importPkg } = this.app.bajo
|
|
3
|
-
const { isEmpty, map, find } = this.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('notFound%s', this.print.write('field.schema'), { 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('selectSchema'),
|
|
13
|
-
choices
|
|
14
|
-
})
|
|
15
|
-
}
|
|
16
|
-
const result = find(this.schemas, { name })
|
|
17
|
-
if (!result) return this.print.fail('cantFindSchema%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
|