Skip to content

Latest commit

 

History

History
1611 lines (1266 loc) · 64.8 KB

File metadata and controls

1611 lines (1266 loc) · 64.8 KB

Changelog

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

BREAKING

  • API refactor to make it harder to ignore errors - SimonSapin, pull/752 fixing issue/709:

    • ast::Document, Schema, and ExecutableDocument not longer contain potential errors that users need to check separately.
    • Instead, various constructors and methods now return a Result, with the Err case containing both both errors and a maybe-incomplete value.
    • Change validate methods of Schema and ExecutableDocument to take ownership of self. On success they return the schema or document (unmodified) wrapped in a Valid<_> 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 with Valid::assume_valid.
    • Make parse_mixed and to_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 of parse.
    • Remove ast::Document::to_schema_builder. Use SchemaBuilder::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>>
     }

Features

  • Add parse_and_validate constructors for Schema and ExecutableDocument - SimonSapin, pull/752: when mutating isn’t needed after parsing, this returns an immutable Valid<_> value in one step.

  • Implement serde Serialize and Deserialize 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 }

Fixes

  • 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

Features

  • Helper features for Name and Type - SimonSapin, pull/739:
    • The name! macro also accepts an identifier: name!(Query) and name!("Query") create equivalent Name values.
    • InvalidNameError now contain a public NodeStr for the input string that is invalid, and implements Display, Debug, and Error traits.
    • Add TryFrom conversion to Name from NodeStr, &NodeStr, &str, String, and &String.
    • Add a ty! macro to build a static ast::Type using GraphQL-like syntax.
  • Add parsing an ast::Type from a string - lrlna and goto-bus-stop, pull/718 fixing issue/715

    Parses GraphQL type syntax:

    use apollo_compiler::ast::Type;
    let ty = Type::parse("[ListItem!]!")?;

Fixes

  • 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

BREAKING

  • 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 to executable::Fragment as well as ScalarType, ObjectType, InterfaceType, EnumType, UnionType, and InputObjectType in schema.
    • Add a fn name(&self) -> &Name method to the schema::ExtendedType enum
    • Add a pub name: Option<Name> field to executable::Operation
    • Remove executable::OperationRef<'_> (which was equivalent to (Option<&Name>, &Node<Operation>)), replacing its uses with &Node<Operation>
  • Rename Directives and Diagnostics to DirectiveList and DiagnosticList - SimonSapin, pull/732 fixing issue/711. The previous names were too similar to Directive and Diagnostic (singular).

  • Rename ComponentStr to ComponentName - SimonSapin, pull/713 and its node: NodeStr field to name: 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 for NodeStr, leaving the possibility of creating one invalid in GraphQL syntax. Validation and serialization would not check this. Name is now a wrapper type for NodeStr. Its new constructor checks validity of the given string and returns a Result. A new name! macro (see below) creates a Name with compile-time checking.
    • OperationType::default_type_name returns a Name instead of &str
    • Type::new_named("x") is removed. Use Type::Named(name!("x")) instead.
    • ComponentStr is renamed to ComponentName. It no longer has infallible conversions from &str or String. Its node field is renamed to name; the type of that field is changed from NodeStr to Name.
    • NodeStr no longer has a to_component method, only Name does
    • Various function or method parameters changed from impl Into<Name> to Name, since there is no longer an infallible conversion from &str

Features

  • Add serialization support for everything - SimonSapin, pull/728.

    Schema, ExecutableDocument, and all AST types already supported serialization to GraphQL syntax through the Display 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 with use apollo_compiler::name;. It creates an ast::Name from a string literal, with a compile-time validity checking. A Name 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 the name! macro, but can also be used on its own:
      let s = apollo_compiler::NodeStr::from_static(&"example");
      assert_eq!(s, "example");

Fixes

  • 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

Features

Maintenance

1.0.0-beta.4 - 2023-10-16

Features

  • 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());
    });

Fixes

  • 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

