diff --git a/changelog.md b/changelog.md index 5a38c39..c7c440b 100644 --- a/changelog.md +++ b/changelog.md @@ -1,9 +1,15 @@ -3.5.2.3 +3.5.3.0 ======= +- @m4dc4p + - [#291](https://github.com/bitemyapp/esqueleto/pull/291) + - Added `ToAlias` and `ToAliasReference` instaces to the `:&` type, mirroring + the tuple instances for the same classes. See [Issue #290](https://github.com/bitemyapp/esqueleto/issues/290) + for discussion. - @NikitaRazmakhnin - [#284](https://github.com/bitemyapp/esqueleto/pull/284) - Add PostgreSQL-specific support of VALUES(..) literals + 3.5.2.2 ======= - @NikitaRazmakhnin diff --git a/esqueleto.cabal b/esqueleto.cabal index 6cc357a..691d579 100644 --- a/esqueleto.cabal +++ b/esqueleto.cabal @@ -1,7 +1,7 @@ cabal-version: 1.12 name: esqueleto -version: 3.5.2.3 +version: 3.5.3.0 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. . diff --git a/src/Database/Esqueleto/Experimental/From/Join.hs b/src/Database/Esqueleto/Experimental/From/Join.hs index 7559ca7..24ea8f4 100644 --- a/src/Database/Esqueleto/Experimental/From/Join.hs +++ b/src/Database/Esqueleto/Experimental/From/Join.hs @@ -61,6 +61,18 @@ instance (SqlSelect a ra, SqlSelect b rb) => SqlSelect (a :& b) (ra :& rb) where toTuple = const Proxy sqlSelectProcessRow = fmap (uncurry (:&)) . sqlSelectProcessRow +-- | Identical to the tuple instance and provided for convenience. +-- +-- @since 3.5.3.0 +instance (ToAlias a, ToAlias b) => ToAlias (a :& b) where + toAlias (a :& b) = (:&) <$> toAlias a <*> toAlias b + +-- | Identical to the tuple instance and provided for convenience. +-- +-- @since 3.5.3.0 +instance (ToAliasReference a, ToAliasReference b) => ToAliasReference (a :& b) where + toAliasReference ident (a :& b) = (:&) <$> (toAliasReference ident a) <*> (toAliasReference ident b) + -- | An @ON@ clause that describes how two tables are related. This should be -- used as an infix operator after a 'JOIN'. For example, -- diff --git a/test/Common/Test.hs b/test/Common/Test.hs index a8c3d5c..b5daa95 100644 --- a/test/Common/Test.hs +++ b/test/Common/Test.hs @@ -2275,7 +2275,6 @@ testExperimentalFrom = do , (l2e, l2e) ] - itDb "compiles" $ do let q = do (persons :& profiles :& posts) <- @@ -2300,6 +2299,24 @@ testExperimentalFrom = do asserting $ upperNames `shouldMatchList` [ Value "JOHN" , Value "MIKE" ] + itDb "allows re-using (:&) joined tables" $ do + let q = do + result@(persons :& profiles :& posts) <- + Experimental.from $ Table @Person + `InnerJoin` Table @Profile + `Experimental.on` (\(people :& profiles) -> + people ^. PersonId ==. profiles ^. ProfilePerson) + `InnerJoin` Table @BlogPost + `Experimental.on` (\(people :& _ :& posts) -> + people ^. PersonId ==. posts ^. BlogPostAuthorId) + pure result + rows <- select $ do + (persons :& profiles :& posts) <- Experimental.from $ q + pure (persons ^. PersonId, profiles ^. ProfileId, posts ^. BlogPostId) + let result = coerce rows :: [(PersonId, ProfileId, BlogPostId)] + -- We don't care about eh result of the query, only that it + -- rendered & executed. + asserting noExceptions listsEqualOn :: (HasCallStack, Show a1, Eq a1) => [a2] -> [a2] -> (a2 -> a1) -> Expectation listsEqualOn a b f = map f a `shouldBe` map f b