Skip to content

Commit 09460d1

Browse files
committed
New operator group
This would allow to build a list of suggestions for the end-user based on distinct values existing in DB.
1 parent c7cbdb5 commit 09460d1

File tree

5 files changed

+142
-2
lines changed

5 files changed

+142
-2
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace GraphQL\Doctrine\Definition\Operator;
6+
7+
use Doctrine\ORM\Mapping\ClassMetadata;
8+
use Doctrine\ORM\QueryBuilder;
9+
use GraphQL\Doctrine\Factory\UniqueNameFactory;
10+
use GraphQL\Type\Definition\LeafType;
11+
12+
final class GroupOperatorType extends AbstractOperator
13+
{
14+
protected function getConfiguration(LeafType $leafType): array
15+
{
16+
$description = <<<STRING
17+
Will apply a `GROUP BY` on the field to select unique values existing in database.
18+
19+
This is typically useful to present a list of suggestions to the end-user, while still allowing him to enter arbitrary values.
20+
STRING;
21+
22+
return [
23+
'description' => $description,
24+
'fields' => [
25+
[
26+
'name' => 'value',
27+
'type' => self::boolean(),
28+
'defaultValue' => null,
29+
'description' => 'This field is never used and can be ignored',
30+
],
31+
],
32+
];
33+
}
34+
35+
public function getDqlCondition(UniqueNameFactory $uniqueNameFactory, ClassMetadata $metadata, QueryBuilder $queryBuilder, string $alias, string $field, ?array $args): ?string
36+
{
37+
$queryBuilder->addGroupBy($alias . '.' . $field);
38+
39+
return null;
40+
}
41+
}

src/Factory/Type/FilterGroupConditionTypeFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use GraphQL\Doctrine\Definition\Operator\EqualOperatorType;
1414
use GraphQL\Doctrine\Definition\Operator\GreaterOperatorType;
1515
use GraphQL\Doctrine\Definition\Operator\GreaterOrEqualOperatorType;
16+
use GraphQL\Doctrine\Definition\Operator\GroupOperatorType;
1617
use GraphQL\Doctrine\Definition\Operator\HaveOperatorType;
1718
use GraphQL\Doctrine\Definition\Operator\InOperatorType;
1819
use GraphQL\Doctrine\Definition\Operator\LessOperatorType;
@@ -183,6 +184,7 @@ private function getOperators(string $fieldName, LeafType $leafType, bool $isAss
183184
LessOrEqualOperatorType::class,
184185
LikeOperatorType::class,
185186
NullOperatorType::class,
187+
GroupOperatorType::class,
186188
];
187189

188190
$associationOperators = [

tests/OperatorsTest.php renamed to tests/Definition/Operator/OperatorsTest.php

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22

33
declare(strict_types=1);
44

5-
namespace GraphQLTests\Doctrine;
5+
namespace GraphQLTests\Doctrine\Definition\Operator;
66

77
use GraphQL\Doctrine\Definition\Operator\AbstractOperator;
88
use GraphQL\Doctrine\Definition\Operator\BetweenOperatorType;
99
use GraphQL\Doctrine\Definition\Operator\EmptyOperatorType;
1010
use GraphQL\Doctrine\Definition\Operator\EqualOperatorType;
1111
use GraphQL\Doctrine\Definition\Operator\GreaterOperatorType;
1212
use GraphQL\Doctrine\Definition\Operator\GreaterOrEqualOperatorType;
13+
use GraphQL\Doctrine\Definition\Operator\GroupOperatorType;
1314
use GraphQL\Doctrine\Definition\Operator\HaveOperatorType;
1415
use GraphQL\Doctrine\Definition\Operator\InOperatorType;
1516
use GraphQL\Doctrine\Definition\Operator\LessOperatorType;
@@ -19,6 +20,7 @@
1920
use GraphQL\Doctrine\Factory\UniqueNameFactory;
2021
use GraphQL\Type\Definition\Type;
2122
use GraphQLTests\Doctrine\Blog\Model\User;
23+
use GraphQLTests\Doctrine\TypesTrait;
2224

2325
final class OperatorsTest extends \PHPUnit\Framework\TestCase
2426
{
@@ -43,10 +45,16 @@ public function testOperator(?string $expected, string $className, ?array $args,
4345

4446
$actual = $operator->getDqlCondition($uniqueNameFactory, $metadata, $queryBuilder, $alias, $field, $args);
4547

46-
self::assertEquals($expected, $actual, 'DQL condition should match');
48+
self::assertSame($expected, $actual, 'DQL condition should match');
49+
4750
if (is_string($expected)) {
4851
self::assertSame(mb_substr_count($expected, ':'), $queryBuilder->getParameters()->count(), 'should declare the same number of parameters that are actually used');
4952
}
53+
54+
if ($className === GroupOperatorType::class) {
55+
self::assertCount(1, $queryBuilder->getDQLPart('groupBy'));
56+
self::assertSame(['alias.field'], $queryBuilder->getDQLPart('groupBy')[0]->getParts());
57+
}
5058
}
5159

5260
public function providerOperator(): array
@@ -334,6 +342,25 @@ public function providerOperator(): array
334342
'not' => true,
335343
],
336344
],
345+
[
346+
null,
347+
GroupOperatorType::class,
348+
null,
349+
],
350+
[
351+
null,
352+
GroupOperatorType::class,
353+
[
354+
'value' => null,
355+
],
356+
],
357+
[
358+
null,
359+
GroupOperatorType::class,
360+
[
361+
'value' => true,
362+
],
363+
],
337364
];
338365
}
339366
}

