content: {-# LANGUAGE DuplicateRecordFields #-}
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE NamedFieldPuns #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE QuasiQuotes #-}
  {-# LANGUAGE TemplateHaskellQuotes #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  
  module Data.Morpheus.QuasiQuoter
    ( gql,
      gqlExpression,
      dsl,
      dslExpression,
    )
  where
  
  import Data.ByteString.Lazy.Char8
    ( ByteString,
      pack,
      unpack,
    )
  import Data.Morpheus.Error
    ( gqlWarnings,
      renderGQLErrors,
    )
  import Data.Morpheus.Ext.Result
    ( Result (..),
    )
  import Data.Morpheus.Internal.Utils
    ( fromLBS,
    )
  import Data.Morpheus.Parser
    ( parseRequest,
      parseSchema,
    )
  import Data.Morpheus.Types.IO (GQLRequest (..))
  import Language.Haskell.TH
  import Language.Haskell.TH.Quote
  import Relude hiding (ByteString)
  
  notSupported :: Text -> a
  notSupported things =
    error
      $ things
      <> " are not supported by the GraphQL QuasiQuoter"
  
  gql :: QuasiQuoter
  gql =
    QuasiQuoter
      { quoteExp = gqlExpression . pack,
        quotePat = notSupported "Patterns",
        quoteType = notSupported "Types",
        quoteDec = notSupported "Declarations"
      }
  
  gqlExpression :: ByteString -> Q Exp
  gqlExpression queryText = case parseRequest request of
    Failure errors -> fail (renderGQLErrors errors)
    Success {result, warnings} ->
      gqlWarnings warnings >> [|(result, query)|]
    where
      query = unpack queryText
      request =
        GQLRequest
          { query = fromLBS queryText,
            operationName = Nothing,
            variables = Nothing
          }
  
  dsl :: QuasiQuoter
  dsl =
    QuasiQuoter
      { quoteExp = dslExpression . pack,
        quotePat = notSupported "Patterns",
        quoteType = notSupported "Types",
        quoteDec = notSupported "Declarations"
      }
  
  dslExpression :: ByteString -> Q Exp
  dslExpression doc = case parseSchema doc of
    Failure errors -> fail (renderGQLErrors errors)
    Success {result, warnings} ->
      gqlWarnings warnings >> [|result|]
  