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/) →