Skip to content

Commit d677587

Browse files
Merge pull request #564 from creative-commoners/pulls/4.3/sortplugin-tests
FIX Add test cases for SortPlugin
2 parents 3db0b0f + f929eb6 commit d677587

File tree

5 files changed

+221
-59
lines changed

5 files changed

+221
-59
lines changed

src/Schema/DataObject/Plugin/QuerySort.php

+4-51
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@
1919
use SilverStripe\ORM\Sortable;
2020
use Exception;
2121
use GraphQL\Type\Definition\ResolveInfo;
22+
use SilverStripe\GraphQL\Schema\Traits\SortTrait;
2223

2324
/**
2425
* Adds a sort parameter to a DataObject query
2526
*/
2627
class QuerySort extends AbstractQuerySortPlugin
2728
{
29+
use SortTrait;
30+
2831
const IDENTIFIER = 'sort';
2932

3033
public function getIdentifier(): string
@@ -105,7 +108,7 @@ public static function sort(array $context): closure
105108
return $list;
106109
}
107110

108-
$sortArgs = static::getSortArgs($info, $args, $rootType, $fieldName);
111+
$sortArgs = self::getSortArgs($info, $args, $fieldName);
109112
$paths = NestedInputBuilder::buildPathsFromArgs($sortArgs);
110113
if (empty($paths)) {
111114
return $list;
@@ -138,56 +141,6 @@ public static function sort(array $context): closure
138141
};
139142
}
140143

141-
private static function getSortArgs(ResolveInfo $info, array $args, string $rootType, string $fieldName): array
142-
{
143-
$sortArgs = [];
144-
$sortOrder = self::getSortOrder($info, $fieldName);
145-
146-
foreach ($sortOrder as $orderName) {
147-
if (!isset($args[$fieldName][$orderName])) {
148-
continue;
149-
}
150-
$sortArgs[$orderName] = $args[$fieldName][$orderName];
151-
unset($args[$fieldName][$orderName]);
152-
}
153-
154-
return array_merge($sortArgs, $args[$fieldName]);
155-
}
156-
157-
/**
158-
* Gets the original order of fields to be sorted based on the query args order.
159-
*
160-
* This is necessary because the underlying GraphQL implementation we're using ignores the
161-
* order of query args, and uses the order that fields are defined in the schema instead.
162-
*/
163-
private static function getSortOrder(ResolveInfo $info, string $fieldName)
164-
{
165-
$relevantNode = $info->fieldDefinition->getName();
166-
167-
// Find the query field node that matches the schema
168-
foreach ($info->fieldNodes as $node) {
169-
if ($node->name->value !== $relevantNode) {
170-
continue;
171-
}
172-
173-
// Find the sort arg
174-
foreach ($node->arguments as $arg) {
175-
if ($arg->name->value !== $fieldName) {
176-
continue;
177-
}
178-
179-
// Get the sort order from the query
180-
$sortOrder = [];
181-
foreach ($arg->value->fields as $field) {
182-
$sortOrder[] = $field->name->value;
183-
}
184-
return $sortOrder;
185-
}
186-
}
187-
188-
return [];
189-
}
190-
191144
/**
192145
* @param NestedInputBuilder $builder
193146
*/

src/Schema/Plugin/SortPlugin.php

+10-2
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@
1414
use SilverStripe\GraphQL\Schema\Resolver\ResolverReference;
1515
use SilverStripe\GraphQL\Schema\Schema;
1616
use SilverStripe\GraphQL\Schema\Services\NestedInputBuilder;
17+
use SilverStripe\GraphQL\Schema\Traits\SortTrait;
1718
use SilverStripe\GraphQL\Schema\Type\InputType;
1819
use SilverStripe\ORM\Sortable;
1920
use Closure;
21+
use GraphQL\Type\Definition\ResolveInfo;
2022

