import SEO from "../components/seo";
import { Section } from "../components/section";

<SEO title="Type System" />

# Server

<Section id="type-system">Type System</Section>

Morpheus GraphQL covers all GraphQL data types with an equivalent
Haskell representation. A prerequisite for these representation types is that
they must be derived by `Generic` and provide corresponding `GQLType` instances.

<Section id="objects" level={2}>
  Object types
</Section>

Object types are represented in Morpheus with Haskell records,
where the parameter `m` passes the resolution monad
to the field resolution functions. The following code snippet, for example,
defines the type Deity with a nullable field `power` and a non-nullable field `name`.

```haskell
data Deity m = Deity
  { name :: m Text         -- Non-Nullable Field
  , power :: m Maybe Text   -- Nullable Field
  } deriving
    ( Generic
    , GQLType
    )
```

<Section id="arguments" level={3}>
  Arguments
</Section>

GraphQL arguments can be represented with two ways:

#### Haskell records

we can use Haskell records to declare GraphQL arguments,
where each field of a record represents a particular
argument, and can be accessed by name.

```haskell
data Query m = Query
  { deity :: DeityArgs -> m Deity
  } deriving
    ( Generic
    , GQLType
    )

data DeityArgs = DeityArgs
  { name      :: Text        -- Required Argument
  , mythology :: Maybe Text  -- Optional Argument
  } deriving
     ( Generic,
       GQLType
     )
```

This approach is quite convenient for representing multiple arguments,
but cumbersome if we only need one argument for each field.
That is why we also introduce "Tagged Arguments".

#### Tagged function arguments

Tagged arguments leverage type-level literals and enable GraphQL
arguments to be represented as a chain of named function arguments.
e.g. the following type defines GraphQL field `deity` with the
optional argument `name` of type `String`.

```haskell
data Query m = Query
  { deity :: Arg "name" (Maybe Text) -> m Deity
  } deriving
    ( Generic
    , GQLType
    )
```

<Section id="query" level={3}>
  Query
</Section>

the GraphQL query type is represented in Morpheus GraphQL as a regular object type named `Query`.

```haskell
data Query m = Query
  { deity ::  m Deity
  } deriving
    ( Generic
    , GQLType
    )
```

<Section id="mutations" level={3}>
  Mutations
</Section>

In addition to queries, Morpheus also supports mutations. They behave just like regular queries and are defined similarly:

```haskell
newtype Mutation m = Mutation
  { createDeity :: MutArgs -> m Deity
  } deriving (Generic, GQLType)

rootResolver :: RootResolver IO  () Query Mutation Undefined
rootResolver =
  RootResolver
    { queryResolver = Query {...}
    , mutationResolver = Mutation { createDeity }
    , subscriptionResolver = Undefined
    }
    where
      -- Mutation Without Event Triggering
      createDeity :: MutArgs -> ResolverM () IO Deity
      createDeity_args = lift setDBAddress

gqlApi :: ByteString -> IO ByteString
gqlApi = interpreter rootResolver
```

<Section id="subscription" level={3}>
  Subscriptions
</Section>

In morpheus subscription and mutation communicate with Events,
`Event` consists with user defined `Channel` and `Content`.

Every subscription has its own Channel by which it will be triggered

```haskell
data Channel
  = ChannelA
  | ChannelB

data Content
  = ContentA Int
  | ContentB Text

newtype Query m = Query
  { deity :: m Deity
  } deriving (Generic,GQLType)

newtype Mutation m = Mutation
  { createDeity :: m Deity
  } deriving (Generic,GQLType)

newtype Subscription (m :: * -> *) = Subscription
  { newDeity :: SubscriptionField (m Deity),
  }
  deriving (Generic,GQLType)


type APIEvent = Event Channel Content

rootResolver :: RootResolver IO APIEvent Query Mutation Subscription
rootResolver = RootResolver
  { queryResolver        = Query { deity = fetchDeity }
  , mutationResolver     = Mutation { createDeity }
  , subscriptionResolver = Subscription { newDeity }
  }
 where
  -- Mutation Without Event Triggering
  createDeity :: ResolverM EVENT IO Address
  createDeity = do
      requireAuthorized
      publish [Event { channels = [ChannelA], content = ContentA 1 }]
      lift dbCreateDeity
  newDeity :: SubscriptionField (ResolverS EVENT IO Deity)
  newDeity = subscribe ChannelA $ do
    -- executed only once
    -- immediate response on failures
    requireAuthorized
    pure $ \(Event _ content) -> do
        -- executes on every event
        lift (getDBAddress content)
```

