packages feed

graphql-spice 1.0.1.0 → 1.0.2.0

raw patch · 5 files changed

+237/−36 lines, 5 filesdep +timedep ~aesondep ~graphqldep ~transformersPVP ok

version bump matches the API change (PVP)

Dependencies added: time

Dependency ranges changed: aeson, graphql, transformers, vector

API changes (from Hackage documentation)

+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL Data.Scientific.Scientific
+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL Data.Time.Calendar.Days.Day
+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL Data.Time.Clock.Internal.DiffTime.DiffTime
+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL Data.Time.Clock.Internal.NominalDiffTime.NominalDiffTime
+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL Data.Time.Clock.Internal.UTCTime.UTCTime
+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL Data.Time.LocalTime.Internal.LocalTime.LocalTime
+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay
+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL GHC.Types.Double
+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL GHC.Types.Float
+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL GHC.Types.Word
+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL GHC.Word.Word16
+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL GHC.Word.Word32
+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL GHC.Word.Word64
+ Language.GraphQL.Class: instance Language.GraphQL.Class.FromGraphQL GHC.Word.Word8
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL Data.Scientific.Scientific
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL Data.Time.Calendar.Days.Day
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL Data.Time.Clock.Internal.DiffTime.DiffTime
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL Data.Time.Clock.Internal.NominalDiffTime.NominalDiffTime
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL Data.Time.Clock.Internal.UTCTime.UTCTime
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL Data.Time.LocalTime.Internal.LocalTime.LocalTime
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL Data.Time.LocalTime.Internal.TimeOfDay.TimeOfDay
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL GHC.Types.Double
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL GHC.Types.Float
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL GHC.Types.Word
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL GHC.Word.Word16
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL GHC.Word.Word32
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL GHC.Word.Word64
+ Language.GraphQL.Class: instance Language.GraphQL.Class.ToGraphQL GHC.Word.Word8
+ Language.GraphQL.Resolver: ErroneousArgumentTypeException :: !Text -> ServerException
+ Language.GraphQL.Resolver: FieldNotResolvedException :: !Text -> ServerException
+ Language.GraphQL.Resolver: data ServerException

Files

