Skip to content
This repository was archived by the owner on Feb 28, 2025. It is now read-only.

Commit 891b621

Browse files
committed
PHPLIB-1348 Add tests on Custom Aggregation Expression Operators
Automatically convert string into Javascript BSON
1 parent 2660e6d commit 891b621

File tree

17 files changed

+349
-38
lines changed

17 files changed

+349
-38
lines changed

generator/config/accumulator/accumulator.yaml

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,29 @@ tests:
6464
avgCopies:
6565
$accumulator:
6666
init:
67-
$code: 'function () { return { count: 0, sum: 0 } }'
67+
$code: |-
68+
function() {
69+
return { count: 0, sum: 0 }
70+
}
6871
accumulate:
69-
$code: 'function (state, numCopies) { return { count: state.count + 1, sum: state.sum + numCopies } }'
72+
$code: |-
73+
function(state, numCopies) {
74+
return { count: state.count + 1, sum: state.sum + numCopies }
75+
}
7076
accumulateArgs: [ "$copies" ],
7177
merge:
72-
$code: 'function (state1, state2) { return { count: state1.count + state2.count, sum: state1.sum + state2.sum } }'
78+
$code: |-
79+
function(state1, state2) {
80+
return {
81+
count: state1.count + state2.count,
82+
sum: state1.sum + state2.sum
83+
}
84+
}
7385
finalize:
74-
$code: 'function (state) { return (state.sum / state.count) }'
86+
$code: |-
87+
function(state) {
88+
return (state.sum / state.count)
89+
}
7590
lang: 'js'
7691

7792
-
@@ -85,16 +100,34 @@ tests:
85100
restaurants:
86101
$accumulator:
87102
init:
88-
$code: 'function (city, userProfileCity) { return { max: city === userProfileCity ? 3 : 1, restaurants: [] } }'
103+
$code: |-
104+
function(city, userProfileCity) {
105+
return { max: city === userProfileCity ? 3 : 1, restaurants: [] }
106+
}
89107
initArgs:
90108
- '$city'
91109
- 'Bettles'
92110
accumulate:
93-
$code: 'function (state, restaurantName) { if (state.restaurants.length < state.max) { state.restaurants.push(restaurantName); } return state; }'
111+
$code: |-
112+
function(state, restaurantName) {
113+
if (state.restaurants.length < state.max) {
114+
state.restaurants.push(restaurantName);
115+
}
116+
return state;
117+
}
94118
accumulateArgs:
95119
- '$name'
96120
merge:
97-
$code: 'function (state1, state2) { return { max: state1.max, restaurants: state1.restaurants.concat(state2.restaurants).slice(0, state1.max) } }'
121+
$code: |-
122+
function(state1, state2) {
123+
return {
124+
max: state1.max,
125+
restaurants: state1.restaurants.concat(state2.restaurants).slice(0, state1.max)
126+
}
127+
}
98128
finalize:
99-
$code: 'function (state) { return state.restaurants }'
129+
$code: |-
130+
function(state) {
131+
return state.restaurants
132+
}
100133
lang: 'js'

generator/config/expression/function.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,54 @@ arguments:
2121
- array
2222
description: |
2323
Arguments passed to the function body. If the body function does not take an argument, you can specify an empty array [ ].
24+
default: []
2425
-
2526
name: lang
2627
type:
2728
- string
2829
default: js
30+
tests:
31+
-
32+
name: 'Usage Example'
33+
link: 'https://www.mongodb.com/docs/manual/reference/operator/aggregation/function/#example-1--usage-example'
34+
pipeline:
35+
-
36+
$addFields:
37+
isFound:
38+
$function:
39+
body:
40+
$code: |-
41+
function(name) {
42+
return hex_md5(name) == "15b0a220baa16331e8d80e15367677ad"
43+
}
44+
args:
45+
- '$name'
46+
lang: 'js'
47+
message:
48+
$function:
49+
body:
50+
$code: |-
51+
function(name, scores) {
52+
let total = Array.sum(scores);
53+
return `Hello ${name}. Your total score is ${total}.`
54+
}
55+
args:
56+
- '$name'
57+
- '$scores'
58+
lang: 'js'
59+
-
60+
name: 'Alternative to $where'
61+
link: 'https://www.mongodb.com/docs/manual/reference/operator/aggregation/function/#example-2--alternative-to--where'
62+
pipeline:
63+
-
64+
$match:
65+
$expr:
66+
$function:
67+
body:
68+
$code: |-
69+
function(name) {
70+
return hex_md5(name) == "15b0a220baa16331e8d80e15367677ad";
71+
}
72+
args:
73+
- '$name'
74+
lang: 'js'