<Section id="scalars" level={2}>
  Scalar types
</Section>

any Haskell data type can be represented as a GraphQL scalar type.
In order to do this, the type must be associated as
`SCALAR` and implemented with `DecodeScalar` and `EncodeScalar` instances.

```haskell
data Odd = Odd Int  deriving (Generic)

instance DecodeScalar Euro where
  decodeScalar (Int x) = pure $ Odd (... )
  decodeScalar _ = Left "invalid Value!"

instance EncodeScalar Euro where
  encodeScalar (Odd value) = Int value

instance GQLType Odd where
  type KIND Odd = SCALAR
```

<Section id="enums" level={2}>
  Enumeration types
</Section>

Data types where all constructors are empty are derived as GraphQL enums.

```haskell
data City
  = Athens
  | Sparta
  | Corinth
  | Delphi
  | Argos
  deriving
    ( Generic
    , GQLType
    )
```

<Section id="wrappers" level={2}>
  Lists and Non-Null
</Section>

GraphQL Lists are represented with Haskell Lists.
However, since in Haskell each type is intrinsically not nullable,
nullable GraphQL fields are represented with `Maybe` Haskell data type and non-nullable
GraphQL fields with regular Haskell datatypes.

<Section id="interfaces" level={2}>
  Interfaces
</Section>

GraphQL interfaces is represented in Morpheus with `TypeGuard`.
in the following data type definition every use of `PersonInterface`
will be represented as GraphQL interface `Person` and allow server to
resolve different types from union `PersonImplements`.

All types of the union `PersonImplements` must be objects
and contain fields of type `Person`, otherwise the derivation fails.

```haskell
  -- interface Person
data Person m = Person { name ::  m Text }
  deriving
    (
      Generic,
      GQLType
    )

data PersonImplements m
  = PersonImplementsUser (User m)
  | PersonImplementsDeity (Deity m)
  deriving
    (
      Generic,
      GQLType
    )

-- typeGuard guards all variabts of union with person fields
type PersonInterface m = TypeGuard Person (PersonImplements m)
```

<Section id="unions" level={2}>
  Unions
</Section>

