From d6703f9646b046848c5e36fa8ce8cea766597f6f Mon Sep 17 00:00:00 2001 From: Paul Brinkmeier Date: Wed, 3 Jul 2024 17:00:58 +0200 Subject: [PATCH] Add tuple decoding into multiple records --- lib/Database/PostgreSQL/Opium/FromRow.hs | 22 ++++++++++++++++++++++ test/Database/PostgreSQL/OpiumSpec.hs | 7 +++++++ 2 files changed, 29 insertions(+) diff --git a/lib/Database/PostgreSQL/Opium/FromRow.hs b/lib/Database/PostgreSQL/Opium/FromRow.hs index 60bcc06..02a1589 100644 --- a/lib/Database/PostgreSQL/Opium/FromRow.hs +++ b/lib/Database/PostgreSQL/Opium/FromRow.hs @@ -53,12 +53,34 @@ class FromRow a where fromRow result columnTable row = runExceptT $ to <$> fromRow' @0 FRProxy (FromRowCtx result columnTable) row +instance + ( Generic a + , GetColumnTable' (Rep a) + , FromRow' 0 (Rep a) + , Generic b + , GetColumnTable' (Rep b) + , FromRow' (NumberOfMembers (Rep a)) (Rep b) + ) => FromRow (a, b) where + getColumnTable Proxy result = runExceptT $ do + ctA <- newColumnTable <$> getColumnTable' @(Rep a) Proxy result + ctB <- newColumnTable <$> getColumnTable' @(Rep b) Proxy result + pure $ ctA `concatColumnTables` ctB + + fromRow result ct row = runExceptT $ do + x <- to <$> fromRow' @0 FRProxy (FromRowCtx result ct) row + y <- to <$> fromRow' @(NumberOfMembers (Rep a)) FRProxy (FromRowCtx result ct) row + pure (x, y) + newtype ColumnTable = ColumnTable (Vector (Column, Oid)) deriving (Eq, Show) newColumnTable :: [(Column, Oid)] -> ColumnTable newColumnTable = ColumnTable . Vector.fromList +concatColumnTables :: ColumnTable -> ColumnTable -> ColumnTable +concatColumnTables (ColumnTable a) (ColumnTable b) = + ColumnTable $ a <> b + indexColumnTable :: ColumnTable -> Int -> (Column, Oid) indexColumnTable (ColumnTable v) i = v `Vector.unsafeIndex` i diff --git a/test/Database/PostgreSQL/OpiumSpec.hs b/test/Database/PostgreSQL/OpiumSpec.hs index f62a62f..7983ee4 100644 --- a/test/Database/PostgreSQL/OpiumSpec.hs +++ b/test/Database/PostgreSQL/OpiumSpec.hs @@ -122,6 +122,13 @@ spec = do row <- Opium.fromRow result columnTable 0 row `shouldBe` Right (ManyFields "abc" 42 1.0 "test" True) + it "Decodes multiple records into a tuple" $ \conn -> do + Just result <- LibPQ.execParams conn "SELECT 'albus' AS name, 123 AS age, 42 AS only" [] LibPQ.Binary + Right columnTable <- Opium.getColumnTable @(Person, Only Int) Proxy result + + row <- Opium.fromRow @(Person, Only Int) result columnTable 0 + row `shouldBe` Right (Person "albus" 123, Only 42) + describe "fetch" $ do it "Passes numbered parameters and retrieves a list of rows" $ \conn -> do rows <- Opium.fetch "SELECT ($1 + $2) AS only" (17 :: Int, 25 :: Int) conn