Skip to content

Commit

Permalink
ENGCOM-8105: MC-36456: union implementation #29426
Browse files Browse the repository at this point in the history
  • Loading branch information
cpartica committed Aug 31, 2020
2 parents d1ff2ca + d3c5778 commit 9c04475
Show file tree
Hide file tree
Showing 30 changed files with 580 additions and 55 deletions.
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

0 comments on commit 9c04475

Please sign in to comment.