To use union type, all you have to do is derive the `GQLType` class. Using GraphQL [_fragments_](https://graphql.org/learn/queries/#fragments), the arguments of each data constructor can be accessed from the GraphQL client.

```haskell
data Character
  = CharacterDeity Deity -- will be unwrapped, since Character + Deity = CharacterDeity
  | SomeDeity Deity -- will be wrapped since Character + Deity != SomeDeity
  | Creature { creatureName :: Text, creatureAge :: Int }
  | Demigod Text Text
  | Zeus
  deriving (Generic, GQLType)
```

where `Deity` is an object.

As we see, there are different kinds of unions. `Morpheus` handles them all.

This type will be represented as

```graphql
union Character = Deity | SomeDeity | Creature | SomeMulti | Zeus

type SomeDeity {
  _0: Deity!
}

type Creature {
  creatureName: String!
  creatureAge: Int!
}

type Demigod {
  _0: Int!
  _1: String!
}

type Zeus {
  _: Unit!
}
```

By default, union members will be generated with wrapper objects.
There is one exception to this: if a constructor of a type is the type name concatenated with the name of the contained type, it will be referenced directly.
That is, given:

```haskell
data Song = { songName :: Text, songDuration :: Float } deriving (Generic, GQLType)

data Skit = { skitName :: Text, skitDuration :: Float } deriving (Generic, GQLType)

data WrappedNode
  = WrappedSong Song
  | WrappedSkit Skit
  deriving (Generic, GQLType)

data NonWrapped
  = NonWrappedSong Song
  | NonWrappedSkit Skit
  deriving (Generic, GQLType)

```

You will get the following schema:

```graphql
# has wrapper types
union WrappedNode = WrappedSong | WrappedSkit

# is a direct union
union NonWrapped = Song | Skit

type WrappedSong {
  _0: Song!
}

type WrappedSKit {
  _0: Skit!
}

type Song {
  songDuration: Float!
  songName: String!
}

type Skit {
  skitDuration: Float!
  skitName: String!
}
```

- for all other unions will be generated new object type. for types without record syntax, fields will be automatically indexed.

- empty constructors will get field `_`associaced with type `Unit`.

<Section id="inputs" level={2}>
  Input types
</Section>

Like object types, input types are represented by Haskell records.
However, they are not permitted to have monad parameters, as they represent serialisable values.

```haskell
data Deity = Deity
  { name :: Text         -- Non-Nullable Field
  , power :: Maybe Text   -- Nullable Field
  } deriving
    ( Generic
    , GQLType
    )
```

<Section id="directives" level={2}>
  Directives
</Section>

### Default GQL Directives

Moprheus GraphQL allows the use of standard GQL directives by applying them to `GQLType.directives`
with the functions `enumDirective`, `fieldDirective`, `typeDirective`. The following examples
demonstrate the use of the Deprecated directive on enums and type fields.

#### Field Diretives

```hs
data Deity = Deity
  { name :: Text,
    power :: Maybe Text
  }
  deriving
    (Generic)

instance GQLType Deity where
  directives _ =
    fieldDirective "power" Deprecated {reason = Just "some reason"}
      <> fieldDirective "name" Deprecated {reason = Nothing}
```

#### Enum Diretives

```hs
data City
  = Athens
  | Sparta
  | Corinth
  | Delphi
  deriving
    (Generic)

instance GQLType City where
  directives _ =
    enumDirective "Sparta" Deprecated {reason = Nothing}
      <> enumDirective "Delphi" Deprecated {reason = Just "oracle left the place"}
```

### Custom Directive Definition

Moprheus GraphQL provides an API for defining custom GQL directives.
These directive definitions should implement `GQLType`, `Generic` and `GQLDirective` instances.
depending on `GQLDirective.DIRECTIVE_LOCATIONS` API requires implementation of one of the following
visitor typeclass instances: `VisitType`, `VisitField`, `VisitEnum`.

The following example demonstrates the `RemovePrefix`` directive definition, which
removes prefixes from GQL objects and input objects.

```hs
import Data.Morpheus ()
import Data.Morpheus.Types
import Data.Text (Text)
import qualified Data.Text as T
import GHC.Generics (Generic)

newtype RemovePrefix = RemovePrefix {prefix :: Text}
  deriving (Generic, GQLType)

instance GQLDirective RemovePrefix where
  type
    DIRECTIVE_LOCATIONS RemovePrefix =
      '[ 'LOCATION_OBJECT,
         'LOCATION_INPUT_OBJECT
       ]

instance VisitType RemovePrefix where
  visitTypeName RemovePrefix {prefix} _ = T.drop (T.length prefix)
```

now we can apply this directive on type `MythologyDeity` to remove prefix `Mythology`.

```hs
data MythologyDeity = MythologyDeity
  { name :: Text,
    power :: Maybe Text
  }
  deriving
    (Generic)

instance GQLType MythologyDeity where
  directives _ = typeDirective  RemovePrefix {prefix = "Mythology"}
