Implement date -> Day decoding

This commit is contained in:
Paul Brinkmeier 2023-09-23 11:11:29 +02:00
parent 4d21e67130
commit 126b8ee6e9
6 changed files with 32 additions and 0 deletions
README.mdflake.nix
lib/Database/PostgreSQL/Opium
opium.cabal
test/Database/PostgreSQL/Opium

@ -63,6 +63,7 @@ getScoreByAge conn = do
- [x] Implement `Float` and `Double` decoding - [x] Implement `Float` and `Double` decoding
- [x] Clean up and document column table stuff - [x] Clean up and document column table stuff
- [x] Decode `LibPQ.Binary` - [x] Decode `LibPQ.Binary`
- [x] Implement `date -> Day` decoding
- [ ] Implement `fetch` (`fetch_` but with parameter passing) - [ ] Implement `fetch` (`fetch_` but with parameter passing)
- [ ] Implement `UTCTime` and zoned time decoding - [ ] Implement `UTCTime` and zoned time decoding
- [ ] Implement JSON decoding - [ ] Implement JSON decoding

@ -20,6 +20,7 @@
hspec hspec
postgresql-libpq postgresql-libpq
text text
time
transformers transformers
vector vector
])) ]))

@ -11,7 +11,9 @@ import Data.Attoparsec.ByteString (Parser)
import Data.Bits (Bits (..)) import Data.Bits (Bits (..))
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import Data.Functor (($>)) import Data.Functor (($>))
import Data.Int (Int32)
import Data.Proxy (Proxy (..)) import Data.Proxy (Proxy (..))
import Data.Time (Day (..))
import Data.Text (Text) import Data.Text (Text)
import Data.Word (Word32, Word64) import Data.Word (Word32, Word64)
import Database.PostgreSQL.LibPQ (Oid) import Database.PostgreSQL.LibPQ (Oid)
@ -107,3 +109,11 @@ boolParser = AP.choice
instance FromField Bool where instance FromField Bool where
validOid Proxy = Oid.boolean validOid Proxy = Oid.boolean
parseField = boolParser parseField = boolParser
-- | See https://www.postgresql.org/docs/current/datatype-datetime.html.
-- Relevant as well: https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/adt/datetime.c;h=267dfd37b2e8b9bc63797c69b9ca2e45e6bfde61;hb=HEAD#l267.
instance FromField Day where
validOid Proxy = Oid.date
parseField = fromJulianDay . fromIntegral <$> intParser @Int32
where
fromJulianDay x = ModifiedJulianDay $ x + 51544

@ -48,3 +48,7 @@ doublePrecision = eq $ Oid 701
-- | Boolean -- | Boolean
boolean :: Oid -> Bool boolean :: Oid -> Bool
boolean = eq $ Oid 16 boolean = eq $ Oid 16
-- | Single days/dates.
date :: Oid -> Bool
date = eq $ Oid 1082

@ -79,6 +79,7 @@ library
containers, containers,
postgresql-libpq, postgresql-libpq,
text, text,
time,
transformers, transformers,
vector vector
@ -122,4 +123,5 @@ test-suite opium-test
bytestring, bytestring,
hspec, hspec,
postgresql-libpq, postgresql-libpq,
time,
text text

@ -4,6 +4,7 @@
module Database.PostgreSQL.Opium.FromFieldSpec (spec) where module Database.PostgreSQL.Opium.FromFieldSpec (spec) where
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import Data.Time (Day (..), fromGregorian)
import Data.Text (Text) import Data.Text (Text)
import Database.PostgreSQL.LibPQ (Connection) import Database.PostgreSQL.LibPQ (Connection)
import Database.PostgreSQL.Opium (FromRow) import Database.PostgreSQL.Opium (FromRow)
@ -72,6 +73,12 @@ newtype ABool = ABool
instance FromRow ABool where instance FromRow ABool where
newtype ADay = ADay
{ day :: Day
} deriving (Eq, Generic, Show)
instance FromRow ADay where
shouldFetch :: (Eq a, FromRow a, Show a) => Connection -> ByteString -> [a] -> IO () shouldFetch :: (Eq a, FromRow a, Show a) => Connection -> ByteString -> [a] -> IO ()
shouldFetch conn query expectedRows = do shouldFetch conn query expectedRows = do
actualRows <- Opium.fetch_ conn query actualRows <- Opium.fetch_ conn query
@ -200,3 +207,10 @@ spec = do
shouldFetch conn "SELECT 'no'::boolean AS bool" [ABool False] shouldFetch conn "SELECT 'no'::boolean AS bool" [ABool False]
shouldFetch conn "SELECT 'off'::boolean AS bool" [ABool False] shouldFetch conn "SELECT 'off'::boolean AS bool" [ABool False]
shouldFetch conn "SELECT 0::boolean AS bool" [ABool False] shouldFetch conn "SELECT 0::boolean AS bool" [ABool False]
describe "FromField Day" $ do
it "Decodes date" $ \conn -> do
shouldFetch conn "SELECT date '1970-01-01' AS day" [ADay $ fromGregorian 1970 1 1]
shouldFetch conn "SELECT date '2023-09-23' AS day" [ADay $ fromGregorian 2023 9 23]
-- Example from postgres doc page
shouldFetch conn "SELECT date 'J2451187' AS day" [ADay $ fromGregorian 1999 1 8]