From a515b67c3a9df2c1a964aafaa31bfb3cb0f7c37c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Tue, 7 Jan 2025 11:29:31 +0100 Subject: [PATCH 1/7] Require latest python version (#1564) --- .github/workflows/tests.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1a4a0d3a6..90a0abd89 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -62,8 +62,12 @@ jobs: fetch-depth: 2 submodules: true + - uses: actions/setup-python@v5 + with: + python-version: '3.13' + - id: setup-mongodb - uses: mongodb-labs/drivers-evergreen-tools@81c6b49dd61e833229d750084f9f3c71b31acd8d + uses: mongodb-labs/drivers-evergreen-tools@master with: version: ${{ matrix.mongodb-version }} topology: ${{ matrix.topology }} From 653d5159fa05daaf7d377128beb1cdb15b105ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Fri, 17 Jan 2025 11:22:07 +0100 Subject: [PATCH 2/7] PHPLIB-1587 Validate hint option using `is_document` and reject PackedArray (#1567) --- src/Exception/InvalidArgumentException.php | 11 +++++++++++ src/Operation/Aggregate.php | 5 ++--- src/Operation/Count.php | 4 ++-- src/Operation/Delete.php | 6 ++---- src/Operation/Distinct.php | 2 +- src/Operation/Find.php | 4 ++-- src/Operation/FindAndModify.php | 4 ++-- src/Operation/Update.php | 5 ++--- tests/TestCase.php | 2 +- 9 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php index 115f6a5c7..964b259c1 100644 --- a/src/Exception/InvalidArgumentException.php +++ b/src/Exception/InvalidArgumentException.php @@ -34,6 +34,17 @@ public static function cannotCombineCodecAndTypeMap(): self return new self('Cannot provide both "codec" and "typeMap" options'); } + /** + * Thrown when an argument or option is expected to be a string or a document. + * + * @param string $name Name of the argument or option + * @param mixed $value Actual value (used to derive the type) + */ + public static function expectedDocumentOrStringType(string $name, mixed $value): self + { + return new self(sprintf('Expected %s to have type "string" or "document" (array or object) but found "%s"', $name, get_debug_type($value))); + } + /** * Thrown when an argument or option is expected to be a document. * diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index 3543fc73c..7c968a250 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -37,7 +37,6 @@ use function is_array; use function is_bool; use function is_integer; -use function is_object; use function is_string; use function MongoDB\is_document; use function MongoDB\is_last_pipeline_operator_write; @@ -150,8 +149,8 @@ public function __construct(private string $databaseName, private ?string $colle throw InvalidArgumentException::invalidType('"explain" option', $this->options['explain'], 'boolean'); } - if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_array($this->options['hint']) && ! is_object($this->options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $this->options['hint'], 'string or array or object'); + if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_document($this->options['hint'])) { + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $this->options['hint']); } if (isset($this->options['let']) && ! is_document($this->options['let'])) { diff --git a/src/Operation/Count.php b/src/Operation/Count.php index 9f9225942..f3d2b7eb6 100644 --- a/src/Operation/Count.php +++ b/src/Operation/Count.php @@ -90,8 +90,8 @@ public function __construct(private string $databaseName, private string $collec throw InvalidArgumentException::expectedDocumentType('"collation" option', $this->options['collation']); } - if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_array($this->options['hint']) && ! is_object($this->options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $this->options['hint'], 'string or array or object'); + if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_document($this->options['hint'])) { + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $this->options['hint']); } if (isset($this->options['limit']) && ! is_integer($this->options['limit'])) { diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php index 477cade91..c5826a6d9 100644 --- a/src/Operation/Delete.php +++ b/src/Operation/Delete.php @@ -26,8 +26,6 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; -use function is_array; -use function is_object; use function is_string; use function MongoDB\is_document; use function MongoDB\is_write_concern_acknowledged; @@ -96,8 +94,8 @@ public function __construct(private string $databaseName, private string $collec throw InvalidArgumentException::expectedDocumentType('"collation" option', $this->options['collation']); } - if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_array($this->options['hint']) && ! is_object($this->options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $this->options['hint'], ['string', 'array', 'object']); + if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_document($this->options['hint'])) { + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $this->options['hint']); } if (isset($this->options['session']) && ! $this->options['session'] instanceof Session) { diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php index a979df229..bd69cde11 100644 --- a/src/Operation/Distinct.php +++ b/src/Operation/Distinct.php @@ -91,7 +91,7 @@ public function __construct(private string $databaseName, private string $collec } if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_document($this->options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $this->options['hint'], 'string or array or object'); + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $this->options['hint']); } if (isset($this->options['maxTimeMS']) && ! is_integer($this->options['maxTimeMS'])) { diff --git a/src/Operation/Find.php b/src/Operation/Find.php index 6516d52c9..a4a010010 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -195,8 +195,8 @@ public function __construct(private string $databaseName, private string $collec } } - if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_array($this->options['hint']) && ! is_object($this->options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $this->options['hint'], 'string or array or object'); + if (isset($this->options['hint']) && ! is_string($this->options['hint']) && ! is_document($this->options['hint'])) { + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $this->options['hint']); } if (isset($this->options['limit']) && ! is_integer($this->options['limit'])) { diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php index e67413b6c..07944db3d 100644 --- a/src/Operation/FindAndModify.php +++ b/src/Operation/FindAndModify.php @@ -151,8 +151,8 @@ public function __construct(private string $databaseName, private string $collec throw InvalidArgumentException::expectedDocumentType('"fields" option', $options['fields']); } - if (isset($options['hint']) && ! is_string($options['hint']) && ! is_array($options['hint']) && ! is_object($options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $options['hint'], ['string', 'array', 'object']); + if (isset($options['hint']) && ! is_string($options['hint']) && ! is_document($options['hint'])) { + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $options['hint']); } if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) { diff --git a/src/Operation/Update.php b/src/Operation/Update.php index 0b47b1cc1..5d011da28 100644 --- a/src/Operation/Update.php +++ b/src/Operation/Update.php @@ -28,7 +28,6 @@ use function is_array; use function is_bool; -use function is_object; use function is_string; use function MongoDB\is_document; use function MongoDB\is_first_key_operator; @@ -122,8 +121,8 @@ public function __construct(private string $databaseName, private string $collec throw InvalidArgumentException::expectedDocumentType('"collation" option', $options['collation']); } - if (isset($options['hint']) && ! is_string($options['hint']) && ! is_array($options['hint']) && ! is_object($options['hint'])) { - throw InvalidArgumentException::invalidType('"hint" option', $options['hint'], ['string', 'array', 'object']); + if (isset($options['hint']) && ! is_string($options['hint']) && ! is_document($options['hint'])) { + throw InvalidArgumentException::expectedDocumentOrStringType('"hint" option', $options['hint']); } if (! is_bool($options['multi'])) { diff --git a/tests/TestCase.php b/tests/TestCase.php index c8c7db09d..2b6b86eb2 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -250,7 +250,7 @@ protected static function getInvalidDocumentCodecValues(): array */ protected static function getInvalidHintValues(): array { - return [123, 3.14, true]; + return [123, 3.14, true, PackedArray::fromPHP([])]; } /** From 3a8a0a7a52b7a865bd85c8e16fa7726e3eca909d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 09:04:38 +0100 Subject: [PATCH 3/7] Bump tests/specifications from `ce35696` to `60fe09f` (#1568) Bumps [tests/specifications](https://github.com/mongodb/specifications) from `ce35696` to `60fe09f`. - [Release notes](https://github.com/mongodb/specifications/releases) - [Commits](https://github.com/mongodb/specifications/compare/ce35696db1c8da0e15a067b8022c853f1d6d1292...60fe09fc17a1963d683e904eb8b43f6675d77a1a) --- updated-dependencies: - dependency-name: tests/specifications dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tests/specifications | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/specifications b/tests/specifications index ce35696db..60fe09fc1 160000 --- a/tests/specifications +++ b/tests/specifications @@ -1 +1 @@ -Subproject commit ce35696db1c8da0e15a067b8022c853f1d6d1292 +Subproject commit 60fe09fc17a1963d683e904eb8b43f6675d77a1a From 8b847861a82cbde782e85b5174b878dd2dd920db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Fri, 24 Jan 2025 11:02:39 +0100 Subject: [PATCH 4/7] PHPLIB-1609 Don't mandate the use of "distanceField" in $geoNear (#1569) The $geoNear distanceField argument is now optional for queries on non-timeseries collections. --- generator/config/stage/geoNear.yaml | 1 + src/Builder/Stage/FactoryTrait.php | 6 +++--- src/Builder/Stage/FluentFactoryTrait.php | 6 +++--- src/Builder/Stage/GeoNearStage.php | 14 +++++++------- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/generator/config/stage/geoNear.yaml b/generator/config/stage/geoNear.yaml index c9968509d..699f15146 100644 --- a/generator/config/stage/geoNear.yaml +++ b/generator/config/stage/geoNear.yaml @@ -11,6 +11,7 @@ arguments: name: distanceField type: - string + optional: true description: | The output field that contains the calculated distance. To specify a field within an embedded document, use dot notation. - diff --git a/src/Builder/Stage/FactoryTrait.php b/src/Builder/Stage/FactoryTrait.php index 7ef8fb62b..983da9e09 100644 --- a/src/Builder/Stage/FactoryTrait.php +++ b/src/Builder/Stage/FactoryTrait.php @@ -248,8 +248,8 @@ public static function fill( * Returns an ordered stream of documents based on the proximity to a geospatial point. Incorporates the functionality of $match, $sort, and $limit for geospatial data. The output documents include an additional distance field and can include a location identifier field. * * @see https://www.mongodb.com/docs/manual/reference/operator/aggregation/geoNear/ - * @param string $distanceField The output field that contains the calculated distance. To specify a field within an embedded document, use dot notation. * @param Document|ResolvesToObject|Serializable|array|stdClass $near The point for which to find the closest documents. + * @param Optional|string $distanceField The output field that contains the calculated distance. To specify a field within an embedded document, use dot notation. * @param Optional|Decimal128|Int64|float|int $distanceMultiplier The factor to multiply all distances returned by the query. For example, use the distanceMultiplier to convert radians, as returned by a spherical query, to kilometers by multiplying by the radius of the Earth. * @param Optional|string $includeLocs This specifies the output field that identifies the location used to calculate the distance. This option is useful when a location field contains multiple locations. To specify a field within an embedded document, use dot notation. * @param Optional|string $key Specify the geospatial indexed field to use when calculating the distance. @@ -265,8 +265,8 @@ public static function fill( * Default: false. */ public static function geoNear( - string $distanceField, Document|Serializable|ResolvesToObject|stdClass|array $near, + Optional|string $distanceField = Optional::Undefined, Optional|Decimal128|Int64|float|int $distanceMultiplier = Optional::Undefined, Optional|string $includeLocs = Optional::Undefined, Optional|string $key = Optional::Undefined, @@ -275,7 +275,7 @@ public static function geoNear( Optional|QueryInterface|array $query = Optional::Undefined, Optional|bool $spherical = Optional::Undefined, ): GeoNearStage { - return new GeoNearStage($distanceField, $near, $distanceMultiplier, $includeLocs, $key, $maxDistance, $minDistance, $query, $spherical); + return new GeoNearStage($near, $distanceField, $distanceMultiplier, $includeLocs, $key, $maxDistance, $minDistance, $query, $spherical); } /** diff --git a/src/Builder/Stage/FluentFactoryTrait.php b/src/Builder/Stage/FluentFactoryTrait.php index 803ca9905..0d6e981ea 100644 --- a/src/Builder/Stage/FluentFactoryTrait.php +++ b/src/Builder/Stage/FluentFactoryTrait.php @@ -295,8 +295,8 @@ public function fill( * Returns an ordered stream of documents based on the proximity to a geospatial point. Incorporates the functionality of $match, $sort, and $limit for geospatial data. The output documents include an additional distance field and can include a location identifier field. * * @see https://www.mongodb.com/docs/manual/reference/operator/aggregation/geoNear/ - * @param string $distanceField The output field that contains the calculated distance. To specify a field within an embedded document, use dot notation. * @param Document|ResolvesToObject|Serializable|array|stdClass $near The point for which to find the closest documents. + * @param Optional|string $distanceField The output field that contains the calculated distance. To specify a field within an embedded document, use dot notation. * @param Optional|Decimal128|Int64|float|int $distanceMultiplier The factor to multiply all distances returned by the query. For example, use the distanceMultiplier to convert radians, as returned by a spherical query, to kilometers by multiplying by the radius of the Earth. * @param Optional|string $includeLocs This specifies the output field that identifies the location used to calculate the distance. This option is useful when a location field contains multiple locations. To specify a field within an embedded document, use dot notation. * @param Optional|string $key Specify the geospatial indexed field to use when calculating the distance. @@ -312,8 +312,8 @@ public function fill( * Default: false. */ public function geoNear( - string $distanceField, Document|Serializable|ResolvesToObject|stdClass|array $near, + Optional|string $distanceField = Optional::Undefined, Optional|Decimal128|Int64|int|float $distanceMultiplier = Optional::Undefined, Optional|string $includeLocs = Optional::Undefined, Optional|string $key = Optional::Undefined, @@ -322,7 +322,7 @@ public function geoNear( Optional|QueryInterface|array $query = Optional::Undefined, Optional|bool $spherical = Optional::Undefined, ): static { - $this->pipeline[] = Stage::geoNear($distanceField, $near, $distanceMultiplier, $includeLocs, $key, $maxDistance, $minDistance, $query, $spherical); + $this->pipeline[] = Stage::geoNear($near, $distanceField, $distanceMultiplier, $includeLocs, $key, $maxDistance, $minDistance, $query, $spherical); return $this; } diff --git a/src/Builder/Stage/GeoNearStage.php b/src/Builder/Stage/GeoNearStage.php index b2aa6588e..845fd2afa 100644 --- a/src/Builder/Stage/GeoNearStage.php +++ b/src/Builder/Stage/GeoNearStage.php @@ -35,8 +35,8 @@ final class GeoNearStage implements StageInterface, OperatorInterface public const NAME = '$geoNear'; public const PROPERTIES = [ - 'distanceField' => 'distanceField', 'near' => 'near', + 'distanceField' => 'distanceField', 'distanceMultiplier' => 'distanceMultiplier', 'includeLocs' => 'includeLocs', 'key' => 'key', @@ -46,12 +46,12 @@ final class GeoNearStage implements StageInterface, OperatorInterface 'spherical' => 'spherical', ]; - /** @var string $distanceField The output field that contains the calculated distance. To specify a field within an embedded document, use dot notation. */ - public readonly string $distanceField; - /** @var Document|ResolvesToObject|Serializable|array|stdClass $near The point for which to find the closest documents. */ public readonly Document|Serializable|ResolvesToObject|stdClass|array $near; + /** @var Optional|string $distanceField The output field that contains the calculated distance. To specify a field within an embedded document, use dot notation. */ + public readonly Optional|string $distanceField; + /** @var Optional|Decimal128|Int64|float|int $distanceMultiplier The factor to multiply all distances returned by the query. For example, use the distanceMultiplier to convert radians, as returned by a spherical query, to kilometers by multiplying by the radius of the Earth. */ public readonly Optional|Decimal128|Int64|float|int $distanceMultiplier; @@ -88,8 +88,8 @@ final class GeoNearStage implements StageInterface, OperatorInterface public readonly Optional|bool $spherical; /** - * @param string $distanceField The output field that contains the calculated distance. To specify a field within an embedded document, use dot notation. * @param Document|ResolvesToObject|Serializable|array|stdClass $near The point for which to find the closest documents. + * @param Optional|string $distanceField The output field that contains the calculated distance. To specify a field within an embedded document, use dot notation. * @param Optional|Decimal128|Int64|float|int $distanceMultiplier The factor to multiply all distances returned by the query. For example, use the distanceMultiplier to convert radians, as returned by a spherical query, to kilometers by multiplying by the radius of the Earth. * @param Optional|string $includeLocs This specifies the output field that identifies the location used to calculate the distance. This option is useful when a location field contains multiple locations. To specify a field within an embedded document, use dot notation. * @param Optional|string $key Specify the geospatial indexed field to use when calculating the distance. @@ -105,8 +105,8 @@ final class GeoNearStage implements StageInterface, OperatorInterface * Default: false. */ public function __construct( - string $distanceField, Document|Serializable|ResolvesToObject|stdClass|array $near, + Optional|string $distanceField = Optional::Undefined, Optional|Decimal128|Int64|float|int $distanceMultiplier = Optional::Undefined, Optional|string $includeLocs = Optional::Undefined, Optional|string $key = Optional::Undefined, @@ -115,8 +115,8 @@ public function __construct( Optional|QueryInterface|array $query = Optional::Undefined, Optional|bool $spherical = Optional::Undefined, ) { - $this->distanceField = $distanceField; $this->near = $near; + $this->distanceField = $distanceField; $this->distanceMultiplier = $distanceMultiplier; $this->includeLocs = $includeLocs; $this->key = $key; From acfe2aca769647793691a01502cfe206312bdbf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Fri, 24 Jan 2025 11:03:41 +0100 Subject: [PATCH 5/7] PHPLIB-1598 Use named types for enums (#1570) --- generator/config/accumulator/bottom.yaml | 2 +- generator/config/accumulator/bottomN.yaml | 2 +- generator/config/accumulator/median.yaml | 2 +- generator/config/accumulator/percentile.yaml | 2 +- generator/config/accumulator/top.yaml | 2 +- generator/config/accumulator/topN.yaml | 2 +- generator/config/expression/median.yaml | 2 +- generator/config/expression/percentile.yaml | 2 +- generator/config/expression/sortArray.yaml | 2 +- generator/config/expressions.php | 29 +++++++------------- generator/config/schema.json | 12 +++++++- generator/config/stage/bucketAuto.yaml | 2 +- generator/config/stage/changeStream.yaml | 4 +-- generator/config/stage/densify.yaml | 2 +- generator/config/stage/fill.yaml | 2 +- generator/config/stage/geoNear.yaml | 2 +- generator/config/stage/merge.yaml | 6 ++-- generator/config/stage/out.yaml | 2 +- generator/config/stage/setWindowFields.yaml | 2 +- src/Builder/Stage/BucketAutoStage.php | 8 +++--- src/Builder/Stage/FactoryTrait.php | 4 +-- src/Builder/Stage/FluentFactoryTrait.php | 4 +-- 22 files changed, 49 insertions(+), 48 deletions(-) diff --git a/generator/config/accumulator/bottom.yaml b/generator/config/accumulator/bottom.yaml index 4ebb897ea..1e363d193 100644 --- a/generator/config/accumulator/bottom.yaml +++ b/generator/config/accumulator/bottom.yaml @@ -12,7 +12,7 @@ arguments: - name: sortBy type: - - object # SortSpec + - sortBy description: | Specifies the order of results, with syntax similar to $sort. - diff --git a/generator/config/accumulator/bottomN.yaml b/generator/config/accumulator/bottomN.yaml index 30bca678c..355d8e09a 100644 --- a/generator/config/accumulator/bottomN.yaml +++ b/generator/config/accumulator/bottomN.yaml @@ -19,7 +19,7 @@ arguments: - name: sortBy type: - - object # SortSpec + - sortBy description: | Specifies the order of results, with syntax similar to $sort. - diff --git a/generator/config/accumulator/median.yaml b/generator/config/accumulator/median.yaml index 708ea3502..e743c6982 100644 --- a/generator/config/accumulator/median.yaml +++ b/generator/config/accumulator/median.yaml @@ -22,7 +22,7 @@ arguments: - name: method type: - - string # AccumulatorPercentile + - accumulatorPercentile description: | The method that mongod uses to calculate the 50th percentile value. The method must be 'approximate'. tests: diff --git a/generator/config/accumulator/percentile.yaml b/generator/config/accumulator/percentile.yaml index b2a6147d4..b3c41b0e4 100644 --- a/generator/config/accumulator/percentile.yaml +++ b/generator/config/accumulator/percentile.yaml @@ -32,7 +32,7 @@ arguments: - name: method type: - - string # AccumulatorPercentile + - accumulatorPercentile description: | The method that mongod uses to calculate the percentile value. The method must be 'approximate'. tests: diff --git a/generator/config/accumulator/top.yaml b/generator/config/accumulator/top.yaml index 2f4deefa2..94923cccd 100644 --- a/generator/config/accumulator/top.yaml +++ b/generator/config/accumulator/top.yaml @@ -13,7 +13,7 @@ arguments: - name: sortBy type: - - object # SortSpec + - sortBy description: | Specifies the order of results, with syntax similar to $sort. - diff --git a/generator/config/accumulator/topN.yaml b/generator/config/accumulator/topN.yaml index c8073e09f..c5eff6056 100644 --- a/generator/config/accumulator/topN.yaml +++ b/generator/config/accumulator/topN.yaml @@ -19,7 +19,7 @@ arguments: - name: sortBy type: - - object # SortSpec + - sortBy description: | Specifies the order of results, with syntax similar to $sort. - diff --git a/generator/config/expression/median.yaml b/generator/config/expression/median.yaml index 2708f7f16..2aac26a1f 100644 --- a/generator/config/expression/median.yaml +++ b/generator/config/expression/median.yaml @@ -22,7 +22,7 @@ arguments: - name: method type: - - string # AccumulatorPercentile + - accumulatorPercentile description: | The method that mongod uses to calculate the 50th percentile value. The method must be 'approximate'. tests: diff --git a/generator/config/expression/percentile.yaml b/generator/config/expression/percentile.yaml index 8c601cc83..b19fc1904 100644 --- a/generator/config/expression/percentile.yaml +++ b/generator/config/expression/percentile.yaml @@ -32,7 +32,7 @@ arguments: - name: method type: - - string # AccumulatorPercentile + - accumulatorPercentile description: | The method that mongod uses to calculate the percentile value. The method must be 'approximate'. tests: diff --git a/generator/config/expression/sortArray.yaml b/generator/config/expression/sortArray.yaml index 962ebf1ce..d558f2233 100644 --- a/generator/config/expression/sortArray.yaml +++ b/generator/config/expression/sortArray.yaml @@ -18,9 +18,9 @@ arguments: - name: sortBy type: - - object # SortSpec - int - sortSpec + - sortBy description: | The document specifies a sort ordering. tests: diff --git a/generator/config/expressions.php b/generator/config/expressions.php index a2c649e8e..f77b45e79 100644 --- a/generator/config/expressions.php +++ b/generator/config/expressions.php @@ -131,45 +131,36 @@ ], // @todo add enum values - 'Granularity' => [ + 'granularity' => [ 'acceptedTypes' => [...$bsonTypes['string']], ], - 'FullDocument' => [ + 'fullDocument' => [ 'acceptedTypes' => [...$bsonTypes['string']], ], - 'FullDocumentBeforeChange' => [ + 'fullDocumentBeforeChange' => [ 'acceptedTypes' => [...$bsonTypes['string']], ], - 'AccumulatorPercentile' => [ + 'accumulatorPercentile' => [ 'acceptedTypes' => [...$bsonTypes['string']], ], - 'WhenMatched' => [ + 'whenMatched' => [ 'acceptedTypes' => [...$bsonTypes['string']], ], - 'WhenNotMatched' => [ + 'whenNotMatched' => [ 'acceptedTypes' => [...$bsonTypes['string']], ], // @todo create specific model classes factories - 'OutCollection' => [ + 'outCollection' => [ 'acceptedTypes' => [...$bsonTypes['object']], ], - 'CollStats' => [ + 'range' => [ 'acceptedTypes' => [...$bsonTypes['object']], ], - 'Range' => [ + 'sortBy' => [ 'acceptedTypes' => [...$bsonTypes['object']], ], - 'FillOut' => [ - 'acceptedTypes' => [...$bsonTypes['object']], - ], - 'SortSpec' => [ - 'acceptedTypes' => [...$bsonTypes['object']], - ], - 'Window' => [ - 'acceptedTypes' => [...$bsonTypes['object']], - ], - 'GeoPoint' => [ + 'geoPoint' => [ 'acceptedTypes' => [...$bsonTypes['object']], ], diff --git a/generator/config/schema.json b/generator/config/schema.json index c92e6ddb7..63739ebcb 100644 --- a/generator/config/schema.json +++ b/generator/config/schema.json @@ -9,7 +9,7 @@ "name": { "$comment": "The name of the operator. Must start with a $", "type": "string", - "pattern": "^\\$[a-z0-9][a-zA-Z0-9]*$" + "pattern": "^\\$?[a-z][a-zA-Z0-9]*$" }, "link": { "$comment": "The link to the operator's documentation on MongoDB's website.", @@ -122,6 +122,16 @@ "timeUnit", "sortSpec", "any", + "granularity", + "fullDocument", + "fullDocumentBeforeChange", + "accumulatorPercentile", + "whenMatched", + "whenNotMatched", + "outCollection", + "range", + "sortBy", + "geoPoint", "resolvesToNumber", "numberFieldPath", "number", "resolvesToDouble", "doubleFieldPath", "double", "resolvesToString", "stringFieldPath", "string", diff --git a/generator/config/stage/bucketAuto.yaml b/generator/config/stage/bucketAuto.yaml index 48c102e11..73775fde8 100644 --- a/generator/config/stage/bucketAuto.yaml +++ b/generator/config/stage/bucketAuto.yaml @@ -30,7 +30,7 @@ arguments: - name: granularity type: - - object # Granularity + - granularity optional: true description: | A string that specifies the preferred number series to use to ensure that the calculated boundary edges end on preferred round numbers or their powers of 10. diff --git a/generator/config/stage/changeStream.yaml b/generator/config/stage/changeStream.yaml index 44fdb3c5c..be413ef5d 100644 --- a/generator/config/stage/changeStream.yaml +++ b/generator/config/stage/changeStream.yaml @@ -17,14 +17,14 @@ arguments: - name: fullDocument type: - - string # FullDocument + - fullDocument optional: true description: | Specifies whether change notifications include a copy of the full document when modified by update operations. - name: fullDocumentBeforeChange type: - - string # FullDocumentBeforeChange + - fullDocumentBeforeChange optional: true description: | Valid values are "off", "whenAvailable", or "required". If set to "off", the "fullDocumentBeforeChange" field of the output document is always omitted. If set to "whenAvailable", the "fullDocumentBeforeChange" field will be populated with the pre-image of the document modified by the current change event if such a pre-image is available, and will be omitted otherwise. If set to "required", then the "fullDocumentBeforeChange" field is always populated and an exception is thrown if the pre-image is not available. diff --git a/generator/config/stage/densify.yaml b/generator/config/stage/densify.yaml index a66cf18dd..46ccbd6dd 100644 --- a/generator/config/stage/densify.yaml +++ b/generator/config/stage/densify.yaml @@ -25,7 +25,7 @@ arguments: - name: range type: - - object # Range + - range description: | Specification for range based densification. tests: diff --git a/generator/config/stage/fill.yaml b/generator/config/stage/fill.yaml index d3a9ec390..2c98fac5c 100644 --- a/generator/config/stage/fill.yaml +++ b/generator/config/stage/fill.yaml @@ -29,7 +29,7 @@ arguments: - name: sortBy type: - - object # SortSpec + - sortBy optional: true description: | Specifies the field or fields to sort the documents within each partition. Uses the same syntax as the $sort stage. diff --git a/generator/config/stage/geoNear.yaml b/generator/config/stage/geoNear.yaml index 699f15146..4967a0823 100644 --- a/generator/config/stage/geoNear.yaml +++ b/generator/config/stage/geoNear.yaml @@ -54,7 +54,7 @@ arguments: - name: near type: - - object # GeoPoint + - geoPoint - resolvesToObject description: | The point for which to find the closest documents. diff --git a/generator/config/stage/merge.yaml b/generator/config/stage/merge.yaml index 2e24ec74e..766092d82 100644 --- a/generator/config/stage/merge.yaml +++ b/generator/config/stage/merge.yaml @@ -12,7 +12,7 @@ arguments: name: into type: - string - - object # OutCollection + - outCollection description: | The output collection. - @@ -33,7 +33,7 @@ arguments: - name: whenMatched type: - - string # WhenMatched + - whenMatched - pipeline optional: true description: | @@ -41,7 +41,7 @@ arguments: - name: whenNotMatched type: - - string # WhenNotMatched + - whenNotMatched optional: true description: | The behavior of $merge if a result document does not match an existing document in the out collection. diff --git a/generator/config/stage/out.yaml b/generator/config/stage/out.yaml index c4cc7948d..0c3597fdf 100644 --- a/generator/config/stage/out.yaml +++ b/generator/config/stage/out.yaml @@ -10,7 +10,7 @@ arguments: - name: coll type: - string - - object # OutCollection + - outCollection description: | Target database name to write documents from $out to. tests: diff --git a/generator/config/stage/setWindowFields.yaml b/generator/config/stage/setWindowFields.yaml index fba751d03..6f86472d7 100644 --- a/generator/config/stage/setWindowFields.yaml +++ b/generator/config/stage/setWindowFields.yaml @@ -11,7 +11,7 @@ arguments: - name: sortBy type: - - object # SortSpec + - sortBy description: | Specifies the field(s) to sort the documents by in the partition. Uses the same syntax as the $sort stage. Default is no sorting. - diff --git a/src/Builder/Stage/BucketAutoStage.php b/src/Builder/Stage/BucketAutoStage.php index 2de5b3c20..11c456e69 100644 --- a/src/Builder/Stage/BucketAutoStage.php +++ b/src/Builder/Stage/BucketAutoStage.php @@ -49,24 +49,24 @@ final class BucketAutoStage implements StageInterface, OperatorInterface public readonly Optional|Document|Serializable|stdClass|array $output; /** - * @var Optional|Document|Serializable|array|stdClass $granularity A string that specifies the preferred number series to use to ensure that the calculated boundary edges end on preferred round numbers or their powers of 10. + * @var Optional|string $granularity A string that specifies the preferred number series to use to ensure that the calculated boundary edges end on preferred round numbers or their powers of 10. * Available only if the all groupBy values are numeric and none of them are NaN. */ - public readonly Optional|Document|Serializable|stdClass|array $granularity; + public readonly Optional|string $granularity; /** * @param ExpressionInterface|Type|array|bool|float|int|null|stdClass|string $groupBy An expression to group documents by. To specify a field path, prefix the field name with a dollar sign $ and enclose it in quotes. * @param int $buckets A positive 32-bit integer that specifies the number of buckets into which input documents are grouped. * @param Optional|Document|Serializable|array|stdClass $output A document that specifies the fields to include in the output documents in addition to the _id field. To specify the field to include, you must use accumulator expressions. * The default count field is not included in the output document when output is specified. Explicitly specify the count expression as part of the output document to include it. - * @param Optional|Document|Serializable|array|stdClass $granularity A string that specifies the preferred number series to use to ensure that the calculated boundary edges end on preferred round numbers or their powers of 10. + * @param Optional|string $granularity A string that specifies the preferred number series to use to ensure that the calculated boundary edges end on preferred round numbers or their powers of 10. * Available only if the all groupBy values are numeric and none of them are NaN. */ public function __construct( Type|ExpressionInterface|stdClass|array|bool|float|int|null|string $groupBy, int $buckets, Optional|Document|Serializable|stdClass|array $output = Optional::Undefined, - Optional|Document|Serializable|stdClass|array $granularity = Optional::Undefined, + Optional|string $granularity = Optional::Undefined, ) { $this->groupBy = $groupBy; $this->buckets = $buckets; diff --git a/src/Builder/Stage/FactoryTrait.php b/src/Builder/Stage/FactoryTrait.php index 983da9e09..7bbf3bc97 100644 --- a/src/Builder/Stage/FactoryTrait.php +++ b/src/Builder/Stage/FactoryTrait.php @@ -79,14 +79,14 @@ public static function bucket( * @param int $buckets A positive 32-bit integer that specifies the number of buckets into which input documents are grouped. * @param Optional|Document|Serializable|array|stdClass $output A document that specifies the fields to include in the output documents in addition to the _id field. To specify the field to include, you must use accumulator expressions. * The default count field is not included in the output document when output is specified. Explicitly specify the count expression as part of the output document to include it. - * @param Optional|Document|Serializable|array|stdClass $granularity A string that specifies the preferred number series to use to ensure that the calculated boundary edges end on preferred round numbers or their powers of 10. + * @param Optional|string $granularity A string that specifies the preferred number series to use to ensure that the calculated boundary edges end on preferred round numbers or their powers of 10. * Available only if the all groupBy values are numeric and none of them are NaN. */ public static function bucketAuto( Type|ExpressionInterface|stdClass|array|bool|float|int|null|string $groupBy, int $buckets, Optional|Document|Serializable|stdClass|array $output = Optional::Undefined, - Optional|Document|Serializable|stdClass|array $granularity = Optional::Undefined, + Optional|string $granularity = Optional::Undefined, ): BucketAutoStage { return new BucketAutoStage($groupBy, $buckets, $output, $granularity); } diff --git a/src/Builder/Stage/FluentFactoryTrait.php b/src/Builder/Stage/FluentFactoryTrait.php index 0d6e981ea..3cfd84cff 100644 --- a/src/Builder/Stage/FluentFactoryTrait.php +++ b/src/Builder/Stage/FluentFactoryTrait.php @@ -106,14 +106,14 @@ public function bucket( * @param int $buckets A positive 32-bit integer that specifies the number of buckets into which input documents are grouped. * @param Optional|Document|Serializable|array|stdClass $output A document that specifies the fields to include in the output documents in addition to the _id field. To specify the field to include, you must use accumulator expressions. * The default count field is not included in the output document when output is specified. Explicitly specify the count expression as part of the output document to include it. - * @param Optional|Document|Serializable|array|stdClass $granularity A string that specifies the preferred number series to use to ensure that the calculated boundary edges end on preferred round numbers or their powers of 10. + * @param Optional|string $granularity A string that specifies the preferred number series to use to ensure that the calculated boundary edges end on preferred round numbers or their powers of 10. * Available only if the all groupBy values are numeric and none of them are NaN. */ public function bucketAuto( Type|ExpressionInterface|stdClass|array|string|int|float|bool|null $groupBy, int $buckets, Optional|Document|Serializable|stdClass|array $output = Optional::Undefined, - Optional|Document|Serializable|stdClass|array $granularity = Optional::Undefined, + Optional|string $granularity = Optional::Undefined, ): static { $this->pipeline[] = Stage::bucketAuto($groupBy, $buckets, $output, $granularity); From fd8dd43cb3c0981f994bfecc04b08038c061888e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 08:46:05 +0100 Subject: [PATCH 6/7] Bump tests/specifications from `60fe09f` to `d9b434d` (#1574) Bumps [tests/specifications](https://github.com/mongodb/specifications) from `60fe09f` to `d9b434d`. - [Release notes](https://github.com/mongodb/specifications/releases) - [Commits](https://github.com/mongodb/specifications/compare/60fe09fc17a1963d683e904eb8b43f6675d77a1a...d9b434db87abec375df46864d4fedb2297bc80ec) --- updated-dependencies: - dependency-name: tests/specifications dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tests/specifications | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/specifications b/tests/specifications index 60fe09fc1..d9b434db8 160000 --- a/tests/specifications +++ b/tests/specifications @@ -1 +1 @@ -Subproject commit 60fe09fc17a1963d683e904eb8b43f6675d77a1a +Subproject commit d9b434db87abec375df46864d4fedb2297bc80ec From cfd8e75e7ede37dd916846553572e044918baae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 27 Jan 2025 14:23:51 +0100 Subject: [PATCH 7/7] Fix CS --- src/Exception/InvalidArgumentException.php | 2 ++ src/Operation/Find.php | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php index 1acc50eeb..c92734a0c 100644 --- a/src/Exception/InvalidArgumentException.php +++ b/src/Exception/InvalidArgumentException.php @@ -38,6 +38,8 @@ public static function cannotCombineCodecAndTypeMap(): self /** * Thrown when an argument or option is expected to be a string or a document. * + * @internal + * * @param string $name Name of the argument or option * @param mixed $value Actual value (used to derive the type) */ diff --git a/src/Operation/Find.php b/src/Operation/Find.php index df79703e6..8d84c7bf0 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -33,7 +33,6 @@ use function is_array; use function is_bool; use function is_integer; -use function is_object; use function is_string; use function MongoDB\is_document;