giswater-cli 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. giswater_admin/README.md +733 -0
  2. giswater_admin/__init__.py +47 -0
  3. giswater_admin/__main__.py +11 -0
  4. giswater_admin/__version__.py +3 -0
  5. giswater_admin/adapters/__init__.py +0 -0
  6. giswater_admin/adapters/psycopg2_adapter.py +165 -0
  7. giswater_admin/cli/__init__.py +5 -0
  8. giswater_admin/cli/context.py +65 -0
  9. giswater_admin/cli/main.py +46 -0
  10. giswater_admin/cli/parser/__init__.py +32 -0
  11. giswater_admin/cli/parser/db.py +22 -0
  12. giswater_admin/cli/parser/global_.py +64 -0
  13. giswater_admin/cli/parser/manifest.py +22 -0
  14. giswater_admin/cli/parser/meta.py +66 -0
  15. giswater_admin/cli/parser/network.py +40 -0
  16. giswater_admin/cli/parser/schema_group.py +113 -0
  17. giswater_admin/cli/version_args.py +14 -0
  18. giswater_admin/commands/__init__.py +1 -0
  19. giswater_admin/commands/_helpers.py +269 -0
  20. giswater_admin/commands/config.py +49 -0
  21. giswater_admin/commands/create.py +259 -0
  22. giswater_admin/commands/dbmodel.py +179 -0
  23. giswater_admin/commands/drop.py +41 -0
  24. giswater_admin/commands/init_db.py +75 -0
  25. giswater_admin/commands/manifest.py +56 -0
  26. giswater_admin/commands/network.py +83 -0
  27. giswater_admin/commands/schema_cmd.py +245 -0
  28. giswater_admin/commands/update.py +151 -0
  29. giswater_admin/commands/update_network.py +121 -0
  30. giswater_admin/commands/version.py +38 -0
  31. giswater_admin/conn.py +113 -0
  32. giswater_admin/engine/__init__.py +74 -0
  33. giswater_admin/engine/builder.py +640 -0
  34. giswater_admin/engine/cancel.py +22 -0
  35. giswater_admin/engine/changelog.py +208 -0
  36. giswater_admin/engine/manifest.py +238 -0
  37. giswater_admin/engine/network_update.py +228 -0
  38. giswater_admin/engine/schema_catalog.py +904 -0
  39. giswater_admin/engine/sql_runner.py +191 -0
  40. giswater_admin/engine/templating.py +83 -0
  41. giswater_admin/engine/timing_report.py +127 -0
  42. giswater_admin/engine/version_guard.py +43 -0
  43. giswater_admin/install/__init__.py +61 -0
  44. giswater_admin/install/config.py +147 -0
  45. giswater_admin/install/dbmodel_paths.py +98 -0
  46. giswater_admin/install/releases.py +167 -0
  47. giswater_admin/install/schema_version.py +168 -0
  48. giswater_admin/log_format.py +308 -0
  49. giswater_admin/output.py +132 -0
  50. giswater_admin/paths.py +27 -0
  51. giswater_admin/releases.py +33 -0
  52. giswater_admin/user_config.py +35 -0
  53. giswater_cli-0.1.1.dist-info/METADATA +761 -0
  54. giswater_cli-0.1.1.dist-info/RECORD +58 -0
  55. giswater_cli-0.1.1.dist-info/WHEEL +5 -0
  56. giswater_cli-0.1.1.dist-info/entry_points.txt +2 -0
  57. giswater_cli-0.1.1.dist-info/licenses/LICENSE +675 -0
  58. giswater_cli-0.1.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,733 @@
