fix: Execute deferred constraint triggers when using Prefer: tx=rollback
Resolves #2020
This commit is contained in:
committed by
Wolfgang Walther
parent
bbc07d3f40
commit
1cb00d3c62
@@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- #2020, Execute deferred constraint triggers when using `Prefer: tx=rollback` - @wolfgangwalther
|
||||||
|
|
||||||
## [9.0.0] - 2021-11-25
|
## [9.0.0] - 2021-11-25
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
Module : PostgREST.Middleware
|
Module : PostgREST.Middleware
|
||||||
Description : Sets CORS policy. Also the PostgreSQL GUCs, role, search_path and pre-request function.
|
Description : Sets CORS policy. Also the PostgreSQL GUCs, role, search_path and pre-request function.
|
||||||
-}
|
-}
|
||||||
|
{-# LANGUAGE BlockArguments #-}
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
module PostgREST.Middleware
|
module PostgREST.Middleware
|
||||||
( runPgLocals
|
( runPgLocals
|
||||||
@@ -170,8 +171,9 @@ optionalRollback
|
|||||||
-> ExceptT Error SQL.Transaction Wai.Response
|
-> ExceptT Error SQL.Transaction Wai.Response
|
||||||
optionalRollback AppConfig{..} ApiRequest{..} transaction = do
|
optionalRollback AppConfig{..} ApiRequest{..} transaction = do
|
||||||
resp <- catchError transaction $ return . errorResponseFor
|
resp <- catchError transaction $ return . errorResponseFor
|
||||||
when (shouldRollback || (configDbTxRollbackAll && not shouldCommit))
|
when (shouldRollback || (configDbTxRollbackAll && not shouldCommit)) $ lift do
|
||||||
(lift SQL.condemn)
|
SQL.sql "SET CONSTRAINTS ALL IMMEDIATE"
|
||||||
|
SQL.condemn
|
||||||
return $ Wai.mapResponseHeaders preferenceApplied resp
|
return $ Wai.mapResponseHeaders preferenceApplied resp
|
||||||
where
|
where
|
||||||
shouldCommit =
|
shouldCommit =
|
||||||
|
|||||||
@@ -70,6 +70,35 @@ shouldRespondToReads reqHeaders respHeaders = do
|
|||||||
[json|[{"id":1}]|]
|
[json|[{"id":1}]|]
|
||||||
{ matchHeaders = respHeaders }
|
{ matchHeaders = respHeaders }
|
||||||
|
|
||||||
|
shouldRaiseExceptions reqHeaders respHeaders = do
|
||||||
|
it "raises immediate constraints" $ do
|
||||||
|
request methodPost "/rpc/raise_constraint"
|
||||||
|
reqHeaders
|
||||||
|
""
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|{
|
||||||
|
"hint":null,
|
||||||
|
"details":"Key (col)=(1) already exists.",
|
||||||
|
"code":"23505",
|
||||||
|
"message":"duplicate key value violates unique constraint \"deferrable_unique_constraint_col_key\""
|
||||||
|
}|]
|
||||||
|
{ matchStatus = 409
|
||||||
|
, matchHeaders = respHeaders }
|
||||||
|
|
||||||
|
it "raises deferred constraints" $ do
|
||||||
|
request methodPost "/rpc/raise_constraint"
|
||||||
|
reqHeaders
|
||||||
|
[json|{"deferred": true}|]
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|{
|
||||||
|
"hint":null,
|
||||||
|
"details":"Key (col)=(1) already exists.",
|
||||||
|
"code":"23505",
|
||||||
|
"message":"duplicate key value violates unique constraint \"deferrable_unique_constraint_col_key\""
|
||||||
|
}|]
|
||||||
|
{ matchStatus = 409
|
||||||
|
, matchHeaders = respHeaders }
|
||||||
|
|
||||||
shouldPersistMutations reqHeaders respHeaders = do
|
shouldPersistMutations reqHeaders respHeaders = do
|
||||||
it "does persist post" $ do
|
it "does persist post" $ do
|
||||||
request methodPost "/items"
|
request methodPost "/items"
|
||||||
@@ -178,28 +207,38 @@ allowed = describe "tx-allow-override = true" $ do
|
|||||||
describe "without Prefer tx" $ do
|
describe "without Prefer tx" $ do
|
||||||
preferDefault `shouldRespondToReads` withoutPreferenceApplied
|
preferDefault `shouldRespondToReads` withoutPreferenceApplied
|
||||||
preferDefault `shouldNotPersistMutations` withoutPreferenceApplied
|
preferDefault `shouldNotPersistMutations` withoutPreferenceApplied
|
||||||
|
preferDefault `shouldRaiseExceptions` withoutPreferenceApplied
|
||||||
|
|
||||||
describe "Prefer tx=commit" $ do
|
describe "Prefer tx=commit" $ do
|
||||||
preferCommit `shouldRespondToReads` withPreferenceCommitApplied
|
preferCommit `shouldRespondToReads` withPreferenceCommitApplied
|
||||||
preferCommit `shouldPersistMutations` withPreferenceCommitApplied
|
preferCommit `shouldPersistMutations` withPreferenceCommitApplied
|
||||||
|
-- Exceptions are always without preference applied,
|
||||||
|
-- because they return before the end of the transaction.
|
||||||
|
preferCommit `shouldRaiseExceptions` withoutPreferenceApplied
|
||||||
|
|
||||||
describe "Prefer tx=rollback" $ do
|
describe "Prefer tx=rollback" $ do
|
||||||
preferRollback `shouldRespondToReads` withPreferenceRollbackApplied
|
preferRollback `shouldRespondToReads` withPreferenceRollbackApplied
|
||||||
preferRollback `shouldNotPersistMutations` withPreferenceRollbackApplied
|
preferRollback `shouldNotPersistMutations` withPreferenceRollbackApplied
|
||||||
|
-- Exceptions are always without preference applied,
|
||||||
|
-- because they return before the end of the transaction.
|
||||||
|
preferRollback `shouldRaiseExceptions` withoutPreferenceApplied
|
||||||
|
|
||||||
disallowed :: SpecWith ((), Application)
|
disallowed :: SpecWith ((), Application)
|
||||||
disallowed = describe "tx-rollback-all = false, tx-allow-override = false" $ do
|
disallowed = describe "tx-rollback-all = false, tx-allow-override = false" $ do
|
||||||
describe "without Prefer tx" $ do
|
describe "without Prefer tx" $ do
|
||||||
preferDefault `shouldRespondToReads` withoutPreferenceApplied
|
preferDefault `shouldRespondToReads` withoutPreferenceApplied
|
||||||
preferDefault `shouldPersistMutations` withoutPreferenceApplied
|
preferDefault `shouldPersistMutations` withoutPreferenceApplied
|
||||||
|
preferDefault `shouldRaiseExceptions` withoutPreferenceApplied
|
||||||
|
|
||||||
describe "Prefer tx=commit" $ do
|
describe "Prefer tx=commit" $ do
|
||||||
preferCommit `shouldRespondToReads` withoutPreferenceApplied
|
preferCommit `shouldRespondToReads` withoutPreferenceApplied
|
||||||
preferCommit `shouldPersistMutations` withoutPreferenceApplied
|
preferCommit `shouldPersistMutations` withoutPreferenceApplied
|
||||||
|
preferCommit `shouldRaiseExceptions` withoutPreferenceApplied
|
||||||
|
|
||||||
describe "Prefer tx=rollback" $ do
|
describe "Prefer tx=rollback" $ do
|
||||||
preferRollback `shouldRespondToReads` withoutPreferenceApplied
|
preferRollback `shouldRespondToReads` withoutPreferenceApplied
|
||||||
preferRollback `shouldPersistMutations` withoutPreferenceApplied
|
preferRollback `shouldPersistMutations` withoutPreferenceApplied
|
||||||
|
preferRollback `shouldRaiseExceptions` withoutPreferenceApplied
|
||||||
|
|
||||||
|
|
||||||
forced :: SpecWith ((), Application)
|
forced :: SpecWith ((), Application)
|
||||||
@@ -207,12 +246,15 @@ forced = describe "tx-rollback-all = true, tx-allow-override = false" $ do
|
|||||||
describe "without Prefer tx" $ do
|
describe "without Prefer tx" $ do
|
||||||
preferDefault `shouldRespondToReads` withoutPreferenceApplied
|
preferDefault `shouldRespondToReads` withoutPreferenceApplied
|
||||||
preferDefault `shouldNotPersistMutations` withoutPreferenceApplied
|
preferDefault `shouldNotPersistMutations` withoutPreferenceApplied
|
||||||
|
preferDefault `shouldRaiseExceptions` withoutPreferenceApplied
|
||||||
|
|
||||||
describe "Prefer tx=commit" $ do
|
describe "Prefer tx=commit" $ do
|
||||||
preferCommit `shouldRespondToReads` withoutPreferenceApplied
|
preferCommit `shouldRespondToReads` withoutPreferenceApplied
|
||||||
preferCommit `shouldNotPersistMutations` withoutPreferenceApplied
|
preferCommit `shouldNotPersistMutations` withoutPreferenceApplied
|
||||||
|
preferCommit `shouldRaiseExceptions` withoutPreferenceApplied
|
||||||
|
|
||||||
describe "Prefer tx=rollback" $ do
|
describe "Prefer tx=rollback" $ do
|
||||||
preferRollback `shouldRespondToReads` withoutPreferenceApplied
|
preferRollback `shouldRespondToReads` withoutPreferenceApplied
|
||||||
preferRollback `shouldNotPersistMutations` withoutPreferenceApplied
|
preferRollback `shouldNotPersistMutations` withoutPreferenceApplied
|
||||||
|
preferRollback `shouldRaiseExceptions` withoutPreferenceApplied
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
@@ -25,6 +25,7 @@ GRANT ALL ON TABLE
|
|||||||
, complex_items
|
, complex_items
|
||||||
, compound_pk
|
, compound_pk
|
||||||
, compound_pk_view
|
, compound_pk_view
|
||||||
|
, deferrable_unique_constraint
|
||||||
, empty_table
|
, empty_table
|
||||||
, has_count_column
|
, has_count_column
|
||||||
, has_fk
|
, has_fk
|
||||||
|
|||||||
Vendored
+14
@@ -2448,3 +2448,17 @@ CREATE TABLE chores (
|
|||||||
, name text
|
, name text
|
||||||
, done bool
|
, done bool
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE deferrable_unique_constraint (
|
||||||
|
col INT UNIQUE DEFERRABLE INITIALLY IMMEDIATE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE FUNCTION raise_constraint(deferred BOOL DEFAULT FALSE) RETURNS void
|
||||||
|
LANGUAGE plpgsql AS $$
|
||||||
|
BEGIN
|
||||||
|
IF deferred THEN
|
||||||
|
SET CONSTRAINTS ALL DEFERRED;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
INSERT INTO deferrable_unique_constraint VALUES (1), (1);
|
||||||
|
END$$;
|
||||||
|
|||||||
Reference in New Issue
Block a user