apollo-compiler 1.31.1

A compiler for the GraphQL query language.
Documentation
use apollo_compiler::schema::SchemaBuilder;
use apollo_compiler::Schema;

#[test]
fn find_definitions_with_directive() {
    let schema = r#"
        type Query { unused: Int }

        type ObjectOne @key(field: "id") {
          id: ID!
          inStock: Boolean!
        }

        type ObjectTwo @key(field: "name") {
          name: String!
          address: String!
        }

        type ObjectThree {
            price: Int
        }

        directive @key(field: String) on OBJECT
    "#;

    let schema = Schema::parse_and_validate(schema, "schema.graphql").unwrap();

    let mut key_definition_names: Vec<&str> = schema
        .types
        .iter()
        .filter(|(_name, def)| def.directives().has("key"))
        .map(|(name, _def)| name.as_str())
        .collect();
    key_definition_names.sort();
    assert_eq!(key_definition_names, ["ObjectOne", "ObjectTwo"])
}

#[test]
fn test_schema_reserialize() {
    let input = r#"
        extend type Query {
            withArg(arg: Boolean): String @deprecated,
        }

        type Query {
            int: Int,
        }

        extend type Query implements Inter

        interface Inter {
            string: String
        }

        extend type Query @customDirective

        extend type Query {
            string: String,
        }

        directive @customDirective on OBJECT
    "#;
    // Order is mostly not preserved
    let expected = expect_test::expect![[r#"
        directive @customDirective on OBJECT

        type Query {
          int: Int
        }

        extend type Query @customDirective

        extend type Query implements Inter

        extend type Query {
          withArg(arg: Boolean): String @deprecated
        }

        extend type Query {
          string: String
        }

        interface Inter {
          string: String
        }
    "#]];
    let schema = Schema::parse_and_validate(input, "schema.graphql").unwrap();
    expected.assert_eq(&schema.to_string());
}

#[test]
fn is_subtype() {
    fn gen_schema_types(schema: &str) -> Schema {
        let base_schema = r#"
            type Query {
                me: String
            }
            type Foo {
                me: String
            }
            type Bar {
                me: String
            }
            type Baz {
                me: String
            }

            union UnionType2 = Foo | Bar
            "#;
        Schema::builder()
            .parse(SUPERGRAPH_BOILERPLATE, "boilerplate")
            .parse(base_schema, "base")
            .parse(schema, "schema")
            .build()
            .unwrap()
    }

    fn gen_schema_interfaces(schema: &str) -> Schema {
        let base_schema = r#"
            type Query {
                me: String
            }
            interface Foo {
                me: String
            }
            interface Bar {
                me: String
            }
            interface Baz {
                me: String,
            }

            type ObjectType2 implements Foo & Bar { me: String }
            interface InterfaceType2 implements Foo & Bar { me: String }
            "#;
        Schema::builder()
            .parse(SUPERGRAPH_BOILERPLATE, "boilerplate")
            .parse(base_schema, "base")
            .parse(schema, "schema")
            .build()
            .unwrap()
    }

    let schema = gen_schema_types("union UnionType = Foo | Bar | Baz");
    assert!(schema.is_subtype("UnionType", "Foo"));
    assert!(schema.is_subtype("UnionType", "Bar"));
    assert!(schema.is_subtype("UnionType", "Baz"));
    assert!(!schema.is_subtype("UnionType", "UnionType"));
    assert!(!schema.is_subtype("UnionType", "Query"));
    assert!(!schema.is_subtype("UnionType", "NotAType"));
    assert!(!schema.is_subtype("NotAType", "Foo"));
    assert!(!schema.is_subtype("Foo", "UnionType"));

    let schema = gen_schema_interfaces("type ObjectType implements Foo & Bar & Baz { me: String }");
    assert!(schema.is_subtype("Foo", "ObjectType"));
    assert!(schema.is_subtype("Bar", "ObjectType"));
    assert!(schema.is_subtype("Baz", "ObjectType"));
    assert!(!schema.is_subtype("Baz", "ObjectType2"));
    assert!(!schema.is_subtype("Foo", "Foo"));
    assert!(!schema.is_subtype("Foo", "Query"));
    assert!(!schema.is_subtype("Foo", "NotAType"));
    assert!(!schema.is_subtype("ObjectType", "Foo"));

    let schema =
        gen_schema_interfaces("interface InterfaceType implements Foo & Bar & Baz { me: String }");
    assert!(schema.is_subtype("Foo", "InterfaceType"));
    assert!(schema.is_subtype("Bar", "InterfaceType"));
    assert!(schema.is_subtype("Baz", "InterfaceType"));
    assert!(!schema.is_subtype("Baz", "InterfaceType2"));
    assert!(!schema.is_subtype("Foo", "Foo"));
    assert!(!schema.is_subtype("Foo", "Query"));
    assert!(!schema.is_subtype("Foo", "NotAType"));
    assert!(!schema.is_subtype("InterfaceType", "Foo"));

    let schema = gen_schema_types("extend union UnionType2 = Baz");
    assert!(schema.is_subtype("UnionType2", "Foo"));
    assert!(schema.is_subtype("UnionType2", "Bar"));
    assert!(schema.is_subtype("UnionType2", "Baz"));

    let schema = gen_schema_interfaces("extend type ObjectType2 implements Baz { me2: String }");
    assert!(schema.is_subtype("Foo", "ObjectType2"));
    assert!(schema.is_subtype("Bar", "ObjectType2"));
    assert!(schema.is_subtype("Baz", "ObjectType2"));

    let schema =
        gen_schema_interfaces("extend interface InterfaceType2 implements Baz { me2: String }");
    assert!(schema.is_subtype("Foo", "InterfaceType2"));
    assert!(schema.is_subtype("Bar", "InterfaceType2"));
    assert!(schema.is_subtype("Baz", "InterfaceType2"));
}

const SUPERGRAPH_BOILERPLATE: &str = r#"
        schema
            @core(feature: "https://specs.apollo.dev/core/v0.1")
            @core(feature: "https://specs.apollo.dev/join/v0.1") {
            query: Query
        }
        directive @core(feature: String!) repeatable on SCHEMA
        directive @join__graph(name: String!, url: String!) on ENUM_VALUE
        enum join__Graph {
            TEST @join__graph(name: "test", url: "http://localhost:4001/graphql")
        }

        "#;

/// https://github.com/graphql/graphql-spec/pull/987
/// https://github.com/apollographql/apollo-rs/issues/682#issuecomment-1752661656
#[test]
fn test_default_root_op_name_ignored_with_explicit_schema_def() {
    let input = r#"
    schema {
        query: Query
        # no mutation here
    }
    type Query {
        viruses: [Virus!]
    }
    type Virus {
        name: String!
        knownMutations: [Mutation!]!
    }
    type Mutation { # happens to use that name but isn't a root operation
        name: String!
        geneSequence: String!
    }
    "#;
    let schema = Schema::parse_and_validate(input, "schema.graphql").unwrap();
    assert!(schema.schema_definition.mutation.is_none())
}

#[test]
fn handles_implicit_root_types() {
    let sdl = r#"
extend type Query {
  foo: String
}

extend type Mutation {
  bar: String
}
"#;

    let builder = SchemaBuilder::new().adopt_orphan_extensions();
    let schema = builder
        .parse(sdl, "schema.graphql")
        .build()
        .expect("schema parsed successfully");

    assert!(schema.schema_definition.query.is_some());
    assert!(schema.schema_definition.mutation.is_some());
}