generator/config/query/where.yaml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,19 @@ tests:
1818
pipeline:
1919
-
2020
$match:
21-
$where: 'function() { return hex_md5(this.name) == "9b53e667f30cd329dca1ec9e6a83e994" }'
21+
$where:
22+
$code: |-
23+
function() {
24+
return hex_md5(this.name) == "9b53e667f30cd329dca1ec9e6a83e994"
25+
}
2226
-
2327
$match:
2428
$expr:
2529
$function:
26-
body: |-
27-
function(name) {
28-
return hex_md5(name) == "9b53e667f30cd329dca1ec9e6a83e994";
29-
}
30+
body:
31+
$code: |-
32+
function(name) {
33+
return hex_md5(name) == "9b53e667f30cd329dca1ec9e6a83e994";
34+
}
3035
args: ['$name']
3136
lang: 'js'

generator/config/schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@
166166
},
167167
"default": {
168168
"$comment": "The default value for the argument.",
169-
"type": ["string", "number", "boolean"]
169+
"type": ["array", "boolean", "number", "string"]
170170
}
171171
},
172172
"required": [

generator/src/OperatorClassGenerator.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace MongoDB\CodeGenerator;
66

7+
use MongoDB\BSON\Javascript;
78
use MongoDB\Builder\Type\Encode;
89
use MongoDB\Builder\Type\OperatorInterface;
910
use MongoDB\Builder\Type\QueryObject;
@@ -151,6 +152,17 @@ public function createClass(GeneratorDefinition $definition, OperatorDefinition
151152
152153
PHP);
153154
}
155+
156+
if ($type->javascript) {
157+
$namespace->addUseFunction('is_string');
158+
$namespace->addUse(Javascript::class);
159+
$constuctor->addBody(<<<PHP
160+
if (is_string(\${$argument->name})) {
161+
\${$argument->name} = new Javascript(\${$argument->name});
162+
}
163+
164+
PHP);
165+
}
154166
}
155167

156168
// Set property from constructor argument

generator/src/OperatorFactoryGenerator.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ private function addMethod(GeneratorDefinition $definition, OperatorDefinition $
8080
} else {
8181
if ($argument->optional) {
8282
$parameter->setDefaultValue(new Literal('Optional::Undefined'));
83+
} elseif ($argument->default !== null) {
84+
$parameter->setDefaultValue($argument->default);
8385
}
8486

8587
$method->addComment('@param ' . $type->doc . ' $' . $argument->name . rtrim(' ' . $argument->description));

generator/src/OperatorGenerator.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ final protected function getType(string $type): ExpressionDefinition
7171
* Expression types can contain class names, interface, native types or "list".
7272
* PHPDoc types are more precise than native types, so we use them systematically even if redundant.
7373
*
74-
* @return object{native:string,doc:string,use:list<class-string>,list:bool,query:bool}
74+
* @return object{native:string,doc:string,use:list<class-string>,list:bool,query:bool,javascript:bool}
7575
*/
7676
final protected function getAcceptedTypes(ArgumentDefinition $arg): stdClass
7777
{
@@ -117,6 +117,9 @@ final protected function getAcceptedTypes(ArgumentDefinition $arg): stdClass
117117
// If the argument is a query, we need to convert it to a QueryObject
118118
$isQuery = in_array('query', $arg->type, true);
119119

120+
// If the argument is code, we need to convert it to a Javascript object
121+
$isJavascript = in_array('javascript', $arg->type, true);
122+
120123
// mixed can only be used as a standalone type
121124
if (in_array('mixed', $nativeTypes, true)) {
122125
$nativeTypes = ['mixed'];
@@ -132,6 +135,7 @@ final protected function getAcceptedTypes(ArgumentDefinition $arg): stdClass
132135
'use' => array_unique($use),
133136
'list' => $listCheck,
134137
'query' => $isQuery,
138+
'javascript' => $isJavascript,
135139
];
136140
}
137141

src/Builder/Accumulator/AccumulatorAccumulator.php

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

src/Builder/Expression/FactoryTrait.php

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

src/Builder/Expression/FunctionOperator.php

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

src/Builder/Query/WhereOperator.php

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

0 commit comments

Comments
 (0)