Skip to content

PHPLIB-1506 Import mongodb/builder #1381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 72 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
1979b84
Initial commit
alcaeus Oct 13, 2023
68cf384
Add composer package config
alcaeus Oct 13, 2023
29d1705
Add git config files
alcaeus Oct 13, 2023
a52d35e
Chore: Enable Issue Template (#2)
tom-selander Oct 16, 2023
cf5b119
Create experimental builder (#1)
GromNaN Oct 17, 2023
9d46af7
PHPLIB-1282 Add factories for system variables (#5)
GromNaN Oct 18, 2023
d526ab8
Fix Javascript type & other PHP types (#4)
GromNaN Oct 18, 2023
dd0a913
PHPLIB-1265 Reject $ in variable and field path (#7)
GromNaN Oct 30, 2023
f9dd4fb
Use final class for factory methods (#10)
GromNaN Oct 31, 2023
e5ab490
PHPLIB-1292 Accept a single array as query to support filter on numer…
GromNaN Oct 31, 2023
49e266d
PHPLIB-1271 Add tests from the documentation (#6)
GromNaN Oct 31, 2023
9a8ad5b
Validate duplicate operators are not used in CombinedFieldQuery (#3)
GromNaN Oct 31, 2023
6f260f9
Expand accepted types for field queries (#11)
GromNaN Nov 2, 2023
d8898ce
Use BSON round-trip to normalize pipelines for comparison (#13)
GromNaN Nov 3, 2023
0bedc20
Add script to help convert JS to Yaml (#15)
GromNaN Nov 9, 2023
a939aa0
Add `first`, `firstN`, `last`, `lastN` operators and tests (#14)
GromNaN Nov 13, 2023
29807ed
Reduce CI matrix as we don't use MongoDB server (#16)
GromNaN Nov 15, 2023
48353b4
Add `$all` and `$elemMatch` field query operator tests (#17)
GromNaN Nov 20, 2023
b0886f8
Various improvements (#19)
alcaeus Dec 22, 2023
919c4e6
PHPLIB-1333 Add tests on Comparison Query Operators (#20)
GromNaN Jan 11, 2024
4176b5a
PHPLIB-1334 Add tests on Logical Query Operators (#21)
GromNaN Jan 12, 2024
5e8b98a
PHPLIB-1343 Add tests on Array Expression Operators (#22)
GromNaN Jan 15, 2024
7b3e2ca
PHPLIB-1344 Add tests on Bitwise Operators (#26)
GromNaN Jan 16, 2024
cd27d8d
PHPLIB-1345 Add tests on Boolean Expression Operators (#27)
GromNaN Jan 16, 2024
3caabb0
PHPLIB-1346 Add tests on Comparison Expression Operators (#28)
GromNaN Jan 16, 2024
320cc26
PHPLIB-1336 Add tests on Evaluation Query Operators (#24)
GromNaN Jan 16, 2024
f665eb3
PHPLIB-1335 Add tests on Element Query Operators (#23)
GromNaN Jan 16, 2024
118184d
PHPLIB-1337 Add tests on Geospatial Query Operators (#25)
GromNaN Jan 16, 2024
7deb802
PHPLIB-1347 Add tests on Conditional Expression Operators (#30)
GromNaN Jan 16, 2024
abe57b5
PHPLIB-1349 Add tests on Data Size Operators (#31)
GromNaN Jan 17, 2024
defeaeb
Fix generator: builder dependency and nowdoc incompatibility (#33)
GromNaN Jan 18, 2024
2660e6d
PHPLIB-1359 Add tests on Accumulators ($group, $bucket, $bucketAuto, …
GromNaN Jan 18, 2024
471e7f7
PHPLIB-1348 Add tests on Custom Aggregation Expression Operators (#35)
GromNaN Jan 18, 2024
92ecc8f
PHPLIB-1352 Add tests on Object Expression Operators (#40)
GromNaN Jan 19, 2024
956f690
PHPLIB-1338 Add tests on $size Array Query Operators (#36)
GromNaN Jan 19, 2024
2603b9c
PHPLIB-1353 Add tests on Set Expression Operators (#41)
GromNaN Jan 19, 2024
8b445be
PHPLIB-1351 Add tests on Miscellaneous Operators (#39)
GromNaN Jan 19, 2024
149dca6
PHPLIB-1350 Add tests on Date Expression Operators and add Yaml tags …
GromNaN Jan 19, 2024
7c9a36a
PHPLIB-1339 Add tests on Bitwise Query Operators (#37)
GromNaN Jan 22, 2024
33dfd41
Prefix Yaml tags with `!bson_` (#43)
GromNaN Jan 22, 2024
26b63d3
PHPLIB-1354 Add tests on String Expression Operators (#42)
GromNaN Jan 22, 2024
3ce798c
Bump actions/cache from 3 to 4 (#45)
dependabot[bot] Jan 23, 2024
d0f0565
Fix bson_regex Yaml tag
GromNaN Jan 23, 2024
7315073
PHPLIB-1356 Add tests on Timestamp Expression Operators (#47)
GromNaN Jan 23, 2024
2ccad18
PHPLIB-1357 Add tests on Trigonometry Expression Operators (#48)
GromNaN Jan 23, 2024
ff4fc79
PHPLIB-1358 Add tests on Type Expression Operators (#49)
GromNaN Jan 24, 2024
b4e2b13
PHPLIB-1361 Add test on $let expression operator (#55)
GromNaN Jan 25, 2024
5951e36
Allow empty strings, let the server return an error (#50)
GromNaN Jan 26, 2024
aa7cffc
PHPLIB-1362 Add tests on Window Operators (#51)
GromNaN Jan 26, 2024
397ff5d
PHPLIB-1250 Split encoders and fix psalm issues (#46)
alcaeus Jan 29, 2024
a99f472
PHPLIB-1342 Add tests on Arithmetic Expression Operators (#52)
GromNaN Jan 29, 2024
c0daa64
PHPLIB-1341 Add tests on Miscellaneous Query Operators (#53)
GromNaN Jan 29, 2024
edd6a1c
PHPLIB-1340 Remove Projection Operators (#54)
GromNaN Jan 31, 2024
ca173b2
PHPLIB-1374 Add tests on all stages (#56)
GromNaN Jan 31, 2024
214baf1
PHPLIB-1355 Add tests to $meta expression (#59)
GromNaN Feb 1, 2024
592b0a0
PHPLIB-1384: Use default value in Query::exists() (#60)
alcaeus Feb 2, 2024
040833d
Add tests for $search and $searchMeta stages (#61)
alcaeus Feb 2, 2024
ceac70d
PHPLIB-1273: Improve $switch syntax (#62)
alcaeus Feb 2, 2024
63dd036
PHPLIB-1381 PHPLIB-1269 Add enum for Sort and TimeUnit (#63)
GromNaN Feb 8, 2024
5ddbc2f
Bump ramsey/composer-install from 2.2.0 to 3.0.0 (#66)
dependabot[bot] Mar 8, 2024
0622bb2
Fix links
GromNaN Mar 8, 2024
12d951c
Add fluent builder for Laravel (#67)
GromNaN Mar 13, 2024
fe8f353
Fix MongoDB namespace for InvalidArgumentException (#68)
GromNaN Mar 13, 2024
7c3375d
Allow to merge an array of stages into a pipeline (#57)
GromNaN Mar 15, 2024
aa4f34c
Add merge-up action (#69)
alcaeus Mar 15, 2024
6bc447f
Fix accepted stage type in FluentFactoryTrait (#71)
GromNaN Mar 25, 2024
2be9ad2
Merge branch 'builder' into PHPLIB-1506
GromNaN Sep 9, 2024
bc7618d
Remove composer constraints already imposed by the main package
GromNaN Sep 9, 2024
eafad05
Skip Pedentry method sort for generated files
GromNaN Sep 9, 2024
4e66bbc
Replace composer package mongodb/builder
GromNaN Sep 9, 2024
7a19e9c
Check generated files are up-to-date
GromNaN Sep 9, 2024
17d2ba8
Exclude rector.php from the artifact
GromNaN Sep 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 8 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ tests export-ignore
benchmark export-ignore
docs export-ignore
examples export-ignore
generator export-ignore
mongo-orchestration export-ignore
stubs export-ignore
tools export-ignore
Expand All @@ -14,6 +15,13 @@ phpunit.evergreen.xml export-ignore
phpunit.xml.dist export-ignore
psalm.xml.dist export-ignore
psalm-baseline.xml export-ignore
rector.php export-ignore

# Prevent generated build files from showing diffs in pull requests
.evergreen/config/generated/** linguist-generated=true
/src/Builder/Accumulator/*.php linguist-generated=true
/src/Builder/Expression/*.php linguist-generated=true
/src/Builder/Query/*.php linguist-generated=true
/src/Builder/Projection/*.php linguist-generated=true
/src/Builder/Stage/*.php linguist-generated=true
/tests/Builder/*/Pipelines.php linguist-generated=true
4 changes: 4 additions & 0 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ inputs:
description: "INI values to pass along to setup-php action"
required: false
default: ""
working-directory:
description: "The directory where composer.json is located, if it is not in the repository root."
required: false

runs:
using: composite
Expand Down Expand Up @@ -49,3 +52,4 @@ runs:
# Revert when psalm supports PHP 8.4
# composer-options: "--no-suggest"
composer-options: "--no-suggest ${{ inputs.php-version == '8.4' && '--ignore-platform-req=php+' || '' }}"
working-directory: "${{ inputs.working-directory }}"
42 changes: 42 additions & 0 deletions .github/workflows/generator.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: "Generator"

on:
merge_group:
pull_request:
branches:
- "v*.*"
- "master"
- "feature/*"
push:
branches:
- "v*.*"
- "master"
- "feature/*"

env:
PHP_VERSION: "8.2"
# TODO: change to "stable" once 1.20.0 is released
# DRIVER_VERSION: "stable"
DRIVER_VERSION: "mongodb/mongo-php-driver@v1.20"

jobs:
psalm:
name: "Diff check"
runs-on: "ubuntu-22.04"

steps:
- name: "Checkout"
uses: "actions/checkout@v4"

- name: "Setup"
uses: "./.github/actions/setup"
with:
php-version: ${{ env.PHP_VERSION }}
driver-version: ${{ env.DRIVER_VERSION }}
working-directory: "generator"

- name: "Run Generator"
run: "generator/generate"

- name: "Check file diff"
run: git add . -N && git diff --exit-code
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
"symfony/phpunit-bridge": "^5.2",
"vimeo/psalm": "^5.13"
},
"replace": {
"mongodb/builder": "*"
},
"autoload": {
"psr-4": { "MongoDB\\": "src/" },
"files": [ "src/functions.php" ]
Expand Down
34 changes: 34 additions & 0 deletions generator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Code Generator for MongoDB PHP Library

This subproject is used to generate the code that is committed to the repository.
The `generator` directory is not included in `mongodb/mongodb` package and is not installed by Composer.

## Contributing

Updating the generated code can be done only by modifying the code generator, or its configuration.

To run the generator, you need to have PHP 8.1+ installed and Composer.

1. Move to the `generator` directory: `cd generator`
1. Install dependencies: `composer install`
1. Run the generator: `./generate`

## Configuration

The `generator/config/*.yaml` files contains the list of operators and stages that are supported by the library.

### Test pipelines

Each operator can contain a `tests` section with a list if pipelines. To represent specific BSON objects,
it is necessary to use Yaml tags:

| BSON Type | Example |
|-------------|--------------------------------------------------------|
| Regex | `!bson_regex '^abc'` <br/> `!bson_regex ['^abc', 'i']` |
| Int64 | `!bson_int64 '123456789'` |
| Decimal128 | `!bson_decimal128 '0.9'` |
| UTCDateTime | `!bson_utcdatetime 0` |
| Binary | `!bson_binary 'IA=='` |

To add new test cases to operators, you can get inspiration from the official MongoDB documentation and use
the `generator/js2yaml.html` web page to manually convert a pipeline array from JS to Yaml.
32 changes: 32 additions & 0 deletions generator/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "mongodb/code-generator",
"type": "project",
"repositories": [
{
"type": "path",
"url": "../",
"symlink": true
}
],
"replace": {
"symfony/polyfill-php80": "*",
"symfony/polyfill-php81": "*"
},
"require": {
"mongodb/mongodb": "@dev",
"nette/php-generator": "^4.1.5",
"nikic/php-parser": "^5",
"symfony/console": "^7",
"symfony/finder": "^7",
"symfony/yaml": "^7"
},
"license": "Apache-2.0",
"autoload": {
"psr-4": {
"MongoDB\\CodeGenerator\\": "src/"
}
},
"config": {
"sort-packages": true
}
}
133 changes: 133 additions & 0 deletions generator/config/accumulator/accumulator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# $schema: ../schema.json
name: $accumulator
link: 'https://www.mongodb.com/docs/manual/reference/operator/aggregation/accumulator/'
type:
- accumulator
encode: object
description: |
Defines a custom accumulator function.
New in MongoDB 4.4.
arguments:
-
name: init
type:
- javascript
description: |
Function used to initialize the state. The init function receives its arguments from the initArgs array expression. You can specify the function definition as either BSON type Code or String.
-
name: initArgs
type:
- resolvesToArray
optional: true
description: |
Arguments passed to the init function.
-
name: accumulate
type:
- javascript
description: |
Function used to accumulate documents. The accumulate function receives its arguments from the current state and accumulateArgs array expression. The result of the accumulate function becomes the new state. You can specify the function definition as either BSON type Code or String.
-
name: accumulateArgs
type:
- resolvesToArray
description: |
Arguments passed to the accumulate function. You can use accumulateArgs to specify what field value(s) to pass to the accumulate function.
-
name: merge
type:
- javascript
description: |
Function used to merge two internal states. merge must be either a String or Code BSON type. merge returns the combined result of the two merged states. For information on when the merge function is called, see Merge Two States with $merge.
-
name: finalize
type:
- javascript
optional: true
description: |
Function used to update the result of the accumulation.
-
name: lang
type:
- string
description: |
The language used in the $accumulator code.

tests:
-
name: 'Use $accumulator to Implement the $avg Operator'
link: 'https://www.mongodb.com/docs/manual/reference/operator/aggregation/accumulator/#use--accumulator-to-implement-the--avg-operator'
pipeline:
-
$group:
_id: '$author'
avgCopies:
$accumulator:
init:
$code: |-
function() {
return { count: 0, sum: 0 }
}
accumulate:
$code: |-
function(state, numCopies) {
return { count: state.count + 1, sum: state.sum + numCopies }
}
accumulateArgs: [ "$copies" ],
merge:
$code: |-
function(state1, state2) {
return {
count: state1.count + state2.count,
sum: state1.sum + state2.sum
}
}
finalize:
$code: |-
function(state) {
return (state.sum / state.count)
}
lang: 'js'

-
name: 'Use initArgs to Vary the Initial State by Group'
link: 'https://www.mongodb.com/docs/manual/reference/operator/aggregation/accumulator/#use-initargs-to-vary-the-initial-state-by-group'
pipeline:
-
$group:
_id:
city: '$city'
restaurants:
$accumulator:
init:
$code: |-
function(city, userProfileCity) {
return { max: city === userProfileCity ? 3 : 1, restaurants: [] }
}
initArgs:
- '$city'
- 'Bettles'
accumulate:
$code: |-
function(state, restaurantName) {
if (state.restaurants.length < state.max) {
state.restaurants.push(restaurantName);
}
return state;
}
accumulateArgs:
- '$name'
merge:
$code: |-
function(state1, state2) {
return {
max: state1.max,
restaurants: state1.restaurants.concat(state2.restaurants).slice(0, state1.max)
}
}
finalize:
$code: |-
function(state) {
return state.restaurants
}
lang: 'js'
47 changes: 47 additions & 0 deletions generator/config/accumulator/addToSet.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# $schema: ../schema.json
name: $addToSet
link: 'https://www.mongodb.com/docs/manual/reference/operator/aggregation/addToSet/'
type:
- accumulator
- window
encode: single
description: |
Returns an array of unique expression values for each group. Order of the array elements is undefined.
Changed in MongoDB 5.0: Available in the $setWindowFields stage.
arguments:
-
name: expression
type:
- expression

tests:
-
name: 'Use in $group Stage'
link: 'https://www.mongodb.com/docs/manual/reference/operator/aggregation/addToSet/#use-in--group-stage'
pipeline:
- $group:
_id:
day:
$dayOfYear:
date: '$date'
year:
$year:
date: '$date'
itemsSold:
$addToSet: '$item'
-
name: 'Use in $setWindowFields Stage'
link: 'https://www.mongodb.com/docs/manual/reference/operator/aggregation/addToSet/#use-in--setwindowfields-stage'
pipeline:
-
$setWindowFields:
partitionBy: '$state'
sortBy:
orderDate: 1
output:
cakeTypesForState:
$addToSet: '$type'
window:
documents:
- 'unbounded'
- 'current'
45 changes: 45 additions & 0 deletions generator/config/accumulator/avg.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# $schema: ../schema.json
name: $avg
link: 'https://www.mongodb.com/docs/manual/reference/operator/aggregation/avg/'
type:
- accumulator
- window
encode: single
description: |
Returns an average of numerical values. Ignores non-numeric values.
Changed in MongoDB 5.0: Available in the $setWindowFields stage.
arguments:
-
name: expression
type:
- resolvesToNumber
tests:
-
name: 'Use in $group Stage'
link: 'https://www.mongodb.com/docs/manual/reference/operator/aggregation/avg/#use-in--group-stage'
pipeline:
- $group:
_id: '$item'
avgAmount:
$avg:
$multiply:
- '$price'
- '$quantity'
avgQuantity:
$avg: '$quantity'
-
name: 'Use in $setWindowFields Stage'
link: 'https://www.mongodb.com/docs/manual/reference/operator/aggregation/avg/#use-in--setwindowfields-stage'
pipeline:
-
$setWindowFields:
partitionBy: '$state'
sortBy:
orderDate: 1
output:
averageQuantityForState:
$avg: '$quantity'
window:
documents:
- 'unbounded'
- 'current'
Loading