1
+ # giswater-admin
2
+
3
+ Headless CLI and engine for the Giswater database schema lifecycle (create, upgrade, drop, inspect). It reads the same YAML manifests under `dbmodel/manifests/` and runs the same `SchemaBuilder` as the QGIS plugin (`GwSchemaBuilderTask` + `QtDbAdapter`), so automation, CI, and the desktop UI do not diverge on SQL execution logic.
4
+
5
+ **See also:** [dbmodel README — Schema architecture](../dbmodel/README.md#schema-architecture) · [dbmodel README — Testing](../dbmodel/README.md#testing)
6
+
7
+ ## Table of contents
8
+
9
+ 1. [Overview](#overview)
10
+ 2. [Where to run it](#where-to-run-it)
11
+ 3. [Architecture](#architecture)
12
+ 4. [Install](#install)
13
+ 5. [Connection](#connection)
14
+ 6. [Invocation rules](#invocation-rules)
15
+ 7. [Global options](#global-options)
16
+ 8. [Commands reference](#commands-reference)
17
+ 9. [Kinds and manifest profiles](#kinds-and-manifest-profiles)
18
+ 10. [Timing and output](#timing-and-output)
19
+ 11. [QGIS integration](#qgis-integration)
20
+ 12. [Unit tests](#unit-tests)
21
+ 13. [Extending the model](#extending-the-model)
22
+ 14. [Keeping docs in sync](#keeping-docs-in-sync)
23
+
24
+ ---
25
+
26
+ ## Overview
27
+
28
+ | Layer | Path | Role |
29
+ |-------|------|------|
30
+ | CLI entry | `giswater_admin/cli/` | Argument parsing, dispatch, context |
31
+ | Commands | `giswater_admin/commands/` | Subcommand handlers (`create`, `dbmodel`, …) |
32
+ | Install | `giswater_admin/install/` | User config, dbmodel cache, release downloads |
33
+ | Engine | `giswater_admin/engine/` | `SchemaBuilder`, manifests, SQL runner (shared with QGIS) |
34
+ | Shared I/O | `conn.py`, `output.py`, `log_format.py` | Connection, stdout/stderr formatting |
35
+
36
+ Legacy shims at package root (`paths.py`, `user_config.py`, `releases.py`) re-export from `install/` for backward compatibility.
37
+
38
+ | Piece | Role |
39
+ |-------|------|
40
+ | `cli/parser/` | Subcommand registration split by domain |
41
+ | `cli/context.py` | Resolve dbmodel path and schema version before dispatch |
42
+ | `cli/main.py` | `main()` entrypoint |
43
+ | `dbmodel/manifests/*.yaml` | Phase graphs per schema kind |
44
+ | `dbmodel/schemas/` | SQL sources (DDL, functions, updates, samples) |
45
+
46
+ Typical flow for a new database:
47
+
48
+ 1. Create an empty PostgreSQL database (outside this CLI).
49
+ 2. `db init` — cluster extensions once per database.
50
+ 3. `schema main create` / `schema addon create` — build project and satellite schemas.
51
+ 4. `schema addon integrate` — wire satellites into ws/ud parents.
52
+ 5. `network show` — inspect topology; `network update` — lockstep upgrade.
53
+
54
+ ---
55
+
56
+ ## Where to run it
57
+
58
+ | Context | Command |
59
+ |---------|---------|
60
+ | **Global CLI (recommended)** | `gw create …` after `pipx install giswater-cli` |
61
+ | Plugin repo checkout | `python3 -m giswater_admin …` or `gw …` with dev dbmodel |
62
+ | Custom dbmodel tree | `gw create … --dbmodel-path /path/to/dbmodel` |
63
+ | CI / Docker tests | See [dbmodel testing](../dbmodel/README.md#testing) |
64
+ | QGIS | N/A (in-process) | `GwSchemaBuilderTask` — no subprocess |
65
+
66
+ **Requirements:** Python 3.9+, PostgreSQL with PostGIS/pgRouting on the **server**.
67
+
68
+ **dbmodel resolution order** (when `--dbmodel-path` is omitted):
69
+
70
+ 1. `--dbmodel-path`
71
+ 2. `GW_DBMODEL_PATH` environment variable
72
+ 3. User config (`gw dbmodel use …`)
73
+ 4. Sibling `dbmodel/` in a plugin repo checkout
74
+
75
+ If nothing matches, run `gw dbmodel install latest` or `gw dbmodel use dev --root /path/to/repo`.
76
+
77
+ ---
78
+
79
+ ## Architecture
80
+
81
+ ```mermaid
82
+ flowchart TB
83
+ subgraph hosts [Execution contexts]
84
+ CLI["gw / python -m giswater_admin"]
85
+ QGIS["GwSchemaBuilderTask + QtDbAdapter"]
86
+ CI["dbmodel/test/bootstrap_inner.sh"]
87
+ end
88
+ subgraph engine [giswater_admin/engine]
89
+ Manifest["manifests/*.yaml"]
90
+ Builder["SchemaBuilder"]
91
+ Runner["sql_runner"]
92
+ end
93
+ subgraph dbmodel_tree [dbmodel/]
94
+ Schemas["schemas/..."]
95
+ Updates["updates M/m/p"]
96
+ end
97
+ PG[(PostgreSQL)]
98
+ CLI --> Builder
99
+ QGIS --> Builder
100
+ CI --> CLI
101
+ Builder --> Manifest
102
+ Builder --> Runner
103
+ Runner --> Schemas
104
+ Runner --> Updates
105
+ Runner --> PG
106
+ ```
107
+
108
+ **Phase types** (declared in manifests, implemented in `engine/manifest.py`):
109
+
110
+ | Type | Behavior |
111
+ |------|----------|
112
+ | `sql_dir` | Run every `*.sql` in listed folders (optional `recursive`) |
113
+ | `version_walk` | Walk `updates/<M>/<m>/<p>/` semver-ordered; `roots:` for ws/ud (common then kind) |
114
+ | `sql_function` | `SELECT schema.fn($${JSON}$$)` (e.g. `lastprocess`) |
115
+ | `sql_file` | Single file with optional `fallback_source` |
116
+ | `sql_inline` | Literal SQL in YAML |
117
+
118
+ ---
119
+
120
+ ## Install
121
+
122
+ ### Global CLI (Windows / Linux / macOS)
123
+
124
+ Install [pipx](https://pipx.pypa.io/) once, then install the CLI package:
125
+
126
+ ```bash
127
+ # macOS
128
+ brew install pipx && pipx ensurepath
129
+
130
+ # Windows / Linux (if pipx is not installed yet)
131
+ python3 -m pip install --user pipx
132
+ python3 -m pipx ensurepath
133
+
134
+ # All platforms
135
+ pipx install giswater-cli
136
+ ```
137
+
138
+ Download a published dbmodel (from the same plugin ZIP used by QGIS):
139
+
140
+ ```bash
141
+ gw dbmodel install latest --set-active
142
+ gw version
143
+ ```
144
+
145
+ Typical first run:
146
+
147
+ ```bash
148
+ gw db init --conn "postgresql://user:pass@127.0.0.1:5432/mydb"
149
+ gw schema main create --type ws --name demo --profile empty --conn "postgresql://user:pass@127.0.0.1:5432/mydb"
150
+ ```
151
+
152
+ **Development without a release** (use your local checkout):
153
+
154
+ ```bash
155
+ gw dbmodel use dev --root /path/to/giswater_qgis_plugin
156
+ gw schema main create --type ws --name test_dev --conn "$CONN" --check
157
+ ```
158
+
159
+ Config and cache locations:
160
+
161
+ | OS | Config | Release cache |
162
+ |----|--------|---------------|
163
+ | Linux / macOS | `~/.config/giswater/config.yaml` | `~/.local/share/giswater/releases/` |
164
+ | Windows | `%APPDATA%/giswater/config.yaml` | `%LOCALAPPDATA%/giswater/releases/` |
165
+
166
+ ### From the plugin repository (contributors)
167
+
168
+ ```bash
169
+ cd /path/to/giswater_qgis_plugin
170
+ python3 -m pip install -e .
171
+ # or legacy:
172
+ python3 -m pip install -r giswater_admin/requirements.txt
173
+ ```
174
+
175
+ Optional virtualenv:
176
+
177
+ ```bash
178
+ python3 -m venv .venv && source .venv/bin/activate
179
+ pip install -e .
180
+ ```
181
+
182
+ **OS packages (server side)** — names vary by distro; install PostGIS and pgRouting for your PostgreSQL major version:
183
+
184
+ - Debian/Ubuntu: `postgresql-16-postgis-3`, `postgresql-16-pgrouting`, …
185
+ - macOS (Homebrew): `postgresql@16`, `postgis`
186
+ - Windows: PostGIS/pgRouting matching your PostgreSQL installer
187
+
188
+ Verify:
189
+
190
+ ```bash
191
+ gw --help
192
+ # or
193
+ python3 -m giswater_admin --help
194
+ ```
195
+
196
+ ### dbmodel management commands
197
+
198
+ | Command | Purpose |
199
+ |---------|---------|
200
+ | `gw dbmodel install latest` | Download plugin ZIP and cache `dbmodel/` |
201
+ | `gw dbmodel install 4.9.0` | Install a specific release |
202
+ | `gw dbmodel list` | Cached versions + remote latest |
203
+ | `gw dbmodel use latest` | Activate latest cached/remote version |
204
+ | `gw dbmodel use dev --root PATH` | Use `PATH/dbmodel` from a checkout |
205
+ | `gw config get` / `gw config set KEY VALUE` | Persistent settings |
206
+
207
+ ---
208
+
209
+ ## Versioning
210
+
211
+ Two independent version numbers:
212
+
213
+ | Version | Example | Meaning |
214
+ |---------|---------|---------|
215
+ | **CLI** (`gw version` → `cli`) | `0.1.0` | The `giswater-cli` tool: commands, fixes, packaging. Bump with [`scripts/bump_cli_version.py`](../scripts/bump_cli_version.py). |
216
+ | **Schema / dbmodel** (`gw version` → `dbmodel-version`) | `4.15.0` | Giswater release whose SQL and `updates/` patches are applied. Comes from the active dbmodel, not from the CLI version. |
217
+
218
+ A single CLI release can create or upgrade schemas for any installed dbmodel version:
219
+
220
+ ```bash
221
+ gw dbmodel install 4.14.0 && gw dbmodel use 4.14.0
222
+ gw create --kind ws --schema legacy --conn "$CONN"
223
+
224
+ gw dbmodel install 4.16.0 && gw dbmodel use 4.16.0
225
+ gw create --kind ws --schema current --conn "$CONN"
226
+ ```
227
+
228
+ Use `--plugin-version X.Y.Z` to override the schema release when auto-detection is not possible (e.g. a custom `--dbmodel-path` without `metadata.txt`).
229
+
230
+ ### CLI releases (`cli-v*`)
231
+
232
+ The CLI is released **independently** from the QGIS plugin:
233
+
234
+ | Event | Tag example | Publishes |
235
+ |-------|-------------|-----------|
236
+ | Plugin Giswater | `v4.16.0` | `giswater.zip` + dbmodel (see repo `release-plugin.yml`) |
237
+ | CLI `gw` | `cli-v0.1.0` | PyPI `giswater-cli` + wheel on GitHub Release |
238
+
239
+ Maintain [`giswater_admin/CHANGELOG.md`](CHANGELOG.md) (Keep a Changelog format) before each release.
240
+
241
+ **First release (`0.1.0`)** — document changes under `## [Unreleased]`, then:
242
+
243
+ ```bash
244
+ python3 scripts/prepare_cli_release.py 0.1.0 --create-github-release
245
+ python3 scripts/prepare_cli_release.py 0.1.0 --execute --create-github-release
246
+ ```
247
+
248
+ (`pyproject.toml` and `giswater_admin/__version__.py` must already be `0.1.0`.)
249
+
250
+ **Subsequent releases** (e.g. `0.2.0`):
251
+
252
+ ```bash
253
+ python3 scripts/bump_cli_version.py 0.2.0
254
+ # Add changes under ## [Unreleased] in giswater_admin/CHANGELOG.md
255
+ python3 scripts/prepare_cli_release.py 0.2.0 --create-github-release
256
+ python3 scripts/prepare_cli_release.py 0.2.0 --execute --create-github-release
257
+ ```
258
+
259
+ When the GitHub Release is published, CI (`.github/workflows/release-cli.yml`) runs tests, validates versions, builds `dist/*`, publishes to PyPI via OIDC (Trusted Publisher, environment `pypi`), and attaches wheels to the release.
260
+
261
+ **One-time PyPI setup:** register a pending publisher at https://pypi.org/manage/account/publishing/ with project `giswater-cli`, owner `Giswater`, repository `giswater_qgis_plugin`, workflow `release-cli.yml`, environment `pypi`. Create the matching `pypi` environment in GitHub repo settings.
262
+
263
+ Users install the tool once (`pipx install giswater-cli`) and refresh schema SQL with `gw dbmodel install` when a new plugin version ships.
264
+
265
+ ### Testing locally
266
+
267
+ ```bash
268
+ cd /path/to/giswater_qgis_plugin
269
+ python3 -m pip install -e .
270
+
271
+ # Ensure gw is on PATH (macOS user install example)
272
+ export PATH="$HOME/Library/Python/3.9/bin:$PATH"
273
+
274
+ gw version
275
+ python3 -m pytest test/cli/ -q
276
+
277
+ # Offline schema plan (no DB)
278
+ gw create --kind ws --schema test --profile empty --check \
279
+ --conn "postgresql://user@127.0.0.1:5432/mydb"
280
+ ```
281
+
282
+ ---
283
+
284
+ ## Connection
285
+
286
+ Resolution order (first match wins):
287
+
288
+ 1. `--conn` — `postgresql://user:pass@host:port/dbname` (or `postgres://…`)
289
+ 2. `--config` — YAML with `host`, `port`, `user`, `password`, `dbname`, and/or `service`
290
+ 3. Environment — `PGHOST`, `PGPORT`, `PGUSER`, `PGPASSWORD`, `PGDATABASE`, `PGSERVICE`
291
+
292
+ **Superuser:** mutating commands (`db init`, `schema` create/integrate/update/drop, `network update`, and `--check` with a live connection) require a PostgreSQL **superuser**. Read-only commands (`schema list`, `network show`) work with any role that can `SELECT` Giswater schemas and `pg_catalog`.
293
+
294
+ ### Linux / macOS
295
+
296
+ ```bash
297
+ export CONN='postgresql://gisadmin:secret@127.0.0.1:5432/giswater_cli'
298
+ python3 -m giswater_admin status --conn "$CONN"
299
+ ```
300
+
301
+ ### Windows (PowerShell)
302
+
303
+ ```powershell
304
+ $env:CONN = "postgresql://gisadmin:secret@127.0.0.1:5432/giswater_cli"
305
+ py -3 -m giswater_admin status --conn $env:CONN
306
+ ```
307
+
308
+ ### Config file
309
+
310
+ ```yaml
311
+ host: 127.0.0.1
312
+ port: 5432
313
+ user: gisadmin
314
+ password: secret
315
+ dbname: giswater_cli
316
+ ```
317
+
318
+ ```bash
319
+ python3 -m giswater_admin status --config /path/conn.yaml
320
+ ```
321
+
322
+ **`--check`:** many subcommands only print the plan or SQL and do not write to the database. `db init --check` does not require a connection.
323
+
324
+ ---
325
+
326
+ ## Invocation rules
327
+
328
+ Global options are on the **parent parser of each subcommand**. They must appear **after** the subcommand name:
329
+
330
+ ```bash
331
+ # Correct
332
+ python3 -m giswater_admin schema main create --type ws --name demo --profile empty --json
333
+
334
+ # Wrong (root parser does not define --json)
335
+ python3 -m giswater_admin --json create ...
336
+ ```
337
+
338
+ ---
339
+
340
+ ## Global options
341
+
342
+ Available on subcommands that include the shared parent parser (`schema …`, `network …`, `db init`, legacy aliases, `manifest list|validate`).
343
+
344
+ | Option | Description |
345
+ |--------|-------------|
346
+ | `--json` | Single JSON object on **stdout** (for `jq`, CI, scripts). |
347
+ | `--quiet` | Suppress info-level progress on stderr; errors/warnings remain. |
348
+ | `-v` / `--verbose` | One aligned line per executed SQL path on stderr. |
349
+ | `-d` / `--debug` | Like `-v` plus `DEBUG` logs with SQL previews. |
350
+ | `--timing` | `── Done … ──` summary (per phase + slowest files). With `-v`, adds ms per file. |
351
+ | `--timing-threshold-ms N` | With `-v --timing`, only log files with duration ≥ N ms. |
352
+ | `--timing-top K` | Number of slowest files in summary (default: 20). |
353
+ | `--timing-detail` | With `--json --timing`, include full per-file list in the JSON payload. |
354
+ | `--dbmodel-path DIR` | Root of the dbmodel tree (default: sibling `dbmodel/` in the plugin repo). |
355
+
356
+ **Connection group** (where applicable):
357
+
358
+ | Option | Description |
359
+ |--------|-------------|
360
+ | `--conn` | PostgreSQL URL. |
361
+ | `--config` | Path to connection YAML. |
362
+
363
+ ---
364
+
365
+ ## Commands reference
366
+
367
+ Base syntax:
368
+
369
+ ```text
370
+ python3 -m giswater_admin <subcommand> [subcommand options] [global options]
371
+ ```
372
+
373
+ Exit codes: **0** success, **1** failure (parse, I/O, PostgreSQL, SQL, invalid plan).
374
+
375
+ ### Command tree
376
+
377
+ ```text
378
+ gw db init
379
+ gw schema main create | update | drop
380
+ gw schema addon create | integrate | update | drop
381
+ gw network show | update
382
+ ```
383
+
384
+ Legacy aliases (`create`, `update`, `drop`, `status`, `init-db`, `update-network`, `audit …`) still work but print a deprecation warning to stderr and are hidden from `--help`.
385
+
386
+ | Old | New |
387
+ |-----|-----|
388
+ | `gw create --kind ws --schema x` | `gw schema main create --type ws --name x` |
389
+ | `gw update --schema ws` | `gw schema main update --name ws` |
390
+ | `gw status` | `gw network show --flat` |
391
+ | `gw init-db` | `gw db init` |
392
+ | `gw update-network` | `gw network update` |
393
+ | `gw audit structure` | `gw schema addon create --type audit` |
394
+ | `gw audit activate --schema ws` | `gw schema addon integrate --type audit --parent ws` |
395
+
396
+ Use `--version X.Y.Z` everywhere (replaces `--plugin-version` / `--to-version`).
397
+
398
+ ---
399
+
400
+ ### `db init`
401
+
402
+ Creates extensions in order: `postgis` → `postgis_raster` → `tablefunc` → `pgrouting` → `unaccent` (optional `postgres_fdw` with `--with-fdw`). Run **once per database** before the first schema create.
403
+
404
+ | Option | Description |
405
+ |--------|-------------|
406
+ | `--with-fdw` | Also `CREATE EXTENSION postgres_fdw`. |
407
+ | `--with-pgtap` | Also `CREATE EXTENSION pgtap` (for dbmodel tests). |
408
+ | `--continue-on-error` | Try all extensions after a failure (default: stop on first error). |
409
+ | `--check` | Print SQL only; no connection required. |
410
+ | `--conn` / `--config` | Connection (optional with `--check`). |
411
+
412
+ ```bash
413
+ gw db init --conn "$CONN"
414
+ gw db init --conn "$CONN" --with-fdw --with-pgtap
415
+ ```
416
+
417
+ ---
418
+
419
+ ### `schema main`
420
+
421
+ ws/ud project schemas.
422
+
423
+ #### `schema main create`
424
+
425
+ | Option | Description |
426
+ |--------|-------------|
427
+ | `--type` | **Required.** `ws` \| `ud` |
428
+ | `--name` | Schema name (default: same as `--type`, e.g. `ws`). |
429
+ | `--profile` | `empty` \| `sample` \| `inventory` (maps to manifest `empty`, `sample_full`, `sample_inv`). |
430
+ | `--lang` | Locale folder (default `en_US`). |
431
+ | `--srid` | EPSG code (default `25831`). |
432
+ | `--version` | Giswater schema release X.Y.Z (default: from active dbmodel). |
433
+ | `--check` | Plan only. |
434
+ | `--conn` / `--config` | Connection. |
435
+
436
+ ```bash
437
+ gw schema main create --type ws --name ws1 --profile sample --lang es_ES --conn "$CONN"
438
+ gw schema main create --type ud --profile empty --conn "$CONN"
439
+ ```
440
+
441
+ #### `schema main update`
442
+
443
+ Upgrades one isolated ws/ud schema. **Blocked** if the schema belongs to an interconnected network (use `network update`). **Downgrades forbidden.**
444
+
445
+ | Option | Description |
446
+ |--------|-------------|
447
+ | `--name` | **Required.** Existing schema. |
448
+ | `--version` | Target version (default: active dbmodel). |
449
+ | `--check` | Plan only. |
450
+ | `--conn` / `--config` | Connection. |
451
+
452
+ ```bash
453
+ gw schema main update --name ws1 --version 4.16.0 --conn "$CONN"
454
+ ```
455
+
456
+ #### `schema main drop`
457
+
458
+ | Option | Description |
459
+ |--------|-------------|
460
+ | `--name` | **Required.** |
461
+ | `--yes` | **Required** to execute. |
462
+ | `--cascade` | `DROP SCHEMA … CASCADE`. |
463
+ | `--check` | SQL only. |
464
+
465
+ ---
466
+
467
+ ### `schema addon`
468
+
469
+ Shared satellite schemas (`utils`, `cibs`, `cm`, `am`, `audit`).
470
+
471
+ #### `schema addon create`
472
+
473
+ Bootstrap a standalone addon (no parent wiring yet).
474
+
475
+ ```bash
476
+ gw schema addon create --type utils --conn "$CONN"
477
+ gw schema addon create --type cibs --name cibs --conn "$CONN"
478
+ gw schema addon create --type audit --conn "$CONN"
479
+ ```
480
+
481
+ #### `schema addon integrate`
482
+
483
+ Wire an addon into one ws/ud parent. Run once per parent (e.g. integrate utils with `ws`, then again with `ud`).
484
+
485
+ | Option | Description |
486
+ |--------|-------------|
487
+ | `--type` | **Required.** `utils` \| `cibs` \| `cm` \| `am` \| `audit` |
488
+ | `--parent` | **Required.** Parent ws or ud schema name. |
489
+ | `--name` | Addon schema name (default: same as `--type`). |
490
+
491
+ ```bash
492
+ gw schema addon integrate --type utils --parent ws --conn "$CONN"
493
+ gw schema addon integrate --type cibs --parent ud --conn "$CONN"
494
+ gw schema addon integrate --type audit --parent ws --conn "$CONN"
495
+ ```
496
+
497
+ #### `schema addon update`
498
+
499
+ Upgrades a **standalone** addon only. If integrated in a network → use `network update`. Downgrades forbidden.
500
+
501
+ ```bash
502
+ gw schema addon update --type cibs --version 4.16.0 --conn "$CONN"
503
+ ```
504
+
505
+ #### `schema addon drop`
506
+
507
+ ```bash
508
+ gw schema addon drop --type utils --yes --cascade --conn "$CONN"
509
+ ```
510
+
511
+ #### `schema list`
512
+
513
+ Read-only inventory of schemas with `sys_version`. No superuser required.
514
+
515
+ | Option | Description |
516
+ |--------|-------------|
517
+ | `--tier` | `all` (default), `main` (ws/ud), or `addon` (utils, cibs, am, cm, audit). |
518
+ | `--type` | Repeatable filter: `ws`, `ud`, `utils`, `cibs`, `am`, `cm`, `audit`. |
519
+ | `--conn` / `--config` | Connection. |
520
+ | `--json` | Machine-readable output. |
521
+
522
+ ```bash
523
+ gw schema list --conn "$CONN"
524
+ gw schema list --conn "$CONN" --tier main
525
+ gw schema list --conn "$CONN" --tier addon --type cibs --json
526
+ ```
527
+
528
+ ---
529
+
530
+ ### `network show`
531
+
532
+ Scans the whole database (all schemas with `sys_version`) and shows the interconnected Giswater network: ws/ud networks, shared satellites, integration links, version skew, and unlinked schemas.
533
+
534
+ | Option | Description |
535
+ |--------|-------------|
536
+ | `--flat` | Deprecated; use `schema list` instead. |
537
+ | `--schema` | Optional. Focus on the cluster containing this schema. |
538
+ | `--conn` / `--config` | Connection. |
539
+
540
+ ```bash
541
+ gw network show --conn "$CONN"
542
+ gw network show --flat --conn "$CONN" --json
543
+ ```
544
+
545
+ ---
546
+
547
+ ### `network update`
548
+
549
+ Lockstep upgrade of the discovered network. For each semver folder (e.g. 4.16.0), runs `utils → cibs → ws → ud → …` before advancing. **Downgrades forbidden** (target must be ≥ every member version).
550
+
551
+ | Option | Description |
552
+ |--------|-------------|
553
+ | `--version` | Target version (default: active dbmodel). |
554
+ | `--locale` | Default `en_US`. |
555
+ | `--check` | Print lockstep plan only. |
556
+ | `--conn` / `--config` | Connection. |
557
+
558
+ ```bash
559
+ gw network update --version 4.16.0 --conn "$CONN" --check
560
+ gw network update --version 4.16.0 --conn "$CONN"
561
+ ```
562
+
563
+ **E2E smoke** (empty DB, create @ 4.15.0, upgrade @ 4.16.0):
564
+
565
+ ```bash
566
+ export CONN='postgresql://user@host:port/giswater_admin_cli'
567
+ chmod +x scripts/gw_e2e_satellites.sh scripts/gw_e2e_network_update.sh
568
+ ./scripts/gw_e2e_network_update.sh
569
+ ```
570
+
571
+ Fixtures under `dbmodel/schemas/**/updates/4/16/0/` (`gw_lockstep_*`) validate cross-schema ordering.
572
+
573
+ ---
574
+
575
+ ### Legacy commands (deprecated)
576
+
577
+ The following still work with stderr warnings:
578
+
579
+ - **`create`** — use `schema main create` or `schema addon create` / `integrate`
580
+ - **`update`** — use `schema main update` or `schema addon update`
581
+ - **`drop`** — use `schema main drop` or `schema addon drop`
582
+ - **`status`** — use `network show --flat`
583
+ - **`init-db`** — use `db init`
584
+ - **`update-network`** — use `network update`
585
+ - **`audit structure|activate|drop`** — use `schema addon create|integrate|drop --type audit`
586
+
587
+ See the migration table at the top of this section.
588
+
589
+ ---
590
+
591
+ ### `manifest`
592
+
593
+ #### `manifest list`
594
+
595
+ Lists YAML files under `--dbmodel-path/manifests/`.
596
+
597
+ ```bash
598
+ python3 -m giswater_admin manifest list
599
+ python3 -m giswater_admin manifest list --dbmodel-path ./dbmodel --json
600
+ ```
601
+
602
+ #### `manifest validate`
603
+
604
+ Validates a manifest file.
605
+
606
+ | Argument | Description |
607
+ |----------|-------------|
608
+ | `path` | Path to `<kind>.yaml` |
609
+
610
+ ```bash
611
+ python3 -m giswater_admin manifest validate dbmodel/manifests/ws.yaml
612
+ python3 -m giswater_admin manifest validate dbmodel/manifests/ws.yaml --json
613
+ ```
614
+
615
+ ---
616
+
617
+ ### End-to-end example (ws + ud + utils)
618
+
619
+ ```bash
620
+ set -e
621
+ export CONN='postgresql://gisadmin:secret@127.0.0.1:5432/giswater_cli'
622
+
623
+ gw db init --conn "$CONN"
624
+ gw schema main create --type ws --name ws_test --profile sample --conn "$CONN"
625
+ gw schema main create --type ud --name ud_test --profile sample --conn "$CONN"
626
+ gw schema addon create --type utils --conn "$CONN"
627
+ gw schema addon integrate --type utils --parent ws_test --conn "$CONN"
628
+ gw network show --flat --conn "$CONN" --json | python3 -m json.tool
629
+ ```
630
+
631
+ ---
632
+
633
+ ## Kinds and manifest profiles
634
+
635
+ | `kind` | Typical profiles | Notes |
636
+ |--------|------------------|-------|
637
+ | **ws** | `empty`, `sample_full`, `sample_inv`, `dev`, `ci`, `update` | Water supply. Updates: `schemas/main/common/updates` then `schemas/main/ws/updates`. |
638
+ | **ud** | same as ws | Sewerage. Updates: common then `schemas/main/ud/updates`. |
639
+ | **utils** | `empty`, `integrate_ws`, `integrate_ud`, `copy_data`, `update` | Standalone create; integrate ws/ud separately; version in `utils.sys_version`. |
640
+ | **am** | `empty`, `update` | Asset management singleton. |
641
+ | **cm** | `bootstrap`, `integrate`, `update` | Bootstrap standalone, then `schema addon integrate --parent …`. |
642
+ | **audit** | `empty`, `integrate`, `update` | Same flow as other addons via `schema addon create|integrate`. |
643
+
644
+ **ws/ud profiles** (from [manifests/ws.yaml](../dbmodel/manifests/ws.yaml)):
645
+
646
+ | Profile | Phases (summary) |
647
+ |---------|------------------|
648
+ | `empty` | `load_base` → `updates` → `lastprocess` → `final_pass` |
649
+ | `sample_full` | … → `load_sample` → `final_pass` |
650
+ | `sample_inv` | … → `load_sample` → `load_inv` → `final_pass` |
651
+ | `dev` | … → `load_dev` → `final_pass` |
652
+ | `ci` | … → `load_sample` → `final_pass` (used by pgTAP bootstrap) |
653
+ | `update` | `reload_fct_ftrg` → `updates` → `lastprocess_upgrade` |
654
+
655
+ Details and folder layout: [dbmodel README — Schema architecture](../dbmodel/README.md#schema-architecture).
656
+
657
+ ---
658
+
659
+ ## Timing and output
660
+
661
+ | Stream | Content |
662
+ |--------|---------|
663
+ | **stdout** | Final result (YAML or JSON with `--json`). |
664
+ | **stderr** | Progress (`log_format.py`), warnings, errors; `-v`/`-d` add per-file lines. |
665
+
666
+ Example stderr with `-v --timing`:
667
+
668
+ ```text
669
+ ── Schema build: ws / gw_ws_test profile=empty v4.9.0 ──
670
+ [581/723] phase updates
671
+ [581/723] 1.2s ws/updates/4/2/0/dml.sql
672
+ ── Done 10.4s 723 files ──
673
+ updates 7.1s (612 files, 68.0%)
674
+ Slowest:
675
+ 3241ms updates ws/updates/4/2/0/dml.sql
676
+ ```
677
+
678
+ Paths are shortened using `--dbmodel-path` as the root prefix.
679
+
680
+ ```bash
681
+ # Slow SQL files during create
682
+ python3 -m giswater_admin create --kind ws --schema gw_ws_test --profile empty \
683
+ --timing --timing-top 30 -v --timing-threshold-ms 30 \
684
+ --conn "$CONN" 2>&1 | tee /tmp/gw_create_timing.log
685
+
686
+ # JSON timing for jq
687
+ python3 -m giswater_admin create --kind ws --schema gw_ws_test --profile empty \
688
+ --timing --timing-detail --json --conn "$CONN" 2>/dev/null | \
689
+ jq '.timing.slowest_by_phase.updates[:20]'
690
+ ```
691
+
692
+ Timing is **per SQL file** only (not per PL/pgSQL function step).
693
+
694
+ ---
695
+
696
+ ## QGIS integration
697
+
698
+ The plugin builds `BuildParams`, runs `SchemaBuilder` in `core/threads/schema_builder_task.py` via `QtDbAdapter`, and can show the same formatted progress in the **Giswater PY** log. After a build, `summarize_build()` from `engine/timing_report.py` feeds the create-project dialog timing label.
699
+
700
+ ---
701
+
702
+ ## Unit tests
703
+
704
+ No Docker required:
705
+
706
+ ```bash
707
+ # From plugin repo root
708
+ python3 -m pytest test/cli test/engine -v
709
+ ```
710
+
711
+ Optional smoke tests against a real cluster (skipped without `PGSERVICE` / `PGDATABASE`):
712
+
713
+ ```bash
714
+ PGSERVICE=localhost_giswater python3 -m pytest test/engine/smoke -v
715
+ ```
716
+
717
+ Database integration tests: [dbmodel/README.md#testing](../dbmodel/README.md#testing).
718
+
719
+ ---
720
+
721
+ ## Extending the model
722
+
723
+ 1. Add or edit `dbmodel/manifests/<kind>.yaml`.
724
+ 2. For a new `kind`, register it in `giswater_admin/cli.py` (`--kind` choices and command validation if needed).
725
+ 3. Validate: `python3 -m giswater_admin manifest validate dbmodel/manifests/<kind>.yaml`.
726
+
727
+ Supported phase types: `sql_dir`, `version_walk` (`root:` or `roots:`), `sql_file`, `sql_function`, `sql_inline`. `dir_walk` is deprecated.
728
+
729
+ ---
730
+
731
+ ## Keeping docs in sync
732
+
733
+ When you add or change CLI flags, update **both** `giswater_admin/cli.py` and this README (global options + affected subcommand tables). A future improvement could dump `argparse` help in CI; that is not automated yet.