Sti3bas / laravel-scout-array-driver

Array driver for Laravel Scout
MIT License
89 stars 8 forks source link

Array driver doesn't support eloquent constraints #19

Open brendanpetty opened 4 months ago

brendanpetty commented 4 months ago

Using https://github.com/teamtnt/laravel-scout-tntsearch-driver/?tab=readme-ov-file#constraints e.g.

$constraints = Item::query(); $constraints->where('draft', false); Item::search($query)->constrain($constraints);

works normally, but fails when testing using this driver.

I'm guessing it's not possible to fix this, but maybe is worth a note / known-issue somewhere in the documentation?

Sti3bas commented 1 month ago

@brendanpetty it shouldn't fail since TNTSearch provides a macro for the Builder class and that is out of scope of array driver: https://github.com/teamtnt/laravel-scout-tntsearch-driver/blob/d57e4c92502ceb99154803aa1866cd3cf1a26604/src/TNTSearchScoutServiceProvider.php#L43

Could you please provide more information?

brendanpetty commented 1 month ago

I mean the test fails... the constraint is not applied if using array driver (as TNTSearch isn't instantiated to use that macro). All results pass through without this 'filtering'/constraining being applied in the testing environment.

Sti3bas commented 1 month ago

@brendanpetty yeah, array driver was not meant to implement other drivers specific features.

I'm currently working on a PR which would allow to fake response data and I think it would also be useful in this case.

Here is an example:

Controller method:

public function index(Request $request)
{
    $post = new Post;

    $constraints = $post->where('foo', 'bar');
    $post = Post::search($request->searchTerm)->constrain($constraints);

    return $post->paginate(10);
}

Test:

/** @test */
public function example()
{
    $constrain = null;

    Builder::macro('constrain', function ($constraints) use (&$constrain) {
        $constrain = $constraints;

        return $this;
    });

    Post::factory()->create(['id' => 1]);
    Post::factory()->create(['id' => 2]);
    Post::factory()->create(['id' => 3]);
    Post::factory()->create(['id' => 4]);

    Search::fakeResponseData([
        'hits' => [
            ['objectID' => 2],
            ['objectID' => 3],
        ]
    ])->query('test-query');

    $response = $this->getJson(route('posts.index', [
        'searchTerm' => 'test-query'
    ]));

    $response->assertOk();

    $this->assertNotNull($constrain);

    $fooClause = collect($constrain->getQuery()->wheres)->firstWhere(fn($clause) => $clause['column'] == 'foo');
    $this->assertNotNull($fooClause);
    $this->assertEquals('bar', $fooClause['value']);

    $this->assertCount(2, $response['data']);
    $this->assertEquals(2, $response['data'][0]['id']);
    $this->assertEquals(3, $response['data'][1]['id']);
}
brendanpetty commented 1 month ago

Thanks, that looks great. Some of my testing is also around the filtering logic, so I'm just going to use the actual search driver for those tests rather than the array driver. A bit more work, unlike the super easy config of your array driver (thanks!).