Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some documentation to graphql_query/ in trustfall_core #138

Merged
merged 6 commits into from
Feb 11, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions trustfall_core/src/graphql_query/directives.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Directives in GraphQL can be identified by staring with `@`. While
//! `trustfall_core` doesn't support all GraphQL directives, some are available.
ginger51011 marked this conversation as resolved.
Show resolved Hide resolved
use std::{collections::HashSet, convert::TryFrom, num::NonZeroUsize, sync::Arc};

use async_graphql_parser::{types::Directive, Positioned};
Expand All @@ -9,14 +11,38 @@ use crate::ir::{Operation, TransformationKind};

use super::error::ParseError;

/// An argument as passed to the `value` array, for example for a `@filter`
/// directive (see [FilterDirective]).
ginger51011 marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum OperatorArgument {
/// Reference to a variable provided to the query. Variable names are always
/// prefixed with `$`.
VariableRef(Arc<str>),

/// Reference to a `@tag`ed value encountered elsewhere
/// in the query. Tag names are always prefixed with `%`.
ginger51011 marked this conversation as resolved.
Show resolved Hide resolved
TagRef(Arc<str>),
}

/// A GraphQL `@filter` directive.
///
/// The following GraphQL filter directive and Rust instance would be
ginger51011 marked this conversation as resolved.
Show resolved Hide resolved
/// equivalent:
///
/// ```graphql
/// @filter(op: ">=", value: ["$some_value"])
/// ```
///
/// and
///
/// ```ignore
/// FilterDirective {
/// operation: Operation::GreaterThanOrEqual(OperatorArgument::VariableRef(Arc::new("$some_value"), 1))
ginger51011 marked this conversation as resolved.
Show resolved Hide resolved
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub(crate) struct FilterDirective {
/// Describes which operation should be made by the filter
pub operation: Operation<(), OperatorArgument>,
}

Expand Down Expand Up @@ -152,8 +178,21 @@ impl TryFrom<&Positioned<Directive>> for FilterDirective {
}
}

/// A GraphQL `@output` directive.
///
/// For example, the following GraphQL and Rust would be equivalent:
ginger51011 marked this conversation as resolved.
Show resolved Hide resolved
/// ```graphql
/// @output(name: "betterName")
/// ```
///
/// and
///
/// ```ignore
/// OutputDirective { name: Some(Arc::new("betterName"))}
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub(crate) struct OutputDirective {
/// The name that should be used for this field when it is given as output
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<Arc<str>>,
}
Expand Down Expand Up @@ -214,8 +253,21 @@ impl TryFrom<&Positioned<Directive>> for OutputDirective {
}
}

/// A GraphQL `@transform` directive.
///
/// For example, the following GraphQL and Rust would be equivalent:
/// ```graphql
/// @transform(op: "count")
/// ```
ginger51011 marked this conversation as resolved.
Show resolved Hide resolved
///
/// and
///
/// ```ignore
/// TransformDirective { kind: TransformationKind::Count }
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub(crate) struct TransformDirective {
/// The `op` in a GraphQL `@transform`
pub kind: TransformationKind,
}

Expand Down Expand Up @@ -277,6 +329,18 @@ impl TryFrom<&Positioned<Directive>> for TransformDirective {
}
}

/// A GraphQL `@tag` directive.
///
/// For example, the following GraphQL and Rust would be equivalent:
ginger51011 marked this conversation as resolved.
Show resolved Hide resolved
/// ```graphql
/// @tag(name: "%tag_name")
/// ```
///
/// and
///
/// ```ignore
/// TagDirective { name: Some(Arc::new("%tag_name"))}
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub(crate) struct TagDirective {
#[serde(default, skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -337,6 +401,7 @@ impl TryFrom<&Positioned<Directive>> for TagDirective {
}
}

/// A GraphQL `@optional` directive.
ginger51011 marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub(crate) struct OptionalDirective {}

Expand All @@ -357,6 +422,7 @@ impl TryFrom<&Positioned<Directive>> for OptionalDirective {
}
}

/// A GraphQL `@fold` directive.
ginger51011 marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub(crate) struct FoldDirective {}

Expand All @@ -377,6 +443,18 @@ impl TryFrom<&Positioned<Directive>> for FoldDirective {
}
}

/// A GraphQL `@recurse` directive.
///
/// For example, the following GraphQL and Rust would be equivalent:
ginger51011 marked this conversation as resolved.
Show resolved Hide resolved
/// ```graphql
/// @recurse(depth: 1)
/// ```
///
/// and
///
/// ```ignore
/// RecurseDirective { depth: NonZeroUsize::new(1usize)}
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub(crate) struct RecurseDirective {
pub depth: NonZeroUsize,
Expand Down
1 change: 1 addition & 0 deletions trustfall_core/src/graphql_query/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! Errors from parsing GraphQL
ginger51011 marked this conversation as resolved.
Show resolved Hide resolved
use async_graphql_parser::Pos;
use async_graphql_value::Value;
use serde::{ser::Error as SerError, Deserialize, Serialize, Serializer};
Expand Down
1 change: 1 addition & 0 deletions trustfall_core/src/graphql_query/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! Translating GraphQL queries to Rust types
ginger51011 marked this conversation as resolved.
Show resolved Hide resolved
pub(crate) mod directives;
pub mod error;
pub(crate) mod query;
5 changes: 5 additions & 0 deletions trustfall_core/src/graphql_query/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ impl ParsedDirective {
}
}

/// Attempts to extract the query root from an [ExecutableDocument]
///
/// May return [ParseError] if the query is empty, there is no query root, or
/// the query root is not formatted properly
fn try_get_query_root(document: &ExecutableDocument) -> Result<&Positioned<Field>, ParseError> {
if let Some(v) = document.fragments.values().next() {
return Err(ParseError::DocumentContainsNonInlineFragments(v.pos));
Expand Down Expand Up @@ -507,6 +511,7 @@ fn make_transform_group(
})
}

/// Parses a query document. May fail if a query root is missing (see [try_get_query_root](try_get_query_root))
pub(crate) fn parse_document(document: &ExecutableDocument) -> Result<Query, ParseError> {
let query_root = try_get_query_root(document)?;

Expand Down