2123
class SortPlugin implements FieldPlugin, SchemaUpdater
2224
{
2325
use Configurable;
2426
use Injectable;
27+
use SortTrait;
2528

2629
const IDENTIFIER = 'sorter';
2730

@@ -86,11 +89,16 @@ public function apply(Field $field, Schema $schema, array $config = []): void
8689
public static function sort(array $context): Closure
8790
{
8891
$fieldName = $context['fieldName'];
89-
return function (?Sortable $list, array $args) use ($fieldName) {
92+
return function (?Sortable $list, array $args, array $context, ResolveInfo $info) use ($fieldName) {
9093
if ($list === null) {
9194
return null;
9295
}
93-
$sortArgs = $args[$fieldName] ?? [];
96+
97+
if (!isset($args[$fieldName])) {
98+
return $list;
99+
}
100+
101+
$sortArgs = self::getSortArgs($info, $args, $fieldName);
94102
$list = $list->sort($sortArgs);
95103

96104
return $list;

src/Schema/Traits/SortTrait.php

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
namespace SilverStripe\GraphQL\Schema\Traits;
4+
5+
use GraphQL\Type\Definition\ResolveInfo;
6+
7+
trait SortTrait
8+
{
9+
private static function getSortArgs(ResolveInfo $info, array $args, string $fieldName): array
10+
{
11+
$sortArgs = [];
12+
$sortOrder = self::getSortOrder($info, $fieldName);
13+
14+
foreach ($sortOrder as $orderName) {
15+
if (!isset($args[$fieldName][$orderName])) {
16+
continue;
17+
}
18+
$sortArgs[$orderName] = $args[$fieldName][$orderName];
19+
unset($args[$fieldName][$orderName]);
20+
}
21+
22+
return array_merge($sortArgs, $args[$fieldName]);
23+
}
24+
25+
/**
26+
* Gets the original order of fields to be sorted based on the query args order.
27+
*
28+
* This is necessary because the underlying GraphQL implementation we're using ignores the
29+
* order of query args, and uses the order that fields are defined in the schema instead.
30+
*/
31+
private static function getSortOrder(ResolveInfo $info, string $fieldName)
32+
{
33+
$relevantNode = $info->fieldDefinition->getName();
34+
35+
// Find the query field node that matches the schema
36+
foreach ($info->fieldNodes as $node) {
37+
if ($node->name->value !== $relevantNode) {
38+
continue;
39+
}
40+
41+
// Find the sort arg
42+
foreach ($node->arguments as $arg) {
43+
if ($arg->name->value !== $fieldName) {
44+
continue;
45+
}
46+
47+
// Get the sort order from the query
48+
$sortOrder = [];
49+
foreach ($arg->value->fields as $field) {
50+
$sortOrder[] = $field->name->value;
51+
}
52+
return $sortOrder;
53+
}
54+
}
55+
56+
return [];
57+
}
58+
}

tests/Schema/IntegrationTest.php

+127-6
Original file line numberDiff line numberDiff line change
@@ -685,14 +685,119 @@ public function provideFilterAndSortOnlyRead(): array
685685
}
686686
}
687687
GRAPHQL,
688+
'expected' => [
689+
["myField" => "test2", "author" => ["firstName" => "tester2"]],
690+
["myField" => "test3", "author" => ["firstName" => "tester2"]],
691+
["myField" => "test1", "author" => ["firstName" => "tester1"]],
692+
],
693+
],
694+
'read with sorter files title DESC' => [
695+
'fixture' => '_SortPlugin',
696+
'query' => <<<GRAPHQL
697+
query {
698+
readDataObjectFakes(sort: { myField: ASC }) {
699+
nodes {
700+
myField
701+
files(sort: { title: DESC }) {
702+
title
703+
}
704+
}
705+
}
706+
}
707+
GRAPHQL,
708+
'expected' => [
709+
["myField" => "test1", "files" => [["title" => "file4"], ["title" => "file3"], ["title" => "file2"], ["title" => "file1"]]],
710+
["myField" => "test2", "files" => []],
711+
["myField" => "test3", "files" => []],
712+
],
713+
],
714+
'read with sorter files ParentID ACS, name DESC' => [
715+
'fixture' => '_SortPlugin',
716+
'query' => <<<GRAPHQL
717+
query {
718+
readDataObjectFakes(sort: { myField: ASC }) {
719+
nodes {
720+
myField
721+
files(sort: { ParentID: ASC, name: DESC }) {
722+
title
723+
}
724+
}
725+
}
726+
}
727+
GRAPHQL,
728+
'expected' => [
729+
["myField" => "test1", "files" => [["title" => "file2"],["title" => "file1"], ["title" => "file4"],["title" => "file3"]]],
730+
["myField" => "test2", "files" => []],
731+
["myField" => "test3", "files" => []],
732+
],
733+
],
734+
'read with sorter files ParentID DESC, name ASC' => [
735+
'fixture' => '_SortPlugin',
736+
'query' => <<<GRAPHQL
737+
query {
738+
readDataObjectFakes(sort: { myField: ASC }) {
739+
nodes {
740+
myField
741+
files(sort: { ParentID: DESC, name: ASC }) {
742+
title
743+
}
744+
}
745+
}
746+
}
747+
GRAPHQL,
748+
'expected' => [
749+
["myField" => "test1", "files" => [["title" => "file3"],["title" => "file4"], ["title" => "file1"],["title" => "file2"]]],
750+
["myField" => "test2", "files" => []],
751+
["myField" => "test3", "files" => []],
752+
],
753+
],
754+
'read with sorter files name ASC, ParentID DESC' => [
755+
'fixture' => '_SortPlugin',
756+
'query' => <<<GRAPHQL
757+
query {
758+
readDataObjectFakes(sort: { myField: ASC }) {
759+
nodes {
760+
myField
761+
files(sort: { name: ASC, ParentID: DESC }) {
762+
title
763+
}
764+
}
765+
}
766+
}
767+
GRAPHQL,
768+
'expected' => [
769+
["myField" => "test1", "files" => [["title" => "file3"],["title" => "file1"], ["title" => "file4"],["title" => "file2"]]],
770+
["myField" => "test2", "files" => []],
771+
["myField" => "test3", "files" => []],
772+
],
773+
],
774+
'read with sorter files name DESC, ParentID ASC' => [
775+
'fixture' => '_SortPlugin',
776+
'query' => <<<GRAPHQL
777+
query {
778+
readDataObjectFakes(sort: { myField: ASC }) {
779+
nodes {
780+
myField
781+
files(sort: { name: DESC, ParentID: ASC }) {
782+
title
783+
}
784+
}
785+
}
786+
}
787+
GRAPHQL,
788+
'expected' => [
789+
["myField" => "test1", "files" => [["title" => "file2"],[ "title" => "file4"],["title" => "file1"],["title" => "file3"]]],
790+
["myField" => "test2", "files" => []],
791+
["myField" => "test3", "files" => []],
792+
],
688793
],
689794
];
690795
}
691796

