| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Hasura.GraphQL.Analyse
Description
Tools to analyze the structure of a GraphQL request.
Synopsis
- data Structure = Structure {
- _stSelection :: HashMap Name FieldInfo
- _stVariables :: HashMap Name VariableInfo
- data FieldInfo
- = FieldObjectInfo GType ObjectInfo
- | FieldScalarInfo GType ScalarInfo
- | FieldEnumInfo GType EnumInfo
- data ScalarInfo = ScalarInfo {
- _siTypeDefinition :: ScalarTypeDefinition
- data EnumInfo = EnumInfo {
- _eiTypeDefinition :: EnumTypeDefinition
- data ObjectInfo = ObjectInfo {
- _oiTypeDefinition :: ObjectTypeDefinition InputValueDefinition
- _oiSelection :: HashMap Name FieldInfo
- data VariableInfo = VariableInfo {
- _viType :: GType
- _viTypeInfo :: InputFieldInfo
- _viDefaultValue :: Maybe (Value Void)
- data InputFieldInfo
- data InputObjectInfo = InputObjectInfo {
- _ioiTypeDefinition :: InputObjectTypeDefinition InputValueDefinition
- _ioiFields :: ~(HashMap Name (GType, InputFieldInfo))
- diagnoseGraphQLQuery :: SchemaIntrospection -> TypedOperationDefinition NoFragments Name -> Maybe [Text]
- analyzeGraphQLQuery :: SchemaIntrospection -> TypedOperationDefinition NoFragments Name -> (Maybe Structure, [Text])
- analyzeObjectSelectionSet :: ObjectTypeDefinition InputValueDefinition -> SelectionSet NoFragments Name -> Analysis (HashMap Name FieldInfo)
- analyzeField :: GType -> TypeDefinition [Name] InputValueDefinition -> Field NoFragments Name -> Analysis (Maybe FieldInfo)
- analyzeVariables :: [VariableDefinition] -> Analysis (HashMap Name VariableInfo)
- analyzeInputField :: Name -> TypeDefinition [Name] InputValueDefinition -> CircularT Name InputFieldInfo Analysis InputFieldInfo
- newtype Analysis a = Analysis (ExceptT AnalysisError (ReaderT (Path, SchemaIntrospection) (Writer [AnalysisError])) a)
- runAnalysis :: SchemaIntrospection -> Analysis a -> (Maybe a, [Text])
- lookupType :: MonadReader (Path, SchemaIntrospection) m => Name -> m (Maybe (TypeDefinition [Name] InputValueDefinition))
- withField :: MonadReader (Path, SchemaIntrospection) m => Name -> m a -> m a
- throwDiagnosis :: (MonadReader (Path, SchemaIntrospection) m, MonadError AnalysisError m) => Diagnosis -> m a
- withCatchAndRecord :: (MonadReader (Path, SchemaIntrospection) m, MonadWriter [AnalysisError] m, MonadError AnalysisError m) => m a -> m (Maybe a)
- data AnalysisError = AnalysisError {
- _aePath :: Path
- _aeDiagnosis :: Diagnosis
- type Path = Seq Text
- data Diagnosis
- = RootTypeNotAnObject
- | TypeNotFound Name
- | EnumSelectionSet Name
- | ScalarSelectionSet Name
- | InputObjectInOutput Name
- | UnionInInput Name
- | ObjectInInput Name
- | InterfaceInInput Name
- | ObjectFieldNotFound Name Name
- | ObjectMissingSelectionSet Name
- | MismatchedFields Name GType GType
- render :: AnalysisError -> Text
- queryRootName :: Name
- mutationRootName :: Name
- subscriptionRootName :: Name
- typenameField :: FieldDefinition InputValueDefinition
- schemaField :: FieldDefinition InputValueDefinition
- typeField :: FieldDefinition InputValueDefinition
- mkReservedField :: Name -> Name -> FieldDefinition InputValueDefinition
Documentation
Overall structure of a given query. We extract the tree of fields in the output, and the graph of input variables.
Constructors
| Structure | |
Fields
| |
Information about the type of an output field; whether the base type is an
object or a scalar, we store the correspoding GType to keep track of the
modifiers applied to it (list or non-nullability).
Constructors
| FieldObjectInfo GType ObjectInfo | |
| FieldScalarInfo GType ScalarInfo | |
| FieldEnumInfo GType EnumInfo |
data ScalarInfo Source #
Constructors
| ScalarInfo | |
Fields
| |
Constructors
| EnumInfo | |
Fields
| |
data ObjectInfo Source #
Constructors
| ObjectInfo | |
Fields
| |
data VariableInfo Source #
Information about a single variable of the query.
Constructors
| VariableInfo | |
Fields
| |
data InputFieldInfo Source #
Information about the type of an input field; whether the base type is an
object or a scalar, we store the correspoding GType to keep track of the
modifiers applied to it (list or non-nullability).
data InputObjectInfo Source #
Constructors
| InputObjectInfo | |
Fields
| |
diagnoseGraphQLQuery :: SchemaIntrospection -> TypedOperationDefinition NoFragments Name -> Maybe [Text] Source #
Given the schema's definition, and a query, validate that the query is consistent. We do this by running the analysis, but discarding the result: we do not care about the structure, only about the validity of the query.
Returns Nothing if the query is valid, or a list of messages otherwise.
analyzeGraphQLQuery :: SchemaIntrospection -> TypedOperationDefinition NoFragments Name -> (Maybe Structure, [Text]) Source #
Given the schema's definition, and a query, run the analysis.
We process all possible fields, and return a partially filled structure if necessary. Given the following query:
query {
foo {
bar
}
does_not_exist {
ghsdflgh
}
}We would return a structure containing:
foo: {
bar: {
}
}AND an error about "does_not_exist" not existing.
In some cases, however, we might not be able to produce a structure at all,
in which case we return Nothing. This either indicates that something was
fundamentally wrong with the structure of the query (such as not finding an
object at the top level), or that a recoverable error was not caught properly
(see withCatchAndRecord).
analyzeObjectSelectionSet :: ObjectTypeDefinition InputValueDefinition -> SelectionSet NoFragments Name -> Analysis (HashMap Name FieldInfo) Source #
Analyze the fields of an object selection set against its definition, and
emit the corresponding Selection. We ignore the fields that fail, and we
continue accumulating the others.
analyzeField :: GType -> TypeDefinition [Name] InputValueDefinition -> Field NoFragments Name -> Analysis (Maybe FieldInfo) Source #
Analyze a given field, and attempt to build a corresponding FieldInfo.
analyzeVariables :: [VariableDefinition] -> Analysis (HashMap Name VariableInfo) Source #
Analyzes the variables in the given query. This builds the graph of input
types associated with the variable. This process is, like any GraphQL schema
operation, inherently self-recursive, and we use CircularT (a lesser
SchemaT) to tie the knot.
analyzeInputField :: Name -> TypeDefinition [Name] InputValueDefinition -> CircularT Name InputFieldInfo Analysis InputFieldInfo Source #
Builds an InputFieldInfo for a given typename.
This function is "memoized" using withCircular to prevent processing the
same type more than once in case the input types are self-recursive.
The monad in which we run our analysis.
Has three capabilities: - reader carries the current path, and the full schema for lookups - writer logs all errors we have caught - except allows for short-circuiting errors
Constructors
| Analysis (ExceptT AnalysisError (ReaderT (Path, SchemaIntrospection) (Writer [AnalysisError])) a) |
runAnalysis :: SchemaIntrospection -> Analysis a -> (Maybe a, [Text]) Source #
lookupType :: MonadReader (Path, SchemaIntrospection) m => Name -> m (Maybe (TypeDefinition [Name] InputValueDefinition)) Source #
Look up a type in the schema.
withField :: MonadReader (Path, SchemaIntrospection) m => Name -> m a -> m a Source #
Add the current field to the error path.
throwDiagnosis :: (MonadReader (Path, SchemaIntrospection) m, MonadError AnalysisError m) => Diagnosis -> m a Source #
Throws an AnalysisError by combining the given diagnosis with the current
path. This interrupts the computation in the given branch, and must be caught
for the analysis to resume.
withCatchAndRecord :: (MonadReader (Path, SchemaIntrospection) m, MonadWriter [AnalysisError] m, MonadError AnalysisError m) => m a -> m (Maybe a) Source #
Runs the given computation. if it fails, cacthes the error, records it in
the monad, and return Nothing. This allows for a clean recovery.
data AnalysisError Source #
Constructors
| AnalysisError | |
Fields
| |
Constructors
| RootTypeNotAnObject | |
| TypeNotFound Name | |
| EnumSelectionSet Name | |
| ScalarSelectionSet Name | |
| InputObjectInOutput Name | |
| UnionInInput Name | |
| ObjectInInput Name | |
| InterfaceInInput Name | |
| ObjectFieldNotFound Name Name | |
| ObjectMissingSelectionSet Name | |
| MismatchedFields Name GType GType |
render :: AnalysisError -> Text Source #
queryRootName :: Name Source #
mutationRootName :: Name Source #
subscriptionRootName :: Name Source #
typenameField :: FieldDefinition InputValueDefinition Source #
schemaField :: FieldDefinition InputValueDefinition Source #
mkReservedField :: Name -> Name -> FieldDefinition InputValueDefinition Source #