All notable changes to apollo-compiler
will be documented in this file.
This project adheres to Semantic Versioning.
1.0.0-beta.8 - 2023-11-30
-
API refactor to make it harder to ignore errors - SimonSapin, pull/752 fixing issue/709:
ast::Document
,Schema
, andExecutableDocument
not longer contain potential errors that users need to check separately.- Instead, various constructors and methods now return a
Result
, with theErr
case containing both both errors and a maybe-incomplete value. - Change
validate
methods ofSchema
andExecutableDocument
to take ownership ofself
. On success they return the schema or document (unmodified) wrapped in aValid<_>
marker type, which is immutable. - Change
ExecutableDocument
to require a&Valid<Schema>
instead of&Schema
, forcing callers to either run validation or opt out explicitly withValid::assume_valid
. - Make
parse_mixed
andto_mixed
validate both the schema and document. Rename them with a_validate
suffix. - Corresponding changes to all of the above in
Parser
method signatures - Remove
ast::Document::check_parse_errors
: parse errors are now encoded in the return value ofparse
. - Remove
ast::Document::to_schema_builder
. UseSchemaBuilder::add_ast
instead. - Move items from the crate top-level to
apollo_compiler::validation
:Diagnostic
DiagnosticList
FileId
NodeLocation
- Move items from the crate top-level to
apollo_compiler::execution
:GraphQLError
GraphQLLocation
- Remove warning-level and advice-level diagnostics. See issue/751.
Highlight of signature changes:
+struct Valid<T>(T); // Implements `Deref` and `AsRef` but not `DerefMut` or `AsMut` + +struct WithErrors<T> { + partial: T, // Errors may cause components to be missing + errors: DiagnosticList, +} -pub fn parse_mixed(…) -> (Schema, ExecutableDocument) +pub fn parse_mixed_validate(…) + -> Result<(Valid<Schema>, Valid<ExecutableDocument>), DiagnosticList> impl ast::Document { - pub fn parse(…) -> Self + pub fn parse(…) -> Result<Self, WithErrors<Self>> - pub fn to_schema(&self) -> Schema + pub fn to_schema(&self) -> Result<Schema, WithErrors<Schema>> - pub fn to_executable(&self) -> ExecutableDocument + pub fn to_executable(&self) -> Result<ExecutableDocument, WithErrors<ExecutableDocument>> - pub fn to_mixed(&self) -> (Schema, ExecutableDocument) + pub fn to_mixed_validate( + &self, + ) -> Result<(Valid<Schema>, Valid<ExecutableDocument>), DiagnosticList> } impl Schema { - pub fn parse(…) -> Self - pub fn validate(&self) -> Result<DiagnosticList, DiagnosticList> + pub fn parse_and_validate(…) -> Result<Valid<Self>, WithErrors<Self>> + pub fn parse(…) -> Result<Self, WithErrors<Self>> + pub fn validate(self) -> Result<Valid<Self>, WithErrors<Self>> } impl SchemaBuilder { - pub fn build(self) -> Schema + pub fn build(self) -> Result<Schema, WithErrors<Schema>> } impl ExecutableDocument { - pub fn parse(schema: &Schema, …) -> Self - pub fn validate(&self, schema: &Schema) -> Result<(), DiagnosticList> + pub fn parse_and_validate(schema: &Valid<Schema>, …) -> Result<Valid<Self>, WithErrors<Self>> + pub fn parse(schema: &Valid<Schema>, …) -> Result<Self, WithErrors<Self>> + pub fn validate(self, schema: &Valid<Schema>) -> Result<Valid<Self>, WithErrors<Self>> }
-
Add
parse_and_validate
constructors forSchema
andExecutableDocument
- SimonSapin, pull/752: when mutating isn’t needed after parsing, this returns an immutableValid<_>
value in one step. -
Implement serde
Serialize
andDeserialize
for some AST types - SimonSapin, pull/760:Node
NodeStr
Name
IntValue
FloatValue
Value
Type
Source locations are not preserved through serialization.
-
Add
ast::Definition::as_*() -> Option<&_>
methods for each variant - SimonSapin, pull/760 -
Serialize (to GraphQL) multi-line strings as block strings - SimonSapin, pull/724: Example before:
"Example\n\nDescription description description" schema { query: MyQuery }
After:
""" Example Description description description """ schema { query: MyQuery }
-
Limit recursion in validation - goto-bus-stop, pull/748 fixing issue/742: Validation now bails out of very long chains of definitions that refer to each other, even if they don't strictly form a cycle. These could previously cause extremely long validation times or stack overflows.
The limit for input objects and directives is set at 32. For fragments, the limit is set at 100. Based on our datasets, real-world documents don't come anywhere close to this.
1.0.0-beta.7 - 2023-11-17
- Helper features for
Name
andType
- SimonSapin, pull/739:- The
name!
macro also accepts an identifier:name!(Query)
andname!("Query")
create equivalentName
values. InvalidNameError
now contain a publicNodeStr
for the input string that is invalid, and implementsDisplay
,Debug
, andError
traits.- Add
TryFrom
conversion toName
fromNodeStr
,&NodeStr
,&str
,String
, and&String
. - Add a
ty!
macro to build a staticast::Type
using GraphQL-like syntax.
- The
-
Add parsing an
ast::Type
from a string - lrlna and goto-bus-stop, pull/718 fixing issue/715Parses GraphQL type syntax:
use apollo_compiler::ast::Type; let ty = Type::parse("[ListItem!]!")?;
-
Fix list and null type validation bugs - goto-bus-stop, pull/746 fixing issue/738 Previous versions of apollo-compiler accepted
null
inside a list even if the list item type was marked as required. Lists were also accepted as inputs to non-list fields. This is now fixed.input Args { string: String ints: [Int!] } type Query { example(args: Args): Int } query { example(args: { # Used to be accepted, now raises an error string: ["1"] # Used to be accepted, now raises an error ints: [1, 2, null, 4] }) }
1.0.0-beta.6 - 2023-11-10
-
Make everything know their own name - SimonSapin, pull/727 fixing issue/708.
In a few places (but not consistently) a
name
field was omitted from some structs used as map values on the basis that it would have been redundant with the map key. This reverts that decision, making it the user’s responsibility when mutating documents to keep names consistent.- Add a
pub name: Name
field toexecutable::Fragment
as well asScalarType
,ObjectType
,InterfaceType
,EnumType
,UnionType
, andInputObjectType
inschema
. - Add a
fn name(&self) -> &Name
method to theschema::ExtendedType
enum - Add a
pub name: Option<Name>
field toexecutable::Operation
- Remove
executable::OperationRef<'_>
(which was equivalent to(Option<&Name>, &Node<Operation>)
), replacing its uses with&Node<Operation>
- Add a
-
Rename
Directives
andDiagnostics
toDirectiveList
andDiagnosticList
- SimonSapin, pull/732 fixing issue/711. The previous names were too similar toDirective
andDiagnostic
(singular). -
Rename
ComponentStr
toComponentName
- SimonSapin, pull/713 and itsnode: NodeStr
field toname: Name
. -
Assorted changed to GraphQL names - SimonSapin, pull/713 fixing issue/710.
- Check validity of
ast::Name
.NodeStr
is a smart string type with infallible conversion from&str
.ast::Name
used to be a type alias forNodeStr
, leaving the possibility of creating one invalid in GraphQL syntax. Validation and serialization would not check this.Name
is now a wrapper type forNodeStr
. Itsnew
constructor checks validity of the given string and returns aResult
. A newname!
macro (see below) creates aName
with compile-time checking. OperationType::default_type_name
returns aName
instead of&str
Type::new_named("x")
is removed. UseType::Named(name!("x"))
instead.ComponentStr
is renamed toComponentName
. It no longer has infallible conversions from&str
orString
. Itsnode
field is renamed toname
; the type of that field is changed fromNodeStr
toName
.NodeStr
no longer has ato_component
method, onlyName
does- Various function or method parameters changed from
impl Into<Name>
toName
, since there is no longer an infallible conversion from&str
- Check validity of
-
Add serialization support for everything - SimonSapin, pull/728.
Schema
,ExecutableDocument
, and all AST types already supported serialization to GraphQL syntax through theDisplay
trait and the.serialize()
method. This is now also the case of all other Rust types representing some element of a GraphQL document:schema::Directives
schema::ExtendedType
schema::ScalarType
schema::ObjectType
schema::InterfaceType
schema::EnumType
schema::UnionType
schema::InputObjectType
executable::Operation
executable::Fragment
executable::SelectionSet
executable::Selection
executable::Field
executable::InlineFragment
executable::FragmentSpread
executable::FieldSet
-
Assorted changed to GraphQL names - SimonSapin, pull/713 fixing issue/710. See also the BREAKING section above.
- Add a
name!("example")
macro, to be imported withuse apollo_compiler::name;
. It creates anast::Name
from a string literal, with a compile-time validity checking. AName
created this way does not own allocated heap memory or a reference counter, so cloning it is extremely cheap. - Add allocation-free
NodeStr::from_static
. This mostly exists to support thename!
macro, but can also be used on its own:let s = apollo_compiler::NodeStr::from_static(&"example"); assert_eq!(s, "example");
- Add a
- Fix crash in validation of self-referential fragments - goto-bus-stop, pull/733 fixing issue/716. Now fragments that cyclically reference themselves inside a nested field also produce a validation error, instead of causing a stack overflow crash.
1.0.0-beta.5 - 2023-11-08
- Diangostic struct is now public by SimonSapin in 11fe454
- Improve lowercase enum value diagnostic by goto-bus-stop in pull/725
- Simplify
SchemaBuilder
internals by SimonSapin in pull/722 - Remove validation dead code by SimonSapin in bd5d107
- Skip schema AST conversion in ExecutableDocument::validate by SimonSapin in pull/726
1.0.0-beta.4 - 2023-10-16
-
JSON Serialisable compiler diagnostics - lrlna and goto-bus-stop, pull/698: This change brings back JSON error format for diagnostics introduced by goto-bus-stop in pull/668 for [email protected]. As a result, diagnostics' line/column numbers are now also accessible as part of the public API.
let json = expect_test::expect![[r#" { "message": "an executable document must not contain an object type definition", "locations": [ { "line": 2, "column": 1 } ] }"#]]; let diagnostics = executable.validate(&schema).unwrap_err(); diagnostics.iter().for_each(|diag| { assert_eq!( diag.get_line_column(), Some(GraphQLLocation { line: 2, column: 1 }) ); json.assert_eq(&serde_json::to_string_pretty(&diag.to_json()).unwrap()); });
- Don’t emit a validation error for relying on argument default - SimonSapin, pull/700 A field argument or directive argument was incorrectly considered required as soon as it had a non-null type, even if it had a default value.
1.0.0-beta.3 - 2023-10-13
- Keep source files in
Arc<Map<…>>
everywhere - SimonSapin, pull/696 Change struct fields fromsources: IndexMap<FileId, Arc<SourceFile>>
(inSchema
) orsource: Option<(FileId, Arc<SourceFile>)>
(inDocument
,ExecutablDocument
,FieldSet
) tosources: SourceMap
, with:Cases other thanpub type SourceMap = Arc<IndexMap<FileId, Arc<SourceFile>>>;
Schema
still only have zero or one source when created by apollo-compiler, but it is now possible to make more sources available to diagnostics, for example when merging documents:Arc::make_mut(&mut doc1.sources).extend(doc2.sources.iter().map(|(k, v)| (*k, v.clone())));
- Add iteration over individual diagnostics - SimonSapin, pull/696:
let schema = Schema::parse(input, "schema.graphql"); if let Err(errors) = schema.validate() { for error in errors.iter() { eprintln!("{error}") } }
- Don’t panic in validation or omit diagnostics when a source location is missing - SimonSapin, pull/697 In apollo-compiler 0.11 every element of the HIR always had a source location because it always came from a parsed input file. In 1.0 source location is always optional. When a node relevant to some diagnostic does not have a source location, the diagnostic should still be emitted but its labels (each printing a bit of source code) may be missing. Essential information should therefore be in the main message, not only in labels.
1.0.0-beta.2 - 2023-10-10
Assorted Schema
API changes - SimonSapin, pull/678
- Type of the
schema_definition
field changed fromOption<SchemaDefinition>
toSchemaDefinition
. Default root operations based on object type names are now stored explicitly inSchemaDefinition
. Serialization relies on a heuristic to decide on implicit schema definition. - Removed
schema_definition_directives
method: no longer having anOption
allows fieldschema.schema_definition.directives
to be accessed directly - Removed
query_root_operation
,mutation_root_operation
, andsubscription_root_operation
methods. Insteadschema.schema_definition.query
etc can be accessed directly.
-
Add
executable::FieldSet
for a selection set with optional outer brackets - lrlna, pull/685 fixing issue/681 This is intended to parse string value of aFieldSet
custom scalar used in some Apollo Federation directives in the context of a specific schema and type. Itsvalidate
method calls a subset of validation rules relevant to selection sets. which is not part of a document.let input = r#" type Query { id: ID organization: Org } type Org { id: ID } "#; let schema = Schema::parse(input, "schema.graphql"); schema.validate().unwrap(); let input = "id organization { id }"; let field_set = FieldSet::parse(&schema, "Query", input, "field_set.graphql"); field_set.validate(&schema).unwrap();
-
Add opt-in configuration for “orphan” extensions to be “adopted” - SimonSapin, pull/678
Type extensions and schema extensions without a corresponding definition are normally ignored except for recording a validation error. In this new mode, an implicit empty definition to extend is generated instead. This behavious is not the default, as it's non-standard. Configure a schema builder to opt in:
let input = "extend type Query { x: Int }"; let schema = apollo_compiler::Schema::builder() .adopt_orphan_extensions() .parse(input, "schema.graphql") .build(); schema.validate()?;
- Allow built-in directives to be redefined - SimonSapin, pull/684 fixing issue/656
- Allow schema extensions to extend a schema definition implied by object types named after default root operations - SimonSapin, pull/678 fixing [issues/682]
1.0.0-beta.1 - 2023-10-05
Compared to 0.11, version 1.0 is a near-complete rewrite of the library
and revamp of the public API.
While in beta, there may still be breaking changes (though not as dramatic)
until 1.0.0 “final”.
If using a beta version, we recommend specifying an exact dependency in Cargo.toml
:
apollo-compiler = "=1.0.0-beta.1"
The API is now centered on Schema
and ExecutableDocument
types.
Users no longer need to create a compiler, add inputs to it, and track them by ID.
Validation is now a method of these types, and returns a Result
to indicate errors.
These types are serializable
(through Display
, .to_string()
, and a .serialize()
config builder),
integrating the functionality of the apollo-encoder crate.
They are also mutable, and can be created programmatically out of thin air.
Node<T>
is a thread-safe reference-counted smart pointer
that provides structural sharing and copy-on-write semantics.
0.11.3 - 2023-10-06
-
expose line/column location and JSON format from diagnostics, by goto-bus-stop in pull/668
You can now use
diagnostic.get_line_column()
to access the line/column number where a validation error occurred.diagnostic.to_json()
returns a GraphQL error structure that's serializable with serde, matching the JSON error format.let diagnostics = compiler.db.validate(); let errors = diagnostics.into_iter().map(ApolloDiagnostic::to_json).collect::<Vec<_>>(); let error_response = serde_json::to_string(&serde_json::json!({ "errors": errors, }))?;
-
improve validation error summaries, by goto-bus-stop in pull/674
Adds more context and a more consistent voice to the "main" message for validation errors. They are now concise, matter-of-fact descriptions of the problem. Information about how to solve the problem is usually already provided by labels and notes on the diagnostic.
- operation
getName
is defined multiple times - interface
NamedEntity
implements itself
The primary use case for this is to make
diagnostic.data.to_string()
return a useful message for text-only error reports, like in JSON responses. The JSON format for diagnostics uses these new messages. - operation
0.11.2 - 2023-09-11
-
Add
validate_standalone_executable
function to validate an executable document without access to a schema, by goto-bus-stop in pull/631, issue/629This runs just those validations that can be done on operations without knowing the types of things.
let compiler = ApolloCompiler::new(); let file_id = compiler.add_executable(r#" { user { ...userData } } "#, "query.graphql"); let diagnostics = compiler.db.validate_standalone_executable(file_id); // Complains about `userData` fragment not existing, but does not complain about `user` being an unknown query.
-
validate input value types, by goto-bus-stop in pull/642
This fixes an oversight in the validation rules implemented by
compiler.db.validate()
. Previously, incorrect types on input values and arguments were not reported:type ObjectType { id: ID! } input InputObject { # accepted in <= 0.11.1, reports "TypeThatDoesNotExist is not in scope" in 0.11.2 property: TypeThatDoesNotExist # accepted in <= 0.11.1, reports "ObjectType is not an input type" in 0.11.2 inputType: ObjectType }
- (TODO: write this)
0.11.1 - 2023-08-24
- disable colours in diagnostics output if the terminal is not interactive, by EverlastingBugstopper in pull/628, issue/499
0.11.0 - 2023-08-18
- add
InterfaceTypeDefinition::implementors(&db)
to list object types and other interfaces that implement an interface, by Geal in pull/616
- fix
SelectionSet::is_introspection
when the same fragment is spread multiple times, by glasser in pull/614, issue/613
- update
apollo-parser
to 0.6.0, by goto-bus-stop in pull/621
0.10.0 - 2023-06-20
SelectionSet::merge
is renamed toSelectionSet::concat
to clarify that it doesn't do field merging, by goto-bus-stop in pull/570hir::InlineFragment::type_condition
now only returnsSome()
if a type condition was explicitly specified, by goto-bus-stop in pull/586
-
add
root_operation_name(OperationType)
helper method onhir::SchemaDefinition
by SimonSapin in pull/579 -
add an
UndefinedDirective
diagnostic type, by goto-bus-stop in pull/587This is used for directives instead of
UndefinedDefinition
.
-
accept objects as values for custom scalars, by goto-bus-stop in pull/585
The GraphQL spec is not entirely clear on this, but this is used in the real world with things like the
_Any
type in Apollo Federation.
- update dependencies, by goto-bus-stop in commit/daf918b
- add a test for validation with
set_type_system_hir()
, by goto-bus-stop in pull/583
0.9.4 - 2023-06-05
-
accept any primitive value type for custom scalar validation, by lrlna in pull/575
If you provide a value to a custom scalar in your GraphQL source text, apollo-compiler now accepts any value type. Previously it was not possible to write values for custom scalars into a query or schema because the value you wrote would never match the custom scalar type.
This now works:
scalar UserID @specifiedBy(url: "https://my-app.net/api-docs/users#id") type Query { username (id: UserID): String }
{ username(id: 575) }
-
add type name to the
UndefinedField
diagnostic data, by goto-bus-stop in pull/577When querying a field that does not exist, the type name that's being queried is stored on the diagnostic, so you can use it when handling the error.
0.9.3 - 2023-05-26
-
fix nullable / non-nullable validations inside lists, by lrlna in pull/567
Providing a variable of type
[Int!]!
to an argument of type[Int]
is now allowed.
- use official ariadne release, by goto-bus-stop in pull/568
0.9.2 - 2023-05-23
-
add
as_$type()
methods tohir::Value
, by goto-bus-stop in pull/564These methods simplify casting the
hir::Value
enum to single Rust types. Added methods:hir::Value::as_i32() -> Option<i32>
hir::Value::as_f64() -> Option<f64>
hir::Value::as_str() -> Option<&str>
hir::Value::as_bool() -> Option<bool>
hir::Value::as_list() -> Option<&Vec<Value>>
hir::Value::as_object() -> Option<&Vec<(Name, Value)>>
hir::Value::as_variable() -> Option<&Variable>
-
non-nullable variables should be accepted for nullable args, by lrlna in pull/565
Fixes several
null
-related issues from 0.9.0. -
add an
UndefinedVariable
diagnostic, by goto-bus-stop in pull/563Previously undefined variables were reported with an
UndefinedDefinition
diagnostic. Splitting it up lets us provide a better error message for missing variables.
0.9.1 - 2023-05-19
- Update the apollo-parser dependency version, by goto-bus-stop in pull/559
0.9.0 - 2023-05-12
This release completes GraphQL validation specification, making the compiler spec-compliant.
You can validate the entire corpus of the compiler, or run individual compiler validation rules. The example below runs the whole corpus, as well specifically runs compiler.db.validate_executable(file_id)
for each of the two defined operations.
let schema = r#"
type Query {
cat: Cat
}
type Cat{
name: String!
nickname: String
purrVolume: Int
doesKnowCommand(catCommand: CatCommand!): Boolean!
}
enum CatCommand {
HOP
}
"#;
let cat_name_op = r#"
query getCatName {
cat {
name
}
}
"#;
let cat_command_op = r#"
query getCatName {
cat {
doesNotKnowCommand
}
}
"#;
let mut compiler = ApolloCompiler::new();
compiler.add_type_system(schema, "schema.graphl");
let cat_name_file = compiler.add_executable(cat_name_op, "cat_name_op.graphql");
let cat_command_file = compiler.add_executable(cat_command_op, "cat_command_op.graphql");
// validate both the operation and the type system
let all_diagnostics = compiler.validate();
assert_eq!(all_diagnostics.len(), 1);
// validate just the executables individual
let cat_name_op_diagnotics = compiler.db.validate_executable(cat_name_file);
assert!(cat_name_op_diagnotics.is_empty());
let cat_command_op_diagnotics = compiler.db.validate_executable(cat_command_file);
// This one has an error, where a field queries is not defined.
assert_eq!(cat_command_op_diagnotics.len(), 1);
for diag in cat_command_op_diagnotics {
println!("{}", diag);
}
-
remove
impl Default
for ApolloCompiler, by [dariuszkuc] in pull/542 -
align HIR extension getters to those of their type definition, by lrlna in pull/540
The following methods were changed:
InputObjectTypeExtension.fields_definition()
->InputObjectTypeDefinition.fields()
ObjectTypeExtension.fields_definition()
->ObjectTypeExtension.fields()
InterfaceTypeExtension.fields_definition()
->InterfaceTypeExtension.fields()
EnumTypeExtension.enum_values_definition()
->EnumTypeExtension.values()
UnionTypeExtension.union_members()
->UnionTypeExtension.members()
- validate values are of correct type, by lrlna in pull/550
- support the built-in
@deprecated
directive on arguments and input values, by goto-bus-stop in pull/518 - validate that variable usage is allowed, by lrlna in pull/537
- validate executable documents do not contain type definitions, by goto-bus-stop in pull/535
- validate union extensions, by goto-bus-stop in pull/534
- validate input object extensions, by goto-bus-stop in pull/533
- validate interface extensions, by goto-bus-stop in pull/532
- validate enum extensions, by goto-bus-stop in pull/528
- validate object type extensions, by goto-bus-stop in pull/524
- validate fragment spread is possible, by goto-bus-stop in pull/511
- fix recursion cycle in
is_introspection
HIR getter, by allancalix and goto-bus-stop in pull/544 and pull/552
0.8.0 - 2023-04-13
There is now an API to set parser's token limits via apollo-compiler
. To
accommodate an additional limit, we changed the API to set several limits
simultaneously.
let op = r#"
query {
a {
a {
a {
a
}
}
}
}
"#;
let mut compiler = ApolloCompiler::new().token_limit(22).recursion_limit(10);
compiler.add_executable(op, "op.graphql");
let errors = compiler.db.syntax_errors();
assert_eq!(errors.len(), 1)
- validate fragment definitions are used, by gocamille in pull/483
- validate fragment type condition exists in the type system and are declared on composite types, by gocamille in pull/483
- validate fragment definitions do not contain cycles, by goto-bus-stop in pull/518
- fix duplicate directive location info, by goto-bus-stop in pull/516
- use
LimitExceeded
diagnostic for limit related errors, by lrlna in pull/520
0.7.2 - 2023-04-03
- validate fragment spread target is defined, by goto-bus-stop in pull/506
- validate circular input objects, by lrlna in pull/505
0.7.1 - 2023-03-28
- validate indirectly self-referential directives by goto-bus-stop in pull/494
- include built-in enum types in
db.type_system()
query by SimonSapin in pull/501 field.field_definition()
works for interface types by zackangelo in pull/502- validate used variables in lists and objects by yanns in pull/497
0.7.0 - 2023-03-28
Important: X breaking changes below, indicated by BREAKING
This release encompasses quite a few validation rules the compiler was missing. Here, we primarily focused on field and directive validation, as well as supporting multi-file diagnostics.
find_operation
query now mimics spec'sgetOperation
functionality and returns the anonymous operation ifNone
is specified for operation name; by lrlna in pull/447- Extensions are applied implicitly in HIR by SimonSapin in pull/481, pull/482, and pull/484
Adding a GraphQL type extension is similar to modifying a type.
This release makes a number of breaking changes to API signatures and behavior
so these modifications are accounted for implicitly.
For example, interface.field(name)
may now return a field
from an extend interface
extension or from the original interface
definition.
We expect that most callers don’t need to tell the difference.
For callers that do, methods with a self_
prefix are added (or renamed)
for accessing components of a definition itself as opposed to added by an extension.
Renamed methods:
SchemaDefinition::root_operation_type_definition
→self_root_operations
ObjectTypeDefinition::fields_definition
→self_fields
InterfaceTypeDefinition::fields_definition
→self_fields
InputObjectTypeDefinition::input_fields_definition
→self_fields
ObjectTypeDefinition::implements_interfaces
→self_implements_interfaces
InterfaceTypeDefinition::implements_interfaces
→self_implements_interfaces
UnionTypeDefinition::union_members
→self_members
EnumTypeDefinition::enum_values_definition
→self_values
TypeDefiniton::directives
→self_directives
SchemaDefiniton::directives
→self_directives
EnumTypeDefiniton::directives
→self_directives
UnionTypeDefiniton::directives
→self_directives
ObjectTypeDefiniton::directives
→self_directives
ScalarTypeDefiniton::directives
→self_directives
InterfaceTypeDefiniton::directives
→self_directives
InputObjectTypeDefiniton::directives
→self_directives
Method names freed by the above are now redefined with new behaviour and signature, and include extensions:
ObjectTypeDefinition::implements_interfaces() -> impl Iterator
InterfaceTypeDefinition::implements_interfaces() -> impl Iterator
TypeDefiniton::directives() -> impl Iterator
SchemaDefiniton::directives() -> impl Iterator
EnumTypeDefiniton::directives() -> impl Iterator
UnionTypeDefiniton::directives() -> impl Iterator
ObjectTypeDefiniton::directives() -> impl Iterator
ScalarTypeDefiniton::directives() -> impl Iterator
InterfaceTypeDefiniton::directives() -> impl Iterator
InputObjectTypeDefiniton::directives() -> impl Iterator
Methods whose behaviour and signature changed, where each method now returns the name of an object type instead of its definition:
SchemaDefinition::query() -> Option<&str>
SchemaDefinition::mutation() -> Option<&str>
SchemaDefinition::subscription() -> Option<&str>
Methods whose behaviour changed to consider extensions, and no signature has changed
TypeDefinition::field(name) -> Option
ObjectTypeDefinition::field(name) -> Option
InterfaceTypeDefinition::field(name) -> Option
New methods which take extensions into consideration:
SchemaDefinition::root_operations() -> impl Iterator
ObjectTypeDefinition::fields() -> impl Iterator
ObjectTypeDefinition::implements_interface(name) -> bool
InterfaceTypeDefinition::fields() -> impl Iterator
InterfaceTypeDefinition::implements_interface(name) -> bool
InputObjectTypeDefinition::self_fields() -> &[_]
InputObjectTypeDefinition::fields() -> impl Iterator
InputObjectTypeDefinition::field(name) -> Option
UnionTypeDefinition::members() -> impl Iterator
UnionTypeDefinition::has_member(name) -> bool
EnumTypeDefinition::values() -> impl Iterator
EnumTypeDefinition::value(name) -> Option
New methods for every type which have a directives
method:
directive_by_name(name) -> Option
directives_by_name(name) -> impl Iterator
- support mutli-file diagnostics by goto-bus-stop in pull/414
- validate directive locations by lrlna in pull/417
- validate undefined directives by lrlna in pull/417
- validate non-repeatable directives in a given location by goto-bus-stop in pull/488
- validate conflicting fields in a selection set (spec: fields can merge) by goto-bus-stop in pull/470
- validate introspection fields in subscriptions by gocamille in [pull/438]
- validate required arguments by goto-bus-stop in pull/452
- validate unique variables by lrlna in pull/455
- validate variables are of input type by lrlna in pull/455
- validate root operation type is of Object Type by lrlna in pull/419
- validate nested fields in selection sets by erikwrede in pull/441
- validate extension existance and kind by goto-bus-stop in pull/458
- validate leaf field selection by yanns in pull/465
- introduce
op.is_introspection
helper method by jregistr in pull/421 - built-in graphql types, including introspection types, are now part of the compiler context by lrlna in pull/489
- fix variables in directive arguments being reported as unused goto-bus-stop in pull/487
op.operation_ty()
does not deref lrlna in pull/434
- tests for operation field type resolution v.s. type extensions by SimonSapin in pull/492
- using [salsa::invoke] macro to annotate trait function location by lrlna in pull/491
- use
Display
forhir::OperationType
andhir::DirectiveLocation
by goto-bus-stop in pull/435 - rework and simplify validation database by lrlna in pull/436
- reset
FileId
between directory tests by goto-bus-stop in pull/437 - remove unncessary into_iter() calls by goto-bus-stop in pull/472
- check test numbers are unique in test output files by goto-bus-stop in pull/471
0.6.0 - 2023-01-18
This release has a few breaking changes as we try to standardise APIs across the compiler. We appreciate your patience with these changes. If you run into trouble, please open an issue.
- Rename
compiler.create_*
methods tocompiler.add_*
, SimonSapin in pull/412 - Rename
schema
totype_system
forcompiler.add_
andcompiler.update_
methods, SimonSapin in pull/413 - Unify
ty
,type_def
andkind
namings in HIR, lrlna in pull/415- in
Type
struct impl:ty()
-->type_def()
- in
TypeDefinition
struct impl:ty()
-->kind()
- in
FragmentDefinition
struct impl:ty()
-->type_def()
- in
RootOperationTypeDefinition
struct:operation_type
field -->operation_ty
- in
FileId
s are unique per process, SimonSapin in [405]- Type alias
compiler.snapshot()
return type toSnapshot
, SimonSapin in [410] - Introduce a type system high-level intermediate representation (HIR) as input to the compiler, SimonSapin in [407]
- Use
#[salsa::transparent]
forfind_*
queries, i.e. not caching query results, lrlna in [403]
- Add compiler benchmarks, lrlna in [404]
- Document
apollo-rs
runs on stable, SimonSapin in [402]
0.5.0 - 2023-01-04
You can now build a compiler from multiple sources. This is especially useful when various parts of a GraphQL document are coming in at different times and need to be analysed as a single context. Or, alternatively, you are looking to lint or validate multiple GraphQL files part of the same context in a given directory or workspace.
The are three different kinds of sources:
document
: for when a source is composed of executable and type system definitions, or you're uncertain of definitions typesschema
: for sources with type system definitions or extensionsexecutable
: for sources with executable definitions/GraphQL queries
You can add a source with create_
and update it with update_
, for example
create_document
and update_document
. Here is an example:
let schema = r#"
type Query {
dog: Dog
}
type Dog {
name: String!
}
"#;
let query = r#"
query getDogName {
dog {
name
}
}
# duplicate name, should show up in diagnostics
query getDogName {
dog {
owner {
name
}
}
}
"#;
let updated_schema = r#"
type Query {
dog: Dog
}
type Dog {
name: String!
owner: Human
}
type Human {
name: String!
}
"#;
let mut compiler = ApolloCompiler::new();
let schema_id = compiler.create_schema(schema, "schema.graphl");
let executable_id = compiler.create_executable(query, "query.graphql");
compiler.update_schema(updated_schema, schema_id);
For more elaborate examples, please refer to multi_source_validation
and
file_watcher
examples in the examples
dir.
We look forward to your feedback on this feature, should you be using it.
Completed in pull/368 in collaboration with goto-bus-stop, SimonSapin and lrlna.
- Remove UUID helpers and related UUID APIs from database by SimonSapin in pull/391
- Merge
DocumentDatabase
trait intoHIRDatabase
by SimonSapin in pull/394 - Replace
hir::Definition
enum withhir::TypeSystemDefinitions
struct by SimonSapin in pull/395 db.type_system_definitions
returns aTypeSystemDefinitions
by SimonSapin in pull/395- Remove
db.db_definitions
,find_definition_by_name
andfind_type_system_definition_by_name
by SimonSapin in pull/395 - Remove queries returning type extensions, instead type definitions in the HIR contain extension information by SimonSapin in pull/387
db.fragments
,db.object_types
,db.scalars
,db.enums
,db.unions
,db.interfaces
,db.input_objects
, anddb.directive_definitions
return name-indexed maps by SimonSapin in pull/387
0.4.1 - 2022-12-13
- add new APIs - SimonSapin, pull/382
db.find_enum_by_name()
to look up anEnumTypeDefinition
.directive.argument_by_name()
to look up the value of an argument to a directive call.scalar_type.is_built_in()
to check if aScalarTypeDefinition
is defined by the GraphQL spec rather than the schema text.enum_value.directives()
to access the directives used on an enum value.hir::Float
is nowCopy
so it can be passed around more easily; usehir_float.get()
to access the underlyingf64
orhir_float.to_i32_checked()
to convert to ani32
.
-
do not panic when creating HIR from a parse tree with syntax errors - goto-bus-stop, pull/381
When using the compiler, nodes with syntax errors in them are ignored. As syntax errors are returned from the parser, you can still tell that something is wrong. The compiler just won't crash the whole program anymore.
0.4.0 - 2022-11-29
-
add parser recursion limit API - SimonSapin, pull/353, issue/296
Calling
ApolloCompiler::with_recursion_limit
instead ofApolloCompiler::new
makes the compiler configure the corresponding parser limit. This limit protects against stack overflow and is enabled either way. Configuring it may be useful for example if you’re also configuring the stack size. -
expose the repeatable attribute on
DirectiveDefinition
- allancalix, pull/367There was previously no way to access the
repeatable
field on theDirectiveDefinition
type. This field is required for validation rules. -
add type extensions - SimonSapin, pull/369
apollo-compiler now partially supports GraphQL
extend
types. Theis_subtype
query takes extensions into account.Some other parts of the compiler, like validation, do not yet support extensions.
-
fix
@include
allowed directive locations - allancalix, pull/366The locations for the
@include
directive wrongly specifiedFragmentDefinition
instead ofFragmentSpread
. It now matches the spec.
- avoid double lookup in
SchemaDefinition::{query,mutation,subscription}
- SimonSapin, pull/364
0.3.0 - 2022-11-02
-
compiler.parse is renamed to compiler.ast - lrlna, pull/290
compiler.ast()
returns theSyntaxTree
produced by the parser and is much clearer method thancompiler.parse()
. -
selection.ty(db) now expects a
db
parameter - lrlna, pull/290As byproduct of separating compiler's query_groups into individual components. Selection's type can now be accessed like so:
let ctx = ApolloCompiler::new(input); let top_product_fields: Vec<String> = top_products .iter() .filter_map(|field| Some(field.ty(&ctx.db)?.name())) .collect();
-
removes db.definitions() API - lrlna, pull/295
db.definitions()
returned a!Send
value that is no longer possible with theParallelDatabase
implementation.To access HIR definitions, use
db.db_definitions()
anddb.type_system_definitions
.
-
add subtype_map and is_subtype queries - lrlna/SimonSapin, pull/333
This allows users to check whether a particular type is a subtype of another type. For example, in a UnionDefinition such as
union SearchResult = Photo | Person
,Person
is a suptype ofSearchResult
. In an InterfaceDefinition such astype Business implements NamedEntity & ValuedEntity { # fields }
,Business
is a subtype ofNamedEntity
. -
pub compiler storage - allow database composition - lrlna, pull/328
This allows for internal query_groups to be exported, and allows users to compose various databases from compiler's existing dbs and their queries.
This is how you'd create a database with storage from apollo-compiler:
use apollo_compiler::{database::{AstStorage, DocumentStorage}}; #[salsa::database(AstStorage, DoumentStorage)] pub struct AnotherDatabase { pub storage: salsa::Storage<AnotherDatabase>, }
You can also see a more detailed linting example in examples dir.
-
validate argument name uniqueness - goto-bus-stop, pull/317
It's an error to declare or provide multiple arguments by the same name, eg:
type Query { things(offset: Int!, offset: Int!): [Thing] # ERR: duplicate argument definition: offset }
query GetThings { things(offset: 10, offset: 20) { id } # ERR: duplicate argument values: offset }
This adds
UniqueArgument
diagnostics and checks for argument duplications in: field definitions, fields, directives, interfaces and directive definitions. -
getter for directives in HIR FragmentSpread - allancalix, pull/315
Allow accessing directives in a given FragmentSpread node in a high-level intermediate representation of the compiler.
-
create validation database - lrlna, pull/303
All validation now happens in its own database, which can be accessed with
ValidationDatabase
andValidationStorage
. -
thread-safe compiler: introduce snapshots - lrlna, pull/295 + pull/332
Implements
ParallelDatabase
forRootDatabase
of the compiler. This allows us to create snapshots that can allow users to query the database from multiple threads. For example:let input = r#" type Query { website: URL, amount: Int } scalar URL @specifiedBy(url: "https://tools.ietf.org/html/rfc3986") "#; let ctx = ApolloCompiler::new(input); let diagnostics = ctx.validate(); for diagnostic in &diagnostics { println!("{}", diagnostic); } assert!(diagnostics.is_empty()); let snapshot = ctx.snapshot(); let snapshot2 = ctx.snapshot(); let thread1 = std::thread::spawn(move || snapshot.find_object_type_by_name("Query".into())); let thread2 = std::thread::spawn(move || snapshot2.scalars()); thread1.join().expect("object_type_by_name panicked"); thread2.join().expect("scalars failed");
-
add description getters to compiler's HIR nodes - aschaeffer, pull/289
Expose getters for descriptions that can be accessed for any definitions that support them. For example:
let input = r#" "Books in a given libary" type Book { id: ID! } "#; let ctx = ApolloCompiler::new(input); let desc = ctx.db.find_object_type_by_name("Book".to_string()).unwrap().description();
-
update parser version - goto-bus-stop, pull/331
-
unused variables return an error diagnostic - lrlna, pull/314
We were previously returning a warning for any unused variables, it is now reported as an error.
-
split up db into several components - lrlna, pull/290
We are splitting up the single
query_group
we had in our db into severalquery_group
s that currently just build upon each other, and eventually could support more complex relationships between one another. The current structure:Inputs
-->DocumentParser
-->Definitions
-->Document
All of these
query_group
s make up theRootDatabase
, i.e.salsa::database
.This also allows external users to build out their own databases with compiler's query groups.
-
support wasm compiler target - allancalix, pull/287, issue/288
apollo-compiler
can now compile to a Wasm target withcargo check --target wasm32-unknown-unknown
.
0.2.0 - 2022-08-16
-
inline_fragment().type_condition() returns Option<&str> - lrlna, pull/282
Instead of returning
Option<&String>
, we now returnOption<&str>
-
Value -> DefaultValue for default_value fields - lrlna, pull/276
default_value getters in Input Value Definitions and Variable Definitions now return
DefaultValue
type. This is a type alias to Value, and makes it consistent with the GraphQL spec.
-
add type information to inline fragments - lrlna, pull/282, issue/280
Inline fragments were missing type correct type information. We now search for applicable type's fields if a type condition exists, otherwise infer information from the current type in scope (as per spec) .Inline fragments
-
fix cycle error in fragment spreads referencing fragments - lrlna, pull/283, issue/281
Because fragment definitions can have fragment spreads, we are running into a self-referential cycle when searching for a fragment definition to get its id. Instead, search for the fragment definition when getting a fragment in a fragment spread in the wrapper API.
-
pub use ApolloDiagnostic - EverlastingBugstopper, pull/268
Exports ApolloDiagnostic to allow users to use it in other contexts.
-
default_value getter in input_value_definition - lrlna, pull/273
A getter for default values in input value definitions.
-
feat(compiler): add db.find_union_by_name() - lrlna, pull/272
Allows to query unions in the database.
-
adds inline_fragments getter to SelectionSet - lrlna, pull/282
Convenience method to get all inline fragments in the current selection set.
0.1.0 - 2022-07-27
Introducing apollo-compiler
!
A query-based compiler for the GraphQL language.
The compiler provides validation and context for GraphQL documents with a comprehensive API.
This is still a work in progress, for outstanding issues, checkout out the apollo-compiler label in our issue tracker.