Skip to content

MC-36456: union implementation #29426

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Sep 2, 2020
Merged
4 changes: 4 additions & 0 deletions app/code/Magento/GraphQl/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<arguments>
<argument name="factoryMapByConfigElementType" xsi:type="array">
<item name="graphql_interface" xsi:type="object">Magento\Framework\GraphQl\Config\Element\InterfaceFactory</item>
<item name="graphql_union" xsi:type="object">Magento\Framework\GraphQl\Config\Element\UnionFactory</item>
<item name="graphql_type" xsi:type="object">Magento\Framework\GraphQl\Config\Element\TypeFactory</item>
<item name="graphql_input" xsi:type="object">Magento\Framework\GraphQl\Config\Element\InputFactory</item>
<item name="graphql_enum" xsi:type="object">Magento\Framework\GraphQl\Config\Element\EnumFactory</item>
Expand Down Expand Up @@ -64,6 +65,7 @@
<item name="Magento\Framework\GraphQl\Config\Element\Type" xsi:type="string">Magento\Framework\GraphQl\Schema\Type\Output\OutputTypeObject</item>
<item name="Magento\Framework\GraphQl\Config\Element\Input" xsi:type="string">Magento\Framework\GraphQl\Schema\Type\Input\InputObjectType</item>
<item name="Magento\Framework\GraphQl\Config\Element\InterfaceType" xsi:type="string">Magento\Framework\GraphQl\Schema\Type\Output\OutputInterfaceObject</item>
<item name="Magento\Framework\GraphQl\Config\Element\UnionType" xsi:type="string">Magento\Framework\GraphQl\Schema\Type\Output\OutputUnionObject</item>
<item name="Magento\Framework\GraphQl\Config\Element\Enum" xsi:type="string">Magento\Framework\GraphQl\Schema\Type\Enum\Enum</item>
</argument>
</arguments>
Expand All @@ -78,13 +80,15 @@
<argument name="formatters" xsi:type="array">
<item name="fields" xsi:type="object">Magento\Framework\GraphQl\Schema\Type\Output\ElementMapper\Formatter\Fields</item>
<item name="interfaces" xsi:type="object">Magento\Framework\GraphQl\Schema\Type\Output\ElementMapper\Formatter\Interfaces</item>
<item name="unions" xsi:type="object">Magento\Framework\GraphQl\Schema\Type\Output\ElementMapper\Formatter\Unions</item>
<item name="resolveType" xsi:type="object">Magento\Framework\GraphQl\Schema\Type\Output\ElementMapper\Formatter\ResolveType</item>
</argument>
</arguments>
</type>
<type name="Magento\Framework\GraphQlSchemaStitching\GraphQlReader\TypeReaderComposite">
<arguments>
<argument name="typeReaders" xsi:type="array">
<item name="union_type" xsi:type="object">Magento\Framework\GraphQlSchemaStitching\GraphQlReader\Reader\UnionType</item>
<item name="enum_type" xsi:type="object">Magento\Framework\GraphQlSchemaStitching\GraphQlReader\Reader\EnumType</item>
<item name="object_type" xsi:type="object">Magento\Framework\GraphQlSchemaStitching\GraphQlReader\Reader\ObjectType</item>
<item name="input_object_type" xsi:type="object">Magento\Framework\GraphQlSchemaStitching\GraphQlReader\Reader\InputObjectType</item>
Expand Down
6 changes: 3 additions & 3 deletions app/code/Magento/GraphQl/etc/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ directive @resolver(class: String="") on QUERY
| OBJECT
| FIELD_DEFINITION
| ARGUMENT_DEFINITION
| INTERFACE
| UNION
| ENUM
| ENUM_VALUE
| INPUT_OBJECT
| INPUT_FIELD_DEFINITION

directive @typeResolver(class: String="") on INTERFACE | OBJECT
directive @typeResolver(class: String="") on UNION
| INTERFACE
| OBJECT

directive @cache(cacheIdentity: String="" cacheable: Boolean=true) on QUERY

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;

