diff --git a/core/src/main/scala/sangria/federation/v2/Directives.scala b/core/src/main/scala/sangria/federation/v2/Directives.scala index 9213b6b..fb1da6c 100644 --- a/core/src/main/scala/sangria/federation/v2/Directives.scala +++ b/core/src/main/scala/sangria/federation/v2/Directives.scala @@ -72,6 +72,17 @@ object Directives { ) } + /** [@interfaceObject](https://www.apollographql.com/docs/federation/federated-types/federated-directives/#interfaceobject) + * directive definition + */ + val InterfaceObjectDefinition: Directive = + Directive(name = "interfaceObject", locations = Set(DirectiveLocation.Object)) + + /** [@extends](https://www.apollographql.com/docs/federation/federated-types/federated-directives#interfaceobject) + * directive + */ + val InterfaceObject: ast.Directive = ast.Directive(name = "interfaceObject") + /** [@extends](https://www.apollographql.com/docs/federation/federated-types/federated-directives#extends) * directive definition */ @@ -89,7 +100,8 @@ object Directives { */ val ShareableDefinition: Directive = Directive( name = "shareable", - locations = Set(DirectiveLocation.Object, DirectiveLocation.FieldDefinition) + locations = Set(DirectiveLocation.Object, DirectiveLocation.FieldDefinition), + repeatable = true ) /** [@shareable](https://www.apollographql.com/docs/federation/federated-types/federated-directives#shareable) diff --git a/core/src/main/scala/sangria/federation/v2/Federation.scala b/core/src/main/scala/sangria/federation/v2/Federation.scala index 4cc58da..deaf43a 100644 --- a/core/src/main/scala/sangria/federation/v2/Federation.scala +++ b/core/src/main/scala/sangria/federation/v2/Federation.scala @@ -78,6 +78,7 @@ object Federation { val federationDirectives: List[Directive] = List( Directives.Key.definition, + Directives.InterfaceObjectDefinition, Directives.ExtendsDefinition, Directives.ShareableDefinition, Directives.InaccessibleDefinition, @@ -95,7 +96,7 @@ object Federation { federationDirectives val federationV2Link = Directives.Link( - url = "https://specs.apollo.dev/federation/v2.1", + url = "https://specs.apollo.dev/federation/v2.3", `import` = Some(importedDirectives.map(d => Link__Import("@" + d.name)).toVector) ) diff --git a/core/src/test/scala/sangria/federation/package.scala b/core/src/test/scala/sangria/federation/package.scala index 438d25d..8755fa5 100644 --- a/core/src/test/scala/sangria/federation/package.scala +++ b/core/src/test/scala/sangria/federation/package.scala @@ -8,7 +8,7 @@ import sangria.schema.SchemaChange.AbstractChange package object federation { - val spec: String = "https://specs.apollo.dev/federation/v2.1" + val spec: String = "https://specs.apollo.dev/federation/v2.3" def beCompatibleWith(expectedSchema: Schema[_, _]): Matcher[Schema[_, _]] = Matcher { schema: Schema[_, _] => diff --git a/core/src/test/scala/sangria/federation/v2/DirectivesSpec.scala b/core/src/test/scala/sangria/federation/v2/DirectivesSpec.scala index 3cb1062..82b88ed 100644 --- a/core/src/test/scala/sangria/federation/v2/DirectivesSpec.scala +++ b/core/src/test/scala/sangria/federation/v2/DirectivesSpec.scala @@ -45,6 +45,11 @@ class DirectivesSpec extends AnyWordSpec { renderLike("""@key(fields: "id", resolvable: false)""") } + "support @interfaceObject directive" in { + // https://www.apollographql.com/docs/federation/federated-types/federated-directives#interfaceobject + Directives.InterfaceObject must renderLike("@interfaceObject") + } + "support @extends directive" in { // https://www.apollographql.com/docs/federation/federated-types/federated-directives#extends Directives.Extends must renderLike("@extends") diff --git a/core/src/test/scala/sangria/federation/v2/FederationSpec.scala b/core/src/test/scala/sangria/federation/v2/FederationSpec.scala index acecb13..804db22 100644 --- a/core/src/test/scala/sangria/federation/v2/FederationSpec.scala +++ b/core/src/test/scala/sangria/federation/v2/FederationSpec.scala @@ -34,7 +34,7 @@ class FederationSpec extends AsyncFreeSpec { val expectedSubGraphSchema = Schema .buildFromAst(graphql""" - schema @link(url: "https://specs.apollo.dev/federation/v2.1", import: ["@key", "@extends", "@shareable", "@inaccessible", "@override", "@external", "@provides", "@requires", "@tag"]) { + schema @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key", "@interfaceObject", "@extends", "@shareable", "@inaccessible", "@override", "@external", "@provides", "@requires", "@tag"]) { query: Query } @@ -61,6 +61,8 @@ class FederationSpec extends AsyncFreeSpec { sdl: String } + directive @interfaceObject on OBJECT + directive @extends on INTERFACE | OBJECT directive @external on FIELD_DEFINITION @@ -73,7 +75,7 @@ class FederationSpec extends AsyncFreeSpec { directive @link(url: String!, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA - directive @shareable on OBJECT | FIELD_DEFINITION + directive @shareable repeatable on OBJECT | FIELD_DEFINITION directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION @@ -110,7 +112,7 @@ class FederationSpec extends AsyncFreeSpec { val expectedSubGraphSchema = Schema .buildFromAst(graphql""" - schema @link(url: "https://specs.apollo.dev/federation/v2.1", import: ["@key", "@extends", "@shareable", "@inaccessible", "@override", "@external", "@provides", "@requires", "@tag"]) { + schema @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key", "@interfaceObject", "@extends", "@shareable", "@inaccessible", "@override", "@external", "@provides", "@requires", "@tag"]) { query: Query } @@ -145,6 +147,8 @@ class FederationSpec extends AsyncFreeSpec { sdl: String } + directive @interfaceObject on OBJECT + directive @extends on INTERFACE | OBJECT directive @external on FIELD_DEFINITION @@ -157,7 +161,7 @@ class FederationSpec extends AsyncFreeSpec { directive @link(url: String!, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA - directive @shareable on OBJECT | FIELD_DEFINITION + directive @shareable repeatable on OBJECT | FIELD_DEFINITION directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION @@ -203,7 +207,7 @@ class FederationSpec extends AsyncFreeSpec { .map(QueryRenderer.renderPretty(_) should be("""{ | data: { | _service: { - | sdl: "schema @link(url: \"https://specs.apollo.dev/federation/v2.1\", import: [\"@key\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@external\", \"@provides\", \"@requires\", \"@tag\"]) {\n query: Query\n}\n\ntype Query {\n field: Int\n}" + | sdl: "schema @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@interfaceObject\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@external\", \"@provides\", \"@requires\", \"@tag\"]) {\n query: Query\n}\n\ntype Query {\n field: Int\n}" | } | } |}""".stripMargin)) @@ -233,7 +237,7 @@ class FederationSpec extends AsyncFreeSpec { .map(QueryRenderer.renderPretty(_) should be("""{ | data: { | _service: { - | sdl: "schema @link(url: \"https://specs.apollo.dev/federation/v2.1\", import: [\"@key\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@external\", \"@provides\", \"@requires\", \"@tag\"]) {\n query: Query\n}\n\ntype Query {\n states: [State]\n}\n\ntype State @key(fields: \"id\") {\n id: Int\n value: String\n}" + | sdl: "schema @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@interfaceObject\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@external\", \"@provides\", \"@requires\", \"@tag\"]) {\n query: Query\n}\n\ntype Query {\n states: [State]\n}\n\ntype State @key(fields: \"id\") {\n id: Int\n value: String\n}" | } | } |}""".stripMargin)) @@ -260,7 +264,7 @@ class FederationSpec extends AsyncFreeSpec { .map(QueryRenderer.renderPretty(_) should be("""{ | data: { | _service: { - | sdl: "schema @link(url: \"https://specs.apollo.dev/federation/v2.1\", import: [\"@key\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@external\", \"@provides\", \"@requires\", \"@tag\"]) {\n query: Query\n}\n\n\"The `Long` scalar type represents non-fractional signed whole numeric values. Long can represent values between -(2^63) and 2^63 - 1.\"\nscalar Long\n\ntype Query {\n foo: Long\n bar: Int\n}" + | sdl: "schema @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@interfaceObject\", \"@extends\", \"@shareable\", \"@inaccessible\", \"@override\", \"@external\", \"@provides\", \"@requires\", \"@tag\"]) {\n query: Query\n}\n\n\"The `Long` scalar type represents non-fractional signed whole numeric values. Long can represent values between -(2^63) and 2^63 - 1.\"\nscalar Long\n\ntype Query {\n foo: Long\n bar: Int\n}" | } | } |}""".stripMargin))