tests/data/ModelWithTraitsFilter.graphqls

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ input GreaterOrEqualOperatorID {
2424
not: Boolean = false
2525
}
2626

27+
"""
28+
Will apply a `GROUP BY` on the field to select unique values existing in database.
29+
30+
This is typically useful to present a list of suggestions to the end-user, while
31+
still allowing him to enter arbitrary values.
32+
"""
33+
input GroupOperatorID {
34+
"""This field is never used and can be ignored"""
35+
value: Boolean = null
36+
}
37+
2738
input InOperatorID {
2839
values: [ID!]!
2940
not: Boolean = false
@@ -94,6 +105,7 @@ input ModelWithTraitsFilterGroupConditionId {
94105
lessOrEqual: LessOrEqualOperatorID
95106
like: LikeOperatorID
96107
null: NullOperatorID
108+
group: GroupOperatorID
97109
}
98110

99111
"""Type to specify join tables in a filter"""

tests/data/PostFilter.graphqls

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,50 @@ input GreaterOrEqualOperatorString {
9797
not: Boolean = false
9898
}
9999

100+
"""
101+
Will apply a `GROUP BY` on the field to select unique values existing in database.
102+
103+
This is typically useful to present a list of suggestions to the end-user, while
104+
still allowing him to enter arbitrary values.
105+
"""
106+
input GroupOperatorBoolean {
107+
"""This field is never used and can be ignored"""
108+
value: Boolean = null
109+
}
110+
111+
"""
112+
Will apply a `GROUP BY` on the field to select unique values existing in database.
113+
114+
This is typically useful to present a list of suggestions to the end-user, while
115+
still allowing him to enter arbitrary values.
116+
"""
117+
input GroupOperatorDateTime {
118+
"""This field is never used and can be ignored"""
119+
value: Boolean = null
120+
}
121+
122+
"""
123+
Will apply a `GROUP BY` on the field to select unique values existing in database.
124+
125+
This is typically useful to present a list of suggestions to the end-user, while
126+
still allowing him to enter arbitrary values.
127+
"""
128+
input GroupOperatorID {
129+
"""This field is never used and can be ignored"""
130+
value: Boolean = null
131+
}
132+
133+
"""
134+
Will apply a `GROUP BY` on the field to select unique values existing in database.
135+
136+
This is typically useful to present a list of suggestions to the end-user, while
137+
still allowing him to enter arbitrary values.
138+
"""
139+
input GroupOperatorString {
140+
"""This field is never used and can be ignored"""
141+
value: Boolean = null
142+
}
143+
100144
"""
101145
When used on single valued association, it will use `IN` operator. On collection
102146
valued association it will use `MEMBER OF` operator.
@@ -287,6 +331,7 @@ input PostFilterGroupConditionBody {
287331
lessOrEqual: LessOrEqualOperatorString
288332
like: LikeOperatorString
289333
null: NullOperatorString
334+
group: GroupOperatorString
290335
}
291336

292337
"""Type to specify a condition on a specific field"""
@@ -300,6 +345,7 @@ input PostFilterGroupConditionCreationDate {
300345
lessOrEqual: LessOrEqualOperatorDateTime
301346
like: LikeOperatorDateTime
302347
null: NullOperatorDateTime
348+
group: GroupOperatorDateTime
303349
}
304350

305351
"""Type to specify a condition on a specific field"""
@@ -318,6 +364,7 @@ input PostFilterGroupConditionId {
318364
lessOrEqual: LessOrEqualOperatorID
319365
like: LikeOperatorID
320366
null: NullOperatorID
367+
group: GroupOperatorID
321368
modulo: ModuloOperatorInt
322369
}
323370

@@ -332,6 +379,7 @@ input PostFilterGroupConditionPublicationDate {
332379
lessOrEqual: LessOrEqualOperatorDateTime
333380
like: LikeOperatorDateTime
334381
null: NullOperatorDateTime
382+
group: GroupOperatorDateTime
335383
}
336384

337385
"""Type to specify a condition on a specific field"""
@@ -345,6 +393,7 @@ input PostFilterGroupConditionStatus {
345393
lessOrEqual: LessOrEqualOperatorString
346394
like: LikeOperatorString
347395
null: NullOperatorString
396+
group: GroupOperatorString
348397
}
349398

350399
"""Type to specify a condition on a specific field"""
@@ -358,6 +407,7 @@ input PostFilterGroupConditionTitle {
358407
lessOrEqual: LessOrEqualOperatorString
359408
like: LikeOperatorString
360409
null: NullOperatorString
410+
group: GroupOperatorString
361411
}
362412

363413
"""Type to specify a condition on a specific field"""
@@ -373,6 +423,7 @@ input PostFilterGroupConditionUser {
373423
lessOrEqual: LessOrEqualOperatorID
374424
like: LikeOperatorID
375425
null: NullOperatorID
426+
group: GroupOperatorID
376427
}
377428

378429
"""Type to specify join tables in a filter"""
@@ -407,6 +458,7 @@ input UserFilterGroupConditionCreationDate {
407458
lessOrEqual: LessOrEqualOperatorDateTime
408459
like: LikeOperatorDateTime
409460
null: NullOperatorDateTime
461+
group: GroupOperatorDateTime
410462
}
411463

412464
"""Type to specify a condition on a specific field"""
@@ -420,6 +472,7 @@ input UserFilterGroupConditionEmail {
420472
lessOrEqual: LessOrEqualOperatorString
421473
like: LikeOperatorString
422474
null: NullOperatorString
475+
group: GroupOperatorString
423476
}
424477

425478
"""Type to specify a condition on a specific field"""
@@ -433,6 +486,7 @@ input UserFilterGroupConditionId {
433486
lessOrEqual: LessOrEqualOperatorID
434487
like: LikeOperatorID
435488
null: NullOperatorID
489+
group: GroupOperatorID
436490
modulo: ModuloOperatorInt
437491
}
438492

@@ -447,6 +501,7 @@ input UserFilterGroupConditionIsAdministrator {
447501
lessOrEqual: LessOrEqualOperatorBoolean
448502
like: LikeOperatorBoolean
449503
null: NullOperatorBoolean
504+
group: GroupOperatorBoolean
450505
}
451506

452507
"""Type to specify a condition on a specific field"""
@@ -462,6 +517,7 @@ input UserFilterGroupConditionManager {
462517
lessOrEqual: LessOrEqualOperatorID
463518
like: LikeOperatorID
464519
null: NullOperatorID
520+
group: GroupOperatorID
465521
}
466522

467523
"""Type to specify a condition on a specific field"""
@@ -475,6 +531,7 @@ input UserFilterGroupConditionName {
475531
lessOrEqual: LessOrEqualOperatorString
476532
like: LikeOperatorString
477533
null: NullOperatorString
534+
group: GroupOperatorString
478535
}
479536

480537
"""Type to specify a condition on a specific field"""
@@ -488,6 +545,7 @@ input UserFilterGroupConditionPassword {
488545
lessOrEqual: LessOrEqualOperatorString
489546
like: LikeOperatorString
490547
null: NullOperatorString
548+
group: GroupOperatorString
491549
}
492550

493551
"""Type to specify a condition on a specific field"""

0 commit comments

Comments
 (0)