```

<Section id="resolver">Resolving</Section>

### Applicative and Monad instances

<Section id="resolver-monad" level={2}>
  Resolver Monad
</Section>

The `Resolver` type has `Applicative` and `Monad` instances that can be used to compose resolvers.

### Handling Errors

for errors you can use use either `liftEither`, `MonadError` or `MonadFail`:
at the and they have same result.

with `liftEither`

```haskell
resolveDeity :: DeityArgs -> ResolverQ e IO Deity
resolveDeity DeityArgs {} = liftEither $ pure $ Left "db error"
```

with `MonadFail`

```haskell
resolveDeity :: DeityArgs -> ResolverQ e IO Deity
resolveDeity DeityArgs { } = fail "db error"
```

with `MonadError`

```haskell
resolveDeity :: DeityArgs -> ResolverQ e IO Deity
resolveDeity DeityArgs { } = throwError ("db error" :: GQLError)
```

# Resolving Approaches

Morpheus GraphQL provides two way of type resolving.

1. **Values as resolvers**: In this approach, you specify values
   for the type definitions, where the resolvers are regular functions.
   However, this approach can sometimes lead to the possibility of overwhelming
   the database with a huge amount of queries.  
   For this reason, the second approach, which involves automatic batching,
   might be the more suitable solution for you.

2. **Named resolvers**: In this approach, we use the type class `ResolveNamed` to define the
   resolver function for each type that handles a batched list of dependencies.
   More information on this approach can be found in the next section.

<Section id="named-resolvers" level={2}>
  Named Resolvers (Batching)
</Section>

As mentioned earlier, in this approach we use `ResolveNamed`
to define the resolver function (with batching) for each type. In this resolver definition,
each type also defines its dependency (identifier), which is used by the
compiler to provide a corresponding output resolution for certain input values.
That is, if we want to resolve a type as a field of another type, we must
specify a type dependency value for that particular type
instead of the type value. For a better illustration,
let's look at the following example:

### App/Posts.hs

Let's say we want to create a GraphQL app for
a blogging website where we can either retrieve
all posts or retrieve them by ID. Scheme definition for this
application would be as follows.

```haskell
newtype Post m = Post
  { title :: m Text
  }
  deriving
    ( Generic,
      GQLType
    )

data Query m = Query
  { posts :: m [Post m],
    post :: Arg "id" ID -> m (Maybe (Post m))
  }
  deriving
    ( Generic,
      GQLType
    )
```

Now that we have type definitions, we can define their resolvers,
starting with type `Post`. The following instance specifies that for each unique `ID`
we can resolve the corresponding `Post`, where the post `title` is retrieved by the post `ID`.

```haskell
getPostTitles :: Monad m => [ID] -> m [Maybe Text]
getPostTitles = <your db query>

resolvePosts :: Monad m => [ID] -> m [Maybe (Post (NamedResolverT m))]
resolvePosts ids = do
  titles <- getPostTitles ids
  pure (map (fmap toPost) titles)
  where
    toPost text = Post {title = lift (pure text)}

instance ResolveNamed m (Post (NamedResolverT m)) where
  type Dep (Post (NamedResolverT m)) = ID
  resolveBatched = resolvePosts
```

Let's go to the next step and define a query resolver. Since the query does not
require an ID, we define its dependency with the unit type.

To resolve the `post` and `posts` fields, we only get post ids and
pass them to the resolve function, which then resolves the
corresponding `Post` values by calling the `ResolveNamed`
instance of the type `Post` with those ids.

```haskell
allPostIds :: m [ID]
allPostIds = <your db query>

resolveQuery :: Monad m => Query (NamedResolverT m)
resolveQuery =
  Query
    { posts = resolve allPostIds,
      post = \(Arg arg) -> resolve (pure arg)
    }

instance ResolveNamed m (Query (NamedResolverT m)) where
  type Dep (Query (NamedResolverT m)) = ()
  resolveBatched = pure . map (const $ Just resolveQuery)
```

In the last step, we can derive the GraphQL application using
the data type `NamedResolvers` by using a single constructor
`NamedResolvers` without any fields.

```haskell
postsApp :: App () IO
postsApp =
  deriveApp
    (NamedResolvers :: NamedResolvers IO () Query Undefined Undefined)
```

In the background, the function `deriveApp` traverses the data types and calls their
own instances of `NamedResolver` for each object and union type. In this way,
a `ResolverMaps` (with type `Map TypeName (DependencyValue -> ResolveValue)`) is derived that can
be used in GraphQL query execution.

As you can see, the `ResolverMaps` derived in this way can be
merged if the types with the same name have the same GraphQL
kind and the same dependency.
Therefore, types in applications derived with `NamedResolvers` can be safely extended,
which we will see in the next section.

### App/Authors.hs

Let's say there is another team that wants to use the `Posts` application as well,
but also needs to provide `Authors` information. The new application should
allow querying of all existing `Authors` and extend the post type with the field `author`.

One way to address these new requirements would be to rewrite our old application,
but that will impact (or even break) the existing application. Here, named resolvers can
be of additional help to us, as `Apps` derived with named resolvers can be merged.
We can define our `Authors` app separately and then merge it with the existing one.

In the following code snippets we define the Author and Query types.

```haskell
data Author m = Author
  { name :: m Text,
    posts :: m [Post m]
  } deriving (Generic, GQLType)

