-
Notifications
You must be signed in to change notification settings - Fork 4
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
PHPLIB-1363 PHPLIB-1355 Add enum for $type
query and $meta
expression
#38
Conversation
$type
list
*/ | ||
enum QueryType: string implements OperatorInterface, FieldQueryInterface | ||
{ | ||
public const ENCODE = Encode::Array; |
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.
Is this the first time a BackedEnum is being used for an encoding type? If so, perhaps it'd be prudent to have BuilderEncoder::encode()
assert that that $value::ENCODE
is Encode::Array
(and you can revise that as needed should another use case come up).
That would address my question about how a BackedEnum might be handled for other switch
cases.
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.
We need to rework the whole encoder class. The "ENCODE" constant will not stay, it may become a method of the Operator interface.
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.
If this isn't already ticketed please do so and drop a reference to the issue.
9443998
to
2134961
Compare
@@ -32,7 +33,7 @@ public function testQueryingByDataType(): void | |||
zipCode: Query::type(2), | |||
), | |||
Stage::match( | |||
zipCode: Query::type('string'), | |||
zipCode: QueryType::String, |
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.
Huh, this is interesting. I had initially considered using an enum case as the argument for Query::type
, but this is interesting as well.
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.
I can customize the Query::type
factory to accept enum values and convert them to string if necessary.
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.
Not sure if that is necessary. This allows people to do whatever they want with the $type
operator, but provides a nice shorthand for all known types.
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.
I assume this only works because QueryType is both an enum and an OperatorInterface (and FieldQueryInterface in that it's associated with a field path). I assume this convenience only works for a single type check, though. Trying to match zipCode
with [QueryType::String, ...]
in order to match multiple types would produce invalid syntax, correct?
And that's where Query::type(...)
comes in.
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.
Per the Psalm error below, what enforces that OperatorInterface instances define an ENCODE
constant?
LGTM, but I think the various Psalm errors need correction.
src/Builder/BuilderEncoder.php
Outdated
@@ -129,6 +130,10 @@ public function encode($value): stdClass|array|string | |||
*/ | |||
private function encodeAsArray(OperatorInterface $value): stdClass | |||
{ | |||
if ($value instanceof BackedEnum) { | |||
return $this->wrap($value, [$value->value]); |
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.
Is the NoInterfaceProperties error below the result of Psalm failing to infer that BackedEnum has an implicit $value
property?
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.
Yes it looks like an issue in palm: vimeo/psalm#10585
phpstan don't have this issue: https://phpstan.org/r/e7094884-1adf-4369-b255-6c7e45367865
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.
How is this related to the NoInterfaceProperties warning earlier in encode()
? There, you're only checking for an instance of FieldPathInterface
and then accessing a $value
property. That seems incorrect for an entirely different reason.
@@ -32,7 +33,7 @@ public function testQueryingByDataType(): void | |||
zipCode: Query::type(2), | |||
), | |||
Stage::match( | |||
zipCode: Query::type('string'), | |||
zipCode: QueryType::String, |
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.
I assume this only works because QueryType is both an enum and an OperatorInterface (and FieldQueryInterface in that it's associated with a field path). I assume this convenience only works for a single type check, though. Trying to match zipCode
with [QueryType::String, ...]
in order to match multiple types would produce invalid syntax, correct?
And that's where Query::type(...)
comes in.
$type
list$type
query and $meta
expression
$type
query and $meta
expression$type
query and $meta
expression
* | ||
* @see https://www.mongodb.com/docs/manual/reference/operator/aggregation/meta/ | ||
*/ | ||
enum Meta: string implements OperatorInterface, ExpressionInterface |
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.
@alcaeus suggested to name it SortMeta
. #56 (comment)
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.
$meta: Behavior suggests the operator can be used in context beyond sorting, such as projections.
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 ExpressionInterface
allows to use it anywhere an expression is expected.
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.
Just realized I had some pending comments that were never posted. Doing so now.
src/Builder/BuilderEncoder.php
Outdated
@@ -129,6 +130,10 @@ public function encode($value): stdClass|array|string | |||
*/ | |||
private function encodeAsArray(OperatorInterface $value): stdClass | |||
{ | |||
if ($value instanceof BackedEnum) { | |||
return $this->wrap($value, [$value->value]); |
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.
How is this related to the NoInterfaceProperties warning earlier in encode()
? There, you're only checking for an instance of FieldPathInterface
and then accessing a $value
property. That seems incorrect for an entirely different reason.
*/ | ||
enum QueryType: string implements OperatorInterface, FieldQueryInterface | ||
{ | ||
public const ENCODE = Encode::Array; |
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.
If this isn't already ticketed please do so and drop a reference to the issue.
* | ||
* @see https://www.mongodb.com/docs/manual/reference/operator/aggregation/meta/ | ||
*/ | ||
enum Meta: string implements OperatorInterface, ExpressionInterface |
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.
$meta: Behavior suggests the operator can be used in context beyond sorting, such as projections.
* { $meta: "indexKey" } expression is for debugging purposes only, and | ||
* not for application logic, and is preferred over cursor.returnKey(). | ||
*/ | ||
case IndexKey = 'indexKey'; |
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.
Do the cases here preclude users from using this with additional modes? $meta: Definition mentions searchScore and searchHighlights for Atlas.
Rebased on top of #46 |
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.
Left some additional comments on the enum cases, and there are already a number of open comment threads from last week.
src/Builder/QueryType.php
Outdated
case JavaScript = 'javascript'; | ||
case Int = 'int'; | ||
case Timestamp = 'timestamp'; | ||
case Long = 'long'; |
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.
case Long = 'long'; | |
case Int64 = 'long'; |
This also leaves nothing to the imagination.
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.
It just occurred to me that you might have chosen these names to be consistent with the ExpressionFactoryTrait field path methods. Unless it was just the first column from the table in $type: Available Types.
In any event, you may want to keep the factory methods consistent with the enums here. And if factory methods will be distinguishing 32-bit and 64-bit integers, I do think explicit names with the bit size are more clear to users than "int" and "long".
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.
I updated all the type name to take more descriptive ones, from the BSON classes when they exist.
src/Builder/QueryType.php
Outdated
case Int = 'int'; | ||
case Timestamp = 'timestamp'; | ||
case Long = 'long'; | ||
case Decimal128 = 'decimal'; |
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.
I do think using the BSON class name was a good idea here, as users could confuse "decimal" with "double" if they didn't realize there was a specific type.
Closing for now. Lets revisit later. Ticket still open. |
Fix PHPLIB-1363
Fix PHPLIB-1355
The enum implements
FieldQueryInterface
so it can be used anywhere a field query is expected. Deprecated types have been skipped.List imported from the doc, including the alias
number
.Usage:
Limitation, it's not possible to use the enum in a list.