CHANGELOG.md view
@@ -6,6 +6,16 @@ and this project adheres to [Haskell Package Versioning Policy](https://pvp.haskell.org/). +## [1.0.2.0] - 2023-07-07+### Added+- `ToGraphQL` and `FromGraphQL` instances for `Word` types, `Float`, `Double`,+  and `Scientific`.+- `ToGraphQL` and `FromGraphQL` instances for `Day`, `DiffTime`,+  `NominalDiffTime`, `UTCTime`, `LocalTime` and `TimeOfDay`.+- `Resolver`: Export `ServerException`.+- `Resolver.defaultResolver`: Throw `FieldNotResolvedException` if the requested+  field is not in the parent object.+ ## [1.0.1.0] - 2023-02-17 ### Added - `ToGraphQL` and `FromGraphQL` typeclasses with instances for basic types.@@ -16,4 +26,5 @@ - JSON serialization. - Test helpers. -[1.0.1.0]: https://www.caraus.tech/projects/pub-graphql-spice/repository/28/diff?rev=v1.0.1.0&rev_to=v1.0.0.0+[1.0.2.0]: https://git.caraus.tech/OSS/graphql-spice/compare/v1.0.1.0...v1.0.2.0+[1.0.1.0]: https://git.caraus.tech/OSS/graphql-spice/compare/v1.0.0.0...v1.0.1.0
graphql-spice.cabal view
@@ -1,13 +1,13 @@ cabal-version:      2.4  name:               graphql-spice-version:            1.0.1.0+version:            1.0.2.0 synopsis:           GraphQL with batteries-description:        Various extensions and convenience functions  for the core+description:        Various extensions and convenience functions for the core                     graphql package. category:           Language-homepage:           https://www.caraus.tech/projects/pub-graphql-spice-bug-reports:        https://www.caraus.tech/projects/pub-graphql-spice/issues+homepage:           https://git.caraus.tech/OSS/graphql-spice+bug-reports:        https://git.caraus.tech/OSS/graphql-spice/issues author:             Eugen Wissner <belka@caraus.de> maintainer:         belka@caraus.de copyright:          (c) 2021-2023 Eugen Wissner@@ -16,11 +16,11 @@ build-type:         Simple extra-source-files: CHANGELOG.md tested-with:-  GHC == 9.2.5+  GHC == 9.2.8  source-repository head   type: git-  location: git://caraus.tech/pub/graphql-spice.git+  location: https://git.caraus.tech/OSS/graphql-spice.git  library     exposed-modules:@@ -32,18 +32,19 @@     hs-source-dirs:   src     ghc-options: -Wall     build-depends:-      aeson ^>= 2.0.3,+      aeson >= 2.0.3 && < 2.3,       base >= 4.7 && < 5,       conduit ^>= 1.3.4,       containers ^>= 0.6.2,       exceptions ^>= 0.10.4,       hspec-expectations >= 0.8.2 && < 0.9,-      graphql >= 1.0,+      graphql >= 1.2,       megaparsec >= 9.0 && < 10,       scientific ^>= 0.3.7,       text >= 1.2 && < 3,-      transformers ^>= 0.5.6,-      vector ^>= 0.12.3,+      time >= 1.11.1,+      transformers >= 0.5.6 && < 0.7,+      vector >= 0.12 && < 0.14,       unordered-containers ^>= 0.2.16     default-language: Haskell2010 @@ -67,5 +68,6 @@     hspec >= 2.9.1 && < 3,     scientific,     text,+    time,     unordered-containers   default-language: Haskell2010
src/Language/GraphQL/Class.hs view
@@ -14,10 +14,30 @@ import Data.Foldable (toList) import Data.Int (Int8, Int16, Int32, Int64) import Data.Text (Text)+import Data.Word (Word8, Word16, Word32, Word64) import qualified Data.Text.Read as Text.Read import Data.Vector (Vector) import qualified Data.Vector as Vector import qualified Language.GraphQL.Type as Type+import Data.Scientific (Scientific, toRealFloat)+import qualified Data.Text as Text+import Data.Time+    ( Day+    , DiffTime+    , LocalTime(..)+    , NominalDiffTime+    , TimeOfDay(..)+    , UTCTime(..)+    , showGregorian+    , secondsToNominalDiffTime+    , secondsToDiffTime+    )+import Data.Time.Format.ISO8601+    ( ISO8601(..)+    , formatParseM+    , iso8601Format+    , iso8601Show+    )  fromGraphQLToIntegral :: Integral a => Type.Value -> Maybe a fromGraphQLToIntegral (Type.Int value) = Just $ fromIntegral value@@ -27,79 +47,225 @@         _conversionError -> Nothing fromGraphQLToIntegral _ = Nothing +iso8601ToGraphQL :: ISO8601 t => t -> Type.Value+iso8601ToGraphQL = Type.String . Text.pack . iso8601Show++fromGraphQLToISO8601 :: ISO8601 t => Type.Value -> Maybe t+fromGraphQLToISO8601 (Type.String value') = formatParseM iso8601Format $ Text.unpack value'+fromGraphQLToISO8601 _ = Nothing+ -- | Instances of this typeclass can be converted to GraphQL internal -- representation.-class ToGraphQL a where+class ToGraphQL a+  where     toGraphQL :: a -> Type.Value -instance ToGraphQL Text where+instance ToGraphQL Text+  where     toGraphQL = Type.String -instance ToGraphQL Int where+instance ToGraphQL Int+  where     toGraphQL = Type.Int . fromIntegral -instance ToGraphQL Int8 where+instance ToGraphQL Int8+  where     toGraphQL = Type.Int . fromIntegral -instance ToGraphQL Int16 where+instance ToGraphQL Int16+  where     toGraphQL = Type.Int . fromIntegral -instance ToGraphQL Int32 where+instance ToGraphQL Int32+  where     toGraphQL = Type.Int -instance ToGraphQL Int64 where+instance ToGraphQL Int64+  where     toGraphQL = Type.Int . fromIntegral -instance ToGraphQL a => ToGraphQL [a] where+instance ToGraphQL Word+  where+    toGraphQL = Type.Int . fromIntegral++instance ToGraphQL Word8+  where+    toGraphQL = Type.Int . fromIntegral++instance ToGraphQL Word16+  where+    toGraphQL = Type.Int . fromIntegral++instance ToGraphQL Word32+  where+    toGraphQL = Type.Int . fromIntegral++instance ToGraphQL Word64+  where+    toGraphQL = Type.Int . fromIntegral++instance ToGraphQL a => ToGraphQL [a]+  where     toGraphQL = Type.List . fmap toGraphQL -instance ToGraphQL a => ToGraphQL (Vector a) where+instance ToGraphQL a => ToGraphQL (Vector a)+  where     toGraphQL = Type.List . toList . fmap toGraphQL -instance ToGraphQL a => ToGraphQL (Maybe a) where+instance ToGraphQL a => ToGraphQL (Maybe a)+  where     toGraphQL (Just justValue) = toGraphQL justValue     toGraphQL Nothing = Type.Null -instance ToGraphQL Bool where+instance ToGraphQL Bool+  where     toGraphQL = Type.Boolean +instance ToGraphQL Float+  where+    toGraphQL = Type.Float . realToFrac++instance ToGraphQL Double+  where+    toGraphQL = Type.Float++instance ToGraphQL Scientific+  where+    toGraphQL = Type.Float . toRealFloat++instance ToGraphQL Day+  where+    toGraphQL = Type.String . Text.pack . showGregorian++instance ToGraphQL DiffTime+  where+    toGraphQL = Type.Int . truncate . (realToFrac :: DiffTime -> Double)++instance ToGraphQL NominalDiffTime+  where+    toGraphQL = Type.Int . truncate . (realToFrac :: NominalDiffTime -> Double)++instance ToGraphQL UTCTime+  where+    toGraphQL = iso8601ToGraphQL++instance ToGraphQL TimeOfDay+  where+    toGraphQL = iso8601ToGraphQL++instance ToGraphQL LocalTime+  where+    toGraphQL = iso8601ToGraphQL+ -- | Instances of this typeclass can be used to convert GraphQL internal -- representation to user-defined type.-class FromGraphQL a where+class FromGraphQL a+  where     fromGraphQL :: Type.Value -> Maybe a -instance FromGraphQL Text where+instance FromGraphQL Text+  where     fromGraphQL (Type.String value) = Just value     fromGraphQL _ = Nothing -instance FromGraphQL Int where+instance FromGraphQL Int+  where     fromGraphQL = fromGraphQLToIntegral -instance FromGraphQL Int8 where+instance FromGraphQL Int8+  where     fromGraphQL = fromGraphQLToIntegral -instance FromGraphQL Int16 where+instance FromGraphQL Int16+  where     fromGraphQL = fromGraphQLToIntegral -instance FromGraphQL Int32 where+instance FromGraphQL Int32+  where     fromGraphQL = fromGraphQLToIntegral -instance FromGraphQL Int64 where+instance FromGraphQL Int64+  where     fromGraphQL = fromGraphQLToIntegral -instance FromGraphQL a => FromGraphQL [a] where+instance FromGraphQL Word+  where+    fromGraphQL = fromGraphQLToIntegral++instance FromGraphQL Word8+  where+    fromGraphQL = fromGraphQLToIntegral++instance FromGraphQL Word16+  where+    fromGraphQL = fromGraphQLToIntegral++instance FromGraphQL Word32+  where+    fromGraphQL = fromGraphQLToIntegral++instance FromGraphQL Word64+  where+    fromGraphQL = fromGraphQLToIntegral++instance FromGraphQL a => FromGraphQL [a]+  where     fromGraphQL (Type.List value) = traverse fromGraphQL value     fromGraphQL _ = Nothing -instance FromGraphQL a => FromGraphQL (Vector a) where+instance FromGraphQL a => FromGraphQL (Vector a)+  where     fromGraphQL (Type.List value) = Vector.fromList         <$> traverse fromGraphQL value     fromGraphQL _ = Nothing -instance FromGraphQL a => FromGraphQL (Maybe a) where+instance FromGraphQL a => FromGraphQL (Maybe a)+  where     fromGraphQL Type.Null = Just Nothing     fromGraphQL value = Just <$> fromGraphQL value -instance FromGraphQL Bool where+instance FromGraphQL Bool+  where     fromGraphQL (Type.Boolean value) = Just value     fromGraphQL _ = Nothing++instance FromGraphQL Float+  where+    fromGraphQL (Type.Float value) = Just $ realToFrac value+    fromGraphQL _ = Nothing++instance FromGraphQL Double+  where+    fromGraphQL (Type.Float value) = Just value+    fromGraphQL _ = Nothing++instance FromGraphQL Scientific+  where+    fromGraphQL (Type.Float value) = Just $ realToFrac value+    fromGraphQL _ = Nothing++instance FromGraphQL Day+  where+    fromGraphQL = fromGraphQLToISO8601++instance FromGraphQL DiffTime+  where+    fromGraphQL (Type.Int value') = Just $ secondsToDiffTime $ fromIntegral value'+    fromGraphQL _ = Nothing++instance FromGraphQL NominalDiffTime+  where+    fromGraphQL (Type.Int value') = Just $ secondsToNominalDiffTime $ fromIntegral value'+    fromGraphQL _ = Nothing++instance FromGraphQL UTCTime+  where+    fromGraphQL = fromGraphQLToISO8601++instance FromGraphQL TimeOfDay+  where+    fromGraphQL = fromGraphQLToISO8601++instance FromGraphQL LocalTime+  where+    fromGraphQL = fromGraphQLToISO8601
src/Language/GraphQL/Resolver.hs view
@@ -6,13 +6,14 @@  -- | Helper functions and exceptions to write resolvers. module Language.GraphQL.Resolver-    ( argument+    ( ServerException(..)+    , argument     , defaultResolver     ) where  import Control.Monad.Catch (Exception(..), MonadCatch(..), MonadThrow(..)) import Control.Monad.Trans.Reader (ReaderT, asks)-import Data.HashMap.Strict ((!))+import qualified Data.HashMap.Strict as HashMap import Data.Text (Text) import qualified Data.Text as Text import Data.Typeable (cast)@@ -49,7 +50,8 @@ defaultResolver fieldName = do     values' <- asks Type.values     case values' of-        Type.Object objectValue -> pure $ objectValue ! fieldName+        Type.Object objectValue+            | Just result <- HashMap.lookup fieldName objectValue -> pure result         _nonObject -> throwM $ FieldNotResolvedException fieldName  -- | Takes an argument name, validates that the argument exists, and optionally
tests/Language/GraphQL/ClassSpec.hs view
@@ -8,6 +8,8 @@     ) where  import Data.Text (Text)+import Data.Time (UTCTime(..))+import Data.Time.Calendar.OrdinalDate (fromOrdinalDate) import qualified Language.GraphQL.Type as Type import Language.GraphQL.Class (FromGraphQL(..), ToGraphQL(..)) import Test.Hspec (Spec, describe, it, shouldBe)@@ -30,6 +32,15 @@         it "converts singleton lists" $             toGraphQL [True] `shouldBe` Type.List [Type.Boolean True] +        it "converts UTCTime" $+            let given = UTCTime+                    { utctDay = fromOrdinalDate 2023 5+                    , utctDayTime = 90+                    }+                actual = toGraphQL given+                expected = Type.String "2023-01-05T00:01:30Z"+             in actual `shouldBe` expected+     describe "FromGraphQL" $ do         it "converts integers" $             fromGraphQL (Type.Int 5) `shouldBe` Just (5 :: Int)@@ -45,3 +56,12 @@          it "converts singleton lists" $             fromGraphQL (Type.List [Type.Boolean True]) `shouldBe` Just [True]++        it "converts UTCTime" $+            let given = Type.String "2023-01-05T00:01:30Z"+                expected = Just $ UTCTime+                    { utctDay = fromOrdinalDate 2023 5+                    , utctDayTime = 90+                    }+                actual = fromGraphQL given+             in actual `shouldBe` expected