laravel-scout-array-driver icon indicating copy to clipboard operation
laravel-scout-array-driver copied to clipboard

Array driver doesn't support eloquent constraints

Open brendanpetty opened this issue 1 year ago • 4 comments
trafficstars

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?

brendanpetty avatar Jul 15 '24 03:07 brendanpetty

@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?

Sti3bas avatar Oct 09 '24 07:10 Sti3bas

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.

brendanpetty avatar Oct 10 '24 02:10 brendanpetty

@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']);
}

Sti3bas avatar Oct 10 '24 08:10 Sti3bas

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!).

brendanpetty avatar Oct 14 '24 02:10 brendanpetty