Skip to content

[9.x] Add $limit to latest() and oldest() #39006

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

Closed
wants to merge 1 commit into from

Conversation

shaedrich
Copy link
Contributor

Adding $limit param to Builder::latest() and Builder::oldest() is just a shortcut but it'll be quite intuitive:

Instead of

$query->latest('id')->take(5)->get();

we can just say

$query->latest('id', 5)->get();

which translates to: "Get the latest five entries ordered by ID column"

Alternatives

Instead of having to pass null for the first parameter or using named parameters, every time, we want to use only the second parameter, we could check for the data type to implement method overloading but I'm not sure if that is needed since users could use named parameters instead.

   /**
     * Add an "order by" clause for a timestamp to the query.
     *
     * @param  string|\Illuminate\Database\Query\Expression  $column
     * @param  int $limit
     * @return $this
     */
    public function latest($column = null, $limit = null)
    {
        [$column, $limit] = $this->query->prepareValueAndOperator(
            func_get_args()
        );

        if (is_null($column)) {
            $column = $this->model->getCreatedAtColumn() ?? 'created_at';
        }

        if (!is_null($limit)) {
            $this->query->limit($limit);   
        }

        $this->query->latest($column);

        return $this;
    }

    /**
     * Add an "order by" clause for a timestamp to the query.
     *
     * @param  string|\Illuminate\Database\Query\Expression  $column
     * @param  int $limit
     * @return $this
     */
    public function oldest($column = null, $limit = null)
    {
        [$column, $limit] = $this->query->prepareValueAndOperator(
            func_get_args()
        );

        if (is_null($column)) {
            $column = $this->model->getCreatedAtColumn() ?? 'created_at';
        }

        if (!is_null($limit)) {
            $this->query->limit($limit);   
        }

        $this->query->oldest($column);

        return $this;
    }

    /**
     * Prepare the value and operator for a where clause.
     *
     * @param array  $params
     * @return array
     *
     * @throws \InvalidArgumentException
     */
    private function prepareOrderByLimitParameters(array $params)
    {
        if (count($params)) {
            return $params;
        }

        if (is_string($params[0]) {
            return [ $params[0], null ];
        } else if (is_numeric($params[0]) {
            return [ null, $params[0];
        }

        throw new InvalidArgumentException('Illegal column and limit combination.');
    }

@staudenmeir
Copy link
Contributor

staudenmeir commented Sep 28, 2021

IMO, that's kind of a dangerous parameter because it breaks eager loading when being applied to relationships. As mentioned in the docs, eager loading queries don't work with limits (laravel/docs#4918, #26035) and I can imagine that's easy to miss with a parameter like this.

@shaedrich
Copy link
Contributor Author

Oh, okay. Good point. Thanks for the hint, Jonas!

There is probably no way to prevent breaking eager loading in this scenario, is there?

@staudenmeir
Copy link
Contributor

We probably could detect eager loading and not apply the limit but that would be way too much hidden magic IMO.

@shaedrich
Copy link
Contributor Author

shaedrich commented Sep 28, 2021

@staudenmeir Okay, thank you nonetheless

That change doesn't fit into your staudenmeir/eloquent-eager-limit package for chance?

@shaedrich shaedrich closed this Sep 28, 2021
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.

2 participants