From 11f8f6a01a199b578f464da10bf1de94ef8336df Mon Sep 17 00:00:00 2001 From: mangoiv Date: Mon, 30 Oct 2023 18:34:40 +0100 Subject: [PATCH 01/20] [fix] add proper MonadFail instance --- squeal-postgresql/src/Squeal/PostgreSQL/Session.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs b/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs index 9adf2324..051e9097 100644 --- a/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs +++ b/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs @@ -214,9 +214,9 @@ instance (Monad m, db0 ~ db1) return = pure (>>=) = flip pqBind -instance (Monad m, db0 ~ db1) +instance (MonadFail m, db0 ~ db1) => Fail.MonadFail (PQ db0 db1 m) where - fail = Fail.fail + fail = lift . Fail.fail instance db0 ~ db1 => MFunctor (PQ db0 db1) where hoist f (PQ pq) = PQ (f . pq) From 75128fbb8918fc1f43a48d88d3ef2dc55f4d737e Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Sun, 5 Nov 2023 09:34:52 +0800 Subject: [PATCH 02/20] fix doc tests hopefully --- squeal-postgresql/src/Squeal/PostgreSQL/Session.hs | 2 +- squeal-postgresql/src/Squeal/PostgreSQL/Session/Oid.hs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs b/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs index 9adf2324..c0fdf71e 100644 --- a/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs +++ b/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs @@ -46,7 +46,7 @@ import Control.Monad.Fix (MonadFix(..)) import Control.Monad.Catch import Control.Monad.IO.Class (MonadIO(..)) import Control.Monad.Morph -import Control.Monad.Reader (ReaderT(..)) +import Control.Monad.Reader import Control.Monad.Trans.Control (MonadBaseControl(..), MonadTransControl(..)) import UnliftIO (MonadUnliftIO(..)) import Data.ByteString (ByteString) diff --git a/squeal-postgresql/src/Squeal/PostgreSQL/Session/Oid.hs b/squeal-postgresql/src/Squeal/PostgreSQL/Session/Oid.hs index 5380e731..d8c67289 100644 --- a/squeal-postgresql/src/Squeal/PostgreSQL/Session/Oid.hs +++ b/squeal-postgresql/src/Squeal/PostgreSQL/Session/Oid.hs @@ -36,7 +36,7 @@ module Squeal.PostgreSQL.Session.Oid import Control.Monad (when) import Control.Monad.Catch (throwM) -import Control.Monad.Reader (ReaderT(ReaderT)) +import Control.Monad.Reader import Data.String import GHC.TypeLits import PostgreSQL.Binary.Decoding (valueParser, int) From 568d2e7d39799b7fc37d63341260b24a61a0bf75 Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Wed, 10 Jan 2024 09:45:51 -0800 Subject: [PATCH 03/20] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index cace7055..b5f5cfd9 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ ![squeal-icon](https://raw.githubusercontent.com/morphismtech/squeal/dev/squeal.gif) -[![GitHub CI](https://github.com/morphismtech/squeal/workflows/CI/badge.svg)](https://github.com/morphismtech/squeal/actions) - [Github](https://github.com/morphismtech/squeal) [Hackage](https://hackage.haskell.org/package/squeal-postgresql) From af8a3f4d5176f109502560cb8ede16ff66684b3c Mon Sep 17 00:00:00 2001 From: Peter Becich Date: Sun, 14 Jan 2024 17:36:28 -0800 Subject: [PATCH 04/20] update GitHub Action https://github.com/haskell/actions deprecated replaced with https://github.com/haskell-actions/setup --- .github/workflows/ci.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7989fde..f3cb488e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,8 +23,8 @@ jobs: options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v2 - - uses: haskell/actions/setup@v1 + - uses: actions/checkout@v4 + - uses: haskell-actions/setup@v2 with: enable-stack: true stack-version: 'latest' @@ -50,7 +50,7 @@ jobs: run: stack haddock --fast - name: cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | ".stack-work" @@ -73,7 +73,7 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: haskell/actions/setup@v1 + - uses: haskell-actions/setup@v2 with: enable-stack: true stack-version: 'latest' @@ -99,7 +99,7 @@ jobs: run: stack haddock --fast --stack-yaml stack-ghc8_10.yaml - name: cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | ".stack-work" @@ -122,7 +122,7 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: haskell/actions/setup@v1 + - uses: haskell-actions/setup@v2 with: enable-stack: true stack-version: 'latest' @@ -148,7 +148,7 @@ jobs: run: stack haddock --fast --stack-yaml stack-ghc8_8.yaml - name: cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | ".stack-work" From 88f7532b87ac7d3d18982a1a38603ef3c184d93c Mon Sep 17 00:00:00 2001 From: Daniel Gasienica Date: Tue, 12 Mar 2024 22:51:14 +0100 Subject: [PATCH 05/20] README: Document macOS database creation --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cace7055..3bdb8152 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ composable and cover a large portion of SQL. ## testing Start postgres on localhost port `5432` and create a database named `exampledb`. +On macOS, you can create the database using `createdb exampledb`. `stack test` From fb0113e5c0bf540bf1eaa5664ecdabb15349280e Mon Sep 17 00:00:00 2001 From: Daniel Gasienica Date: Tue, 12 Mar 2024 22:52:09 +0100 Subject: [PATCH 06/20] Introduce parametrized query --- squeal-postgresql/exe/Example.hs | 70 +++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/squeal-postgresql/exe/Example.hs b/squeal-postgresql/exe/Example.hs index 6fe3cd9d..5f0e656a 100644 --- a/squeal-postgresql/exe/Example.hs +++ b/squeal-postgresql/exe/Example.hs @@ -54,7 +54,7 @@ type OrgSchema = , "organization" ::: 'NoDef :=> 'NotNull 'PGint4 ]) ] -type Schemas +type Schemas = '[ "public" ::: PublicSchema, "user" ::: UserSchema, "org" ::: OrgSchema ] setup :: Definition (Public '[]) Schemas @@ -93,7 +93,7 @@ setup = (OnDelete Cascade) (OnUpdate Cascade) `as` #fk_member :* foreignKey #organization (#org ! #organizations) #id (OnDelete Cascade) (OnUpdate Cascade) `as` #fk_organization ) - + teardown :: Definition Schemas (Public '[]) teardown = dropType #positive >>> dropSchemaCascade #user >>> dropSchemaCascade #org @@ -106,6 +106,11 @@ insertEmail :: Manipulation_ Schemas (Int32, Maybe Text) () insertEmail = insertInto_ (#user ! #emails) (Values_ (Default `as` #id :* Set (param @1) `as` #user_id :* Set (param @2) `as` #email)) +insertOrganization :: Manipulation_ Schemas (Only Text) (Only Int32) +insertOrganization = insertInto (#org ! #organizations) + (Values_ (Default `as` #id :* Set (param @1) `as` #name)) + (OnConflict (OnConstraint #pk_organizations) DoNothing) (Returning_ (#id `as` #fromOnly)) + getUsers :: Query_ Schemas () User getUsers = select_ (#u ! #name `as` #userName :* #e ! #email `as` #userEmail :* #u ! #vec `as` #userVec) @@ -113,6 +118,20 @@ getUsers = select_ & innerJoin (table ((#user ! #emails) `as` #e)) (#u ! #id .== #e ! #user_id)) ) +getOrganizations :: Query_ Schemas () Organization +getOrganizations = select_ + (#o ! #id `as` #orgId :* #o ! #name `as` #orgName) + (from (table (#org ! #organizations `as` #o))) + +getOrganizationsBy :: Query_ Schemas (Only Int32) Organization +getOrganizationsBy = + select_ + (#o ! #id `as` #orgId :* #o ! #name `as` #orgName) + ( + from (table (#org ! #organizations `as` #o)) + & where_ (#o ! #id .== param @1) + ) + upsertUser :: Manipulation_ Schemas (Int32, String, VarArray [Maybe Int16]) () upsertUser = insertInto (#user ! #users `as` #u) (Values_ (Set (param @1) `as` #id :* setUser)) @@ -137,28 +156,59 @@ users = , User "Carole" (Just "carole@hotmail.com") (VarArray [Just 3,Nothing, Just 4]) ] +data Organization + = Organization + { orgId :: Int32 + , orgName :: Text + } deriving (Show, GHC.Generic) +instance SOP.Generic Organization +instance SOP.HasDatatypeInfo Organization + +organizations :: [Organization] +organizations = + [ Organization { orgId = 1, orgName = "ACME" } + , Organization { orgId = 2, orgName = "Haskell Foundation" } + ] + session :: (MonadIO pq, MonadPQ Schemas pq) => pq () session = do - liftIO $ Char8.putStrLn "manipulating" - idResults <- traversePrepared insertUser ([(userName user, userVec user) | user <- users]) - ids <- traverse (fmap fromOnly . getRow 0) (idResults :: [Result (Only Int32)]) - traversePrepared_ insertEmail (zip (ids :: [Int32]) (userEmail <$> users)) - liftIO $ Char8.putStrLn "querying" + liftIO $ Char8.putStrLn "===> manipulating" + userIdResults <- traversePrepared insertUser [(userName user, userVec user) | user <- users] + userIds <- traverse (fmap fromOnly . getRow 0) (userIdResults :: [Result (Only Int32)]) + traversePrepared_ insertEmail (zip (userIds :: [Int32]) (userEmail <$> users)) + + orgIdResults <- traversePrepared + insertOrganization + [Only (orgName organization) | organization <- organizations] + _ <- traverse (fmap fromOnly . getRow 0) (orgIdResults :: [Result (Only Int32)]) + + liftIO $ Char8.putStrLn "===> querying: users" usersResult <- runQuery getUsers usersRows <- getRows usersResult liftIO $ print (usersRows :: [User]) + liftIO $ Char8.putStrLn "===> querying: organizations" + organizationsResult <- runQuery getOrganizations + organizationRows <- getRows organizationsResult + liftIO $ print (organizationRows :: [Organization]) + + organizationsResult2 <- runQueryParams getOrganizationsBy (Only (1 :: Int32)) + organizationRows2 <- getRows organizationsResult2 + liftIO $ print (organizationRows2 :: [Organization]) + main :: IO () main = do - Char8.putStrLn "squeal" + Char8.putStrLn "===> squeal" connectionString <- pure "host=localhost port=5432 dbname=exampledb user=postgres password=postgres" Char8.putStrLn $ "connecting to " <> connectionString connection0 <- connectdb connectionString - Char8.putStrLn "setting up schema" + + Char8.putStrLn "===> setting up schema" connection1 <- execPQ (define setup) connection0 connection2 <- execPQ session connection1 - Char8.putStrLn "tearing down schema" + + Char8.putStrLn "===> tearing down schema" connection3 <- execPQ (define teardown) connection2 finish connection3 From f1104aa11fbd4f1eddba51215c0546c4125f3b12 Mon Sep 17 00:00:00 2001 From: Daniel Gasienica Date: Tue, 12 Mar 2024 23:05:43 +0100 Subject: [PATCH 07/20] Parametrize query --- squeal-postgresql/exe/Example.hs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/squeal-postgresql/exe/Example.hs b/squeal-postgresql/exe/Example.hs index 5f0e656a..ca3be07d 100644 --- a/squeal-postgresql/exe/Example.hs +++ b/squeal-postgresql/exe/Example.hs @@ -123,13 +123,21 @@ getOrganizations = select_ (#o ! #id `as` #orgId :* #o ! #name `as` #orgName) (from (table (#org ! #organizations `as` #o))) -getOrganizationsBy :: Query_ Schemas (Only Int32) Organization -getOrganizationsBy = +getOrganizationsBy :: + Condition + 'Ungrouped + '[] + '[] + Schemas + '[ 'NotNull 'PGint4] + '["o" ::: ["id" ::: NotNull PGint4, "name" ::: NotNull PGtext]] -> + Query_ Schemas (Only Int32) Organization +getOrganizationsBy condition = select_ (#o ! #id `as` #orgId :* #o ! #name `as` #orgName) ( from (table (#org ! #organizations `as` #o)) - & where_ (#o ! #id .== param @1) + & where_ condition ) upsertUser :: Manipulation_ Schemas (Int32, String, VarArray [Maybe Int16]) () @@ -192,7 +200,8 @@ session = do organizationRows <- getRows organizationsResult liftIO $ print (organizationRows :: [Organization]) - organizationsResult2 <- runQueryParams getOrganizationsBy (Only (1 :: Int32)) + organizationsResult2 <- runQueryParams + (getOrganizationsBy ((#o ! #id) .== param @1)) (Only (1 :: Int32)) organizationRows2 <- getRows organizationsResult2 liftIO $ print (organizationRows2 :: [Organization]) From 722af9b74b9d57ac06410c8b351f6b1f605726eb Mon Sep 17 00:00:00 2001 From: Daniel Gasienica Date: Wed, 13 Mar 2024 00:10:06 +0100 Subject: [PATCH 08/20] FAIL: How to make this generic? --- squeal-postgresql/exe/Example.hs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/squeal-postgresql/exe/Example.hs b/squeal-postgresql/exe/Example.hs index ca3be07d..daf31a14 100644 --- a/squeal-postgresql/exe/Example.hs +++ b/squeal-postgresql/exe/Example.hs @@ -9,6 +9,9 @@ , TypeOperators #-} +{-# LANGUAGE ScopedTypeVariables #-} + + module Main (main, main2, upsertUser) where import Control.Monad.IO.Class (MonadIO (..)) @@ -124,14 +127,15 @@ getOrganizations = select_ (from (table (#org ! #organizations `as` #o))) getOrganizationsBy :: + forall pgty hsty. Condition 'Ungrouped '[] '[] Schemas - '[ 'NotNull 'PGint4] + '[ 'NotNull pgty ] '["o" ::: ["id" ::: NotNull PGint4, "name" ::: NotNull PGtext]] -> - Query_ Schemas (Only Int32) Organization + Query_ Schemas (Only hsty) Organization getOrganizationsBy condition = select_ (#o ! #id `as` #orgId :* #o ! #name `as` #orgName) @@ -205,6 +209,11 @@ session = do organizationRows2 <- getRows organizationsResult2 liftIO $ print (organizationRows2 :: [Organization]) + organizationsResult3 <- runQueryParams + (getOrganizationsBy ((#o ! #name) .== param @1)) (Only ("ACME" :: Text)) + organizationRows3 <- getRows organizationsResult3 + liftIO $ print (organizationRows2 :: [Organization]) + main :: IO () main = do Char8.putStrLn "===> squeal" From 3a1851b62fab908c5bc7d213de26cb3c556c1019 Mon Sep 17 00:00:00 2001 From: Daniel Gasienica Date: Wed, 13 Mar 2024 23:02:16 +0100 Subject: [PATCH 09/20] Make `getOrganizationsBy` generic --- squeal-postgresql/exe/Example.hs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/squeal-postgresql/exe/Example.hs b/squeal-postgresql/exe/Example.hs index daf31a14..27f167d0 100644 --- a/squeal-postgresql/exe/Example.hs +++ b/squeal-postgresql/exe/Example.hs @@ -10,7 +10,7 @@ #-} {-# LANGUAGE ScopedTypeVariables #-} - +{-# LANGUAGE AllowAmbiguousTypes #-} module Main (main, main2, upsertUser) where @@ -128,6 +128,7 @@ getOrganizations = select_ getOrganizationsBy :: forall pgty hsty. + NullPG hsty ~ NotNull pgty => Condition 'Ungrouped '[] @@ -205,14 +206,14 @@ session = do liftIO $ print (organizationRows :: [Organization]) organizationsResult2 <- runQueryParams - (getOrganizationsBy ((#o ! #id) .== param @1)) (Only (1 :: Int32)) + (getOrganizationsBy @'PGint4 @Int32 ((#o ! #id) .== param @1)) (Only (1 :: Int32)) organizationRows2 <- getRows organizationsResult2 liftIO $ print (organizationRows2 :: [Organization]) organizationsResult3 <- runQueryParams - (getOrganizationsBy ((#o ! #name) .== param @1)) (Only ("ACME" :: Text)) + (getOrganizationsBy @'PGtext @Text ((#o ! #name) .== param @1)) (Only ("Haskell Foundation" :: Text)) organizationRows3 <- getRows organizationsResult3 - liftIO $ print (organizationRows2 :: [Organization]) + liftIO $ print (organizationRows3 :: [Organization]) main :: IO () main = do From 168813cb68626f8c826e5f3e4abe6754b28cbdce Mon Sep 17 00:00:00 2001 From: Daniel Gasienica Date: Wed, 13 Mar 2024 23:09:20 +0100 Subject: [PATCH 10/20] Simplify by removing `pgty` --- squeal-postgresql/exe/Example.hs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/squeal-postgresql/exe/Example.hs b/squeal-postgresql/exe/Example.hs index 27f167d0..a4724a2c 100644 --- a/squeal-postgresql/exe/Example.hs +++ b/squeal-postgresql/exe/Example.hs @@ -127,14 +127,14 @@ getOrganizations = select_ (from (table (#org ! #organizations `as` #o))) getOrganizationsBy :: - forall pgty hsty. - NullPG hsty ~ NotNull pgty => + forall hsty. + (ToPG Schemas hsty) => Condition 'Ungrouped '[] '[] Schemas - '[ 'NotNull pgty ] + '[NullPG hsty] '["o" ::: ["id" ::: NotNull PGint4, "name" ::: NotNull PGtext]] -> Query_ Schemas (Only hsty) Organization getOrganizationsBy condition = @@ -206,12 +206,12 @@ session = do liftIO $ print (organizationRows :: [Organization]) organizationsResult2 <- runQueryParams - (getOrganizationsBy @'PGint4 @Int32 ((#o ! #id) .== param @1)) (Only (1 :: Int32)) + (getOrganizationsBy @Int32 ((#o ! #id) .== param @1)) (Only (1 :: Int32)) organizationRows2 <- getRows organizationsResult2 liftIO $ print (organizationRows2 :: [Organization]) organizationsResult3 <- runQueryParams - (getOrganizationsBy @'PGtext @Text ((#o ! #name) .== param @1)) (Only ("Haskell Foundation" :: Text)) + (getOrganizationsBy @Text ((#o ! #name) .== param @1)) (Only ("ACME" :: Text)) organizationRows3 <- getRows organizationsResult3 liftIO $ print (organizationRows3 :: [Organization]) From 21057aa06d19cbbc6b63be7b209918b3d0c25d17 Mon Sep 17 00:00:00 2001 From: Daniel Gasienica Date: Wed, 13 Mar 2024 23:30:25 +0100 Subject: [PATCH 11/20] Query by custom type However, this is not (yet) type-safe. --- squeal-postgresql/exe/Example.hs | 75 +++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 15 deletions(-) diff --git a/squeal-postgresql/exe/Example.hs b/squeal-postgresql/exe/Example.hs index a4724a2c..88772bff 100644 --- a/squeal-postgresql/exe/Example.hs +++ b/squeal-postgresql/exe/Example.hs @@ -9,11 +9,15 @@ , TypeOperators #-} -{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeFamilies #-} module Main (main, main2, upsertUser) where +import Control.Monad.Except (MonadError (throwError)) import Control.Monad.IO.Class (MonadIO (..)) import Data.Int (Int16, Int32) import Data.Text (Text) @@ -49,6 +53,7 @@ type OrgSchema = '[ "pk_organizations" ::: 'PrimaryKey '["id"] ] :=> '[ "id" ::: 'Def :=> 'NotNull 'PGint4 , "name" ::: 'NoDef :=> 'NotNull 'PGtext + , "type" ::: 'NoDef :=> 'NotNull 'PGtext ]) , "members" ::: 'Table ( '[ "fk_member" ::: 'ForeignKey '["member"] "user" "users" '["id"] @@ -86,7 +91,8 @@ setup = >>> createTable (#org ! #organizations) ( serial `as` #id :* - (text & notNullable) `as` #name ) + (text & notNullable) `as` #name :* + (text & notNullable) `as` #type ) ( primaryKey #id `as` #pk_organizations ) >>> createTable (#org ! #members) @@ -109,9 +115,9 @@ insertEmail :: Manipulation_ Schemas (Int32, Maybe Text) () insertEmail = insertInto_ (#user ! #emails) (Values_ (Default `as` #id :* Set (param @1) `as` #user_id :* Set (param @2) `as` #email)) -insertOrganization :: Manipulation_ Schemas (Only Text) (Only Int32) +insertOrganization :: Manipulation_ Schemas (Text, OrganizationType) (Only Int32) insertOrganization = insertInto (#org ! #organizations) - (Values_ (Default `as` #id :* Set (param @1) `as` #name)) + (Values_ (Default `as` #id :* Set (param @1) `as` #name :* Set (param @2) `as` #type)) (OnConflict (OnConstraint #pk_organizations) DoNothing) (Returning_ (#id `as` #fromOnly)) getUsers :: Query_ Schemas () User @@ -123,7 +129,10 @@ getUsers = select_ getOrganizations :: Query_ Schemas () Organization getOrganizations = select_ - (#o ! #id `as` #orgId :* #o ! #name `as` #orgName) + ( #o ! #id `as` #orgId :* + #o ! #name `as` #orgName :* + #o ! #type `as` #orgType + ) (from (table (#org ! #organizations `as` #o))) getOrganizationsBy :: @@ -135,11 +144,14 @@ getOrganizationsBy :: '[] Schemas '[NullPG hsty] - '["o" ::: ["id" ::: NotNull PGint4, "name" ::: NotNull PGtext]] -> + '["o" ::: ["id" ::: NotNull PGint4, "name" ::: NotNull PGtext, "type" ::: NotNull PGtext]] -> Query_ Schemas (Only hsty) Organization getOrganizationsBy condition = select_ - (#o ! #id `as` #orgId :* #o ! #name `as` #orgName) + ( #o ! #id `as` #orgId :* + #o ! #name `as` #orgName :* + #o ! #type `as` #orgType + ) ( from (table (#org ! #organizations `as` #o)) & where_ condition @@ -173,14 +185,39 @@ data Organization = Organization { orgId :: Int32 , orgName :: Text + , orgType :: OrganizationType } deriving (Show, GHC.Generic) instance SOP.Generic Organization instance SOP.HasDatatypeInfo Organization +data OrganizationType + = ForProfit + | NonProfit + deriving (Show, GHC.Generic) +instance SOP.Generic OrganizationType +instance SOP.HasDatatypeInfo OrganizationType + +instance IsPG OrganizationType where + type PG OrganizationType = 'PGtext +instance ToPG db OrganizationType where + toPG = toPG . toText + where + toText ForProfit = "for-profit" :: Text + toText NonProfit = "non-profit" :: Text + +instance FromPG OrganizationType where + fromPG = do + value <- fromPG @Text + fromText value + where + fromText "for-profit" = pure ForProfit + fromText "non-profit" = pure NonProfit + fromText value = throwError $ "Invalid organization type: \"" <> value <> "\"" + organizations :: [Organization] organizations = - [ Organization { orgId = 1, orgName = "ACME" } - , Organization { orgId = 2, orgName = "Haskell Foundation" } + [ Organization { orgId = 1, orgName = "ACME", orgType = ForProfit } + , Organization { orgId = 2, orgName = "Haskell Foundation", orgType = NonProfit } ] session :: (MonadIO pq, MonadPQ Schemas pq) => pq () @@ -192,7 +229,7 @@ session = do orgIdResults <- traversePrepared insertOrganization - [Only (orgName organization) | organization <- organizations] + [(orgName organization, orgType organization) | organization <- organizations] _ <- traverse (fmap fromOnly . getRow 0) (orgIdResults :: [Result (Only Int32)]) liftIO $ Char8.putStrLn "===> querying: users" @@ -200,21 +237,29 @@ session = do usersRows <- getRows usersResult liftIO $ print (usersRows :: [User]) - liftIO $ Char8.putStrLn "===> querying: organizations" - organizationsResult <- runQuery getOrganizations - organizationRows <- getRows organizationsResult - liftIO $ print (organizationRows :: [Organization]) + liftIO $ Char8.putStrLn "===> querying: organizations: all" + organizationsResult1 <- runQuery getOrganizations + organizationRows1 <- getRows organizationsResult1 + liftIO $ print (organizationRows1 :: [Organization]) + liftIO $ Char8.putStrLn "===> querying: organizations: by ID (2)" organizationsResult2 <- runQueryParams - (getOrganizationsBy @Int32 ((#o ! #id) .== param @1)) (Only (1 :: Int32)) + (getOrganizationsBy @Int32 ((#o ! #id) .== param @1)) (Only (2 :: Int32)) organizationRows2 <- getRows organizationsResult2 liftIO $ print (organizationRows2 :: [Organization]) + liftIO $ Char8.putStrLn "===> querying: organizations: by name (ACME)" organizationsResult3 <- runQueryParams (getOrganizationsBy @Text ((#o ! #name) .== param @1)) (Only ("ACME" :: Text)) organizationRows3 <- getRows organizationsResult3 liftIO $ print (organizationRows3 :: [Organization]) + liftIO $ Char8.putStrLn "===> querying: organizations: by type (non-profit)" + organizationsResult4 <- runQueryParams + (getOrganizationsBy @Text ((#o ! #type) .== param @1)) (Only NonProfit) + organizationRows4 <- getRows organizationsResult4 + liftIO $ print (organizationRows4 :: [Organization]) + main :: IO () main = do Char8.putStrLn "===> squeal" From 2157aac3b3d6caf31c72354882185dc5cffb8505 Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Tue, 19 Mar 2024 12:09:35 -0700 Subject: [PATCH 12/20] ghc updates --- .github/workflows/ci.yml | 22 +++++++++++----------- README.md | 2 ++ squeal-postgresql/README.md | 2 +- stack-ghc9_6.yaml | 4 +--- stack.yaml | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f3cb488e..14b23e2d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: branches: [ dev ] jobs: - ghc9_0: + ghc_default: runs-on: ubuntu-latest services: @@ -56,7 +56,7 @@ jobs: ".stack-work" "/root/.stack/" key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - ghc8_10: + ghc9_6: runs-on: ubuntu-latest services: @@ -81,10 +81,10 @@ jobs: stack-setup-ghc: true - name: build - run: stack build --fast --stack-yaml stack-ghc8_10.yaml + run: stack build --fast --stack-yaml stack-ghc9_6.yaml - name: test - run: stack test --fast --stack-yaml stack-ghc8_10.yaml + run: stack test --fast --stack-yaml stack-ghc9_6.yaml env: PG_USER: postgres PG_HOST: localhost @@ -93,10 +93,10 @@ jobs: PG_PORT: ${{ job.services.postgres.ports['5432'] }} - name: benchmark - run: stack bench --fast --stack-yaml stack-ghc8_10.yaml + run: stack bench --fast --stack-yaml stack-ghc9_6.yaml - name: documentation - run: stack haddock --fast --stack-yaml stack-ghc8_10.yaml + run: stack haddock --fast --stack-yaml stack-ghc9_6.yaml - name: cache uses: actions/cache@v3 @@ -105,7 +105,7 @@ jobs: ".stack-work" "/root/.stack/" key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - ghc8_8: + ghc9_4: runs-on: ubuntu-latest services: @@ -130,10 +130,10 @@ jobs: stack-setup-ghc: true - name: build - run: stack build --fast --stack-yaml stack-ghc8_8.yaml + run: stack build --fast --stack-yaml stack-ghc9_4.yaml - name: test - run: stack test --fast --stack-yaml stack-ghc8_8.yaml + run: stack test --fast --stack-yaml stack-ghc9_4.yaml env: PG_USER: postgres PG_HOST: localhost @@ -142,10 +142,10 @@ jobs: PG_PORT: ${{ job.services.postgres.ports['5432'] }} - name: benchmark - run: stack bench --fast --stack-yaml stack-ghc8_8.yaml + run: stack bench --fast --stack-yaml stack-ghc9_4.yaml - name: documentation - run: stack haddock --fast --stack-yaml stack-ghc8_8.yaml + run: stack haddock --fast --stack-yaml stack-ghc9_4.yaml - name: cache uses: actions/cache@v3 diff --git a/README.md b/README.md index b5f5cfd9..0cd15ee6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ ![squeal-icon](https://raw.githubusercontent.com/morphismtech/squeal/dev/squeal.gif) +[![GithubWorkflowCI](https://github.com/morphismtech/squeal/actions/workflows/ci.yml/badge.svg)](https://github.com/morphismtech/squeal/actions/workflows/ci.yml) + [Github](https://github.com/morphismtech/squeal) [Hackage](https://hackage.haskell.org/package/squeal-postgresql) diff --git a/squeal-postgresql/README.md b/squeal-postgresql/README.md index 1cd89548..775a88c4 100644 --- a/squeal-postgresql/README.md +++ b/squeal-postgresql/README.md @@ -2,7 +2,7 @@ ![squeal-icon](https://raw.githubusercontent.com/morphismtech/squeal/dev/squeal.gif) -[![CircleCI](https://circleci.com/gh/echatav/squeal.svg?style=svg&circle-token=a699a654ef50db2c3744fb039cf2087c484d1226)](https://circleci.com/gh/morphismtech/squeal) +[![GithubWorkflowCI](https://github.com/morphismtech/squeal/actions/workflows/ci.yml/badge.svg)](https://github.com/morphismtech/squeal/actions/workflows/ci.yml) [Github](https://github.com/morphismtech/squeal) diff --git a/stack-ghc9_6.yaml b/stack-ghc9_6.yaml index 895dc347..c5529aee 100644 --- a/stack-ghc9_6.yaml +++ b/stack-ghc9_6.yaml @@ -1,7 +1,5 @@ -resolver: nightly-2023-08-29 +resolver: lts-22.13 packages: - squeal-postgresql - squeal-postgresql-ltree - squeal-postgresql-uuid-ossp -extra-deps: -- records-sop-0.1.1.1 diff --git a/stack.yaml b/stack.yaml index df8c0068..c5529aee 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,4 +1,4 @@ -resolver: lts-19.33 +resolver: lts-22.13 packages: - squeal-postgresql - squeal-postgresql-ltree From ffccddf14ee8d181c8f2ea3e3e570e3da5683c90 Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Tue, 19 Mar 2024 15:50:40 -0700 Subject: [PATCH 13/20] test doctest on CI --- squeal-postgresql/squeal-postgresql.cabal | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/squeal-postgresql/squeal-postgresql.cabal b/squeal-postgresql/squeal-postgresql.cabal index 8fa67808..7aec8502 100644 --- a/squeal-postgresql/squeal-postgresql.cabal +++ b/squeal-postgresql/squeal-postgresql.cabal @@ -126,8 +126,8 @@ test-suite doctest build-depends: base >= 4.12.0.0 && < 5.0 , doctest >= 0.16.3 - if impl(ghc >= 9.0.0) - buildable: False + -- if impl(ghc >= 9.0.0) + -- buildable: False test-suite properties default-language: Haskell2010 From 336e5c07e3d08ce0dfa727e38646526c35ae4fac Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Tue, 19 Mar 2024 16:13:39 -0700 Subject: [PATCH 14/20] remove --- .github/workflows/ci.yml | 20 ++++++++++---------- squeal-postgresql/squeal-postgresql.cabal | 4 ++-- stack-ghc9_6.yaml | 5 ----- 3 files changed, 12 insertions(+), 17 deletions(-) delete mode 100644 stack-ghc9_6.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14b23e2d..6b206078 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,7 @@ jobs: ".stack-work" "/root/.stack/" key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - ghc9_6: + ghc9_4: runs-on: ubuntu-latest services: @@ -81,10 +81,10 @@ jobs: stack-setup-ghc: true - name: build - run: stack build --fast --stack-yaml stack-ghc9_6.yaml + run: stack build --fast --stack-yaml stack-ghc9_4.yaml - name: test - run: stack test --fast --stack-yaml stack-ghc9_6.yaml + run: stack test --fast --stack-yaml stack-ghc9_4.yaml env: PG_USER: postgres PG_HOST: localhost @@ -93,10 +93,10 @@ jobs: PG_PORT: ${{ job.services.postgres.ports['5432'] }} - name: benchmark - run: stack bench --fast --stack-yaml stack-ghc9_6.yaml + run: stack bench --fast --stack-yaml stack-ghc9_4.yaml - name: documentation - run: stack haddock --fast --stack-yaml stack-ghc9_6.yaml + run: stack haddock --fast --stack-yaml stack-ghc9_4.yaml - name: cache uses: actions/cache@v3 @@ -105,7 +105,7 @@ jobs: ".stack-work" "/root/.stack/" key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - ghc9_4: + ghc9_2: runs-on: ubuntu-latest services: @@ -130,10 +130,10 @@ jobs: stack-setup-ghc: true - name: build - run: stack build --fast --stack-yaml stack-ghc9_4.yaml + run: stack build --fast --stack-yaml stack-ghc9_2.yaml - name: test - run: stack test --fast --stack-yaml stack-ghc9_4.yaml + run: stack test --fast --stack-yaml stack-ghc9_2.yaml env: PG_USER: postgres PG_HOST: localhost @@ -142,10 +142,10 @@ jobs: PG_PORT: ${{ job.services.postgres.ports['5432'] }} - name: benchmark - run: stack bench --fast --stack-yaml stack-ghc9_4.yaml + run: stack bench --fast --stack-yaml stack-ghc9_2.yaml - name: documentation - run: stack haddock --fast --stack-yaml stack-ghc9_4.yaml + run: stack haddock --fast --stack-yaml stack-ghc9_2.yaml - name: cache uses: actions/cache@v3 diff --git a/squeal-postgresql/squeal-postgresql.cabal b/squeal-postgresql/squeal-postgresql.cabal index 7aec8502..8fa67808 100644 --- a/squeal-postgresql/squeal-postgresql.cabal +++ b/squeal-postgresql/squeal-postgresql.cabal @@ -126,8 +126,8 @@ test-suite doctest build-depends: base >= 4.12.0.0 && < 5.0 , doctest >= 0.16.3 - -- if impl(ghc >= 9.0.0) - -- buildable: False + if impl(ghc >= 9.0.0) + buildable: False test-suite properties default-language: Haskell2010 diff --git a/stack-ghc9_6.yaml b/stack-ghc9_6.yaml deleted file mode 100644 index c5529aee..00000000 --- a/stack-ghc9_6.yaml +++ /dev/null @@ -1,5 +0,0 @@ -resolver: lts-22.13 -packages: -- squeal-postgresql -- squeal-postgresql-ltree -- squeal-postgresql-uuid-ossp From e8b97a9b37c5c93928d09c1f810def5ebef763d8 Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Wed, 11 Sep 2024 19:03:03 -0700 Subject: [PATCH 15/20] ArrayField --- .../src/Squeal/PostgreSQL/Session.hs | 1 - .../src/Squeal/PostgreSQL/Session/Decode.hs | 37 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs b/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs index 25c4a85e..71ad1cce 100644 --- a/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs +++ b/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs @@ -44,7 +44,6 @@ import Control.Monad (MonadPlus(..)) import Control.Monad.Base (MonadBase(..)) import Control.Monad.Fix (MonadFix(..)) import Control.Monad.Catch -import Control.Monad.IO.Class (MonadIO(..)) import Control.Monad.Morph import Control.Monad.Reader import Control.Monad.Trans.Control (MonadBaseControl(..), MonadTransControl(..)) diff --git a/squeal-postgresql/src/Squeal/PostgreSQL/Session/Decode.hs b/squeal-postgresql/src/Squeal/PostgreSQL/Session/Decode.hs index b52ddb06..e4f55580 100644 --- a/squeal-postgresql/src/Squeal/PostgreSQL/Session/Decode.hs +++ b/squeal-postgresql/src/Squeal/PostgreSQL/Session/Decode.hs @@ -43,6 +43,7 @@ module Squeal.PostgreSQL.Session.Decode , genericProductRow , appendRows , consRow + , ArrayField (..) -- * Decoding Classes , FromValue (..) , FromField (..) @@ -533,6 +534,42 @@ instance {-# OVERLAPPABLE #-} IsLabel fld (MaybeT (DecodeRow row) y) fromLabel = MaybeT . decodeRow $ \(_ SOP.:* bs) -> runDecodeRow (runMaybeT (fromLabel @fld)) bs +{- | Utility for decoding array fields in a `DecodeRow`, +accessed via overloaded labels. +-} +newtype ArrayField row y = ArrayField + { runArrayField + :: StateT Strict.ByteString (Except Strict.Text) y + -> DecodeRow row [y] + } +instance {-# OVERLAPPING #-} + ( KnownSymbol fld + , PG y ~ ty + , arr ~ 'NotNull ('PGvararray ('NotNull ty)) + ) => IsLabel fld (ArrayField (fld ::: arr ': row) y) where + fromLabel = ArrayField $ \yval -> + decodeRow $ \(SOP.K bytesMaybe SOP.:* _) -> do + let + flderr = mconcat + [ "field name: " + , "\"", fromString (symbolVal (SOP.Proxy @fld)), "\"; " + ] + yarr + = devalue + . array + . dimensionArray replicateM + . valueArray + . revalue + $ yval + case bytesMaybe of + Nothing -> Left (flderr <> "encountered unexpected NULL") + Just bytes -> runExcept (evalStateT yarr bytes) +instance {-# OVERLAPPABLE #-} IsLabel fld (ArrayField row y) + => IsLabel fld (ArrayField (field ': row) y) where + fromLabel = ArrayField $ \yval -> + decodeRow $ \(_ SOP.:* bytess) -> + runDecodeRow (runArrayField (fromLabel @fld) yval) bytess + -- | A `GenericRow` constraint to ensure that a Haskell type -- is a record type, -- has a `RowPG`, From b126ae9d7f0f1c925e29308fd7d3639de4e633de Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Fri, 13 Sep 2024 18:32:21 -0700 Subject: [PATCH 16/20] array functions --- .../src/Squeal/PostgreSQL/Expression/Array.hs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/squeal-postgresql/src/Squeal/PostgreSQL/Expression/Array.hs b/squeal-postgresql/src/Squeal/PostgreSQL/Expression/Array.hs index c35e8b74..003d36b0 100644 --- a/squeal-postgresql/src/Squeal/PostgreSQL/Expression/Array.hs +++ b/squeal-postgresql/src/Squeal/PostgreSQL/Expression/Array.hs @@ -37,6 +37,15 @@ module Squeal.PostgreSQL.Expression.Array , unnest , arrAny , arrAll + , arrayAppend + , arrayPrepend + , arrayCat + , arrayPosition + , arrayPositionBegins + , arrayPositions + , arrayRemoveNull + , arrayReplace + , trimArray ) where import Data.String @@ -47,6 +56,7 @@ import qualified Generics.SOP as SOP import Squeal.PostgreSQL.Expression import Squeal.PostgreSQL.Expression.Logic +import Squeal.PostgreSQL.Expression.Null import Squeal.PostgreSQL.Expression.Type import Squeal.PostgreSQL.Query.From.Set import Squeal.PostgreSQL.Render @@ -240,3 +250,42 @@ arrAny -> Expression grp lat with db params from (null ('PGvararray ty2)) -- ^ array -> Condition grp lat with db params from arrAny x (?) xs = x ? (UnsafeExpression $ "ANY" <+> parenthesized (renderSQL xs)) + +arrayAppend :: '[null ('PGvararray ty), ty] ---> null ('PGvararray ty) +arrayAppend = unsafeFunctionN "array_append" + +arrayPrepend :: '[ty, null ('PGvararray ty)] ---> null ('PGvararray ty) +arrayPrepend = unsafeFunctionN "array_prepend" + +arrayCat + :: '[null ('PGvararray ty), null ('PGvararray ty)] + ---> null ('PGvararray ty) +arrayCat = unsafeFunctionN "array_cat" + +arrayPosition :: '[null ('PGvararray ty), ty] ---> 'Null 'PGint8 +arrayPosition = unsafeFunctionN "array_position" + +arrayPositionBegins + :: '[null ('PGvararray ty), ty, null 'PGint8] ---> 'Null 'PGint8 +arrayPositionBegins = unsafeFunctionN "array_position" + +arrayPositions + :: '[null ('PGvararray ty), ty] + ---> null ('PGvararray ('NotNull 'PGint8)) +arrayPositions = unsafeFunctionN "array_positions" + +arrayRemove :: '[null ('PGvararray ty), ty] ---> null ('PGvararray ty) +arrayRemove = unsafeFunctionN "array_remove" + +arrayRemoveNull :: null ('PGvararray ('Null ty)) --> null ('PGvararray ('NotNull ty)) +arrayRemoveNull arr = UnsafeExpression (renderSQL (arrayRemove (arr *: null_))) + +arrayReplace + :: '[null ('PGvararray ty), ty, ty] + ---> null ('PGvararray ty) +arrayReplace = unsafeFunctionN "array_replace" + +trimArray + :: '[null ('PGvararray ty), 'NotNull 'PGint8] + ---> null ('PGvararray ty) +trimArray = unsafeFunctionN "trim_array" From cfe347f2e479f38ba464f28f397c8e598a3578b3 Mon Sep 17 00:00:00 2001 From: Michael Xavier Date: Mon, 9 Dec 2024 16:47:36 -0800 Subject: [PATCH 17/20] Add support for postgresql-binary-0.14 postgresql-binary-0.14, which is now in stackage nightlies, swaps out the type `NetAddr IP` from the `network-ip` package for its inet type with `IPRange` from the `iproute` package. This change adds CPP so that both build. --- squeal-postgresql/squeal-postgresql.cabal | 1 + .../src/Squeal/PostgreSQL/Session/Decode.hs | 13 ++++++++++--- .../src/Squeal/PostgreSQL/Session/Encode.hs | 11 ++++++++++- squeal-postgresql/src/Squeal/PostgreSQL/Type/PG.hs | 11 ++++++++++- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/squeal-postgresql/squeal-postgresql.cabal b/squeal-postgresql/squeal-postgresql.cabal index 8fa67808..6beadb4c 100644 --- a/squeal-postgresql/squeal-postgresql.cabal +++ b/squeal-postgresql/squeal-postgresql.cabal @@ -99,6 +99,7 @@ library , free-categories >= 0.2.0.0 , generics-sop >= 0.5.1.0 , hashable >= 1.3.0.0 + , iproute >= 1.7.0 , mmorph >= 1.1.3 , monad-control >= 1.0.2.3 , mtl >= 2.2.2 diff --git a/squeal-postgresql/src/Squeal/PostgreSQL/Session/Decode.hs b/squeal-postgresql/src/Squeal/PostgreSQL/Session/Decode.hs index b52ddb06..9a5f4670 100644 --- a/squeal-postgresql/src/Squeal/PostgreSQL/Session/Decode.hs +++ b/squeal-postgresql/src/Squeal/PostgreSQL/Session/Decode.hs @@ -68,6 +68,11 @@ import Data.Bits import Data.Coerce (coerce) import Data.Functor.Constant (Constant(Constant)) import Data.Int (Int16, Int32, Int64) +#if MIN_VERSION_postgresql_binary(0, 14, 0) +import Data.IP (IPRange) +#else +import Network.IP.Addr (NetAddr, IP) +#endif import Data.Kind import Data.Scientific (Scientific) import Data.String (fromString) @@ -78,7 +83,6 @@ import Data.Vector (Vector) import Database.PostgreSQL.LibPQ (Oid(Oid)) import GHC.OverloadedLabels import GHC.TypeLits -import Network.IP.Addr (NetAddr, IP) import PostgreSQL.Binary.Decoding hiding (Composite) import Unsafe.Coerce @@ -200,8 +204,11 @@ instance FromPG Money where fromPG = devalue $ Money <$> int instance FromPG UUID where fromPG = devalue uuid -instance FromPG (NetAddr IP) where - fromPG = devalue inet +#if MIN_VERSION_postgresql_binary(0, 14, 0) +instance FromPG IPRange where fromPG = devalue inet +#else +instance FromPG (NetAddr IP) where fromPG = devalue inet +#endif instance FromPG Char where fromPG = devalue char instance FromPG Strict.Text where diff --git a/squeal-postgresql/src/Squeal/PostgreSQL/Session/Encode.hs b/squeal-postgresql/src/Squeal/PostgreSQL/Session/Encode.hs index f917d8c3..b3641dd3 100644 --- a/squeal-postgresql/src/Squeal/PostgreSQL/Session/Encode.hs +++ b/squeal-postgresql/src/Squeal/PostgreSQL/Session/Encode.hs @@ -11,6 +11,7 @@ encoding of statement parameters {-# LANGUAGE AllowAmbiguousTypes , ConstraintKinds + , CPP , DataKinds , DefaultSignatures , FlexibleContexts @@ -59,6 +60,11 @@ import Data.Functor.Const (Const(Const)) import Data.Functor.Constant (Constant(Constant)) import Data.Functor.Contravariant import Data.Int (Int16, Int32, Int64) +#if MIN_VERSION_postgresql_binary(0, 14, 0) +import Data.IP (IPRange) +#else +import Network.IP.Addr (NetAddr, IP) +#endif import Data.Kind import Data.Scientific (Scientific) import Data.Text as Strict (Text) @@ -69,7 +75,6 @@ import Data.Vector (Vector) import Data.Word (Word32) import Foreign.C.Types (CUInt(CUInt)) import GHC.TypeLits -import Network.IP.Addr (NetAddr, IP) import PostgreSQL.Binary.Encoding hiding (Composite, field) import qualified Data.Aeson as Aeson @@ -121,7 +126,11 @@ instance ToPG db Double where toPG = pure . float8 instance ToPG db Scientific where toPG = pure . numeric instance ToPG db Money where toPG = pure . int8_int64 . cents instance ToPG db UUID where toPG = pure . uuid +#if MIN_VERSION_postgresql_binary(0, 14, 0) +instance ToPG db IPRange where toPG = pure . inet +#else instance ToPG db (NetAddr IP) where toPG = pure . inet +#endif instance ToPG db Char where toPG = pure . char_utf8 instance ToPG db Strict.Text where toPG = pure . text_strict instance ToPG db Lazy.Text where toPG = pure . text_lazy diff --git a/squeal-postgresql/src/Squeal/PostgreSQL/Type/PG.hs b/squeal-postgresql/src/Squeal/PostgreSQL/Type/PG.hs index c7ecef25..8ae4ebc5 100644 --- a/squeal-postgresql/src/Squeal/PostgreSQL/Type/PG.hs +++ b/squeal-postgresql/src/Squeal/PostgreSQL/Type/PG.hs @@ -10,6 +10,7 @@ into corresponding Postgres types. -} {-# LANGUAGE AllowAmbiguousTypes + , CPP , DeriveAnyClass , DeriveFoldable , DeriveFunctor @@ -57,12 +58,16 @@ import Data.Functor.Const (Const) import Data.Functor.Constant (Constant) import Data.Kind (Type) import Data.Int (Int16, Int32, Int64) +#if MIN_VERSION_postgresql_binary(0, 14, 0) +import Data.IP (IPRange) +#else +import Network.IP.Addr (NetAddr, IP) +#endif import Data.Scientific (Scientific) import Data.Time (Day, DiffTime, LocalTime, TimeOfDay, TimeZone, UTCTime) import Data.Vector (Vector) import Data.UUID.Types (UUID) import GHC.TypeLits -import Network.IP.Addr (NetAddr, IP) import qualified Data.ByteString.Lazy as Lazy (ByteString) import qualified Data.ByteString as Strict (ByteString) @@ -166,7 +171,11 @@ instance IsPG DiffTime where type PG DiffTime = 'PGinterval -- | `PGuuid` instance IsPG UUID where type PG UUID = 'PGuuid -- | `PGinet` +#if MIN_VERSION_postgresql_binary(0, 14, 0) +instance IsPG IPRange where type PG IPRange = 'PGinet +#else instance IsPG (NetAddr IP) where type PG (NetAddr IP) = 'PGinet +#endif -- | `PGjson` instance IsPG Value where type PG Value = 'PGjson -- | `PGvarchar` From 73a40224e7f750e10a3e1b11d07853ccfb1b2413 Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Mon, 23 Dec 2024 08:39:02 -0800 Subject: [PATCH 18/20] Update Session.hs --- squeal-postgresql/src/Squeal/PostgreSQL/Session.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs b/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs index 25c4a85e..71ad1cce 100644 --- a/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs +++ b/squeal-postgresql/src/Squeal/PostgreSQL/Session.hs @@ -44,7 +44,6 @@ import Control.Monad (MonadPlus(..)) import Control.Monad.Base (MonadBase(..)) import Control.Monad.Fix (MonadFix(..)) import Control.Monad.Catch -import Control.Monad.IO.Class (MonadIO(..)) import Control.Monad.Morph import Control.Monad.Reader import Control.Monad.Trans.Control (MonadBaseControl(..), MonadTransControl(..)) From d7cdd01b771a3bf5d837d161094301c7ff4a7b9c Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Mon, 23 Dec 2024 09:09:46 -0800 Subject: [PATCH 19/20] v 0.9.2.0 --- squeal-postgresql/squeal-postgresql.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/squeal-postgresql/squeal-postgresql.cabal b/squeal-postgresql/squeal-postgresql.cabal index 6beadb4c..699b212c 100644 --- a/squeal-postgresql/squeal-postgresql.cabal +++ b/squeal-postgresql/squeal-postgresql.cabal @@ -1,6 +1,6 @@ cabal-version: 2.2 name: squeal-postgresql -version: 0.9.1.3 +version: 0.9.2.0 synopsis: Squeal PostgreSQL Library description: Squeal is a type-safe embedding of PostgreSQL in Haskell homepage: https://github.com/morphismtech/squeal From 533cab7bbc4ccd8da2872af511c79acf9896cd8c Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Mon, 23 Dec 2024 09:16:38 -0800 Subject: [PATCH 20/20] Update RELEASE NOTES.md --- RELEASE NOTES.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/RELEASE NOTES.md b/RELEASE NOTES.md index 6daa97c7..23b4f25b 100644 --- a/RELEASE NOTES.md +++ b/RELEASE NOTES.md @@ -1,5 +1,13 @@ ## RELEASE NOTES +## Version 0.9.2.0 + +Thanks to MangoIV, Peter Becich, Daniel Gasienica and Michael Xavier Well +for their contributions! + +Fixes for various bugs and updates added as well as some new array functions +and array decoding functionality. + ## Version 0.9.0.0 Thanks to William Yao and Cullin Poresky for their contributions!