Make getColumnTable report missing columns
This commit is contained in:
parent
591f4cddfa
commit
ab396b9db6
@ -62,16 +62,16 @@ fetchResult result = do
|
|||||||
runExceptT $ mapM (ExceptT . flip fromRow result) [0..nRows - 1]
|
runExceptT $ mapM (ExceptT . flip fromRow result) [0..nRows - 1]
|
||||||
|
|
||||||
class FromRow a where
|
class FromRow a where
|
||||||
getColumnTable :: Proxy a -> Result -> IO [LibPQ.Column]
|
getColumnTable :: Proxy a -> Result -> IO (Either Error [Column])
|
||||||
default getColumnTable :: (Generic a, GetColumnTable' (Rep a)) => Proxy a -> Result -> IO [LibPQ.Column]
|
default getColumnTable :: (Generic a, GetColumnTable' (Rep a)) => Proxy a -> Result -> IO (Either Error [Column])
|
||||||
getColumnTable Proxy = getColumnTable' @(Rep a) Proxy
|
getColumnTable Proxy = runExceptT . getColumnTable' @(Rep a) Proxy
|
||||||
|
|
||||||
fromRow :: Row -> Result -> IO (Either Error a)
|
fromRow :: Row -> Result -> IO (Either Error a)
|
||||||
default fromRow :: (Generic a, FromRow' (Rep a)) => Row -> Result -> IO (Either Error a)
|
default fromRow :: (Generic a, FromRow' (Rep a)) => Row -> Result -> IO (Either Error a)
|
||||||
fromRow row result = fmap to <$> fromRow' row result
|
fromRow row result = fmap to <$> fromRow' row result
|
||||||
|
|
||||||
class GetColumnTable' f where
|
class GetColumnTable' f where
|
||||||
getColumnTable' :: Proxy (f p) -> Result -> IO [LibPQ.Column]
|
getColumnTable' :: Proxy (f p) -> Result -> ExceptT Error IO [Column]
|
||||||
|
|
||||||
instance GetColumnTable' f => GetColumnTable' (M1 D c f) where
|
instance GetColumnTable' f => GetColumnTable' (M1 D c f) where
|
||||||
getColumnTable' Proxy = getColumnTable' @f Proxy
|
getColumnTable' Proxy = getColumnTable' @f Proxy
|
||||||
@ -83,17 +83,15 @@ instance (GetColumnTable' f, GetColumnTable' g) => GetColumnTable' (f :*: g) whe
|
|||||||
getColumnTable' Proxy result =
|
getColumnTable' Proxy result =
|
||||||
(++) <$> getColumnTable' @f Proxy result <*> getColumnTable' @g Proxy result
|
(++) <$> getColumnTable' @f Proxy result <*> getColumnTable' @g Proxy result
|
||||||
|
|
||||||
checkColumn :: FromField f => Proxy f -> String -> Result -> IO [Column]
|
checkColumn :: FromField f => Proxy f -> String -> Result -> ExceptT Error IO [Column]
|
||||||
checkColumn Proxy nameStr result = LibPQ.fnumber result name >>= \case
|
checkColumn Proxy nameStr result = do
|
||||||
Just column -> do
|
column <- ExceptT $ maybe (Left $ ErrorMissingColumn nameText) Right <$> LibPQ.fnumber result name
|
||||||
-- TODO: Rewrite FromField to check whether oid works for decoding t
|
-- TODO: Rewrite FromField to check whether oid works for decoding t
|
||||||
_oid <- LibPQ.ftype result column
|
_oid <- ExceptT $ Right <$> LibPQ.ftype result column
|
||||||
pure [column]
|
pure [column]
|
||||||
Nothing -> do
|
|
||||||
-- TODO: Return ErrorMissingColumn
|
|
||||||
undefined
|
|
||||||
where
|
where
|
||||||
name = Encoding.encodeUtf8 $ Text.pack nameStr
|
nameText = Text.pack nameStr
|
||||||
|
name = Encoding.encodeUtf8 nameText
|
||||||
|
|
||||||
instance {-# OVERLAPPABLE #-} (FromField t, KnownSymbol nameSym) => GetColumnTable' (M1 S ('MetaSel ('Just nameSym) nu ns dl) (Rec0 t)) where
|
instance {-# OVERLAPPABLE #-} (FromField t, KnownSymbol nameSym) => GetColumnTable' (M1 S ('MetaSel ('Just nameSym) nu ns dl) (Rec0 t)) where
|
||||||
getColumnTable' Proxy = checkColumn @t Proxy $ symbolVal @nameSym Proxy
|
getColumnTable' Proxy = checkColumn @t Proxy $ symbolVal @nameSym Proxy
|
||||||
|
@ -29,6 +29,7 @@ p \/ q = \x -> p x || q x
|
|||||||
|
|
||||||
data FieldError
|
data FieldError
|
||||||
= FieldErrorUnexpectedNull
|
= FieldErrorUnexpectedNull
|
||||||
|
-- TODO: Move this to the normal Error
|
||||||
| FieldErrorInvalidOid Oid
|
| FieldErrorInvalidOid Oid
|
||||||
| FieldErrorInvalidField Oid Text String
|
| FieldErrorInvalidField Oid Text String
|
||||||
deriving (Eq, Show)
|
deriving (Eq, Show)
|
||||||
|
@ -36,19 +36,24 @@ spec = do
|
|||||||
it "Gets the column table for a result" $ \conn -> do
|
it "Gets the column table for a result" $ \conn -> do
|
||||||
Just result <- LibPQ.execParams conn "SELECT name, age FROM person" [] LibPQ.Text
|
Just result <- LibPQ.execParams conn "SELECT name, age FROM person" [] LibPQ.Text
|
||||||
columnTable <- Opium.getColumnTable @Person Proxy result
|
columnTable <- Opium.getColumnTable @Person Proxy result
|
||||||
columnTable `shouldBe` [0, 1]
|
columnTable `shouldBe` Right [0, 1]
|
||||||
|
|
||||||
it "Gets the numbers right for funky configurations" $ \conn -> do
|
it "Gets the numbers right for funky configurations" $ \conn -> do
|
||||||
Just result0 <- LibPQ.execParams conn "SELECT age, name FROM person" [] LibPQ.Text
|
Just result0 <- LibPQ.execParams conn "SELECT age, name FROM person" [] LibPQ.Text
|
||||||
columnTable0 <- Opium.getColumnTable @Person Proxy result0
|
columnTable0 <- Opium.getColumnTable @Person Proxy result0
|
||||||
columnTable0 `shouldBe` [1, 0]
|
columnTable0 `shouldBe` Right [1, 0]
|
||||||
|
|
||||||
Just result1 <- LibPQ.execParams conn "SELECT 0 a, 1 b, 2 c, age, 4 d, name FROM person" [] LibPQ.Text
|
Just result1 <- LibPQ.execParams conn "SELECT 0 a, 1 b, 2 c, age, 4 d, name FROM person" [] LibPQ.Text
|
||||||
columnTable1 <- Opium.getColumnTable @Person Proxy result1
|
columnTable1 <- Opium.getColumnTable @Person Proxy result1
|
||||||
columnTable1 `shouldBe` [5, 3]
|
columnTable1 `shouldBe` Right [5, 3]
|
||||||
|
|
||||||
|
it "Fails for missing columns" $ \conn -> do
|
||||||
|
Just result <- LibPQ.execParams conn "SELECT 0 a FROM person" [] LibPQ.Text
|
||||||
|
columnTable <- Opium.getColumnTable @Person Proxy result
|
||||||
|
columnTable `shouldBe` Left (Opium.ErrorMissingColumn "name")
|
||||||
|
|
||||||
describe "fromRow" $ do
|
describe "fromRow" $ do
|
||||||
it "decodes rows in a Result" $ \conn -> do
|
it "Decodes rows in a Result" $ \conn -> do
|
||||||
Just result <- LibPQ.execParams conn "SELECT * FROM person" [] LibPQ.Text
|
Just result <- LibPQ.execParams conn "SELECT * FROM person" [] LibPQ.Text
|
||||||
|
|
||||||
row0 <- Opium.fromRow @Person (LibPQ.Row 0) result
|
row0 <- Opium.fromRow @Person (LibPQ.Row 0) result
|
||||||
@ -57,35 +62,31 @@ spec = do
|
|||||||
row1 <- Opium.fromRow @Person (LibPQ.Row 1) result
|
row1 <- Opium.fromRow @Person (LibPQ.Row 1) result
|
||||||
row1 `shouldBe` Right (Person "albus" 103)
|
row1 `shouldBe` Right (Person "albus" 103)
|
||||||
|
|
||||||
it "decodes NULL into Nothing for Maybes" $ \conn -> do
|
it "Decodes NULL into Nothing for Maybes" $ \conn -> do
|
||||||
Just result <- LibPQ.execParams conn "SELECT NULL AS a" [] LibPQ.Text
|
Just result <- LibPQ.execParams conn "SELECT NULL AS a" [] LibPQ.Text
|
||||||
|
|
||||||
row <- Opium.fromRow (LibPQ.Row 0) result
|
row <- Opium.fromRow (LibPQ.Row 0) result
|
||||||
row `shouldBe` Right (MaybeTest Nothing)
|
row `shouldBe` Right (MaybeTest Nothing)
|
||||||
|
|
||||||
it "decodes values into Just for Maybes" $ \conn -> do
|
it "Decodes values into Just for Maybes" $ \conn -> do
|
||||||
Just result <- LibPQ.execParams conn "SELECT 'abc' AS a" [] LibPQ.Text
|
Just result <- LibPQ.execParams conn "SELECT 'abc' AS a" [] LibPQ.Text
|
||||||
|
|
||||||
row <- Opium.fromRow (LibPQ.Row 0) result
|
row <- Opium.fromRow (LibPQ.Row 0) result
|
||||||
row `shouldBe` Right (MaybeTest $ Just "abc")
|
row `shouldBe` Right (MaybeTest $ Just "abc")
|
||||||
|
|
||||||
describe "fetch_" $ do
|
describe "fetch_" $ do
|
||||||
it "retrieves a list of rows" $ \conn -> do
|
it "Retrieves a list of rows" $ \conn -> do
|
||||||
rows <- Opium.fetch_ conn "SELECT * FROM person"
|
rows <- Opium.fetch_ conn "SELECT * FROM person"
|
||||||
rows `shouldBe` Right [Person "paul" 25, Person "albus" 103]
|
rows `shouldBe` Right [Person "paul" 25, Person "albus" 103]
|
||||||
|
|
||||||
it "fails for invalid queries" $ \conn -> do
|
it "Fails for invalid queries" $ \conn -> do
|
||||||
rows <- Opium.fetch_ @Person conn "MRTLBRNFT"
|
rows <- Opium.fetch_ @Person conn "MRTLBRNFT"
|
||||||
rows `shouldSatisfy` isLeft
|
rows `shouldSatisfy` isLeft
|
||||||
|
|
||||||
it "fails for missing columns" $ \conn -> do
|
it "Fails for unexpected NULLs" $ \conn -> do
|
||||||
rows <- Opium.fetch_ @Person conn "SELECT name FROM person"
|
|
||||||
rows `shouldBe` Left (Opium.ErrorMissingColumn "age")
|
|
||||||
|
|
||||||
it "fails for unexpected NULLs" $ \conn -> do
|
|
||||||
rows <- Opium.fetch_ @Person conn "SELECT NULL AS name, 0 AS age"
|
rows <- Opium.fetch_ @Person conn "SELECT NULL AS name, 0 AS age"
|
||||||
rows `shouldBe` Left (Opium.ErrorUnexpectedNull (LibPQ.Row 0) "name")
|
rows `shouldBe` Left (Opium.ErrorUnexpectedNull (LibPQ.Row 0) "name")
|
||||||
|
|
||||||
it "fails for the wrong column type" $ \conn -> do
|
it "Fails for the wrong column type" $ \conn -> do
|
||||||
rows <- Opium.fetch_ @Person conn "SELECT 'quby' AS name, 'indeterminate' AS age"
|
rows <- Opium.fetch_ @Person conn "SELECT 'quby' AS name, 'indeterminate' AS age"
|
||||||
rows `shouldBe` Left (Opium.ErrorDecode (LibPQ.Row 0) "age" $ Opium.FieldErrorInvalidOid $ LibPQ.Oid 25)
|
rows `shouldBe` Left (Opium.ErrorDecode (LibPQ.Row 0) "age" $ Opium.FieldErrorInvalidOid $ LibPQ.Oid 25)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user