Skip to content

Commit 48353b4

Browse files
authored
Add $all and $elemMatch field query operator tests (mongodb#17)
* Add $all and $elemMatch query operator tests * Accept a single Query operator in $elemMatch * Remove variadic argument for $elemMatch operator to prevent ambiquity
1 parent 29807ed commit 48353b4

File tree

11 files changed

+433
-17
lines changed

11 files changed

+433
-17
lines changed

generator/config/projection/elemMatch.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: $elemMatch
33
link: 'https://www.mongodb.com/docs/manual/reference/operator/projection/elemMatch/'
44
type:
55
- projection
6-
encode: object
6+
encode: single
77
description: |
88
Projects the first element in an array that matches the specified $elemMatch condition.
99
arguments:

generator/config/query/all.yaml

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,34 @@ arguments:
1010
-
1111
name: value
1212
type:
13-
- any
13+
- fieldQuery
1414
variadic: array
15+
tests:
16+
-
17+
name: 'Use $all to Match Values'
18+
link: 'https://www.mongodb.com/docs/manual/reference/operator/query/all/#use--all-to-match-values'
19+
pipeline:
20+
-
21+
$match:
22+
tags:
23+
$all:
24+
- 'appliance'
25+
- 'school'
26+
- 'book'
27+
-
28+
name: 'Use $all with $elemMatch'
29+
link: 'https://www.mongodb.com/docs/manual/reference/operator/query/all/#use--all-with--elemmatch'
30+
pipeline:
31+
-
32+
$match:
33+
qty:
34+
$all:
35+
-
36+
$elemMatch:
37+
size: 'M'
38+
num:
39+
$gt: 50
40+
-
41+
$elemMatch:
42+
num: 100
43+
color: 'green'

generator/config/query/elemMatch.yaml

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,66 @@ name: $elemMatch
33
link: 'https://www.mongodb.com/docs/manual/reference/operator/query/elemMatch/'
44
type:
55
- fieldQuery
6-
encode: object
6+
encode: single
77
description: |
88
The $elemMatch operator matches documents that contain an array field with at least one element that matches all the specified query criteria.
99
arguments:
1010
-
1111
name: query
1212
type:
1313
- query
14+
- fieldQuery
15+
tests:
16+
-
17+
name: 'Element Match'
18+
link: 'https://www.mongodb.com/docs/manual/reference/operator/query/elemMatch/#element-match'
19+
pipeline:
20+
-
21+
$match:
22+
results:
23+
$elemMatch:
24+
$gte: 80
25+
$lt: 85
26+
-
27+
name: 'Array of Embedded Documents'
28+
link: 'https://www.mongodb.com/docs/manual/reference/operator/query/elemMatch/#array-of-embedded-documents'
29+
pipeline:
30+
-
31+
$match:
32+
results:
33+
$elemMatch:
34+
product: 'xyz'
35+
score:
36+
$gte: 8
37+
-
38+
name: 'Single Query Condition'
39+
link: 'https://www.mongodb.com/docs/manual/reference/operator/query/elemMatch/#single-query-condition'
40+
pipeline:
41+
-
42+
$match:
43+
results:
44+
$elemMatch:
45+
product:
46+
$ne: 'xyz'
47+
-
48+
name: 'Using $or with $elemMatch'
49+
pipeline:
50+
-
51+
$match:
52+
game:
53+
$elemMatch:
54+
$or:
55+
-
56+
score:
57+
$gt: 10
58+
-
59+
score:
60+
$lt: 5
61+
-
62+
name: 'Single field operator'
63+
pipeline:
64+
-
65+
$match:
66+
results:
67+
$elemMatch:
68+
$gt: 10

src/Builder/Projection/ElemMatchOperator.php

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Builder/Query.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use MongoDB\BSON\Regex;
88
use MongoDB\BSON\Type;
99
use MongoDB\Builder\Query\RegexOperator;
10+
use MongoDB\Builder\Type\CombinedFieldQuery;
1011
use MongoDB\Builder\Type\FieldQueryInterface;
1112
use MongoDB\Builder\Type\QueryInterface;
1213
use MongoDB\Builder\Type\QueryObject;
@@ -40,6 +41,14 @@ public static function regex(Regex|string $regex, string|null $flags = null): Re
4041
return self::generatedRegex($regex);
4142
}
4243

