8000 PHPORM-47 Improve Builder::whereBetween to support CarbonPeriod and reject invalid array by GromNaN · Pull Request #10 · GromNaN/laravel-mongodb · GitHub
[go: up one dir, main page]

Skip to content
This repository was archived by the owner on Aug 22, 2023. It is now read-only.

PHPORM-47 Improve Builder::whereBetween to support CarbonPeriod and reject invalid array #10

Merged
merged 8 commits into from
Jul 19, 2023

Conversation

GromNaN
Copy link
Owner
@GromNaN GromNaN commented Jul 12, 2023

Fix PHPORM-47

The Query\Builder::whereBetween() method can be used like this:

whereBetween('date_field', [min, max])
whereBetween('date_field', collect([min, max]))
whereBetween('date_field', CarbonPeriod)

Laravel allows other formats: the $values array is flatten and the builder assumes there are at least 2 elements and ignore the others. It's a design that can lead to misunderstandings. I prefer to raise an exception when we have incorrect values, rather than trying to guess what the developer would like to do.

Support for CarbonPeriod was fixed in Laravel 10: laravel/framework#46720 because the query builder was taking the 1st 2 values of the iterator instead of the start & end dates.

Copy link
Collaborator
@alcaeus alcaeus left a comment

Choose a reason for hiding this comment

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

Changes LGTM. Just a couple of suggestions around exceptions and formatting for complex expectations.

Comment on lines 569 to 574
if (! array_is_list($values)) {
throw new \InvalidArgumentException('Between $values must be a list with exactly two elements: [min, max]');
}
if (count($values) !== 2) {
throw new \InvalidArgumentException('Between $values must have exactly two elements: [min, max]');
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

The first message does a good job at explaining the expected format, but the second one is less clear about it. I suggest combining these two cases into a single conditional:

Suggested change
if (! array_is_list($values)) {
throw new \InvalidArgumentException('Between $values must be a list with exactly two elements: [min, max]');
}
if (count($values) !== 2) {
throw new \InvalidArgumentException('Between $values must have exactly two elements: [min, max]');
}
if (! array_is_list($values) || count($values) !== 2) {
throw new \InvalidArgumentException('Between $values must be a list with exactly two elements: [min, max]');
}

Copy link
Owner Author
@GromNaN GromNaN Jul 13, 2023

Choose a reason for hiding this comment

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

I think it's a good place to use assert, because this check should be skipped for production.

        assert(
            !is_array($values) || array_is_list($values) && count($values) === 2,
           new \InvalidArgumentException('Between $values must be a list with exactly two elements: [min, max]')
        );

The exception will be throw exactly in the same way when assert is enabled (by default).

Copy link
Collaborator

Choose a reason for hiding this comment

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

While assert definitely is a good call for such code, I'm not sure Laravel users have this configured appropriately for development. Is this pattern used in other places in Laravel?

Copy link
Owner Author

Choose a reason for hiding this comment

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

I've not seen it used in Laravel codebase.

@GromNaN GromNaN force-pushed the PHPORM-47 branch 2 times, most recently from e0dd130 to 63ef1fa Compare July 13, 2023 08:07
@GromNaN GromNaN requested review from jmikola and alcaeus July 17, 2023 09:10
Copy link
Collaborator
@jmikola jmikola left a comment

Choose a reason for hiding this comment

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

Question about adding additional unit tests, but I expect those may not be necessary.

LGTM.

@@ -554,11 +555,20 @@ public function whereAll($column, array $values, $boolean = 'and', $not = false)

/**
* @inheritdoc
* @param array{mixed, mixed}|CarbonPeriod $values
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could a list shape be used here, or is this package not yet requiring Psalm 5?

]],
[], // options
]],
fn (Builder $builder) => $builder->whereNotBetween('id', [1, 2]),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Looking at this again, I don't understand why this flips the query into separate $lte and $gte ranges instead of wrapping whereBetween() with $not, but that's beyond the scope of this PR.

fn (Builder $builder) => $builder->whereBetween('id', [[1], [2, 3]]),
];

yield 'whereNotBetween array of numbers' => [
Copy link
Collaborator

Choose a reason for hiding this comment

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

It might make sense to move this below all of the whereBetween yield statements to keep things grouped by the method being tested.

Also, this appears to be the only whereNotBetween test. For orWhereNotBetween you also test "nested array of numbers" and "collection" (no "CarbonPeriod"). Should there be additional tests, or would those be redundant? It looks like the implementation of the "NotBetween" methods is outside of this package.

@GromNaN GromNaN merged commit cf103ba into master Jul 19, 2023
@GromNaN GromNaN deleted the PHPORM-47 branch July 19, 2023 08:39
GromNaN added a commit that referenced this pull request Aug 22, 2023
…eject invalid array (#10)

The Query\Builder::whereBetween() method can be used like this:

whereBetween('date_field', [min, max])
whereBetween('date_field', collect([min, max]))
whereBetween('date_field', CarbonPeriod)

Laravel allows other formats: the $values array is flatten and the builder assumes there are at least 2 elements and ignore the others. It's a design that can lead to misunderstandings. I prefer to raise an exception when we have incorrect values, rather than trying to guess what the developer would like to do.

Support for CarbonPeriod was fixed in Laravel 10: laravel/framework#46720 because the query builder was taking the 1st 2 values of the iterator instead of the start & end dates.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0