@carllee1983/dbcli 1.5.2 → 1.7.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/CHANGELOG.md +28 -0
- package/README.dev.md +51 -54
- package/README.md +85 -17
- package/README.zh-TW.md +79 -15
- package/assets/SKILL.md +95 -500
- package/assets/reference.md +510 -0
- package/assets/snippets/.keep +0 -0
- package/assets/snippets/README.md +18 -0
- package/assets/snippets/diag/cache-hit.mysql.sql +19 -0
- package/assets/snippets/diag/cache-hit.postgres.sql +18 -0
- package/assets/snippets/diag/connections.mysql.sql +16 -0
- package/assets/snippets/diag/connections.postgres.sql +16 -0
- package/assets/snippets/diag/db-size.mysql.sql +10 -0
- package/assets/snippets/diag/db-size.postgres.sql +9 -0
- package/assets/snippets/diag/index-usage.mysql.sql +15 -0
- package/assets/snippets/diag/index-usage.postgres.sql +14 -0
- package/assets/snippets/diag/locks.mysql.sql +14 -0
- package/assets/snippets/diag/locks.postgres.sql +15 -0
- package/assets/snippets/diag/long-running.mysql.sql +14 -0
- package/assets/snippets/diag/long-running.postgres.sql +19 -0
- package/assets/snippets/diag/missing-indexes.mysql.sql +13 -0
- package/assets/snippets/diag/missing-indexes.postgres.sql +15 -0
- package/assets/snippets/diag/table-sizes.mysql.sql +14 -0
- package/assets/snippets/diag/table-sizes.postgres.sql +13 -0
- package/dist/cli.mjs +2591 -514
- package/package.json +2 -2
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
# dbcli — full command reference
|
|
2
|
+
|
|
3
|
+
Companion to [SKILL.md](SKILL.md). Exhaustive flags, copy-paste examples, `shell`, `completion`, `upgrade`, `migrate` DDL, and extended MongoDB examples.
|
|
4
|
+
|
|
5
|
+
For cross-engine support status, see `docs/feature-matrix.md` in the repository.
|
|
6
|
+
|
|
7
|
+
## Commands
|
|
8
|
+
|
|
9
|
+
### init
|
|
10
|
+
|
|
11
|
+
Initialize `.dbcli` configuration file. Typically run manually by the developer — avoid running on behalf of the user unless explicitly requested.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
dbcli init # Single connection (v1 format)
|
|
15
|
+
dbcli init --system mysql --host localhost --port 3306 --user root --name mydb
|
|
16
|
+
dbcli init --use-env-refs # Store env var references
|
|
17
|
+
dbcli init --no-interactive --force # Non-interactive mode
|
|
18
|
+
|
|
19
|
+
# MongoDB
|
|
20
|
+
dbcli init --system mongodb --uri "mongodb://user:pass@host:27017/mydb?authSource=admin"
|
|
21
|
+
dbcli init --system mongodb --host localhost --port 27017 --user admin --password secret --name mydb
|
|
22
|
+
dbcli init --system mongodb --host localhost --port 27017 --name mydb # No auth
|
|
23
|
+
|
|
24
|
+
# Multi-connection (v2 format)
|
|
25
|
+
dbcli init --conn-name staging --env-file .env.staging # Named connection with custom env file
|
|
26
|
+
dbcli init --conn-name prod --env-file .env.production --use-env-refs --skip-test
|
|
27
|
+
dbcli init --remove staging # Remove a named connection
|
|
28
|
+
dbcli init --rename staging:production # Rename a connection
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Key options:** `--system`, `--permission`, `--use-env-refs`, `--skip-test`, `--no-interactive`, `--force`, `--conn-name <name>`, `--env-file <path>`, `--remove <name>`, `--rename <old:new>`
|
|
32
|
+
|
|
33
|
+
**MongoDB-specific options:** `--uri <uri>` (full connection URI), `--auth-source <db>` (auth database, default: `admin` when user/password set)
|
|
34
|
+
|
|
35
|
+
**Multi-connection:** Using `--conn-name` or `--env-file` creates a v2 config with named connections. Each connection can have its own env file and permission level. Existing v1 configs are automatically imported as the `default` connection when upgrading.
|
|
36
|
+
|
|
37
|
+
> **AI agent note on `--use-env-refs`:** If an existing `.dbcli` config contains `{"$env": "DB_HOST"}` style references, the connection values are read from environment variables at runtime. Do NOT re-run `init` to replace these references with actual values — the env-ref format is intentional for CI/CD and multi-environment setups.
|
|
38
|
+
|
|
39
|
+
### use
|
|
40
|
+
|
|
41
|
+
Switch or display the default database connection (v2 multi-connection config).
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
dbcli use # Show current default connection
|
|
45
|
+
dbcli use staging # Switch default to 'staging'
|
|
46
|
+
dbcli use --list # List all connections (* marks default)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Any command can also use `--use <name>` to temporarily select a connection without changing the default:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
dbcli query --use staging "SELECT * FROM users LIMIT 10"
|
|
53
|
+
dbcli list --use prod
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Requires v2 config** (created with `dbcli init --conn-name`).
|
|
57
|
+
|
|
58
|
+
### list
|
|
59
|
+
|
|
60
|
+
List all tables (SQL) or collections (MongoDB).
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
dbcli list
|
|
64
|
+
dbcli list --format json
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Permission:** query-only+
|
|
68
|
+
|
|
69
|
+
> **MongoDB:** Lists collections with estimated document count instead of tables.
|
|
70
|
+
|
|
71
|
+
### schema
|
|
72
|
+
|
|
73
|
+
Display table schema or scan entire database.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
dbcli schema # Scan all tables, save to .dbcli/schemas/
|
|
77
|
+
dbcli schema users # Show single table schema
|
|
78
|
+
dbcli schema users --format json
|
|
79
|
+
dbcli schema --refresh # Detect and apply schema changes
|
|
80
|
+
dbcli schema --reset # Clear all schema data and re-fetch
|
|
81
|
+
dbcli schema --reset --force # Skip confirmation
|
|
82
|
+
|
|
83
|
+
# Per-connection schema isolation (v2 multi-connection config)
|
|
84
|
+
dbcli schema --use staging # Scan staging DB; saves to .dbcli/schemas/staging/
|
|
85
|
+
dbcli schema --use prod # Scan prod DB; saves to .dbcli/schemas/prod/
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Options:** `--format <table|json>`, `--refresh`, `--reset`, `--force`, `--use <connection>`
|
|
89
|
+
**Permission:** query-only+
|
|
90
|
+
|
|
91
|
+
**Schema storage (v1.4+):** Schema is persisted as layered files under `.dbcli/schemas/`. With v2 multi-connection config each connection gets its own subdirectory (`.dbcli/schemas/<connection>/`). Run `dbcli schema --use <connection>` once per connection before querying it — otherwise `schema <table>` may return data from the wrong connection's cache.
|
|
92
|
+
|
|
93
|
+
### query
|
|
94
|
+
|
|
95
|
+
Execute SQL query (MySQL/PostgreSQL/MariaDB) or JSON filter/pipeline (MongoDB).
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# SQL databases
|
|
99
|
+
dbcli query "SELECT * FROM users LIMIT 10"
|
|
100
|
+
dbcli query "SELECT id, email FROM users" --format json
|
|
101
|
+
dbcli query "SELECT * FROM logs" --no-limit
|
|
102
|
+
|
|
103
|
+
# MongoDB: JSON filter (find)
|
|
104
|
+
dbcli query '{"status": "active"}' --collection users
|
|
105
|
+
dbcli query '{"age": {"$gt": 18}}' --collection users --format json
|
|
106
|
+
|
|
107
|
+
# MongoDB: aggregation pipeline
|
|
108
|
+
dbcli query '[{"$match": {"status": "active"}}, {"$group": {"_id": "$role", "count": {"$sum": 1}}}]' --collection users
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Options:** `--format <table|json|csv>`, `--limit <number>`, `--no-limit`, `--collection <name>` (MongoDB only)
|
|
112
|
+
**Permission:** query-only+
|
|
113
|
+
|
|
114
|
+
> **MongoDB notes:**
|
|
115
|
+
> - SQL syntax is rejected — use JSON object (filter) or JSON array (pipeline)
|
|
116
|
+
> - `--collection <name>` is required
|
|
117
|
+
> - Auto-limit does not apply; use `$limit` in your pipeline if needed
|
|
118
|
+
|
|
119
|
+
### q
|
|
120
|
+
|
|
121
|
+
Run a saved query snippet by `@name`. Snippets are parameterised SELECT/WITH statements resolved from three layers, with **local > shared > builtin** precedence (a local file always shadows shared and builtin variants of the same key):
|
|
122
|
+
|
|
123
|
+
- `builtin` — bundled with dbcli (e.g. `@diag/*`); read-only at runtime.
|
|
124
|
+
- `.dbcli-shared/queries/` — committed, team-shared.
|
|
125
|
+
- `.dbcli/queries/` — gitignored, personal override.
|
|
126
|
+
|
|
127
|
+
Engine variants (`name.postgres.sql` / `name.mysql.sql`) at the same layer are merged; the variant matching the active connection's engine is selected at execution time.
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
dbcli q @dau # run with declared defaults
|
|
131
|
+
dbcli q @dau --param days=30 --format json # override a param
|
|
132
|
+
dbcli q @analytics/revenue --param-file params.json
|
|
133
|
+
dbcli q @dau --dry-run # show final SQL + bind values
|
|
134
|
+
dbcli q @dau --no-limit # disable size guard wrap
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Options:**
|
|
138
|
+
- `--format <table|json|csv>` — output format (default: `table`)
|
|
139
|
+
- `--param <key=value>` — pass a parameter (repeatable)
|
|
140
|
+
- `--param-file <path>` — JSON object whose keys are param names
|
|
141
|
+
- `--no-limit` — skip the `SELECT * FROM (…) AS _dbcli_guard LIMIT 1000` wrap
|
|
142
|
+
- `--dry-run` — print the bound SQL + values without executing
|
|
143
|
+
- `--use <name>` — pick a v2 named connection
|
|
144
|
+
|
|
145
|
+
**Permission:** query-only+
|
|
146
|
+
|
|
147
|
+
#### Snippet file format
|
|
148
|
+
|
|
149
|
+
Each `.sql` file is plain SQL with optional YAML frontmatter inside a leading `-- ---` block. Lines outside frontmatter form the SQL body.
|
|
150
|
+
|
|
151
|
+
```sql
|
|
152
|
+
-- ---
|
|
153
|
+
-- name: DAU
|
|
154
|
+
-- description: Daily Active Users
|
|
155
|
+
-- engine: postgres # or [postgres, mysql]
|
|
156
|
+
-- params:
|
|
157
|
+
-- days:
|
|
158
|
+
-- type: int # int | string | float | bool | date | datetime
|
|
159
|
+
-- default: 7
|
|
160
|
+
-- required: false
|
|
161
|
+
-- description: lookback window in days
|
|
162
|
+
-- enum: [7, 30, 90]
|
|
163
|
+
-- tags: [analytics]
|
|
164
|
+
-- ---
|
|
165
|
+
SELECT COUNT(DISTINCT user_id) AS dau
|
|
166
|
+
FROM events
|
|
167
|
+
WHERE created_at > NOW() - (:days || ' days')::interval;
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Param placeholders use `:name`. They are rewritten to `$1, $2, …` (Postgres) or `?, ?, …` (MySQL) at execution time and passed as bind values — string interpolation is never used.
|
|
171
|
+
|
|
172
|
+
#### Param type coercion
|
|
173
|
+
|
|
174
|
+
| Declared `type` | Accepts |
|
|
175
|
+
|-----------------|---------|
|
|
176
|
+
| `int` | integer literal |
|
|
177
|
+
| `float` | decimal literal |
|
|
178
|
+
| `bool` | `true` / `false` / `1` / `0` / `yes` / `no` |
|
|
179
|
+
| `string` | any value |
|
|
180
|
+
| `date` | `YYYY-MM-DD` |
|
|
181
|
+
| `datetime` | ISO 8601 |
|
|
182
|
+
|
|
183
|
+
`enum` (optional) restricts the accepted values; mismatch is a hard error. CLI `--param` overrides `--param-file`, which overrides the snippet's `default`.
|
|
184
|
+
|
|
185
|
+
#### Safety invariants
|
|
186
|
+
|
|
187
|
+
- Only `SELECT` / `WITH` (CTE) bodies are accepted; `INSERT/UPDATE/DELETE/DDL` are rejected by the parser.
|
|
188
|
+
- Multi-statement bodies (`SELECT 1; DROP TABLE x`) are rejected.
|
|
189
|
+
- Template syntax inside SQL (`${…}`, `{{…}}`) is rejected — use `:name` parameters.
|
|
190
|
+
- Files exceeding 64 KiB are rejected.
|
|
191
|
+
- `--no-limit` is honoured only at the outermost level; nested subqueries are still wrapped by the size guard.
|
|
192
|
+
|
|
193
|
+
### queries
|
|
194
|
+
|
|
195
|
+
Manage saved snippets — discover, inspect, scaffold, and edit local copies. Mutating
|
|
196
|
+
subcommands (`delete`, `rename`, `copy`, `import`) only operate on the local layer
|
|
197
|
+
(`.dbcli/queries/`); builtin and shared snippets are never modified in place.
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
# Discovery / inspection
|
|
201
|
+
dbcli queries list # all snippets (builtin + shared + local)
|
|
202
|
+
dbcli queries list --tag analytics --engine postgres --format json
|
|
203
|
+
dbcli queries list --source local # only personal overrides
|
|
204
|
+
dbcli queries show @dau # frontmatter + SQL
|
|
205
|
+
dbcli queries show @dau --format json # MCP-shaped contract
|
|
206
|
+
|
|
207
|
+
# Authoring
|
|
208
|
+
dbcli queries new @new/sample # scaffold under .dbcli-shared/queries/
|
|
209
|
+
dbcli queries new @scratch --local # personal copy under .dbcli/queries/
|
|
210
|
+
dbcli queries edit @dau # opens local first, falls back to shared
|
|
211
|
+
dbcli queries edit @dau --shared # always edit the shared file
|
|
212
|
+
dbcli queries check # parse all snippets; exit 1 on errors
|
|
213
|
+
dbcli queries check --strict # promote warnings (e.g. missing engine) to errors
|
|
214
|
+
|
|
215
|
+
# Local-layer file management
|
|
216
|
+
dbcli queries delete @scratch # remove local file(s); prompts unless --force
|
|
217
|
+
dbcli queries delete @scratch --force
|
|
218
|
+
dbcli queries rename @scratch @analytics/dau # rename within local layer; preserves engine suffix
|
|
219
|
+
dbcli queries copy @diag/connections @my/connections # fork builtin/shared into local for editing
|
|
220
|
+
dbcli queries import ./hotfix.sql # import an external .sql into .dbcli/queries/
|
|
221
|
+
dbcli queries import ./hotfix.sql --as @diag/custom # override the snippet key
|
|
222
|
+
dbcli queries export @dau --output dau.sql # write snippet body to a file (stdout if omitted)
|
|
223
|
+
dbcli queries export @diag/connections --engine postgres # pick a variant when multiple engines exist
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**`list` options:** `--format <table|json|csv>`, `--tag <tag>`, `--engine <postgres|mysql>`, `--source <local|shared>`
|
|
227
|
+
**`show` options:** `--format <table|json|csv>`
|
|
228
|
+
**`new` options:** `--local`, `--edit`
|
|
229
|
+
**`edit` options:** `--shared`
|
|
230
|
+
**`check` options:** `--strict`, `--format <table|json|csv>`
|
|
231
|
+
**`delete` options:** `--force` (skip the confirmation prompt). Refuses to run if `@name` has no local copy.
|
|
232
|
+
**`rename` options:** `--force`. Both names must start with `@`. Engine suffix (`.postgres.sql` / `.mysql.sql`) is preserved; frontmatter `name:` is rewritten to the new key.
|
|
233
|
+
**`copy` options:** *(none)*. Copies every variant (all engines) of the source into the local layer; fails if the destination already has a local copy.
|
|
234
|
+
**`import` options:** `--force` (overwrite existing local file), `--as <name>` (override snippet key; defaults to filename without `.postgres` / `.mysql` suffix). Source must be `.sql` and parse cleanly (frontmatter validated, non-SELECT bodies rejected).
|
|
235
|
+
**`export` options:** `--output <path>` (write to file; otherwise stdout), `--engine <postgres|mysql>` (required when the snippet has multiple engine variants).
|
|
236
|
+
|
|
237
|
+
`--format json` on `list` and `show` emits a stable, machine-readable shape — designed to back a future MCP server without further refactor.
|
|
238
|
+
|
|
239
|
+
### insert
|
|
240
|
+
|
|
241
|
+
Insert data into a table.
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
dbcli insert users --data '{"name":"Alice","email":"alice@example.com"}'
|
|
245
|
+
dbcli insert users --data '{"name":"Alice"}' --dry-run
|
|
246
|
+
dbcli insert users --data '{"name":"Alice"}' --force
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Options:** `--data <json>`, `--dry-run`, `--force`
|
|
250
|
+
**Permission:** read-write+
|
|
251
|
+
|
|
252
|
+
### update
|
|
253
|
+
|
|
254
|
+
Update existing data.
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
dbcli update users --where "id=1" --set '{"name":"Bob"}'
|
|
258
|
+
dbcli update users --where "id=1" --set '{"name":"Bob"}' --dry-run
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Options:** `--where <condition>` (required), `--set <json>` (required), `--dry-run`, `--force`
|
|
262
|
+
**Permission:** read-write+
|
|
263
|
+
|
|
264
|
+
### delete
|
|
265
|
+
|
|
266
|
+
Delete data from a table.
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
dbcli delete users --where "id=1"
|
|
270
|
+
dbcli delete users --where "id=1" --dry-run
|
|
271
|
+
dbcli delete users --where "id=1" --force
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Options:** `--where <condition>` (required), `--dry-run`, `--force`
|
|
275
|
+
**Permission:** data-admin+
|
|
276
|
+
|
|
277
|
+
### export
|
|
278
|
+
|
|
279
|
+
Export query results to file or stdout.
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
dbcli export "SELECT * FROM users" --format csv --output users.csv
|
|
283
|
+
dbcli export "SELECT * FROM users" --format csv --output users.csv --force # Skip overwrite confirmation
|
|
284
|
+
dbcli export "SELECT * FROM users" --format json | jq '.[]'
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Options:** `--format <json|csv>` (required), `--output <path>`, `--force`
|
|
288
|
+
**Permission:** query-only+
|
|
289
|
+
|
|
290
|
+
### blacklist
|
|
291
|
+
|
|
292
|
+
Manage sensitive data blacklist to prevent AI access to restricted tables/columns.
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
dbcli blacklist list # Show current blacklist
|
|
296
|
+
dbcli blacklist table add payments # Block entire table
|
|
297
|
+
dbcli blacklist table remove payments # Unblock table
|
|
298
|
+
dbcli blacklist column add users.password # Block specific column
|
|
299
|
+
dbcli blacklist column remove users.password
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**Subcommands:** `list`, `table add <name>`, `table remove <name>`, `column add <table.column>`, `column remove <table.column>`
|
|
303
|
+
|
|
304
|
+
### check
|
|
305
|
+
|
|
306
|
+
Run data health checks on tables.
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
dbcli check users # Check single table
|
|
310
|
+
dbcli check users --format json # JSON output (default)
|
|
311
|
+
dbcli check --all # Check all tables (huge tables auto-skipped)
|
|
312
|
+
dbcli check --all --include-large # Include huge tables
|
|
313
|
+
dbcli check orders --checks nulls,orphans # Specific checks only
|
|
314
|
+
dbcli check orders --sample 10000 # Sample size for large tables
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Checks:** `nulls`, `duplicates`, `orphans`, `emptyStrings`, `rowCount`, `size`
|
|
318
|
+
**Options:** `--all`, `--include-large`, `--checks <types>`, `--sample <number>`, `--format <json|table>`
|
|
319
|
+
**Permission:** query-only+
|
|
320
|
+
|
|
321
|
+
### diff
|
|
322
|
+
|
|
323
|
+
Compare schema snapshots to detect changes.
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
dbcli diff --snapshot before.json # Save current schema snapshot
|
|
327
|
+
dbcli diff --against before.json # Compare current vs snapshot
|
|
328
|
+
dbcli diff --against before.json --format json
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**Options:** `--snapshot <path>`, `--against <path>`, `--format <json|table>`
|
|
332
|
+
**Permission:** query-only+
|
|
333
|
+
|
|
334
|
+
### status
|
|
335
|
+
|
|
336
|
+
Show current configuration status (safe for AI agents, no credentials exposed).
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
dbcli status # JSON output (default)
|
|
340
|
+
dbcli status --format text # Human-readable text output
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Output:** `permission`, `system`, `blacklist` summary, `version`
|
|
344
|
+
**Permission:** query-only+
|
|
345
|
+
|
|
346
|
+
### doctor
|
|
347
|
+
|
|
348
|
+
Run diagnostic checks on environment, configuration, connection, and data.
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
dbcli doctor # Colored text output
|
|
352
|
+
dbcli doctor --format json # JSON output for AI agents
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Checks:**
|
|
356
|
+
- Environment: Bun version, dbcli version (compares with npm registry)
|
|
357
|
+
- Configuration: config file exists/valid, permission level, blacklist completeness (detects unprotected sensitive columns)
|
|
358
|
+
- Connection & Data: database connectivity, schema cache freshness (warns if > 7 days), large table warnings (> 1M rows)
|
|
359
|
+
|
|
360
|
+
> **MongoDB SRV diagnostics:** When the active connection uses `mongodb+srv://`, `doctor` reports whether the current runtime can resolve SRV records directly or only through the DNS-over-HTTPS fallback used by dbcli. This helps spot execution-environment DNS restrictions even when Compass can connect.
|
|
361
|
+
|
|
362
|
+
**Exit code:** 0 if all pass or warnings only, 1 if any error
|
|
363
|
+
**Options:** `--format <text|json>`
|
|
364
|
+
|
|
365
|
+
### completion
|
|
366
|
+
|
|
367
|
+
Generate shell completion scripts for tab auto-complete.
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
dbcli completion bash # Output bash completion script
|
|
371
|
+
dbcli completion zsh # Output zsh completion script
|
|
372
|
+
dbcli completion fish # Output fish completion script
|
|
373
|
+
dbcli completion --install # Auto-detect shell and install
|
|
374
|
+
dbcli completion --install zsh # Install for specific shell
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**Supported shells:** bash, zsh, fish
|
|
378
|
+
|
|
379
|
+
### upgrade
|
|
380
|
+
|
|
381
|
+
Check for updates and self-upgrade dbcli to the latest version from npm.
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
dbcli upgrade # Check and upgrade if newer version available
|
|
385
|
+
dbcli upgrade --check # Only check, do not upgrade
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
**Options:** `--check`
|
|
389
|
+
|
|
390
|
+
**Background check:** Every command silently checks the npm registry for a newer version (at most once per 24 hours, cached in `.dbcli/version-check.json`). If a newer version is found, a one-line hint is printed to stderr after the command completes. Pass `-q` / `--quiet` to suppress the hint.
|
|
391
|
+
|
|
392
|
+
### `dbcli shell`
|
|
393
|
+
|
|
394
|
+
Start an interactive database shell.
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
dbcli shell # Interactive mode with SQL + dbcli commands
|
|
398
|
+
dbcli shell --sql # SQL-only mode
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
Inside the shell:
|
|
402
|
+
- Type SQL statements ending with `;` to execute
|
|
403
|
+
- Type dbcli commands without the `dbcli` prefix (e.g., `schema users`)
|
|
404
|
+
- Use Tab for auto-completion (SQL keywords, table names, column names)
|
|
405
|
+
- Type `.help` for meta commands (.quit, .clear, .format, .history, .timing)
|
|
406
|
+
- Multi-line SQL: keeps accumulating until `;` is found
|
|
407
|
+
- History persists across sessions (~/.dbcli_history)
|
|
408
|
+
|
|
409
|
+
### migrate
|
|
410
|
+
|
|
411
|
+
Schema DDL operations. **All commands default to dry-run** — use `--execute` to actually run the SQL. Destructive operations (DROP) also require `--force`.
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
# Create table
|
|
415
|
+
dbcli migrate create posts \
|
|
416
|
+
--column "id:serial:pk" \
|
|
417
|
+
--column "title:varchar(200):not-null" \
|
|
418
|
+
--column "body:text" \
|
|
419
|
+
--column "created_at:timestamp:default=now()"
|
|
420
|
+
|
|
421
|
+
# Drop table (dry-run by default)
|
|
422
|
+
dbcli migrate drop posts
|
|
423
|
+
dbcli migrate drop posts --execute --force # Actually drop
|
|
424
|
+
|
|
425
|
+
# Add/drop/alter column
|
|
426
|
+
dbcli migrate add-column users bio text --nullable
|
|
427
|
+
dbcli migrate drop-column users temp_field --execute --force
|
|
428
|
+
dbcli migrate alter-column users name --type "varchar(200)"
|
|
429
|
+
dbcli migrate alter-column users email --rename user_email
|
|
430
|
+
dbcli migrate alter-column users status --set-default "'active'"
|
|
431
|
+
dbcli migrate alter-column users bio --drop-default
|
|
432
|
+
dbcli migrate alter-column users bio --set-nullable
|
|
433
|
+
dbcli migrate alter-column users email --drop-nullable
|
|
434
|
+
|
|
435
|
+
# Index management
|
|
436
|
+
dbcli migrate add-index users --columns email --unique
|
|
437
|
+
dbcli migrate add-index users --columns "last_name,first_name" --name idx_fullname
|
|
438
|
+
dbcli migrate drop-index idx_fullname --execute --force
|
|
439
|
+
|
|
440
|
+
# Constraint management
|
|
441
|
+
dbcli migrate add-constraint orders --fk user_id --references users.id --on-delete cascade
|
|
442
|
+
dbcli migrate add-constraint users --unique email
|
|
443
|
+
dbcli migrate add-constraint users --check "age >= 0"
|
|
444
|
+
dbcli migrate drop-constraint orders fk_orders_user_id --execute --force
|
|
445
|
+
|
|
446
|
+
# Enum (PostgreSQL only — MySQL uses inline ENUM in column type)
|
|
447
|
+
dbcli migrate add-enum status active inactive suspended
|
|
448
|
+
dbcli migrate alter-enum status --add-value archived
|
|
449
|
+
dbcli migrate drop-enum status --execute --force
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
**Column spec format:** `name:type[:modifier[:modifier...]]`
|
|
453
|
+
- Modifiers: `pk`, `not-null`, `unique`, `auto-increment`, `default=<value>`, `references=<table>.<column>`
|
|
454
|
+
- Serial types: `serial`, `bigserial`, `smallserial` (auto-expand per DB dialect)
|
|
455
|
+
|
|
456
|
+
**Options (all subcommands):** `--execute`, `--force`, `--config <path>`
|
|
457
|
+
**Permission:** admin
|
|
458
|
+
|
|
459
|
+
**AI agent note:** Always use dry-run first (no `--execute`) to preview generated SQL. Only add `--execute` after confirming the SQL is correct. For DROP operations, both `--execute` and `--force` are required.
|
|
460
|
+
|
|
461
|
+
## MongoDB Support
|
|
462
|
+
|
|
463
|
+
MongoDB connections use a JSON-based query model instead of SQL. Treat MongoDB support as a narrower document-database path, not as a full SQL feature equivalent.
|
|
464
|
+
|
|
465
|
+
Atlas-style `mongodb+srv://` URIs are supported. `list` and `query` run against the database configured for the connection, and `query` always requires `--collection <name>`.
|
|
466
|
+
|
|
467
|
+
**Supported commands:** `init`, `use`, `list`, `schema`, `query`, `insert`, `update`, `delete`, `status`, `shell`, `doctor`, `upgrade`, `completion`
|
|
468
|
+
|
|
469
|
+
**Limited support:**
|
|
470
|
+
|
|
471
|
+
- `schema` samples collection documents to infer field names/types. It does not provide relational constraints, primary keys, foreign keys, or reliable index metadata.
|
|
472
|
+
- `query` accepts only JSON object filters or aggregation pipeline arrays and always requires `--collection <name>`.
|
|
473
|
+
- `insert` inserts one JSON document into the named collection.
|
|
474
|
+
- `update` accepts a JSON filter in `--where` or simple `key=value` conditions. If `--set` does not use MongoDB update operators such as `$set`, dbcli wraps it in `$set`.
|
|
475
|
+
- `delete` deletes all documents matching the JSON/simple filter.
|
|
476
|
+
- MongoDB write paths do not currently provide the same SQL dry-run, relational schema validation, or column-level blacklist filtering guarantees as SQL writes.
|
|
477
|
+
- `shell` blocks raw SQL for MongoDB; use `query <json> --collection <name>` inside the shell.
|
|
478
|
+
|
|
479
|
+
**Not supported (exit with error):** `q` saved-query execution, `export`, `diff`, `migrate`
|
|
480
|
+
|
|
481
|
+
**Not a supported MongoDB target:** `check` is designed for relational health checks and emits SQL-style checks.
|
|
482
|
+
|
|
483
|
+
### MongoDB-specific workflow
|
|
484
|
+
|
|
485
|
+
```bash
|
|
486
|
+
# 1. Initialize (URI or individual params)
|
|
487
|
+
dbcli init --system mongodb --uri "mongodb+srv://user:pass@cluster.example.mongodb.net/mydb"
|
|
488
|
+
|
|
489
|
+
# 2. List collections
|
|
490
|
+
dbcli list --format json
|
|
491
|
+
|
|
492
|
+
# 3. Query with JSON filter (find) or pipeline (aggregate)
|
|
493
|
+
dbcli query '{}' --collection orders --format json # All documents
|
|
494
|
+
dbcli query '{"status": "paid"}' --collection orders # Filter
|
|
495
|
+
dbcli query '[{"$match": {"status":"paid"}}, {"$count":"total"}]' --collection orders # Pipeline
|
|
496
|
+
|
|
497
|
+
# 4. Document writes (permission-gated; no SQL dry-run semantics)
|
|
498
|
+
dbcli insert orders --data '{"status":"paid","total":42}'
|
|
499
|
+
dbcli update orders --where '{"status":"pending"}' --set '{"status":"paid"}'
|
|
500
|
+
dbcli delete orders --where '{"status":"cancelled"}' --force
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
### Query syntax
|
|
504
|
+
|
|
505
|
+
| Intent | Syntax |
|
|
506
|
+
|--------|--------|
|
|
507
|
+
| All documents | `'{}'` |
|
|
508
|
+
| Field filter | `'{"field": "value"}'` |
|
|
509
|
+
| Comparison | `'{"age": {"$gt": 18}}'` |
|
|
510
|
+
| Aggregation | `'[{"$match": {...}}, {"$group": {...}}]'` |
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Built-in snippets
|
|
2
|
+
|
|
3
|
+
Files under this directory are bundled with dbcli and resolved at runtime as
|
|
4
|
+
the `builtin` tier. Every file is a valid `.sql` snippet.
|
|
5
|
+
|
|
6
|
+
## Naming
|
|
7
|
+
|
|
8
|
+
- Single-engine variant: `<topic>.<engine>.sql` — loader derives key
|
|
9
|
+
`@<dir>/<topic>` and engine from the suffix.
|
|
10
|
+
- Cross-engine variant: `<topic>.sql` with explicit
|
|
11
|
+
`engine: [postgres, mysql]` in frontmatter.
|
|
12
|
+
|
|
13
|
+
## Override
|
|
14
|
+
|
|
15
|
+
Users can shadow any built-in snippet by placing a same-key file in
|
|
16
|
+
`.dbcli-shared/queries/` (team) or `.dbcli/queries/` (personal). Override is
|
|
17
|
+
per-engine: a local `connections.postgres.sql` only shadows the postgres
|
|
18
|
+
variant; the mysql variant is still served from builtin.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
-- ---
|
|
2
|
+
-- name: InnoDB buffer pool hit ratio (mysql)
|
|
3
|
+
-- description: Reads from disk vs. read requests from the buffer pool.
|
|
4
|
+
-- engine: mysql
|
|
5
|
+
-- ---
|
|
6
|
+
SELECT
|
|
7
|
+
(SELECT VARIABLE_VALUE FROM performance_schema.global_status
|
|
8
|
+
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads') AS pool_reads,
|
|
9
|
+
(SELECT VARIABLE_VALUE FROM performance_schema.global_status
|
|
10
|
+
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests') AS pool_read_requests,
|
|
11
|
+
ROUND(
|
|
12
|
+
1 -
|
|
13
|
+
(SELECT VARIABLE_VALUE FROM performance_schema.global_status
|
|
14
|
+
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads')
|
|
15
|
+
/
|
|
16
|
+
NULLIF(
|
|
17
|
+
(SELECT VARIABLE_VALUE FROM performance_schema.global_status
|
|
18
|
+
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests'), 0)
|
|
19
|
+
, 4) AS hit_ratio;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- ---
|
|
2
|
+
-- name: Cache hit ratio (postgres)
|
|
3
|
+
-- description: Heap and index buffer cache hit ratios across user tables.
|
|
4
|
+
-- engine: postgres
|
|
5
|
+
-- ---
|
|
6
|
+
SELECT SUM(heap_blks_read) AS heap_read,
|
|
7
|
+
SUM(heap_blks_hit) AS heap_hit,
|
|
8
|
+
ROUND(
|
|
9
|
+
SUM(heap_blks_hit)::numeric
|
|
10
|
+
/ NULLIF(SUM(heap_blks_hit) + SUM(heap_blks_read), 0)
|
|
11
|
+
, 4) AS heap_hit_ratio,
|
|
12
|
+
SUM(idx_blks_read) AS idx_read,
|
|
13
|
+
SUM(idx_blks_hit) AS idx_hit,
|
|
14
|
+
ROUND(
|
|
15
|
+
SUM(idx_blks_hit)::numeric
|
|
16
|
+
/ NULLIF(SUM(idx_blks_hit) + SUM(idx_blks_read), 0)
|
|
17
|
+
, 4) AS idx_hit_ratio
|
|
18
|
+
FROM pg_statio_user_tables;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-- ---
|
|
2
|
+
-- name: Active connections (mysql)
|
|
3
|
+
-- description: Non-sleep processes ordered by elapsed time.
|
|
4
|
+
-- engine: mysql
|
|
5
|
+
-- ---
|
|
6
|
+
SELECT id,
|
|
7
|
+
user,
|
|
8
|
+
host,
|
|
9
|
+
db,
|
|
10
|
+
command,
|
|
11
|
+
time AS duration_seconds,
|
|
12
|
+
state,
|
|
13
|
+
info AS query
|
|
14
|
+
FROM information_schema.processlist
|
|
15
|
+
WHERE command <> 'Sleep'
|
|
16
|
+
ORDER BY time DESC;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-- ---
|
|
2
|
+
-- name: Active connections (postgres)
|
|
3
|
+
-- description: Active sessions excluding idle, ordered by query start.
|
|
4
|
+
-- engine: postgres
|
|
5
|
+
-- ---
|
|
6
|
+
SELECT pid,
|
|
7
|
+
usename AS user,
|
|
8
|
+
application_name AS app,
|
|
9
|
+
client_addr AS client,
|
|
10
|
+
state,
|
|
11
|
+
NOW() - query_start AS duration,
|
|
12
|
+
query
|
|
13
|
+
FROM pg_stat_activity
|
|
14
|
+
WHERE state IS NOT NULL
|
|
15
|
+
AND state <> 'idle'
|
|
16
|
+
ORDER BY query_start;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
-- ---
|
|
2
|
+
-- name: Database size (mysql)
|
|
3
|
+
-- description: Total data + index size per schema in MB.
|
|
4
|
+
-- engine: mysql
|
|
5
|
+
-- ---
|
|
6
|
+
SELECT table_schema AS `database`,
|
|
7
|
+
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS size_mb
|
|
8
|
+
FROM information_schema.tables
|
|
9
|
+
GROUP BY table_schema
|
|
10
|
+
ORDER BY size_mb DESC;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- ---
|
|
2
|
+
-- name: Database size (postgres)
|
|
3
|
+
-- description: Each database with pretty-printed total size.
|
|
4
|
+
-- engine: postgres
|
|
5
|
+
-- ---
|
|
6
|
+
SELECT datname AS database,
|
|
7
|
+
pg_size_pretty(pg_database_size(datname)) AS size
|
|
8
|
+
FROM pg_database
|
|
9
|
+
ORDER BY pg_database_size(datname) DESC;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- ---
|
|
2
|
+
-- name: Index usage (mysql)
|
|
3
|
+
-- description: Index I/O wait counts ordered by total uses.
|
|
4
|
+
-- engine: mysql
|
|
5
|
+
-- ---
|
|
6
|
+
SELECT object_schema AS `schema`,
|
|
7
|
+
object_name AS `table`,
|
|
8
|
+
index_name,
|
|
9
|
+
count_star AS uses,
|
|
10
|
+
count_read AS reads,
|
|
11
|
+
count_write AS writes
|
|
12
|
+
FROM performance_schema.table_io_waits_summary_by_index_usage
|
|
13
|
+
WHERE object_schema NOT IN ('mysql','performance_schema','sys')
|
|
14
|
+
AND index_name IS NOT NULL
|
|
15
|
+
ORDER BY count_star ASC;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- ---
|
|
2
|
+
-- name: Index usage (postgres)
|
|
3
|
+
-- description: Indexes ordered by scan count (low scans = candidates to drop).
|
|
4
|
+
-- engine: postgres
|
|
5
|
+
-- ---
|
|
6
|
+
SELECT schemaname AS schema,
|
|
7
|
+
relname AS table,
|
|
8
|
+
indexrelname AS index,
|
|
9
|
+
idx_scan AS scans,
|
|
10
|
+
idx_tup_read AS tuples_read,
|
|
11
|
+
idx_tup_fetch AS tuples_fetched,
|
|
12
|
+
pg_size_pretty(pg_relation_size(indexrelid)) AS index_size
|
|
13
|
+
FROM pg_stat_user_indexes
|
|
14
|
+
ORDER BY idx_scan ASC;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- ---
|
|
2
|
+
-- name: Lock waits (mysql)
|
|
3
|
+
-- description: InnoDB lock waits with waiting and blocking transactions.
|
|
4
|
+
-- engine: mysql
|
|
5
|
+
-- ---
|
|
6
|
+
SELECT waiting.trx_mysql_thread_id AS waiting_thread,
|
|
7
|
+
waiting.trx_query AS waiting_query,
|
|
8
|
+
blocking.trx_mysql_thread_id AS blocking_thread,
|
|
9
|
+
blocking.trx_query AS blocking_query
|
|
10
|
+
FROM performance_schema.data_lock_waits AS w
|
|
11
|
+
JOIN information_schema.innodb_trx AS waiting
|
|
12
|
+
ON w.requesting_engine_transaction_id = waiting.trx_id
|
|
13
|
+
JOIN information_schema.innodb_trx AS blocking
|
|
14
|
+
ON w.blocking_engine_transaction_id = blocking.trx_id;
|