From bbf14b08611ffe7faf7a702a11e61d989f452b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 13 Jan 2025 16:38:04 +0100 Subject: [PATCH 1/2] PHPORM-209 Add query builder helper to set read preference --- src/Query/Builder.php | 32 ++++++++++++++++++++++++++++++++ tests/Query/BuilderTest.php | 21 +++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 910844cdd..b0e4f6b86 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -28,6 +28,7 @@ use MongoDB\Builder\Type\QueryInterface; use MongoDB\Builder\Type\SearchOperatorInterface; use MongoDB\Driver\Cursor; +use MongoDB\Driver\ReadPreference; use Override; use RuntimeException; use stdClass; @@ -113,6 +114,8 @@ class Builder extends BaseBuilder */ public $hint; + private ReadPreference $readPreference; + /** * Custom options to add to the query. * @@ -1534,6 +1537,31 @@ public function options(array $options) return $this; } + /** + * Set the read preference for the query + * + * @see https://www.php.net/manual/en/class.mongodb-driver-readpreference.php + * + * @param string $mode + * @param array $tagSets + * @param array $options + * + * @return $this + */ + public function readPreference(string $mode, ?array $tagSets = null, ?array $options = null): static + { + $this->readPreference = new ReadPreference($mode, $tagSets, $options); + + return $this; + } + + public function typeMap(array $typeMap): static + { + $this->options['typeMap'] = $typeMap; + + return $this; + } + /** * Performs a full-text search of the field or fields in an Atlas collection. * NOTE: $search is only available for MongoDB Atlas clusters, and is not available for self-managed deployments. @@ -1642,6 +1670,10 @@ private function inheritConnectionOptions(array $options = []): array } } + if (! isset($options['readPreference']) && isset($this->readPreference)) { + $options['readPreference'] = $this->readPreference; + } + return $options; } diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index 20f4a4db2..2644a39cf 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -15,6 +15,7 @@ use Mockery as m; use MongoDB\BSON\Regex; use MongoDB\BSON\UTCDateTime; +use MongoDB\Driver\ReadPreference; use MongoDB\Laravel\Connection; use MongoDB\Laravel\Query\Builder; use MongoDB\Laravel\Query\Grammar; @@ -1416,6 +1417,26 @@ function (Builder $elemMatchQuery): void { ['find' => [['embedded._id' => 1], []]], fn (Builder $builder) => $builder->where('embedded->id', 1), ]; + + yield 'options' => [ + ['find' => [[], ['comment' => 'hello']]], + fn (Builder $builder) => $builder->options(['comment' => 'hello']), + ]; + + yield 'readPreference' => [ + ['find' => [[], ['readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED)]]], + fn (Builder $builder) => $builder->readPreference(ReadPreference::SECONDARY_PREFERRED), + ]; + + yield 'readPreference advanced' => [ + ['find' => [[], ['readPreference' => new ReadPreference(ReadPreference::NEAREST, [['dc' => 'ny']], ['maxStalenessSeconds' => 120])]]], + fn (Builder $builder) => $builder->readPreference(ReadPreference::NEAREST, [['dc' => 'ny']], ['maxStalenessSeconds' => 120]), + ]; + + yield 'hint' => [ + ['find' => [[], ['hint' => ['foo' => 1]]]], + fn (Builder $builder) => $builder->hint(['foo' => 1]), + ]; } #[DataProvider('provideExceptions')] From b9d6867b840aad55a608fa2571dd51fc0406a977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 13 Jan 2025 16:40:42 +0100 Subject: [PATCH 2/2] Support query timeout as decimal number of seconds --- src/Query/Builder.php | 13 +++---------- tests/Query/BuilderTest.php | 5 +++++ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Query/Builder.php b/src/Query/Builder.php index b0e4f6b86..4c7c8513f 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -103,7 +103,7 @@ class Builder extends BaseBuilder /** * The maximum amount of seconds to allow the query to run. * - * @var int + * @var int|float */ public $timeout; @@ -214,7 +214,7 @@ public function project($columns) /** * The maximum amount of seconds to allow the query to run. * - * @param int $seconds + * @param int|float $seconds * * @return $this */ @@ -457,7 +457,7 @@ public function toMql(): array // Apply order, offset, limit and projection if ($this->timeout) { - $options['maxTimeMS'] = $this->timeout * 1000; + $options['maxTimeMS'] = (int) ($this->timeout * 1000); } if ($this->orders) { @@ -1555,13 +1555,6 @@ public function readPreference(string $mode, ?array $tagSets = null, ?array $opt return $this; } - public function typeMap(array $typeMap): static - { - $this->options['typeMap'] = $typeMap; - - return $this; - } - /** * Performs a full-text search of the field or fields in an Atlas collection. * NOTE: $search is only available for MongoDB Atlas clusters, and is not available for self-managed deployments. diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index 2644a39cf..2cc0c5764 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -1437,6 +1437,11 @@ function (Builder $elemMatchQuery): void { ['find' => [[], ['hint' => ['foo' => 1]]]], fn (Builder $builder) => $builder->hint(['foo' => 1]), ]; + + yield 'timeout' => [ + ['find' => [[], ['maxTimeMS' => 2345]]], + fn (Builder $builder) => $builder->timeout(2.3456), + ]; } #[DataProvider('provideExceptions')]