diff --git a/README.md b/README.md index 45deec3fde..f834617549 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ _stack.yml_ resolver: lts-14.8 extra-deps: - - morpheus-graphql-0.8.0 + - morpheus-graphql-0.9.0 ``` As Morpheus is quite new, make sure stack can find morpheus-graphql by running `stack upgrade` and `stack update` @@ -90,10 +90,11 @@ rootResolver = subscriptionResolver = Undefined } where - queryDeity QueryDeityArgs {queryDeityArgsName} = pure Deity {deityName, deityPower} - where - deityName _ = pure "Morpheus" - deityPower _ = pure (Just "Shapeshifting") + queryDeity QueryDeityArgs {queryDeityArgsName} = pure Deity + { + deityName = pure "Morpheus" + , deityPower = pure (Just "Shapeshifting") + } api :: ByteString -> IO ByteString api = interpreter rootResolver @@ -402,36 +403,35 @@ data Content type MyEvent = Event Channel Content newtype Query m = Query - { deity :: () -> m Deity + { deity :: m Deity } deriving (Generic) newtype Mutation m = Mutation - { createDeity :: () -> m Deity + { createDeity :: m Deity } deriving (Generic) newtype Subscription (m :: * -> * ) = Subscription - { newDeity :: () -> m Deity + { newDeity :: m Deity } deriving (Generic) type APIEvent = Event Channel Content rootResolver :: GQLRootResolver IO APIEvent Query Mutation Subscription rootResolver = GQLRootResolver - { queryResolver = Query { deity } + { queryResolver = Query { deity = fetchDeity } , mutationResolver = Mutation { createDeity } , subscriptionResolver = Subscription { newDeity } } where - deity _args = fetchDeity -- Mutation Without Event Triggering - createDeity :: () -> ResolveM EVENT IO Address - createDeity _args = MutResolver \$ do + createDeity :: ResolveM EVENT IO Address + createDeity = MutResolver \$ do value <- lift dbCreateDeity pure ( [Event { channels = [ChannelA], content = ContentA 1 }], value ) - newDeity _args = SubResolver [ChannelA] subResolver + newDeity = SubResolver [ChannelA] subResolver where subResolver (Event [ChannelA] (ContentA _value)) = fetchDeity -- resolve New State subResolver (Event [ChannelA] (ContentB _value)) = fetchDeity -- resolve New State diff --git a/changelog.md b/changelog.md index 24ae8f497e..5f8650e0a1 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,6 @@ # Changelog -## [0.9.0] - * +## [0.9.0] - 02.01.2020 ### Added diff --git a/docs/index.md b/docs/index.md index 257d73bd2d..80520a91f5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,12 +1,13 @@ --- layout: home --- + # Morpheus GraphQL [![Hackage](https://img.shields.io/hackage/v/morpheus-graphql.svg)](https://hackage.haskell.org/package/morpheus-graphql) [![CircleCI](https://circleci.com/gh/morpheusgraphql/morpheus-graphql.svg?style=svg)](https://circleci.com/gh/morpheusgraphql/morpheus-graphql) Build GraphQL APIs with your favourite functional language! -Morpheus GraphQL (Server & Client) helps you to build GraphQL APIs in Haskell with native haskell types. -Morpheus will convert your haskell types to a GraphQL schema and all your resolvers are just native Haskell functions. Mopheus GraphQL can also convert your GraphQL Schema or Query to Haskell types and validate them in compile time. +Morpheus GraphQL (Server & Client) helps you to build GraphQL APIs in Haskell with native Haskell types. +Morpheus will convert your Haskell types to a GraphQL schema and all your resolvers are just native Haskell functions. Mopheus GraphQL can also convert your GraphQL Schema or Query to Haskell types and validate them in compile time. Morpheus is still in an early stage of development, so any feedback is more than welcome, and we appreciate any contribution! Just open an issue here on GitHub, or join [our Slack channel](https://morpheus-graphql-slack-invite.herokuapp.com/) to get in touch. @@ -32,7 +33,7 @@ _stack.yml_ resolver: lts-14.8 extra-deps: - - morpheus-graphql-0.8.0 + - morpheus-graphql-0.9.0 ``` As Morpheus is quite new, make sure stack can find morpheus-graphql by running `stack upgrade` and `stack update` @@ -93,10 +94,11 @@ rootResolver = subscriptionResolver = Undefined } where - queryDeity QueryDeityArgs {queryDeityArgsName} = pure Deity {deityName, deityPower} - where - deityName _ = pure "Morpheus" - deityPower _ = pure (Just "Shapeshifting") + queryDeity QueryDeityArgs {queryDeityArgsName} = pure Deity + { + deityName = pure "Morpheus" + , deityPower = pure (Just "Shapeshifting") + } api :: ByteString -> IO ByteString api = interpreter rootResolver @@ -104,9 +106,9 @@ api = interpreter rootResolver Template Haskell Generates types: `Query` , `Deity`, `DeityArgs`, that can be used by `rootResolver` -`descriptions` and `deprecations` will be displayed in intropsection. +`descriptions` and `deprecations` will be displayed in introspection. -`importGQLDocumentWithNamespace` will generate Types with namespaced fields. if you don't need napespacing use `importGQLDocument` +`importGQLDocumentWithNamespace` will generate Types with namespaced fields. If you don't need napespacing use `importGQLDocument` ### with Native Haskell Types @@ -234,8 +236,7 @@ To use union type, all you have to do is derive the `GQLType` class. Using Graph ```haskell data Character - = data Character = - CharacterDeity Deity -- Only should generate direct link + = CharacterDeity Deity -- Only should generate direct link -- RECORDS | Creature { creatureName :: Text, creatureAge :: Int } --- Types @@ -248,17 +249,17 @@ data Character deriving (Generic, GQLType) ``` -where deity is and object +where `Deity` is an object. -as you see there ar different kinds of unions. `morpheus` handles them all. +As you see there are different kinds of unions. `morpheus` handles them all. -this type will be represented as +This type will be represented as ```gql union Character = - Deity # unwrapped union: because Character + Deity = CharacterDeity + Deity # unwrapped union: becouse Character + Deity = CharacterDeity | Creature - | SomeDeity # wrapped union: because Character + Deity != SomeDeity + | SomeDeity # wrapped union: becouse Character + Deity != SomeDeity | CharacterInt | SomeMutli | CharacterEnumObject # object wrapped for enums @@ -294,7 +295,7 @@ enum CharacterEnum { - namespaced Unions: `CharacterDeity` where `Character` is TypeConstructor and `Deity` referenced object (not scalar) type: will be generate regular graphql Union -- for for all other unions will be generated new object type. for types without record syntaxt, fields will be automatally indexed. +- for all other unions will be generated new object type. for types without record syntaxt, fields will be automatally indexed. - all empty constructors in union will be summed in type `Enum` (e.g `CharacterEnum`), this enum will be wrapped in `CharacterEnumObject` and added to union members. @@ -392,7 +393,7 @@ gqlApi = interpreter rootResolver im morpheus subscription and mutation communicating with Events, `Event` consists with user defined `Channel` and `Content`. -every subscription has own Channel by which will be triggered +Every subscription has its own Channel by which it will be triggered ```haskell data Channel @@ -406,36 +407,35 @@ data Content type MyEvent = Event Channel Content newtype Query m = Query - { deity :: () -> m Deity + { deity :: m Deity } deriving (Generic) newtype Mutation m = Mutation - { createDeity :: () -> m Deity + { createDeity :: m Deity } deriving (Generic) newtype Subscription (m :: * -> * ) = Subscription - { newDeity :: () -> m Deity + { newDeity :: m Deity } deriving (Generic) type APIEvent = Event Channel Content rootResolver :: GQLRootResolver IO APIEvent Query Mutation Subscription rootResolver = GQLRootResolver - { queryResolver = Query { deity } + { queryResolver = Query { deity = fetchDeity } , mutationResolver = Mutation { createDeity } , subscriptionResolver = Subscription { newDeity } } where - deity _args = fetchDeity -- Mutation Without Event Triggering - createDeity :: () -> ResolveM EVENT IO Address - createDeity _args = MutResolver \$ do + createDeity :: ResolveM EVENT IO Address + createDeity = MutResolver \$ do value <- lift dbCreateDeity pure ( [Event { channels = [ChannelA], content = ContentA 1 }], value ) - newDeity _args = SubResolver [ChannelA] subResolver + newDeity = SubResolver [ChannelA] subResolver where subResolver (Event [ChannelA] (ContentA _value)) = fetchDeity -- resolve New State subResolver (Event [ChannelA] (ContentB _value)) = fetchDeity -- resolve New State diff --git a/examples/package.yaml b/examples/package.yaml index 48be3c15f8..b769dcf818 100644 --- a/examples/package.yaml +++ b/examples/package.yaml @@ -16,7 +16,7 @@ dependencies: - containers >= 0.4.2.1 && < 0.7 - mtl >= 2.0 && <= 2.3 - websockets >= 0.11.0 && <= 0.13 - - morpheus-graphql >= 0.8.0 + - morpheus-graphql >= 0.9.0 - scotty - wai - warp diff --git a/examples/src/Server/Subscription/SimpleSubscription.hs b/examples/src/Server/Subscription/SimpleSubscription.hs index a977df33ce..e8faefe3bb 100644 --- a/examples/src/Server/Subscription/SimpleSubscription.hs +++ b/examples/src/Server/Subscription/SimpleSubscription.hs @@ -29,30 +29,30 @@ data Content type MyEvent = Event Channel Content newtype Query m = Query - { deity :: () -> m Deity + { deity :: m Deity } deriving (Generic) newtype Mutation m = Mutation - { createDeity :: () -> m Deity + { createDeity :: m Deity } deriving (Generic) newtype Subscription (m :: * -> * ) = Subscription - { newDeity :: () -> m Deity + { newDeity :: m Deity } deriving (Generic) type APIEvent = Event Channel Content rootResolver :: GQLRootResolver IO APIEvent Query Mutation Subscription rootResolver = GQLRootResolver - { queryResolver = Query { deity = const fetchDeity } + { queryResolver = Query { deity = fetchDeity } , mutationResolver = Mutation { createDeity } , subscriptionResolver = Subscription { newDeity } } where -- TODO: resolver $ dbDeity "" Nothing - createDeity _args = MutResolver $ pure + createDeity = MutResolver $ pure ([Event { channels = [ChannelA], content = ContentA 1 }], someDeity) - newDeity _args = SubResolver [ChannelA] subResolver + newDeity = SubResolver [ChannelA] subResolver where subResolver (Event [ChannelA] (ContentA _value)) = fetchDeity -- resolve New State subResolver (Event [ChannelA] (ContentB _value)) = fetchDeity -- resolve New State diff --git a/package.yaml b/package.yaml index f4497e98c3..79905c4277 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: morpheus-graphql -version: 0.8.0 +version: 0.9.0 github: "nalchevanidze/morpheus-graphql" license: MIT author: "Daviti Nalchevanidze" diff --git a/src/Data/Morpheus/Execution/Document/Encode.hs b/src/Data/Morpheus/Execution/Document/Encode.hs index 74481aa698..c64f3305e3 100644 --- a/src/Data/Morpheus/Execution/Document/Encode.hs +++ b/src/Data/Morpheus/Execution/Document/Encode.hs @@ -82,7 +82,6 @@ deriveEncode GQLTypeD { typeKindD, typeD = TypeD { tName, tCons = [ConsD { cFiel | otherwise = [ iLiftOp fo_ ''ResolvingStrategy , iLiftOp fo_ ''Resolver - , iLiftOp po_ ''ResolvingStrategy , typeT ''MapStrategy [fo_, po_] , iTypeable fo_ , iTypeable po_ diff --git a/src/Data/Morpheus/Types/Internal/Resolving/Core.hs b/src/Data/Morpheus/Types/Internal/Resolving/Core.hs index 4d62b946eb..78f9d8c943 100644 --- a/src/Data/Morpheus/Types/Internal/Resolving/Core.hs +++ b/src/Data/Morpheus/Types/Internal/Resolving/Core.hs @@ -39,7 +39,6 @@ import Data.Morpheus.Types.Internal.AST.Base ( Position(..) , Message - , Name ) import Data.Text ( Text , pack diff --git a/test/Feature/InputType/API.hs b/test/Feature/InputType/API.hs index fc6e73978e..7f09740510 100644 --- a/test/Feature/InputType/API.hs +++ b/test/Feature/InputType/API.hs @@ -10,7 +10,6 @@ module Feature.InputType.API where import Data.Morpheus ( interpreter ) -import Data.Morpheus.Kind ( OBJECT ) import Data.Morpheus.Types ( GQLRequest , GQLResponse , GQLRootResolver(..) @@ -34,10 +33,7 @@ data F2Args = F2Args data A = A { a1 :: F1Args -> IORes () Text , a2 :: F2Args -> IORes () Int - } deriving (Generic) - -instance GQLType A where - type KIND A = OBJECT + } deriving (Generic, GQLType) newtype Query (m :: * -> *) = Query { q1 :: A diff --git a/test/Feature/Schema/A2.hs b/test/Feature/Schema/A2.hs index 67f7ca35e3..0eb68732e5 100644 --- a/test/Feature/Schema/A2.hs +++ b/test/Feature/Schema/A2.hs @@ -1,17 +1,14 @@ -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE DeriveAnyClass #-} module Feature.Schema.A2 ( A(..) ) where -import Data.Morpheus.Kind (OBJECT) -import Data.Morpheus.Types (GQLType (..)) +import Data.Morpheus.Types (GQLType) import GHC.Generics (Generic) newtype A = A { bla :: Int - } deriving (Generic) - -instance GQLType A where - type KIND A = OBJECT + } deriving (Generic, GQLType) diff --git a/test/Feature/Schema/API.hs b/test/Feature/Schema/API.hs index a54ede8cc9..0c6a126423 100644 --- a/test/Feature/Schema/API.hs +++ b/test/Feature/Schema/API.hs @@ -9,7 +9,6 @@ module Feature.Schema.API ) where import Data.Morpheus (interpreter) -import Data.Morpheus.Kind (OBJECT) import Data.Morpheus.Types (GQLRequest, GQLResponse, GQLRootResolver (..), GQLType (..), Undefined (..)) import Data.Text (Text) import qualified Feature.Schema.A2 as A2 (A (..)) @@ -18,10 +17,7 @@ import GHC.Generics (Generic) data A = A { aText :: Text , aInt :: Int - } deriving (Generic) - -instance GQLType A where - type KIND A = OBJECT + } deriving (Generic, GQLType) data Query (m :: * -> * ) = Query { a1 :: A diff --git a/test/Feature/UnionType/API.hs b/test/Feature/UnionType/API.hs index c3bd98b77a..ed07fbdfa6 100644 --- a/test/Feature/UnionType/API.hs +++ b/test/Feature/UnionType/API.hs @@ -10,9 +10,6 @@ module Feature.UnionType.API where import Data.Morpheus ( interpreter ) -import Data.Morpheus.Kind ( OBJECT - , UNION - ) import Data.Morpheus.Types ( GQLRequest , GQLResponse , GQLRootResolver(..) @@ -23,37 +20,25 @@ import Data.Morpheus.Types ( GQLRequest import Data.Text ( Text ) import GHC.Generics ( Generic ) -instance GQLType A where - type KIND A = OBJECT - -instance GQLType B where - type KIND B = OBJECT - -instance GQLType C where - type KIND C = OBJECT - -instance GQLType Sum where - type KIND Sum = UNION - data A = A { aText :: Text , aInt :: Int - } deriving (Generic) + } deriving (Generic, GQLType) data B = B { bText :: Text , bInt :: Int - } deriving (Generic) + } deriving (Generic, GQLType) data C = C { cText :: Text , cInt :: Int - } deriving (Generic) + } deriving (Generic, GQLType) data Sum = SumA A | SumB B - deriving (Generic) + deriving (Generic, GQLType) data Query m = Query { union :: () -> m [Sum] diff --git a/test/Feature/WrappedTypeName/API.hs b/test/Feature/WrappedTypeName/API.hs index 358c9e0d81..dcddcca7e3 100644 --- a/test/Feature/WrappedTypeName/API.hs +++ b/test/Feature/WrappedTypeName/API.hs @@ -9,28 +9,20 @@ module Feature.WrappedTypeName.API ) where import Data.Morpheus (interpreter) -import Data.Morpheus.Kind (OBJECT) import Data.Morpheus.Types (Event, GQLRequest, GQLResponse, GQLRootResolver (..), GQLType (..), IORes, Resolver (..), constRes) import Data.Text (Text) -import Data.Typeable (Typeable) import GHC.Generics (Generic) -instance Typeable a => GQLType (WA a) where - type KIND (WA a) = OBJECT - -instance (Typeable a, Typeable b) => GQLType (Wrapped a b) where - type KIND (Wrapped a b) = OBJECT - data Wrapped a b = Wrapped { fieldA :: a , fieldB :: b - } deriving (Generic) + } deriving (Generic, GQLType) data WA m = WA { aText :: () -> m Text , aInt :: Int - } deriving (Generic) + } deriving (Generic,GQLType) data Query m = Query { a1 :: WA m