BREAKING

  • Keep source files in Arc<Map<…>> everywhere - SimonSapin, pull/696 Change struct fields from sources: IndexMap<FileId, Arc<SourceFile>> (in Schema) or source: Option<(FileId, Arc<SourceFile>)> (in Document, ExecutablDocument, FieldSet) to sources: SourceMap, with:
    pub type SourceMap = Arc<IndexMap<FileId, Arc<SourceFile>>>;
    Cases other than 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())));

Features

  • 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}")
        }
    }

Fixes

  • 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

BREAKING

Assorted Schema API changes - SimonSapin, pull/678

  • Type of the schema_definition field changed from Option<SchemaDefinition> to SchemaDefinition. Default root operations based on object type names are now stored explicitly in SchemaDefinition. Serialization relies on a heuristic to decide on implicit schema definition.
  • Removed schema_definition_directives method: no longer having an Option allows field schema.schema_definition.directives to be accessed directly
  • Removed query_root_operation, mutation_root_operation, and subscription_root_operation methods. Instead schema.schema_definition.query etc can be accessed directly.

Features

  • 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 a FieldSet custom scalar used in some Apollo Federation directives in the context of a specific schema and type. Its validate 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()?;

Fixes

  • 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

BREAKING

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"

Features

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

Features

  • 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.

0.11.2 - 2023-09-11

Features

  • Add validate_standalone_executable function to validate an executable document without access to a schema, by goto-bus-stop in pull/631, issue/629

    This 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.

Fixes

  • 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
    }

[0.12.0] (unreleased) - 2023-mm-dd

BREAKING

  • (TODO: write this)

0.11.1 - 2023-08-24

Features

0.11.0 - 2023-08-18

Features

  • add InterfaceTypeDefinition::implementors(&db) to list object types and other interfaces that implement an interface, by Geal in pull/616

Fixes

Maintenance

0.10.0 - 2023-06-20

BREAKING

  • SelectionSet::merge is renamed to SelectionSet::concat to clarify that it doesn't do field merging, by goto-bus-stop in pull/570
  • hir::InlineFragment::type_condition now only returns Some() if a type condition was explicitly specified, by goto-bus-stop in pull/586

Features

  • add root_operation_name(OperationType) helper method on hir::SchemaDefinition by SimonSapin in pull/579

  • add an UndefinedDirective diagnostic type, by goto-bus-stop in pull/587

    This is used for directives instead of UndefinedDefinition.

Fixes

  • 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.

Maintenance

0.9.4 - 2023-06-05

Features

  • 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/577

    When 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

Fixes

  • 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.

Maintenance

0.9.2 - 2023-05-23

Features

  • add as_$type() methods to hir::Value, by goto-bus-stop in pull/564

    These 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>

Fixes

  • 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/563

    Previously 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

Fixes

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);
}

BREAKING

  • 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()

Features

Fixes

0.8.0 - 2023-04-13

BREAKING

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)

by lrlna in pull/512

Features

Fixes

0.7.2 - 2023-04-03

Features

Fixes

  • db.interfaces() checks pre-computed hir for interfaces first, by lrlna in de4baea

0.7.1 - 2023-03-28

Features

Fixes

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.

BREAKING

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_definitionself_root_operations
  • ObjectTypeDefinition::fields_definitionself_fields
  • InterfaceTypeDefinition::fields_definitionself_fields
  • InputObjectTypeDefinition::input_fields_definitionself_fields
  • ObjectTypeDefinition::implements_interfacesself_implements_interfaces
  • InterfaceTypeDefinition::implements_interfacesself_implements_interfaces
  • UnionTypeDefinition::union_membersself_members
  • EnumTypeDefinition::enum_values_definitionself_values
  • TypeDefiniton::directivesself_directives
  • SchemaDefiniton::directivesself_directives
  • EnumTypeDefiniton::directivesself_directives
  • UnionTypeDefiniton::directivesself_directives
  • ObjectTypeDefiniton::directivesself_directives
  • ScalarTypeDefiniton::directivesself_directives
  • InterfaceTypeDefiniton::directivesself_directives
  • InputObjectTypeDefiniton::directivesself_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

