Commit 821311ae authored by Alfredo Di Napoli's avatar Alfredo Di Napoli

JSON enum roundtrips for BackendErrorType

parent 922529c3
...@@ -144,6 +144,7 @@ library ...@@ -144,6 +144,7 @@ library
Gargantext.Database.Schema.User Gargantext.Database.Schema.User
Gargantext.Defaults Gargantext.Defaults
Gargantext.System.Logging Gargantext.System.Logging
Gargantext.Utils.Dict
Gargantext.Utils.Jobs Gargantext.Utils.Jobs
Gargantext.Utils.Jobs.Internal Gargantext.Utils.Jobs.Internal
Gargantext.Utils.Jobs.Map Gargantext.Utils.Jobs.Map
......
...@@ -21,7 +21,6 @@ import Gargantext.Database.Query.Table.Node.Error hiding (nodeError) ...@@ -21,7 +21,6 @@ import Gargantext.Database.Query.Table.Node.Error hiding (nodeError)
import Servant.Server import Servant.Server
import qualified Data.Aeson as JSON import qualified Data.Aeson as JSON
import qualified Network.HTTP.Types.Status as HTTP import qualified Network.HTTP.Types.Status as HTTP
import Data.Data
import qualified Data.Text as T import qualified Data.Text as T
backendErrorTypeToErrStatus :: BackendErrorType -> HTTP.Status backendErrorTypeToErrStatus :: BackendErrorType -> HTTP.Status
...@@ -53,9 +52,9 @@ nodeErrorToFrontendError ne = case ne of ...@@ -53,9 +52,9 @@ nodeErrorToFrontendError ne = case ne of
NoListFound _lid NoListFound _lid
-> undefined -> undefined
NoRootFound NoRootFound
-> mkFrontendErr' renderedError Proxy FE_node_error_root_not_found -> mkFrontendErr' renderedError FE_node_error_root_not_found
NoCorpusFound NoCorpusFound
-> mkFrontendErr' renderedError Proxy FE_node_error_corpus_not_found -> mkFrontendErr' renderedError FE_node_error_corpus_not_found
NoUserFound _ur NoUserFound _ur
-> undefined -> undefined
MkNode MkNode
......
...@@ -48,6 +48,7 @@ import Gargantext.Core.Types (HasValidationError(..)) ...@@ -48,6 +48,7 @@ import Gargantext.Core.Types (HasValidationError(..))
import Gargantext.Database.Admin.Types.Node import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Query.Table.Node.Error import Gargantext.Database.Query.Table.Node.Error
import Gargantext.Database.Query.Tree.Error import Gargantext.Database.Query.Tree.Error
import Gargantext.Utils.Dict
import Prelude import Prelude
import Servant (ServerError) import Servant (ServerError)
import Servant.Job.Core import Servant.Job.Core
...@@ -146,11 +147,6 @@ instance Eq FrontendError where ...@@ -146,11 +147,6 @@ instance Eq FrontendError where
Nothing -> False Nothing -> False
Just Refl -> fe_data_1 == fe_data_2 Just Refl -> fe_data_1 == fe_data_2
data Dict (c :: k -> Constraint) (a :: k) where
Dict :: c a => Dict c a
deriving instance Show (Dict c a)
class ( SingI payload class ( SingI payload
, ToJSON (ToFrontendErrorData payload) , ToJSON (ToFrontendErrorData payload)
, FromJSON (ToFrontendErrorData payload) , FromJSON (ToFrontendErrorData payload)
...@@ -212,17 +208,15 @@ instance FromJSON (ToFrontendErrorData 'BE_tree_error_root_not_found) where ...@@ -212,17 +208,15 @@ instance FromJSON (ToFrontendErrorData 'BE_tree_error_root_not_found) where
pure RootNotFound{..} pure RootNotFound{..}
mkFrontendErr :: IsFrontendErrorData payload mkFrontendErr :: IsFrontendErrorData payload
=> Proxy (payload :: BackendErrorType) => ToFrontendErrorData payload
-> ToFrontendErrorData payload
-> FrontendError -> FrontendError
mkFrontendErr et = mkFrontendErr' mempty et mkFrontendErr et = mkFrontendErr' mempty et
mkFrontendErr' :: IsFrontendErrorData payload mkFrontendErr' :: forall payload. IsFrontendErrorData payload
=> T.Text => T.Text
-> Proxy (payload :: BackendErrorType) -> ToFrontendErrorData (payload :: BackendErrorType)
-> ToFrontendErrorData payload
-> FrontendError -> FrontendError
mkFrontendErr' diag (Proxy :: Proxy payload) pl = FrontendError diag (fromSing $ sing @payload) pl mkFrontendErr' diag pl = FrontendError diag (fromSing $ sing @payload) pl
instance Arbitrary BackendErrorType where instance Arbitrary BackendErrorType where
arbitrary = arbitraryBoundedEnum arbitrary = arbitraryBoundedEnum
...@@ -236,25 +230,20 @@ instance Arbitrary FrontendError where ...@@ -236,25 +230,20 @@ instance Arbitrary FrontendError where
genFrontendErr :: T.Text -> BackendErrorType -> Gen FrontendError genFrontendErr :: T.Text -> BackendErrorType -> Gen FrontendError
genFrontendErr txt be = case be of genFrontendErr txt be = case be of
BE_node_error_root_not_found BE_node_error_root_not_found
-> pure $ mkFrontendErr' txt (Proxy @'BE_node_error_root_not_found) FE_node_error_root_not_found -> pure $ mkFrontendErr' txt FE_node_error_root_not_found
BE_node_error_corpus_not_found BE_node_error_corpus_not_found
-> pure $ mkFrontendErr' txt (Proxy @'BE_node_error_corpus_not_found) FE_node_error_corpus_not_found -> pure $ mkFrontendErr' txt FE_node_error_corpus_not_found
BE_tree_error_root_not_found BE_tree_error_root_not_found
-> do rootId <- arbitrary -> do rootId <- arbitrary
pure $ mkFrontendErr' txt (Proxy @'BE_tree_error_root_not_found) (RootNotFound rootId) pure $ mkFrontendErr' txt (RootNotFound rootId)
-- | This compiles if we use the correct payload type, or otherwise it won't:
-- >>> mkFrontendErr (Proxy @'BE_phylo_corpus_not_ready) NodeNotFound
_myTest :: FrontendError
_myTest = mkFrontendErr (Proxy @'BE_node_error_root_not_found) FE_node_error_root_not_found
instance ToJSON BackendErrorType where instance ToJSON BackendErrorType where
toJSON = JSON.String . T.pack . drop 3 . show toJSON = JSON.String . T.pack . drop 3 . show
instance FromJSON BackendErrorType where instance FromJSON BackendErrorType where
parseJSON (String s) = case readMaybe (T.unpack $ "BE_" <> s) of parseJSON (String s) = case readMaybe (T.unpack $ "BE_" <> s) of
Just v -> pure v Just v -> pure v
Nothing -> fail $ "FromJSON BackendErrorType unexpected value: " <> T.unpack s Nothing -> fail $ "FromJSON BackendErrorType unexpected value: " <> T.unpack s
parseJSON ty = typeMismatch "BackendErrorType" ty parseJSON ty = typeMismatch "BackendErrorType" ty
instance ToJSON FrontendError where instance ToJSON FrontendError where
......
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE StandaloneDeriving #-}
module Gargantext.Utils.Dict where
import Prelude
import Data.Kind
-- A dictionary allowing us to treat constraints as first class values.
data Dict (c :: k -> Constraint) (a :: k) where
Dict :: c a => Dict c a
deriving instance Show (Dict c a)
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE QuasiQuotes #-}
module Test.Offline.JSON (tests) where module Test.Offline.JSON (tests) where
...@@ -27,6 +28,16 @@ jsonRoundtrip :: (Show a, FromJSON a, ToJSON a, Eq a) => a -> Property ...@@ -27,6 +28,16 @@ jsonRoundtrip :: (Show a, FromJSON a, ToJSON a, Eq a) => a -> Property
jsonRoundtrip a = jsonRoundtrip a =
counterexample ("Parsed JSON: " <> C8.unpack (encode a)) $ eitherDecode (encode a) === Right a counterexample ("Parsed JSON: " <> C8.unpack (encode a)) $ eitherDecode (encode a) === Right a
class (Show a, FromJSON a, ToJSON a, Eq a, Enum a, Bounded a) => EnumBoundedJSON a
instance EnumBoundedJSON BackendErrorType
jsonEnumRoundtrip :: forall a. Dict EnumBoundedJSON a -> Property
jsonEnumRoundtrip d = case d of
Dict -> conjoin $ map (prop Dict) [minBound .. maxBound]
where
prop :: Dict EnumBoundedJSON a -> a -> Property
prop Dict a = counterexample ("Parsed JSON: " <> C8.unpack (encode a)) $ eitherDecode (encode a) === Right a
tests :: TestTree tests :: TestTree
tests = testGroup "JSON" [ tests = testGroup "JSON" [
testProperty "NodeId roundtrips" (jsonRoundtrip @NodeId) testProperty "NodeId roundtrips" (jsonRoundtrip @NodeId)
...@@ -34,6 +45,7 @@ tests = testGroup "JSON" [ ...@@ -34,6 +45,7 @@ tests = testGroup "JSON" [
, testProperty "Datafield roundtrips" (jsonRoundtrip @Datafield) , testProperty "Datafield roundtrips" (jsonRoundtrip @Datafield)
, testProperty "WithQuery roundtrips" (jsonRoundtrip @WithQuery) , testProperty "WithQuery roundtrips" (jsonRoundtrip @WithQuery)
, testProperty "FrontendError roundtrips" (jsonRoundtrip @FrontendError) , testProperty "FrontendError roundtrips" (jsonRoundtrip @FrontendError)
, testProperty "BackendErrorType roundtrips" (jsonEnumRoundtrip (Dict @_ @BackendErrorType))
, testCase "WithQuery frontend compliance" testWithQueryFrontend , testCase "WithQuery frontend compliance" testWithQueryFrontend
, testGroup "Phylo" [ , testGroup "Phylo" [
testProperty "PeriodToNode" (jsonRoundtrip @PeriodToNodeData) testProperty "PeriodToNode" (jsonRoundtrip @PeriodToNodeData)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment