diff --git a/changelog.md b/changelog.md index 28a7e50e3..374965c31 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,9 @@ - @blujupiter32 - [#379](https://github.com/bitemyapp/esqueleto/pull/379) - Fix a bug where `not_ (a &&. b)` would be interpeted as `(not_ a) &&. b` +- @RikvanToor + - [#373](https://github.com/bitemyapp/esqueleto/pull/373), [#410](https://github.com/bitemyapp/esqueleto/pull/410) + - Fix name clashes when using CTEs multiple times - @TeofilC - [#394](https://github.com/bitemyapp/esqueleto/pull/394) - Use TH quotes to eliminate some CPP. diff --git a/esqueleto.cabal b/esqueleto.cabal index 262e92307..c4c69c4fa 100644 --- a/esqueleto.cabal +++ b/esqueleto.cabal @@ -87,6 +87,7 @@ test-suite specs main-is: Spec.hs other-modules: Common.Test + Common.Test.CTE Common.Test.Models Common.Test.Import Common.Test.Select diff --git a/src/Database/Esqueleto/Experimental/From/CommonTableExpression.hs b/src/Database/Esqueleto/Experimental/From/CommonTableExpression.hs index a0d72b9f0..2a7898b97 100644 --- a/src/Database/Esqueleto/Experimental/From/CommonTableExpression.hs +++ b/src/Database/Esqueleto/Experimental/From/CommonTableExpression.hs @@ -53,7 +53,11 @@ with query = do let clause = CommonTableExpressionClause NormalCommonTableExpression ident (\info -> toRawSql SELECT info aliasedQuery) Q $ W.tell mempty{sdCteClause = [clause]} ref <- toAliasReference ident aliasedValue - pure $ From $ pure (ref, (\_ info -> (useIdent info ident, mempty))) + pure $ From $ do + newIdent <- newIdentFor (DBName "cte") + localRef <- toAliasReference newIdent ref + let makeLH info = useIdent info ident <> " AS " <> useIdent info newIdent + pure (localRef, (\_ info -> (makeLH info, mempty))) -- | @WITH@ @RECURSIVE@ allows one to make a recursive subquery, which can -- reference itself. Like @WITH@, this is supported in most modern SQL engines. diff --git a/test/Common/Test.hs b/test/Common/Test.hs index f79cafd55..823b4c9a7 100644 --- a/test/Common/Test.hs +++ b/test/Common/Test.hs @@ -91,6 +91,7 @@ import qualified UnliftIO.Resource as R import Common.Record (testDeriveEsqueletoRecord) import Common.Test.Select +import qualified Common.Test.CTE as CTESpec -- Test schema -- | this could be achieved with S.fromList, but not all lists @@ -2426,6 +2427,7 @@ tests = testLocking testOverloadedRecordDot testDeriveEsqueletoRecord + CTESpec.testCTE insert' :: ( Functor m , BaseBackend backend ~ PersistEntityBackend val diff --git a/test/Common/Test/CTE.hs b/test/Common/Test/CTE.hs new file mode 100644 index 000000000..7243a5662 --- /dev/null +++ b/test/Common/Test/CTE.hs @@ -0,0 +1,35 @@ +{-# language TypeApplications #-} + +module Common.Test.CTE where + +import Common.Test.Models +import Common.Test.Import +import Database.Persist.TH + +testCTE :: SpecDb +testCTE = describe "CTE" $ do + itDb "can refer to the same CTE twice" $ do + let q :: SqlQuery (SqlExpr (Value Int), SqlExpr (Value Int)) + q = do + bCte <- with $ do + b <- from $ table @B + pure b + + a :& b1 :& b2 <- from $ + table @A + `innerJoin` bCte + `on` do + \(a :& b) -> + a ^. AK ==. b ^. BK + `innerJoin` bCte + `on` do + \(a :& _ :& b2) -> + a ^. AK ==. b2 ^. BK + pure (a ^. AK, a ^. AV +. b1 ^. BV +. b2 ^. BV) + insert_ $ A { aK = 1, aV = 2 } + insert_ $ B { bK = 1, bV = 3 } + ret <- select q + asserting $ do + ret `shouldMatchList` + [ (Value 1, Value (2 + 3 + 3)) + ] diff --git a/test/Common/Test/Models.hs b/test/Common/Test/Models.hs index dc6b94530..2a1ada117 100644 --- a/test/Common/Test/Models.hs +++ b/test/Common/Test/Models.hs @@ -182,6 +182,16 @@ share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistUpperCase| address String deriving Show deriving Eq + + A + k Int + v Int + Primary k + + B + k Int + v Int + Primary k |] -- Unique Test schema diff --git a/test/PostgreSQL/Test.hs b/test/PostgreSQL/Test.hs index 583d89fcb..695a35769 100644 --- a/test/PostgreSQL/Test.hs +++ b/test/PostgreSQL/Test.hs @@ -1347,7 +1347,6 @@ testPostgresqlLocking = do EP.forUpdateOf p EP.skipLocked return p - liftIO $ print nonLockedRowsSpecifiedTable pure $ length nonLockedRowsSpecifiedTable `shouldBe` 2 withAsync sideThread $ \sideThreadAsync -> do @@ -1371,7 +1370,6 @@ testPostgresqlLocking = do EP.forUpdateOf p EP.skipLocked return p - liftIO $ print nonLockedRowsAfterUpdate asserting sideThreadAsserts asserting $ length nonLockedRowsAfterUpdate `shouldBe` 3