diff --git a/README.md b/README.md index efdb9ee..5618d56 100644 --- a/README.md +++ b/README.md @@ -67,3 +67,5 @@ getScoreByAge conn = do - [ ] Implement JSON decoding - [ ] Implement `ByteString` decoding (`bytea`) - Can we make the fromField instance choose whether it wants binary or text? +- [ ] Implement (anonymous) composite types + - It seems that in order to decode these, we'd need to use binary mode. In order to avoid writing everything twice it would be wise to move the whole `FromField` machinery to decoding from binary first diff --git a/lib/Database/PostgreSQL/Opium/FromField.hs b/lib/Database/PostgreSQL/Opium/FromField.hs index e723b78..338e43b 100644 --- a/lib/Database/PostgreSQL/Opium/FromField.hs +++ b/lib/Database/PostgreSQL/Opium/FromField.hs @@ -41,22 +41,28 @@ class FromField a where -- | See https://www.postgresql.org/docs/current/datatype-character.html. instance FromField Text where - validOid _ = Oid.text \/ Oid.character \/ Oid.characterVarying + validOid Proxy = Oid.text \/ Oid.character \/ Oid.characterVarying parseField = takeText -- | See https://www.postgresql.org/docs/current/datatype-character.html. instance FromField String where - validOid _ = validOid @Text Proxy + validOid Proxy = validOid @Text Proxy parseField = Text.unpack <$> parseField -- | See https://www.postgresql.org/docs/current/datatype-character.html. -- This instance accepts all character types but fails to decode fields that are not exactly one character. instance FromField Char where - validOid _ = validOid @Text Proxy + validOid Proxy = validOid @Text Proxy parseField = anyChar +-- | See https://www.postgresql.org/docs/current/datatype-numeric.html. instance FromField Int where - validOid _ = Oid.smallint \/ Oid.integer \/ Oid.bigint + validOid Proxy = Oid.smallint \/ Oid.integer \/ Oid.bigint + parseField = signed decimal + +-- | See https://www.postgresql.org/docs/current/datatype-numeric.html. +instance FromField Integer where + validOid Proxy = Oid.smallint \/ Oid.integer \/ Oid.bigint parseField = signed decimal doubleParser :: Parser Double @@ -70,11 +76,11 @@ doubleParser = choice infinity = 1 / 0 instance FromField Float where - validOid _ = Oid.real + validOid Proxy = Oid.real parseField = fmap double2Float doubleParser instance FromField Double where - validOid _ = Oid.real \/ Oid.doublePrecision + validOid Proxy = Oid.real \/ Oid.doublePrecision parseField = doubleParser boolParser :: Parser Bool @@ -85,5 +91,5 @@ boolParser = choice -- | See https://www.postgresql.org/docs/current/datatype-boolean.html. instance FromField Bool where - validOid _ = Oid.boolean + validOid Proxy = Oid.boolean parseField = boolParser diff --git a/test/Database/PostgreSQL/Opium/FromFieldSpec.hs b/test/Database/PostgreSQL/Opium/FromFieldSpec.hs index 74b50ec..966ef55 100644 --- a/test/Database/PostgreSQL/Opium/FromFieldSpec.hs +++ b/test/Database/PostgreSQL/Opium/FromFieldSpec.hs @@ -18,6 +18,12 @@ newtype AnInt = AnInt instance FromRow AnInt where +newtype AnInteger = AnInteger + { integer :: Integer + } deriving (Eq, Generic, Show) + +instance FromRow AnInteger where + newtype AText = AText { text :: Text } deriving (Eq, Generic, Show) @@ -72,7 +78,17 @@ spec = do shouldFetch conn "SELECT 42::INTEGER AS int" [AnInt 42] it "Decodes bigint" $ \conn -> do - shouldFetch conn "SELECT 42::BIGINT AS int" [AnInt 42] + shouldFetch conn "SELECT pow(2, 48)::BIGINT AS int" [AnInt $ (2 :: Int) ^ (48 :: Int)] + + describe "FromField Integer" $ do + it "Decodes smallint" $ \conn -> do + shouldFetch conn "SELECT 42::SMALLINT AS integer" [AnInteger 42] + + it "Decodes integer" $ \conn -> do + shouldFetch conn "SELECT pow(2, 20)::INTEGER AS integer" [AnInteger $ (2 :: Integer) ^ (20 :: Integer)] + + it "Decodes bigint" $ \conn -> do + shouldFetch conn "SELECT pow(2, 48)::BIGINT AS integer" [AnInteger $ (2 :: Integer) ^ (48 :: Integer)] describe "FromField Text" $ do it "Decodes text" $ \conn -> do