/**
* Resolver for Item
*/
class Item implements ResolverInterface
{
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\TestModuleGraphQlQuery\Model\Resolver;

use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;

/**
* Resolver for Union type TestUnion
*/
class TestUnion implements ResolverInterface
{
/**
* @inheritDoc
*/
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null
) {
return [
'custom_name1' => 'custom_name1_value',
'custom_name2' => 'custom_name2_value',
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\TestModuleGraphQlQuery\Model\Resolver;

use Magento\Framework\GraphQl\Query\Resolver\TypeResolverInterface;

/**
* Type Resolver for union
*/
class UnionTypeResolver implements TypeResolverInterface
{
/**
* @inheritDoc
*/
public function resolveType(array $data): string
{
if (!empty($data)) {
return 'TypeCustom1';
}
return '';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

type Query {
testItem(id: Int!) : Item @resolver(class: "Magento\\TestModuleGraphQlQuery\\Model\\Resolver\\Item")
testUnion: TestUnion @resolver(class: "Magento\\TestModuleGraphQlQuery\\Model\\Resolver\\TestUnion")
}

type Mutation {
Expand All @@ -18,3 +19,14 @@ type MutationItem {
item_id: Int
name: String
}

union TestUnion @doc(description: "some kind of union") @typeResolver(class: "Magento\\TestModuleGraphQlQuery\\Model\\Resolver\\UnionTypeResolver") =
TypeCustom1 | TypeCustom2

type TypeCustom1 {
custom_name1: String
}

type TypeCustom2 {
custom_name2: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use Magento\TestFramework\TestCase\GraphQlAbstract;

/**
* Class GraphQlQueryTest
* Test for basic GraphQl features
*/
class GraphQlQueryTest extends GraphQlAbstract
{
Expand Down Expand Up @@ -100,4 +100,29 @@ public function testQueryViaGetRequestWithVariablesReturnsResults()

$this->assertArrayHasKey('testItem', $response);
}

public function testQueryTestUnionResults()
{
$query = <<<QUERY
{
testUnion {
__typename
... on TypeCustom1 {
custom_name1
}
... on TypeCustom2 {
custom_name2
}
}
}
QUERY;

$response = $this->graphQlQuery($query);

$this->assertArrayHasKey('testUnion', $response);
$testUnion = $response['testUnion'];
$this->assertArrayHasKey('custom_name1', $testUnion);
$this->assertEquals('custom_name1_value', $testUnion['custom_name1']);
$this->assertArrayNotHasKey('custom_name2', $testUnion);
}
}
10 changes: 9 additions & 1 deletion lib/internal/Magento/Framework/GraphQl/Config/Element/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,15 @@ public function getFields() : array
/**
* Get interfaces the type implements, if any. Return an empty array if none are configured.
*
* @return string[]
* Example return array(
* array(
* 'interface' => 'SomeDefinedTypeInterface',
* 'copyFields' => true
* ),
* ...
* ),
*
* @return array
*/
public function getInterfaces() : array
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Framework\GraphQl\Config\Element;

use Magento\Framework\GraphQl\Config\ConfigElementFactoryInterface;
use Magento\Framework\GraphQl\Config\ConfigElementInterface;
use Magento\Framework\ObjectManagerInterface;

/**
* Factory for config elements of 'union' type.
*/
class UnionFactory implements ConfigElementFactoryInterface
{
/**
* @var ObjectManagerInterface
*/
private $objectManager;

/**
* @param ObjectManagerInterface $objectManager
*/
public function __construct(
ObjectManagerInterface $objectManager
) {
$this->objectManager = $objectManager;
}

/**
* Instantiate an object representing 'union' GraphQL config element.
*
* @param array $data
* @return ConfigElementInterface
*/
public function createFromConfigData(array $data): ConfigElementInterface
{
return $this->create($data, $data['types'] ?? []);
}

/**
* Create union object based off array of configured GraphQL.
*
* Union data must contain name, type resolver, and possible concrete types definitions
* The type resolver should point to an implementation of the TypeResolverInterface
* that decides what concrete GraphQL type to output. Description is the only optional field.
*
* @param array $unionData
* @param array $types
* @return UnionType
*/
public function create(
array $unionData,
array $types
) : UnionType {
return $this->objectManager->create(
UnionType::class,
[
'name' => $unionData['name'],
'typeResolver' => $unionData['typeResolver'],
'types' => $types,
'description' => isset($unionData['description']) ? $unionData['description'] : ''
]
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Framework\GraphQl\Config\Element;

use Magento\Framework\GraphQl\Config\ConfigElementInterface;

/**
* Defines the contract for the union configuration data type.
*/
interface UnionInterface extends ConfigElementInterface
{
/**
* Get a list of fields that make up the possible return or input values of a type.
*
* @return Type[]
*/
public function getTypes(): array;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Framework\GraphQl\Config\Element;

/**
* Class representing 'union' GraphQL config element.
*/
class UnionType implements UnionInterface
{
/**
* @var string
*/
private $name;

/**
* @var string[]
*/
private $types;

/**
* @var string
*/
private $typeResolver;

/**
* @var string
*/
private $description;

/**
* @param string $name
* @param string $typeResolver
* @param string[] $types
* @param string $description
*/
public function __construct(
string $name,
string $typeResolver,
array $types,
string $description
) {
$this->name = $name;
$this->types = $types;
$this->typeResolver = $typeResolver;
$this->description = $description;
}

/**
* Get the type name.
*
* @return string
*/
public function getName(): string
{
return $this->name;
}

/**
* Get a list of fields that make up the possible return or input values of a type.
*
* @return string[]
*/
public function getTypes(): array
{
return $this->types;
}

/**
* Return the name of the resolver class that determines the concrete type to display in the result.
*
* @return string
*/
public function getTypeResolver(): string
{
return $this->typeResolver;
}

/**
* Get a human-readable description of the type.
*
* @return string
*/
public function getDescription(): string
{
return $this->description;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function __construct(
}

/**
* {@inheritdoc}
* @inheritDoc
*/
public function applyArgument(
SearchCriteriaInterface $searchCriteria,
Expand Down
Loading