algolia / scout-extended

Scout Extended: The Full Power of Algolia in Laravel
https://www.algolia.com/doc/framework-integration/laravel/getting-started/introduction-to-scout-extended/
MIT License
393 stars 85 forks source link

Scout `lazyMap` method not implemented, returns no results #298

Closed bakerkretzmar closed 2 years ago

bakerkretzmar commented 2 years ago

Description

Laravel Scout has a companion method to map, lazyMap, which uses a generator under the hood to keep memory usage low. That lazyMap method doesn't play nicely with Scout Extended, in basically the same way as the underlying issue in #279—it uses Algolia's objectID to retrieve models, which it expects to be the actual model key, but which with Scout Extended installed is actually something like App\Event::20.

The map method does this too, but Scout Extended overrides it and accounts for the primary key thing inside the ModelsResolver class.

I can't switch to using the map method because the code calling lazyMap is inside Laravel Nova, in the global search code. I'll file an issue there too.

Ideally Scout Extended would also override lazyMap, with functionality similar to map but returning a generator or lazy collection if possible. I'll try to take a crack at a PR for that in the next week or two.

In the meantime, for anyone else running into this, I managed to work around it by overriding the Laravel\Nova\Query\Builder class:

// In the `register` method of `app/Providers/NovaServiceProvider.php`

use App\Nova\Builder;
use Laravel\Nova\Contracts\QueryBuilder;

$this->app->bind(QueryBuilder::class, fn ($app, $parameters) => new Builder(...$parameters));

// `app/Nova/Builder.php`

use Illuminate\Support\LazyCollection;
use Laravel\Nova\Query\Builder as Nova;

class Builder extends Nova
{
    public function cursor()
    {
        $queryBuilder = $this->applyQueryCallbacks($this->queryBuilder);

        // Remove or comment out this part
        // if (method_exists($queryBuilder, 'cursor')) {
        //     return $queryBuilder->cursor();
        // }

        return LazyCollection::make(function () use ($queryBuilder) {
            yield from $queryBuilder->get()
                ->each(function ($result) {
                    yield $result;
                });
        });
    }
}
DevinCodes commented 2 years ago

Hi @bakerkretzmar ,

Thank you for reporting this. Feel free to assign me to your PR once it's open so I can review and release 🙂

Cheers!