Table schemas
A table's schema is part of its identity on PostgreSQL: app.users and users are two
different tables. Declare it with #[besu(schema = "...")], and Besu qualifies every
statement it writes for that table.
The attribute is stored on TableDef::schema, so it travels with the handle into Schema.
The two declarations have to live in different modules, because the handle identifier comes
from the table name.
Looking a table up
Schema::find is the identity the differ uses: None means the connection's default schema.
Schema::get takes the qualified spelling that a Change carries, and Schema::table is the
lenient lookup that prefers the unqualified table and falls back to the first name match.
What introspection reports
PostgreSQL introspection asks the connection for current_schema(). A table in that schema
is reported with schema: None; a table anywhere else carries its real schema name.
The default schema stays implicit on purpose. Naming it explicitly in #[besu(schema = "public")] would make every declared table look like a different table from the one
introspection reports, and push would try to create a second copy.
If search_path is empty, current_schema() returns NULL and every table is reported with
its real schema.
CREATE SCHEMA is not emitted
Besu qualifies names and creates tables inside a schema, but it never creates the schema
itself. push and generate have no statement for it. Create it once, in a migration or by
hand:
The schema has to exist before a push that names it, or the CREATE TABLE fails.
Which schemas push manages
push manages the default schema and every schema a declared table names. It does not manage
anything else:
- A table in a schema the snapshot never mentions is left alone, not reported as a
DropTable. A shared database does not make every push destructive. - Remove the last declared table of a schema and that schema is no longer managed, so the drop is not reported either. Drop the table by hand, or keep the schema named by another table.
On SQLite and MySQL
The same attribute is the namespace the backend understands:
- SQLite treats a schema as an attached database. Set it only if you have run
ATTACH DATABASE; an unattached name fails when the statement runs. - MySQL treats a schema as a database name.
Both render the name as a qualifier: "app"."users".
Gotchas
- A schema is not a table prefix.
Database::prefixedrewrites table names for shared databases;schemaqualifies them. Combining them applies the prefix to the table name and leaves the schema as written. - An enum type is qualified the same way. An enum outside the default schema is named
schema.typeinSchema::enums, and a column of that type carries the qualified name. - Renaming a schema is not modelled. It looks like dropping every table in the old schema
and creating them in the new one. Use
ALTER SCHEMA ... RENAME TO ...in a migration. pushnever drops a schema. Even when every table in it is dropped, the empty schema stays.DROP SCHEMAis migration SQL.- Views follow the same naming rule and are diffed once the declaration names one; see views.