data Query m = Query
  { authors :: m [Author m]
  }
  deriving (Generic, GQLType)
```

As you can see, we can query `authors`, with each `Author` having their fields `name` and `posts`.
in the same manner as before, we can also provide their resolver implementation.

```haskell
getAuthorPostIds :: Monad m => [ID] -> m [[ID]]
getAuthorPostIds = <your db query>

getAuthorNames :: Monad m => [ID] -> m [Text]
getAuthorNames = <your db query>

getAuthors :: Monad m => [ID] -> m [Maybe (Author (NamedResolverT m))]
getAuthors ids = do
  postIds <- getAuthorPostIds ids
  names <- getAuthorNames ids
  pure (zipWith toAuthor names postIds)

toAuthor :: Monad m => Text -> [ID] -> Maybe (Author (NamedResolverT m))
toAuthor authorName postId =
  Just
    Author
      { name = lift (pure authorName),
        posts = resolve (pure postId)
      }

instance ResolveNamed m (Author (NamedResolverT m)) where
  type Dep (Author (NamedResolverT m)) = ID
  resolveBatched = getAuthors

getAllAuthorIds :: Monad m => m [ID]
getAllAuthorIds = undefined

resolveQuery :: Monad m => Query (NamedResolverT m)
resolveQuery = Query {authors = resolve getAllAuthorIds}

instance ResolveNamed m (Query (NamedResolverT m)) where
  type Dep (Query (NamedResolverT m)) = ()
  resolveBatched = pure . map (const $ Just resolveQuery)
```

At this stage, we have already implemented Authors and Query and now we can also
start thinking about the Post Type.

First note, that the post type used in this app does not need to
be imported from the `App/Posts.hs`. We can simply define our type `Post` with the new
field `author` and all other fields associated with the post type will be automatically
completed by the app `App/Posts.hs`, after the merging.

```haskell
-- is alternative to extend type
newtype Post m = Post
  { author :: m (Author m)
  } deriving
    ( Generic
    , GQLType
    )
```

Now we can start implementing the resolver for it.
It is of critical importance here, that the dependency of this type
is the same as the dependency of `Post` in `App/Posts.hs`. If the
argument of the function does not match, one of the implementations
will be unable to decode the argument during resolution and it will fail.

```haskell
getPostAuthorIds :: Monad m => [ID] -> m [ID]
getPostAuthorIds = <your db query>

resolvePosts :: Monad m => [ID] -> m [Maybe (Post (NamedResolverT m))]
resolvePosts ids = do
  autors <- getPostAuthorIds ids
  pure (map toPost autors)
  where
    toPost autorId = Just $ Post {author = resolve (pure autorId)}

instance ResolveNamed m (Post (NamedResolverT m)) where
  type Dep (Post (NamedResolverT m)) = ID
  resolveBatched = resolvePosts
```

Since all resolvers are implemented, we can also derive the application.
Note that this application can be used as a standalone application, however
the standalone version can only display the information provided by the Authors,
i.e. the Post type will only have one field authors,
and in the query we can only access authors.

```haskell
authorsApp :: App () IO
authorsApp =
  deriveApp
    (NamedResolvers :: NamedResolvers IO () Query Undefined Undefined)
```

However, if we want to access information from both apps,
the next section will show us how to merge them.

### App.hs

The data type `App` has a `Semigroup` instance that allows to
join multiple apps together.

```haskell
app :: App () IO
app = authorsApp <> postsApp
```

Since both the `Post` type definitions have the same dependency `ID`,
the interpreter safely merge these two apps where type
`Post` will be extended with new field `author`.
