packages feed

esqueleto 3.6.0.1 → 3.6.0.2

raw patch · 4 files changed

+59/−6 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

changelog.md view
@@ -1,3 +1,12 @@+3.6.0.2+=======+- @parsonsmatt+    - [#436](https://github.com/bitemyapp/esqueleto/pull/436)+        - After a set operation, resume ident allocation from the union of+          both branches' ident states (previously the left branch's state+          only), so the enclosing query can never reuse an ident either+          branch consumed.+ 3.6.0.1 ======= - @parsonsmatt
esqueleto.cabal view
@@ -1,7 +1,7 @@ cabal-version: 1.12  name:           esqueleto-version:        3.6.0.1+version:        3.6.0.2 synopsis:       Type-safe EDSL for SQL queries on persistent backends. description:    @esqueleto@ is a bare bones, type-safe EDSL for SQL queries that works with unmodified @persistent@ SQL backends.  Its language closely resembles SQL, so you don't have to learn new concepts, just new syntax, and it's fairly easy to predict the generated SQL and optimize it for your backend. Most kinds of errors committed when writing SQL are caught as compile-time errors---although it is possible to write type-checked @esqueleto@ queries that fail at runtime.                 .
src/Database/Esqueleto/Experimental/From/SqlSetOperation.hs view
@@ -78,11 +78,13 @@     -- sibling SELECTs, so identical idents cannot collide.     Q $ lift $ S.put stateBefore     (_, rightClause) <- unSqlSetOperation (toSqlSetOperation rhs) p-    -- Only 'leftValue' escapes, so resume from the left branch's state.-    -- Resuming from the right branch's state would reuse idents appearing-    -- in 'leftValue' whenever the right branch allocated fewer idents-    -- (a variant of issue #299).-    Q $ lift $ S.put stateAfterLeft+    stateAfterRight <- Q $ lift S.get+    -- Resume from the union of both branches' states, so the enclosing+    -- query can never reuse an ident either branch consumed: the left+    -- branch's idents escape in 'leftValue' (a variant of issue #299),+    -- and the right branch's, while branch-internal, shouldn't be+    -- handed out again either.+    Q $ lift $ S.put (IdentState (inUse stateAfterLeft <> inUse stateAfterRight))     pure (leftValue, \info -> leftClause info <> (operation, mempty) <> rightClause info)  -- | Overloaded @union_@ function to support use in both 'SqlSetOperation'
test/PostgreSQL/Test.hs view
@@ -1687,6 +1687,48 @@                     pure (c, val @Int 1)             asserting noExceptions +        itDb "allocates fresh idents for a lateral join after a right-heavy union" $ do+            -- The left branch selects only references to a CTE, so the right+            -- branch consumes more idents than the left one. Idents allocated+            -- after the union (here, inside a correlated lateral subquery)+            -- must not collide with either branch's.+            lid <- insert l1+            let lordQuery = do+                    l <- Experimental.from $ table @Lord+                    pure (l ^. LordId, l ^. LordDogs)+            result <- select $ do+                lordCte <- with lordQuery+                (lordId, dogs) :& dogs2 <-+                    Experimental.from $+                        (Experimental.from lordCte `union_` lordQuery)+                        `CrossJoin` \(k, _) -> do+                            l2 <- Experimental.from $ table @Lord+                            where_ $ l2 ^. LordId ==. k+                            pure (l2 ^. LordDogs)+                pure (lordId, dogs, dogs2)+            asserting $ result `shouldMatchList`+                [ (Value lid, Value (Just 36), Value (Just 36)) ]++        itDb "separates a branch CTE from CTEs declared after the union" $ do+            -- The right branch declares its own CTE; a CTE introduced in the+            -- enclosing query afterwards must get a distinct ident and+            -- resolve independently of the branch-scoped one.+            lid <- insert l1+            let lordQuery = do+                    l <- Experimental.from $ table @Lord+                    pure (l ^. LordId, l ^. LordDogs)+                branchCteQuery = do+                    c <- with lordQuery+                    Experimental.from c+            result <- select $ do+                (k, d) <- Experimental.from $ lordQuery `union_` branchCteQuery+                outerCte <- with lordQuery+                (k2, d2) <- Experimental.from outerCte+                where_ $ k2 ==. k+                pure (k, d, d2)+            asserting $ result `shouldMatchList`+                [ (Value lid, Value (Just 36), Value (Just 36)) ]+ testPostgresqlNullsOrdering :: SpecDb testPostgresqlNullsOrdering = do   describe "Postgresql NULLS orderings work" $ do