Features

Fixes

Maintenance

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.

BREAKING

  • Rename compiler.create_* methods to compiler.add_*, SimonSapin in pull/412
  • Rename schema to type_system for compiler.add_ and compiler.update_ methods, SimonSapin in pull/413
  • Unify ty, type_def and kind 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

Features

  • FileIds are unique per process, SimonSapin in [405]
  • Type alias compiler.snapshot() return type to Snapshot, SimonSapin in [410]
  • Introduce a type system high-level intermediate representation (HIR) as input to the compiler, SimonSapin in [407]

Fixes

  • Use #[salsa::transparent] for find_* queries, i.e. not caching query results, lrlna in [403]

Maintenance

  • Add compiler benchmarks, lrlna in [404]

Documentation

  • Document apollo-rs runs on stable, SimonSapin in [402]

0.5.0 - 2023-01-04

Highlights

Multi-file support

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 types
  • schema: for sources with type system definitions or extensions
  • executable: 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.

BREAKING

  • Remove UUID helpers and related UUID APIs from database by SimonSapin in pull/391
  • Merge DocumentDatabase trait into HIRDatabase by SimonSapin in pull/394
  • Replace hir::Definition enum with hir::TypeSystemDefinitions struct by SimonSapin in pull/395
  • db.type_system_definitions returns a TypeSystemDefinitions by SimonSapin in pull/395
  • Remove db.db_definitions, find_definition_by_name and find_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

Features

  • db.fragments, db.object_types, db.scalars, db.enums, db.unions, db.interfaces, db.input_objects, and db.directive_definitions return name-indexed maps by SimonSapin in pull/387

0.4.1 - 2022-12-13

Features

Fixes

  • 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

Features

  • add parser recursion limit API - SimonSapin, pull/353, issue/296

    Calling ApolloCompiler::with_recursion_limit instead of ApolloCompiler::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/367

    There was previously no way to access the repeatable field on the DirectiveDefinition type. This field is required for validation rules.

  • add type extensions - SimonSapin, pull/369

    apollo-compiler now partially supports GraphQL extend types. The is_subtype query takes extensions into account.

    Some other parts of the compiler, like validation, do not yet support extensions.

Fixes

  • fix @include allowed directive locations - allancalix, pull/366

    The locations for the @include directive wrongly specified FragmentDefinition instead of FragmentSpread. It now matches the spec.

Maintenance

  • avoid double lookup in SchemaDefinition::{query,mutation,subscription} - SimonSapin, pull/364

0.3.0 - 2022-11-02

Breaking

  • compiler.parse is renamed to compiler.ast - lrlna, pull/290

    compiler.ast() returns the SyntaxTree produced by the parser and is much clearer method than compiler.parse().

  • selection.ty(db) now expects a db parameter - lrlna, pull/290

    As 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 the ParallelDatabase implementation.

    To access HIR definitions, use db.db_definitions() and db.type_system_definitions.

Features

  • 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 of SearchResult. In an InterfaceDefinition such as type Business implements NamedEntity & ValuedEntity { # fields }, Business is a subtype of NamedEntity.

  • 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 and ValidationStorage.

  • thread-safe compiler: introduce snapshots - lrlna, pull/295 + pull/332

    Implements ParallelDatabase for RootDatabase 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();

Fixes

  • 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.

Maintenance

  • split up db into several components - lrlna, pull/290

    We are splitting up the single query_group we had in our db into several query_groups 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_groups make up the RootDatabase, 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 with cargo check --target wasm32-unknown-unknown.

0.2.0 - 2022-08-16

Breaking

  • inline_fragment().type_condition() returns Option<&str> - lrlna, pull/282

    Instead of returning Option<&String>, we now return Option<&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.

Fixes

  • 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.

Features

  • 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.