{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}

{-|
Module      :  Data.GraphQL.Query
Maintainer  :  Brandon Chinn <brandonchinn178@gmail.com>
Stability   :  experimental
Portability :  portable

Definitions needed by GraphQL queries.
-}
module Data.GraphQL.Query (
  GraphQLQuery (..),
  query,
) where

import Data.Aeson (Value)
import Data.Aeson.Schema (IsSchema, Schema)
import Data.Text (Text)
import qualified Data.Text as Text
import Language.Haskell.TH.Quote (QuasiQuoter (..))
import Language.Haskell.TH.Syntax (lift)

-- | A type class for defining GraphQL queries.
--
--  Should be generated via the `graphql-codegen` command. Any manual instances needs
--  to be certain that `getArgs query` satisfies the arguments defined in
--  `getQueryText query`, and that the result adheres to `ResultSchema query`.
class (IsSchema (ResultSchema query)) => GraphQLQuery query where
  type ResultSchema query :: Schema
  getQueryName :: query -> Text
  getQueryText :: query -> Text
  getArgs :: query -> Value

-- | A quasiquoter that interpolates the given string as raw text.
--
--  Trying to avoid a dependency on raw-strings-qq
query :: QuasiQuoter
query :: QuasiQuoter
query =
  QuasiQuoter
    { quoteExp :: String -> Q Exp
quoteExp = forall {m :: * -> *}. Quote m => Text -> m Exp
liftText forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
Text.strip forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack
    , quotePat :: String -> Q Pat
quotePat = forall a. HasCallStack => String -> a
error String
"Cannot use the 'query' QuasiQuoter for patterns"
    , quoteType :: String -> Q Type
quoteType = forall a. HasCallStack => String -> a
error String
"Cannot use the 'query' QuasiQuoter for types"
    , quoteDec :: String -> Q [Dec]
quoteDec = forall a. HasCallStack => String -> a
error String
"Cannot use the 'query' QuasiQuoter for declarations"
    }
  where
    liftText :: Text -> m Exp
liftText Text
s = [|Text.pack $(lift $ Text.unpack s)|]