692797
/**
693798
* @dataProvider provideFilterAndSortOnlyRead
694799
*/
695-
public function testFilterAndSortOnlyRead($fixture, $query)
800+
public function testFilterAndSortOnlyRead(string $fixture, string $query, array $expected)
696801
{
697802
$author = Member::create(['FirstName' => 'tester1']);
698803
$author->write();
@@ -709,18 +814,34 @@ public function testFilterAndSortOnlyRead($fixture, $query)
709814
$dataObject3 = DataObjectFake::create(['MyField' => 'test3', 'AuthorID' => $author2->ID]);
710815
$dataObject3->write();
711816

817+
$file1 = File::create(['Title' => 'file1', 'Name' => 'asc_name']);
818+
$file1->ParentID = 1;
819+
$file1->write();
820+
821+
$file2 = File::create(['Title' => 'file2', 'Name' => 'desc_name']);
822+
$file2->ParentID = 1;
823+
$file2->write();
824+
825+
$file3 = File::create(['Title' => 'file3', 'Name' => 'asc_name']);
826+
$file3->ParentID = 2;
827+
$file3->write();
828+
829+
$file4 = File::create(['Title' => 'file4', 'Name' => 'desc_name']);
830+
$file4->ParentID = 2;
831+
$file4->write();
832+
833+
$dataObject1->Files()->add($file1);
834+
$dataObject1->Files()->add($file2);
835+
$dataObject1->Files()->add($file3);
836+
$dataObject1->Files()->add($file4);
712837

713838
$factory = new TestSchemaBuilder(['_' . __FUNCTION__ . $fixture]);
714839
$schema = $this->createSchema($factory);
715840

716841
$result = $this->querySchema($schema, $query);
717842
$this->assertSuccess($result);
718843
$records = $result['data']['readDataObjectFakes']['nodes'] ?? [];
719-
$this->assertResults([
720-
["myField" => "test2", "author" => ["firstName" => "tester2"]],
721-
["myField" => "test3", "author" => ["firstName" => "tester2"]],
722-
["myField" => "test1", "author" => ["firstName" => "tester1"]],
723-
], $records);
844+
$this->assertResults($expected, $records);
724845
}
725846

726847
public function testAggregateProperties()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
SilverStripe\GraphQL\Tests\Fake\DataObjectFake:
2+
operations:
3+
read:
4+
plugins:
5+
sort:
6+
before: paginateList
7+
fields:
8+
myField: true
9+
AuthorID: true
10+
author:
11+
fields:
12+
firstName: true
13+
files:
14+
fields:
15+
title: true
16+
plugins:
17+
sorter:
18+
fields:
19+
id: true
20+
title: true
21+
name: true
22+
ParentID: true

0 commit comments

Comments
 (0)