Support variables in AST transformation
This commit is contained in:
parent
e716bc57e7
commit
b7a72591fd
@ -3,6 +3,7 @@ module Data.GraphQL.AST.Core where
|
|||||||
|
|
||||||
import Data.Int (Int32)
|
import Data.Int (Int32)
|
||||||
import Data.List.NonEmpty (NonEmpty)
|
import Data.List.NonEmpty (NonEmpty)
|
||||||
|
import Data.String
|
||||||
|
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
|
|
||||||
@ -31,4 +32,7 @@ data Value = ValueInt Int32
|
|||||||
| ValueObject [ObjectField]
|
| ValueObject [ObjectField]
|
||||||
deriving (Eq,Show)
|
deriving (Eq,Show)
|
||||||
|
|
||||||
|
instance IsString Value where
|
||||||
|
fromString = ValueString . fromString
|
||||||
|
|
||||||
data ObjectField = ObjectField Name Value deriving (Eq,Show)
|
data ObjectField = ObjectField Name Value deriving (Eq,Show)
|
||||||
|
@ -4,10 +4,10 @@ import Control.Applicative (empty)
|
|||||||
import Control.Monad ((<=<))
|
import Control.Monad ((<=<))
|
||||||
import Data.Bifunctor (first)
|
import Data.Bifunctor (first)
|
||||||
import Data.Either (partitionEithers)
|
import Data.Either (partitionEithers)
|
||||||
|
import Data.Foldable (fold, foldMap)
|
||||||
import qualified Data.List.NonEmpty as NonEmpty
|
import qualified Data.List.NonEmpty as NonEmpty
|
||||||
import Data.Maybe (maybeToList)
|
import Data.Maybe (maybeToList)
|
||||||
import Data.Monoid (Alt(Alt,getAlt))
|
import Data.Monoid (Alt(Alt,getAlt))
|
||||||
import Data.Foldable (foldMap)
|
|
||||||
|
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
|
|
||||||
@ -25,7 +25,11 @@ type Fragmenter = Name -> [Core.Field]
|
|||||||
document :: Schema.Subs -> Full.Document -> Maybe Core.Document
|
document :: Schema.Subs -> Full.Document -> Maybe Core.Document
|
||||||
document subs defs = operations subs fr ops
|
document subs defs = operations subs fr ops
|
||||||
where
|
where
|
||||||
(fr, ops) = first foldFrags . partitionEithers . NonEmpty.toList $ defrag <$> defs
|
(fr, ops) = first foldFrags
|
||||||
|
. partitionEithers
|
||||||
|
. NonEmpty.toList
|
||||||
|
$ defrag subs
|
||||||
|
<$> defs
|
||||||
|
|
||||||
foldFrags :: [Fragmenter] -> Fragmenter
|
foldFrags :: [Fragmenter] -> Fragmenter
|
||||||
foldFrags fs n = getAlt $ foldMap (Alt . ($ n)) fs
|
foldFrags fs n = getAlt $ foldMap (Alt . ($ n)) fs
|
||||||
@ -46,53 +50,70 @@ operation
|
|||||||
-> Maybe Core.Operation
|
-> Maybe Core.Operation
|
||||||
operation subs fr (Full.OperationSelectionSet sels) =
|
operation subs fr (Full.OperationSelectionSet sels) =
|
||||||
operation subs fr $ Full.OperationDefinition Full.Query empty empty empty sels
|
operation subs fr $ Full.OperationDefinition Full.Query empty empty empty sels
|
||||||
operation _subs fr (Full.OperationDefinition ot _n _vars _dirs sels) =
|
-- TODO: Validate Variable definitions with substituter
|
||||||
|
operation subs fr (Full.OperationDefinition ot _n _vars _dirs sels) =
|
||||||
case ot of
|
case ot of
|
||||||
Full.Query -> Core.Query <$> node
|
Full.Query -> Core.Query <$> node
|
||||||
Full.Mutation -> Core.Mutation <$> node
|
Full.Mutation -> Core.Mutation <$> node
|
||||||
where
|
where
|
||||||
node = traverse (hush <=< selection fr) sels
|
node = traverse (hush <=< selection subs fr) sels
|
||||||
|
|
||||||
selection :: Fragmenter -> Full.Selection -> Maybe (Either [Core.Field] Core.Field)
|
selection
|
||||||
selection fr (Full.SelectionField _fld) = Right <$> field fr _fld
|
:: Schema.Subs
|
||||||
selection fr (Full.SelectionFragmentSpread (Full.FragmentSpread n _dirs)) = Just . Left $ fr n
|
-> Fragmenter
|
||||||
selection _ (Full.SelectionInlineFragment _) = error "Inline fragments not supported yet"
|
-> Full.Selection
|
||||||
|
-> Maybe (Either [Core.Field] Core.Field)
|
||||||
|
selection subs fr (Full.SelectionField fld) =
|
||||||
|
Right <$> field subs fr fld
|
||||||
|
selection _ fr (Full.SelectionFragmentSpread (Full.FragmentSpread n _dirs)) =
|
||||||
|
Just . Left $ fr n
|
||||||
|
selection _ _ (Full.SelectionInlineFragment _) =
|
||||||
|
error "Inline fragments not supported yet"
|
||||||
|
|
||||||
-- * Fragment replacement
|
-- * Fragment replacement
|
||||||
|
|
||||||
-- | Extract Fragments into a single Fragmenter function and a Operation
|
-- | Extract Fragments into a single Fragmenter function and a Operation
|
||||||
-- Definition.
|
-- Definition.
|
||||||
defrag :: Full.Definition -> Either Fragmenter Full.OperationDefinition
|
defrag
|
||||||
defrag (Full.DefinitionOperation op) = Right op
|
:: Schema.Subs
|
||||||
defrag (Full.DefinitionFragment fragDef) = Left $ fragmentDefinition fragDef
|
-> Full.Definition
|
||||||
|
-> Either Fragmenter Full.OperationDefinition
|
||||||
|
defrag _ (Full.DefinitionOperation op) =
|
||||||
|
Right op
|
||||||
|
defrag subs (Full.DefinitionFragment fragDef) =
|
||||||
|
Left $ fragmentDefinition subs fragDef
|
||||||
|
|
||||||
fragmentDefinition :: Full.FragmentDefinition -> Fragmenter
|
fragmentDefinition :: Schema.Subs -> Full.FragmentDefinition -> Fragmenter
|
||||||
fragmentDefinition (Full.FragmentDefinition name _tc _dirs sels) name' =
|
fragmentDefinition subs (Full.FragmentDefinition name _tc _dirs sels) name' =
|
||||||
-- TODO: Support fragments within fragments. Fold instead of map.
|
-- TODO: Support fragments within fragments. Fold instead of map.
|
||||||
if name == name'
|
if name == name'
|
||||||
then either id pure =<< maybeToList =<< NonEmpty.toList (selection mempty <$> sels)
|
then either id pure =<< maybeToList
|
||||||
|
=<< NonEmpty.toList (selection subs mempty <$> sels)
|
||||||
else empty
|
else empty
|
||||||
|
|
||||||
field :: Fragmenter -> Full.Field -> Maybe Core.Field
|
field :: Schema.Subs -> Fragmenter -> Full.Field -> Maybe Core.Field
|
||||||
field fr (Full.Field a n args _ sels) =
|
field subs fr (Full.Field a n args _dirs sels) =
|
||||||
Core.Field a n (argument <$> args) <$> traverse (hush <=< selection fr) sels
|
Core.Field a n (fold $ argument subs `traverse` args)
|
||||||
|
<$> traverse (hush <=< selection subs fr) sels
|
||||||
|
|
||||||
argument :: Full.Argument -> Core.Argument
|
argument :: Schema.Subs -> Full.Argument -> Maybe Core.Argument
|
||||||
argument (Full.Argument n v) = Core.Argument n (value v)
|
argument subs (Full.Argument n v) = Core.Argument n <$> value subs v
|
||||||
|
|
||||||
value :: Full.Value -> Core.Value
|
value :: Schema.Subs -> Full.Value -> Maybe Core.Value
|
||||||
value (Full.ValueVariable _) = error "Variables within fragments not supported yet"
|
value subs (Full.ValueVariable n) = subs n
|
||||||
value (Full.ValueInt i) = Core.ValueInt i
|
value _ (Full.ValueInt i) = pure $ Core.ValueInt i
|
||||||
value (Full.ValueFloat f) = Core.ValueFloat f
|
value _ (Full.ValueFloat f) = pure $ Core.ValueFloat f
|
||||||
value (Full.ValueString x) = Core.ValueString x
|
value _ (Full.ValueString x) = pure $ Core.ValueString x
|
||||||
value (Full.ValueBoolean b) = Core.ValueBoolean b
|
value _ (Full.ValueBoolean b) = pure $ Core.ValueBoolean b
|
||||||
value Full.ValueNull = Core.ValueNull
|
value _ Full.ValueNull = pure Core.ValueNull
|
||||||
value (Full.ValueEnum e) = Core.ValueEnum e
|
value _ (Full.ValueEnum e) = pure $ Core.ValueEnum e
|
||||||
value (Full.ValueList l) = Core.ValueList (value <$> l)
|
value subs (Full.ValueList l) =
|
||||||
value (Full.ValueObject o) = Core.ValueObject (objectField <$> o)
|
Core.ValueList <$> traverse (value subs) l
|
||||||
|
value subs (Full.ValueObject o) =
|
||||||
|
Core.ValueObject <$> traverse (objectField subs) o
|
||||||
|
|
||||||
objectField :: Full.ObjectField -> Core.ObjectField
|
objectField :: Schema.Subs -> Full.ObjectField -> Maybe Core.ObjectField
|
||||||
objectField (Full.ObjectField n v) = Core.ObjectField n (value v)
|
objectField subs (Full.ObjectField n v) = Core.ObjectField n <$> value subs v
|
||||||
|
|
||||||
hush :: Either a b -> Maybe b
|
hush :: Either a b -> Maybe b
|
||||||
hush = either (const Nothing) Just
|
hush = either (const Nothing) Just
|
||||||
|
@ -48,7 +48,7 @@ type Fields = [Field]
|
|||||||
type Arguments = [Argument]
|
type Arguments = [Argument]
|
||||||
|
|
||||||
-- | Variable substitution function.
|
-- | Variable substitution function.
|
||||||
type Subs = Text -> Maybe Text
|
type Subs = Name -> Maybe Value
|
||||||
|
|
||||||
-- | Create a new 'Resolver' with the given 'Name' from the given 'Resolver's.
|
-- | Create a new 'Resolver' with the given 'Name' from the given 'Resolver's.
|
||||||
object :: Alternative f => Name -> Resolvers f -> Resolver f
|
object :: Alternative f => Name -> Resolvers f -> Resolver f
|
||||||
@ -110,7 +110,6 @@ withField name f (Field alias name' _ _) =
|
|||||||
where
|
where
|
||||||
aliasOrName = fromMaybe name alias
|
aliasOrName = fromMaybe name alias
|
||||||
|
|
||||||
|
|
||||||
-- | Takes a list of 'Resolver's and a list of 'Field's and applies each
|
-- | Takes a list of 'Resolver's and a list of 'Field's and applies each
|
||||||
-- 'Resolver' to each 'Field'. Resolves into a value containing the
|
-- 'Resolver' to each 'Field'. Resolves into a value containing the
|
||||||
-- resolved 'Field', or a null value and error information.
|
-- resolved 'Field', or a null value and error information.
|
||||||
|
Loading…
Reference in New Issue
Block a user