Skip to content

PHPORM-90 Fix whereNot to use $nor #2624

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

Merged
merged 2 commits into from
Sep 19, 2023
Merged

Conversation

GromNaN
Copy link
Member

@GromNaN GromNaN commented Sep 18, 2023

Fix #2623 #2418 PHPORM-90

$not cannot be used with an expression. I switched to $nor, that negates a list of expressions.

The query could be optimized, but I expect the mongo server to be smart enough to do it.

Example of optimization I chose not to do because that would require to detect when there is a single field expression (related to GromNaN/laravel-mongodb#13 (comment))

This expression:

{ field: { operator: value } }

Is negated with:

{ $nor: [ { field: { operator: value } } ] }

While it could also be:

{ field: { $not: { operator: value } }

@GromNaN GromNaN requested review from jmikola and alcaeus September 18, 2023 19:50
@codecov-commenter

This comment was marked as resolved.

if (str_ends_with($where['boolean'], 'not')) {
$result = ['$not' => $result];
$result = ['$nor' => [$result]];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see PHPORM-90 linked to anything. This this bug predate us taking over the library, or was it introduced during some recent query refactoring? If the latter, we should link it up.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented whereNot in GromNaN/laravel-mongodb#13. The issue PHPORM-49 is now linked in Jira.

@@ -1053,8 +1053,9 @@ protected function compileWheres(): array
$method = 'compileWhere' . $where['type'];
$result = $this->{$method}($where);

// Negate the expression
Copy link
Member

@jmikola jmikola Sep 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is $result always going to be an <expression> at this point, and never an <operator-expression> as it expected by $not?

This is related to my other comment, in that I'm curious how this wasn't discovered sooner unless it was only recently introduced. This also hints at a gap in functional test coverage running generated queries on a live server.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, compileWhere* function always return expressions with $and, $or or a field name, and now $nor.

{
// implicit equality operator
$users = User::whereNot('title', 'admin')->get();
$this->assertCount(6, $users);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is failing if I run it on version 3.9.3: the generated query was { title: 'admin' }, which is wrong because it ignore the negation.
In the current master, the query is { $not: { title: 'admin' } }, which is invalid and rejected by the server.
With this patch, the working query is { $nor: [ { title: 'admin' } ] }.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewing the generated query was { title: 'admin' }, which is wrong because it ignore the negation.

I'm not sure if I realized this when originally reviewing PHPORM-49, but the fact that earlier versions completely ignored negations with no feedback to the user sounds like pretty disastrous bug.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like someone asked for this feature: #2418

@@ -1053,8 +1053,9 @@ protected function compileWheres(): array
$method = 'compileWhere' . $where['type'];
$result = $this->{$method}($where);

// Negate the expression
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, compileWhere* function always return expressions with $and, $or or a field name, and now $nor.

if (str_ends_with($where['boolean'], 'not')) {
$result = ['$not' => $result];
$result = ['$nor' => [$result]];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented whereNot in GromNaN/laravel-mongodb#13. The issue PHPORM-49 is now linked in Jira.

@GromNaN GromNaN requested a review from jmikola September 19, 2023 13:03
@GromNaN GromNaN mentioned this pull request Sep 19, 2023
@GromNaN GromNaN merged commit 7880990 into mongodb:master Sep 19, 2023
@GromNaN GromNaN deleted the PHPORM-90 branch September 19, 2023 13:39
@GromNaN GromNaN added this to the 4.0 milestone Nov 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Error executing whereNot
4 participants