1# Chapter 11: postjevsql-sidecar/src, config, secrets and a plan
2
3Everything the sidecar decides, with nothing that talks to a database. Three
4files, each one a rule you can test with plain `cargo test`.
5
6**One config file.** `config.rs` reads the TOML every launcher writes:
7
8```toml
9[target]
10server = "target"          # the foreign server's local name (the default)
11host = "db.example.com"
12port = 5432                # the default
13dbname = "app"
14sslmode = "verify-full"    # the default
15use_remote_estimate = true # the default
16schemas = ["public"]       # imported into same-named local schemas
17
18[[mapping]]
19local_user = "app"
20remote_user = "app_ro"
21password_file = "/run/secrets/app_ro"  # or $POSTJEVSQL_TARGET_PASSWORD
22
23[jev]
24api_key_file = "/run/secrets/typesafe" # or $TYPESAFE_API_KEY
25```
26
27It also takes `sslrootcert`, `fetch_size` (default 100, the scan's in-flight
28window, so each window is one round trip), and a mapping's `password_env`.
29An unknown key is an error, not a typo quietly ignored.
30
31**Every secret from exactly one place.** `secret.rs` resolves each secret
32from a file or an env var. Both set is an error, because a precedence rule
33would silently use the wrong credential, and so is neither, for a secret the
34command needs. (A mapping with no password at all is how PG18's
35`use_scram_passthrough` is asked for.) An empty file or variable is an error
36too. The error names
37the file and the variable, never the value.
38
39**A plan, not a rebuild.** `sync.rs` compares the target's tables with the
40sidecar's foreign tables and plans the changes, one at a time: create a
41table, drop one, add, drop or rename a column, change a type or a `NOT NULL`.
42It never drops a table to import it again, because the sidecar's own views,
43grants and functions over a foreign table would go with it.
44
45```mermaid
46flowchart LR
47  T["the target's catalog"] --> P["sync::plan"]
48  L["the sidecar's foreign tables"] --> P
49  P --> C["CreateTable · DropTable · AddColumn · DropColumn · RenameColumn · AlterType · SetNotNull"]
50```
51
52> **Aside: how a rename is told from a drop.** A column is matched by its
53> remote name. When exactly one column disappeared and one appeared at the
54> same position, with the same type and nullability, that is a rename.
55> Anything else is a drop and an add, and the CLI's dependency check refuses
56> the drop if a view uses the column. Guessing generously here would rename
57> the wrong thing; guessing stingily only ever refuses.
58
59> **Try it.** `cargo test -p postjevsql-sidecar` runs these files' tests in
60> a fraction of a second.
61
62## For the people who maintain it
63
64| File | What |
65| --- | --- |
66| [lib.rs](lib.rs) | The three modules. |
67| [config.rs](config.rs) | `Config`, `Target`, `SslMode` (`verify-full` by default; the weaker modes are for loopback tests), `Mapping`, `Jev`. |
68| [secret.rs](secret.rs) | `Sources` and `Source`: a secret from a file or an env var, exactly one, and `SecretError`, which names the sources. |
69| [sync.rs](sync.rs) | `Table`, `Column`, `Change`, `Touches` (what a change can break), `plan`, and `ident`/`lit` for quoting. |
70
71← Previous: [Chapter 10, postjevsql-sidecar/](../) · Up: [postjevsql-sidecar](../) · Next: [Chapter 12, cli/](../cli/) →