diff --git a/src/Utils/ASTDefinitionBuilder.php b/src/Utils/ASTDefinitionBuilder.php index c11fc6b55..07764bb9d 100644 --- a/src/Utils/ASTDefinitionBuilder.php +++ b/src/Utils/ASTDefinitionBuilder.php @@ -536,16 +536,36 @@ private function makeScalarDef(ScalarTypeDefinitionNode $def): CustomScalarType ]); } - /** @throws InvariantViolation */ + /** + * @throws \Exception + * @throws \ReflectionException + * @throws InvariantViolation + */ private function makeInputObjectDef(InputObjectTypeDefinitionNode $def): InputObjectType { $name = $def->name->value; /** @var array $extensionASTNodes (proven by schema validation) */ $extensionASTNodes = $this->typeExtensionsMap[$name] ?? []; + $oneOfDirective = Directive::oneOfDirective(); + + // Check for @oneOf directive in the definition node + $isOneOf = Values::getDirectiveValues($oneOfDirective, $def) !== null; + + // Check for @oneOf directive in extension nodes + if (! $isOneOf) { + foreach ($extensionASTNodes as $extensionNode) { + if (Values::getDirectiveValues($oneOfDirective, $extensionNode) !== null) { + $isOneOf = true; + break; + } + } + } + return new InputObjectType([ 'name' => $name, 'description' => $def->description->value ?? null, + 'isOneOf' => $isOneOf, 'fields' => fn (): array => $this->makeInputFields([$def, ...$extensionASTNodes]), 'astNode' => $def, 'extensionASTNodes' => $extensionASTNodes, diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 5c9d8a525..d54244b7d 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -563,6 +563,7 @@ protected static function printInputObject(InputObjectType $type, array $options return static::printDescription($options, $type) . "input {$type->name}" + . ($type->isOneOf() ? ' @oneOf' : '') . static::printBlock($fields); } diff --git a/tests/Utils/BuildSchemaTest.php b/tests/Utils/BuildSchemaTest.php index 11cd8c2d8..1b87ea784 100644 --- a/tests/Utils/BuildSchemaTest.php +++ b/tests/Utils/BuildSchemaTest.php @@ -1042,6 +1042,39 @@ public function testCorrectlyExtendInputObjectType(): void self::assertSame($inputSDL, $this->printAllASTNodes($someInput)); } + /** @see it('Correctly extend input object type with @oneOf directive') */ + public function testCorrectlyExtendInputObjectTypeWithOneOfDirective(): void + { + $inputSDL = <<<'GRAPHQL' + input SomeInput { + first: String + } + + extend input SomeInput @oneOf { + second: Int + } + + GRAPHQL; + + $schema = BuildSchema::build($inputSDL); + + $someInput = $schema->getType('SomeInput'); + assert($someInput instanceof InputObjectType); + + // Verify that the @oneOf directive from the extension is properly applied + self::assertTrue($someInput->isOneOf()); + + $expectedSomeInputSDL = <<<'GRAPHQL' + input SomeInput @oneOf { + first: String + second: Int + } + GRAPHQL; + + self::assertSame($expectedSomeInputSDL, SchemaPrinter::printType($someInput)); + self::assertSame($inputSDL, $this->printAllASTNodes($someInput)); + } + /** @see it('Correctly assign AST nodes') */ public function testCorrectlyAssignASTNodes(): void { diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index 64ee4eb20..b72500aa4 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -764,6 +764,32 @@ public function testInputType(): void ); } + /** @see it('Print Input Type with @oneOf directive') */ + public function testInputTypeWithOneOfDirective(): void + { + $inputType = new InputObjectType([ + 'name' => 'InputType', + 'isOneOf' => true, + 'fields' => [ + 'int' => Type::int(), + ], + ]); + + $schema = new Schema([ + 'types' => [$inputType], + ]); + + self::assertPrintedSchemaEquals( + <<<'GRAPHQL' + input InputType @oneOf { + int: Int + } + + GRAPHQL, + $schema + ); + } + /** @see it('Custom Scalar') */ public function testCustomScalar(): void {