-
-
Notifications
You must be signed in to change notification settings - Fork 504
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
Add sort operator to $search stage #2554
Changes from 2 commits
a5745bf
9490058
6fa3a0c
b0f2ba5
9ab1b97
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,8 +10,15 @@ | |
use Doctrine\ODM\MongoDB\Aggregation\Stage\Search\SupportsAllSearchOperators; | ||
use Doctrine\ODM\MongoDB\Aggregation\Stage\Search\SupportsAllSearchOperatorsTrait; | ||
|
||
use function in_array; | ||
use function is_array; | ||
use function is_string; | ||
use function strtolower; | ||
|
||
/** | ||
* @psalm-type CountType = 'lowerBound'|'total' | ||
* @psalm-type SortMetaKeywords = 'searchScore' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks odd, name suggests there can be multiple keywords yet this is a string. Is this coming from MongoDB itself? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I used the same strategy we use in the |
||
* @psalm-type SortMeta = array{'$meta': SortMetaKeywords} | ||
* @psalm-type SearchStageExpression = array{ | ||
* '$search': object{ | ||
* index?: string, | ||
|
@@ -25,6 +32,7 @@ | |
* maxNumPassages?: int, | ||
* }, | ||
* returnStoredSource?: bool, | ||
* sort?: object, | ||
* autocomplete?: object, | ||
* compound?: object, | ||
* embeddedDocument?: object, | ||
|
@@ -53,6 +61,9 @@ class Search extends Stage implements SupportsAllSearchOperators | |
private ?bool $returnStoredSource = null; | ||
private ?SearchOperator $operator = null; | ||
|
||
/** @var array<string, -1|1|SortMeta> */ | ||
private array $sort = []; | ||
|
||
public function __construct(Builder $builder) | ||
{ | ||
parent::__construct($builder); | ||
|
@@ -79,6 +90,10 @@ public function getExpression(): array | |
$params->returnStoredSource = $this->returnStoredSource; | ||
} | ||
|
||
if ($this->sort) { | ||
$params->sort = (object) $this->sort; | ||
} | ||
|
||
if ($this->operator !== null) { | ||
$operatorName = $this->operator->getOperatorName(); | ||
$params->$operatorName = $this->operator->getOperatorParams(); | ||
|
@@ -128,6 +143,27 @@ public function returnStoredSource(bool $returnStoredSource = true): static | |
return $this; | ||
} | ||
|
||
public function sort($fieldName, $order = null): static | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add PHPDoc, especially given multiple meanings of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This all grew out of the query builder, which allows for precisely that: $builder
->sort('foo', 1)
->sort('bar', -1);
// Equivalent to the above
$builder
->sort(['foo' => 1, 'bar' => -1]); I've kept this strategy when creating the egg builder, and now it continues in the In the new aggregation pipeline builder we're creating we're instead leveraging named arguments for this: Stage::sort(foo: 1, bar: -1) Long story short, this is going to change once the MongoDB-supported builder is stable enough for us to use it underneath and deprecate ODM's builder :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
this looks nice :) looking forward to it! |
||
{ | ||
$allowedMetaSort = ['searchScore']; | ||
|
||
$fields = is_array($fieldName) ? $fieldName : [$fieldName => $order]; | ||
|
||
foreach ($fields as $fieldName => $order) { | ||
if (is_string($order)) { | ||
if (in_array($order, $allowedMetaSort, true)) { | ||
$order = ['$meta' => $order]; | ||
} else { | ||
$order = strtolower($order) === 'asc' ? 1 : -1; | ||
} | ||
} | ||
|
||
$this->sort[$fieldName] = $order; | ||
} | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* @param T $operator | ||
* | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,11 @@ public function returnStoredSource(bool $returnStoredSource): Search | |
return $this->search->returnStoredSource($returnStoredSource); | ||
} | ||
|
||
public function sort($fieldName, $order = null): Search | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PHPDoc is missing here too |
||
{ | ||
return $this->search->sort($fieldName, $order); | ||
} | ||
|
||
/** | ||
* @return array<string, object> | ||
* @psalm-return non-empty-array<non-empty-string, object> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's wrong with native return type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
sort
method for aSearch
stage does not return a sort stage, but handles this internally. We've had this with other stages (e.g.GeoNear::limit
), but I believe I can still use a native type ofStage
and refine it using the@return
annotation.