Skip to content
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

Support deferrable constraints for SQL #5306

Closed
squivix opened this issue Mar 3, 2024 · 0 comments · Fixed by #5384
Closed

Support deferrable constraints for SQL #5306

squivix opened this issue Mar 3, 2024 · 0 comments · Fixed by #5384
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@squivix
Copy link

squivix commented Mar 3, 2024

Is your feature request related to a problem? Please describe.
I'm always frustrated when I try to insert a lot of data in a single transaction and the foreign key constraints are violated because the related row was not inserted yet in that statement, but will be inserted later as part of the same transaction. SQL has a solution for this: deferring constraint checks until the commit of the transaction.

In postgres this is done by setting the constraint to be DEFERRABLE, and setting the constraint check timing for the transaction to DEFERRED. Or just setting the default behavior of the constraint to be DEFERRABLE INITIALLY DEFERRED to apply by default for all transactions.

Describe the solution you'd like
It would be nice if we can set deferrablility and default check timing through the ORM, maybe as options in the relationship decorators (@ManyToOne, @OneToOne, etc).

For example:

@ManyToOne({entity:()=>EntityA, deferMode:"DEFERRABLE", defaultDeferTiming:"DEFERRED"})
entityA!: Ref<EntityA>;

Then the generated migration would be:

this.addSql('create table "entity_b" ("id" serial primary key, "entity_a_id" int not null);');
this.addSql('alter table "entity_b" add constraint "entity_b_entity_a_id_foreign" foreign key ("entity_a_id") references "entity_a" ("id") on update cascade deferrable initially deferred;');

And we could have a default global value for these options. I don't know if there's a place for driver-specific configs, or maybe we could put them with the orm options.

Also for the transaction, maybe we could have an option for the check timing in em.begin() or em.transactional():

await em.begin({checkTiming: "DEFERRED"})

Describe alternatives you've considered
I could manually edit the migration files to make constraints deferrable, and run a raw query to SET CONSTRAINTS DEFERRED

Or alternatively I could insert my data in an order that guarentees no conflicts even within the same transaction.

Additional context
Somewhat related issue #1175 because I saw a test for immediate constraints in the issue tests.

@squivix squivix added the enhancement New feature or request label Mar 3, 2024
@B4nan B4nan added the help wanted Extra attention is needed label Mar 3, 2024
B4nan added a commit that referenced this issue Mar 27, 2024
This PR adds the option to specify constraints as deferrable for
relations.

On OneToOne and ManyToOne relations you can now specify a `deferMode`
property, which can be either `not deferrable` (default), `immediate` or
`deferred`. Those are also covered by a new `DeferMode` enum.

Closes #5306

---------

Co-authored-by: Martin Adámek <banan23@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants