diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 910844cdd..4c7c8513f 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; @@ -102,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; @@ -113,6 +114,8 @@ class Builder extends BaseBuilder */ public $hint; + private ReadPreference $readPreference; + /** * Custom options to add to the query. * @@ -211,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 */ @@ -454,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) { @@ -1534,6 +1537,24 @@ 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; + } + /** * 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 +1663,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..2cc0c5764 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,31 @@ 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]), + ]; + + yield 'timeout' => [ + ['find' => [[], ['maxTimeMS' => 2345]]], + fn (Builder $builder) => $builder->timeout(2.3456), + ]; } #[DataProvider('provideExceptions')]