Unsupported database type
2 min read
The database factory switches on config.type and its default branch throws.
Why a default that throws beats a default that defaults
The tempting alternative is falling back to SQLite when the type is unrecognised. It would make this error disappear and it would be considerably worse: a production deployment with a typo in its database type would start cleanly, run against a local SQLite file, and appear healthy while writing to nothing anyone intended.
Refusing means a misconfiguration stops the process at startup, which is the cheapest possible moment to find it.
What causes it
Almost always a typo or a casing difference — postgresql where the code expects
postgres, or a value that arrived from an environment variable with
surrounding whitespace.
The interesting neighbour
The Postgres branch immediately above carries a cast worth reading:
// The Postgres adapter is structurally compatible for the queries we issue;
// cast at this single boundary rather than threading a union everywhere.
return createPostgresAdapter(config.postgresUrl) as unknown as Database;
That is an honest comment about a real compromise. Database is typed as the
SQLite handle, and Postgres is asserted compatible at one point rather than the
codebase carrying a union through every call site.
It works because the queries issued are within the intersection of both. It is worth knowing the portability is nominal rather than structural — if a Postgres-specific query is ever needed, this cast is where the design will push back.
A closed set, on purpose
The supported types are enumerated rather than looked up dynamically. That means adding a backend is a code change with a review attached, not a configuration value somebody can invent — and the compiler helps, because a new case in the union forces every switch over it to account for the addition.
The cost is that supporting a new database is never a one-line config change. That is the correct cost: a database backend is not a setting.