44+
/**
45+
* Combine multiple field query operators that apply to a same field.
46+
*/
47+
public static function fieldQuery(FieldQueryInterface|Type|stdClass|array|bool|float|int|string|null ...$query): FieldQueryInterface
48+
{
49+
return new CombinedFieldQuery($query);
50+
}
51+
4352
public static function query(QueryInterface|FieldQueryInterface|Type|stdClass|array|bool|float|int|string|null ...$query): QueryInterface
4453
{
4554
return QueryObject::create($query);

src/Builder/Query/AllOperator.php

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Builder/Query/ElemMatchOperator.php

Lines changed: 9 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Builder/Query/FactoryTrait.php

Lines changed: 8 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MongoDB\Tests\Builder\Query;
6+
7+
use MongoDB\Builder\Pipeline;
8+
use MongoDB\Builder\Query;
9+
use MongoDB\Builder\Stage;
10+
use MongoDB\Tests\Builder\PipelineTestCase;
11+
12+
/**
13+
* Test $all query
14+
*/
15+
class AllOperatorTest extends PipelineTestCase
16+
{
17+
public function testUseAllToMatchValues(): void
18+
{
19+
$pipeline = new Pipeline(
20+
Stage::match(
21+
tags: Query::all('appliance', 'school', 'book'),
22+
),
23+
);
24+
25+
$this->assertSamePipeline(Pipelines::AllUseAllToMatchValues, $pipeline);
26+
}
27+
28+
public function testUseAllWithElemMatch(): void
29+
{
30+
$pipeline = new Pipeline(
31+
Stage::match(
32+
qty: Query::all(
33+
Query::elemMatch(
34+
Query::query(
35+
size: 'M',
36+
num: Query::gt(50),
37+
),
38+
),
39+
Query::elemMatch(
40+
Query::query(
41+
num: 100,
42+
color: 'green',
43+
),
44+
),
45+
),
46+
),
47+
);
48+
49+
$this->assertSamePipeline(Pipelines::AllUseAllWithElemMatch, $pipeline);
50+
}
51+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MongoDB\Tests\Builder\Query;
6+
7+
use MongoDB\Builder\Pipeline;
8+
use MongoDB\Builder\Query;
9+
use MongoDB\Builder\Stage;
10+
use MongoDB\Tests\Builder\PipelineTestCase;
11+
12+
/**
13+
* Test $elemMatch query
14+
*/
15+
class ElemMatchOperatorTest extends PipelineTestCase
16+
{
17+
public function testArrayOfEmbeddedDocuments(): void
18+
{
19+
$pipeline = new Pipeline(
20+
Stage::match(
21+
results: Query::elemMatch(
22+
Query::query(
23+
product: 'xyz',
24+
score: Query::gte(8),
25+
),
26+
),
27+
),
28+
);
29+
30+
$this->assertSamePipeline(Pipelines::ElemMatchArrayOfEmbeddedDocuments, $pipeline);
31+
}
32+
33+
public function testElementMatch(): void
34+
{
35+
$pipeline = new Pipeline(
36+
Stage::match(
37+
results: Query::elemMatch(
38+
Query::fieldQuery(
39+
Query::gte(80),
40+
Query::lt(85),
41+
),
42+
),
43+
),
44+
);
45+
46+
$this->assertSamePipeline(Pipelines::ElemMatchElementMatch, $pipeline);
47+
}
48+
49+
public function testSingleFieldOperator(): void
50+
{
51+
$pipeline = new Pipeline(
52+
Stage::match(
53+
results: Query::elemMatch(
54+
Query::gt(10),
55+
),
56+
),
57+
);
58+
59+
$this->assertSamePipeline(Pipelines::ElemMatchSingleFieldOperator, $pipeline);
60+
}
61+
62+
public function testSingleQueryCondition(): void
63+
{
64+
$pipeline = new Pipeline(
65+
Stage::match(
66+
results: Query::elemMatch(
67+
Query::query(
68+
product: Query::ne('xyz'),
69+
),
70+
),
71+
),
72+
);
73+
74+
$this->assertSamePipeline(Pipelines::ElemMatchSingleQueryCondition, $pipeline);
75+
}
76+
77+
public function testUsingOrWithElemMatch(): void
78+
{
79+
$pipeline = new Pipeline(
80+
Stage::match(
81+
game: Query::elemMatch(
82+
Query::or(
83+
Query::query(score: Query::gt(10)),
84+
Query::query(score: Query::lt(5)),
85+
),
86+
),
87+
),
88+
);
89+
90+
$this->assertSamePipeline(Pipelines::ElemMatchUsingOrWithElemMatch, $pipeline);
91+
}
92+
}

0 commit comments

Comments
 (0)