Repository navigation
feat(schema)!: support PostgreSQL namespaces and definition directories #489
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
db051a2
feat(schema): support PostgreSQL namespaces and definition directories
medz f39ec22
fix(migrate): preserve legacy PostgreSQL default schema identity
medz a9f0758
fix(migrate): qualify PostgreSQL catalog probes
medz 04fc094
test(generate): verify custom roots through real build_runner
medz edc0420
feat(schema)!: require explicit migration to namespace identities
medz fde3de6
fix(generate): preserve URL paths for directory builders
medz ea8258b
fix(generate): reject outputs that become schema inputs
medz 2300ad7
fix(schema): reject dotted manual table identities
medz 451078d
fix(schema): reject empty and NUL table identity components
medz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| # Database schemas and definition files | ||
|
|
||
| Keep model declarations unchanged when splitting a schema. PostgreSQL uses the | ||
| first directory name as the database schema. MySQL, MariaDB and SQLite use a flat | ||
| directory of definition files for one configured database. | ||
|
|
||
| | Source | PostgreSQL | MySQL, MariaDB, SQLite | | ||
| | --- | --- | --- | | ||
| | `lib/schema.dart` | Default `public` schema | Configured database | | ||
| | `lib/schema/{schema}/*.dart` | Named database schema | Not a declaration layout | | ||
| | `lib/schema/*.dart` | Use a schema subdirectory | Split model declarations | | ||
|
|
||
| Neither directory pattern is recursive. Imported enums, codecs and default | ||
| factories can live elsewhere. In directory mode, referenced models must be | ||
| declared in the selected layout; an import or export cannot change their schema. | ||
| Generated `.orm.dart` and `.snapshot.dart` files are not declaration inputs. | ||
|
|
||
| ## PostgreSQL | ||
|
|
||
| ```text | ||
| lib/schema/ | ||
| public/ | ||
| profiles.dart | ||
| auth/ | ||
| users.dart | ||
| sessions.dart | ||
| ``` | ||
|
|
||
| `lib/schema/auth/users.dart`: | ||
|
|
||
| ```dart | ||
| import 'package:orm/schema.dart'; | ||
|
|
||
| final user = model('Users', ( | ||
| id: identity(), | ||
| displayName: text(name: 'DisplayName'), | ||
| )); | ||
| ``` | ||
|
|
||
| `lib/schema/public/profiles.dart`: | ||
|
|
||
| ```dart | ||
| import 'package:orm/schema.dart'; | ||
| import '../auth/users.dart' as auth; | ||
|
|
||
| final profile = model('profiles', ( | ||
| id: identity(), | ||
| accountId: integer(), | ||
| ), relations: (p) => ( | ||
| account: references(p.accountId, () => auth.user), | ||
| )); | ||
| ``` | ||
|
|
||
| Generate offline using the project configuration, or select the engine explicitly: | ||
|
|
||
| ```sh | ||
| dart run orm generate lib/schema --database postgres | ||
| ``` | ||
|
|
||
| The client and snapshot are `lib/schema.orm.dart` and `lib/schema.snapshot.dart`. | ||
| Only default `public` models produce flat access such as `db.user`. Declaring a | ||
| non-default schema groups all model access by schema: | ||
|
|
||
| ```dart | ||
| final account = await db.auth.user.create(displayName: 'Alice'); | ||
| await db.public.profile.create(accountId: account.id); | ||
| ``` | ||
|
|
||
| Grouped row types include their schema, such as `AuthUser` and `PublicProfile`. | ||
| Different schemas may declare the same model and table names. Names must remain | ||
| distinct within their schema. Schema directory names must also be usable as Dart | ||
| database members; invalid names and generated type collisions are reported. | ||
| Case-sensitive database names cannot always be represented on a case-insensitive | ||
| source filesystem; the generator does not silently rename or merge them. | ||
|
|
||
| Relationships use the target declaration's schema. Cross-schema foreign keys and | ||
| queries use the same PostgreSQL database and connection; they do not open another | ||
| database or introduce distributed transactions. | ||
|
|
||
| ## Single files and generation roots | ||
|
|
||
| `lib/schema`, `lib/schema/` and `lib/schema.dart` select the same definition root. | ||
| If both the file and directory exist, generation combines their declarations. | ||
| The sibling file contributes to the default schema. Exporting a declaration that | ||
| was already discovered does not duplicate it; independent conflicting models | ||
| produce an error instead of overriding one another. | ||
|
|
||
| Select the engine through `OrmConfig.history.dialect` or `--database`. Directory | ||
| generation requires an engine and never connects to discover it. Single-file | ||
| programmatic generation without an engine retains engine-neutral metadata; select | ||
| PostgreSQL explicitly when generating its physical namespaces. | ||
|
|
||
| With an engine selected, table ordering is deterministic. Splitting declarations | ||
| or renaming a file within one schema does not change the physical snapshot. | ||
| Moving a model to another schema changes its database identity and requires a | ||
| reviewed migration. Existing migration definitions and fingerprints stay frozen. | ||
|
|
||
| PostgreSQL namespace identity is a breaking change. Older unqualified snapshots | ||
| are not automatically matched to `public` tables. Regenerate the client and | ||
| snapshot, then review the migration before applying it. A generated replacement | ||
| plan requires `--allow-destructive` and recreates the affected tables, deleting | ||
| their rows. Projects that need to retain data must author and review that data | ||
| migration explicitly. Historical migration files must not be rewritten. | ||
|
|
||
| ## SQL names and migration ownership | ||
|
|
||
| The schema, table and column names are separate identifiers. The example above | ||
| queries `"auth"."Users"` and `"DisplayName"`. PostgreSQL generation also explicitly | ||
| qualifies default models with `"public"`. Querying these tables does not depend | ||
| on a later `SET search_path` or an identically named temporary table. | ||
|
|
||
| Do not write `model('auth.Users', ...)`: dotted table names are rejected. | ||
| Manual `TableSchema` definitions apply the same rule to table names, namespaces | ||
| and foreign-key targets when constructed, and also reject empty names and NUL | ||
| characters. Column names use snake_case unless | ||
| their helper specifies `name:`. Explicit physical | ||
| names retain their spelling and quotes are escaped for the selected dialect; | ||
| quoting does not change the database's own rules for case equality. | ||
|
|
||
| Generated PostgreSQL creation plans include the required `CREATE SCHEMA IF NOT | ||
| EXISTS` statements. Review these through the normal migration workflow and use a | ||
| role with the required privileges. Removing models never automatically drops a | ||
| schema or runs `DROP SCHEMA ... CASCADE`. Explicit table moves can use | ||
| `SchemaRenames.tables` with the before/after identities, for example | ||
| `{'auth.Users': 'archive.Users'}`; these keys match snapshot identities and are | ||
| not interpreted as arbitrary SQL. | ||
|
|
||
| Migration locks cover one PostgreSQL database, including work spanning several | ||
| schemas. Catalog verification, foreign keys, query inspection, cursors and change | ||
| subscriptions distinguish schema-qualified tables. Namespace getters do not grant | ||
| database permissions. Raw SQL remains trusted application SQL and follows its | ||
| own explicit names and session state. | ||
|
|
||
| MySQL/MariaDB cross-database models and SQLite attached-database models are outside | ||
| this layout feature. Their definition files continue to describe one database. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.