beam
beam copied to clipboard
Error reporting is not sufficient
Hi,
My app gets following exception up on basic select all from a single table:
ManyErrors [
BeamRowReadError {brreColumn = Nothing, brreError = ColumnErrorInternal "Prelude.read: no parse"},
BeamRowReadError {brreColumn = Just 17, brreError = ColumnTypeMismatch {ctmHaskellType = "Null", ctmSQLType = "TEXT", ctmMessage = "conversion failed: data is not null"}},
BeamRowReadError {brreColumn = Just 0, brreError = ColumnTypeMismatch {ctmHaskellType = "Null", ctmSQLType = "TEXT", ctmMessage = "conversion failed: data is not null"}}]
I would like to see table name and a showed raw row which has problem values.
I achieved an intermediate success with hard coding logger to show the raw row causing the issue:
- translateErrors :: Maybe Int -> SomeException -> Maybe SomeException
- translateErrors col (SomeException e) =
+ translateErrors :: Maybe Int -> [SQLData] -> SomeException -> Maybe SomeException
+ translateErrors col rawRow (SomeException e) =
case cast e of
Just (ConversionFailed { errSQLType = typeString
, errHaskellType = hsString
, errMessage = msg }) ->
- Just (SomeException (BeamRowReadError col (ColumnTypeMismatch hsString typeString ("conversion failed: " ++ msg))))
+ Just (SomeException (BeamRowReadError col (ColumnTypeMismatch hsString typeString
+ ("conversion failed: " ++ msg ++ " for row: " ++ show rawRow))))
Just (UnexpectedNull {}) ->
Just (SomeException (BeamRowReadError col ColumnUnexpectedNull))
Just (Incompatible { errSQLType = typeString
, errHaskellType = hsString
, errMessage = msg }) ->
- Just (SomeException (BeamRowReadError col (ColumnTypeMismatch hsString typeString ("incompatible: " ++ msg))))
+ Just (SomeException (BeamRowReadError col (ColumnTypeMismatch hsString typeString
+ ("incompatible: " ++ msg ++ " for row: " ++ show rawRow))))
Nothing -> Nothing
finish = pure
@@ -230,7 +232,7 @@ instance FromBackendRow Sqlite a => FromRow (BeamSqliteRow a) where
RP $ ReaderT $ \ro -> StateT $ \st@(col, _) ->
case runStateT (runReaderT (unRP field) ro) st of
Ok (x, st') -> runStateT (runReaderT (unRP (next x)) ro) st'
- Errors errs -> Errors (mapMaybe (translateErrors (Just col)) errs)
+ Errors errs -> Errors (mapMaybe (translateErrors (Just col) (snd st)) errs)
Logging data might not be acceptable for production mode so I tried to make the feature plugable via runBeamSqliteDebug, but I don't see how to deliver another callback to translateErrors. I extended FromBackendRowF with extra field for the callback, but how to update existing instances?
newtype RawRowShow = RawRowShow (forall a. Show a => a -> Maybe String)
data FromBackendRowF be f where
ParseOneField :: (BackendFromField be a, Typeable a) => RawRowShow -> (a -> f) -> FromBackendRowF be f
e.g.
parseOneField :: (BackendFromField be a, Typeable a) => FromBackendRowM be a
parseOneField = do
x <- FromBackendRowM (liftF (ParseOneField id id))
pure x
peekField :: (Typeable a, BackendFromField be a) => FromBackendRowM be (Maybe a)
peekField = fmap Just (FromBackendRowM (liftF (ParseOneField id id))) <|> pure Nothing