Skip to content

[7.0] Fix engine results order #369

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

Merged
merged 3 commits into from
Apr 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Engines/AlgoliaEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ public function map(Builder $builder, $results, $model)
$builder, $objectIds
)->filter(function ($model) use ($objectIds) {
return in_array($model->getScoutKey(), $objectIds);
})->sortBy(function($model) use ($objectIds) {
return array_search($model->getScoutKey(), $objectIds);
});
}

Expand Down
103 changes: 72 additions & 31 deletions tests/AlgoliaEngineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

namespace Laravel\Scout\Tests;

use stdClass;
use Mockery as m;
use Laravel\Scout\Builder;
use PHPUnit\Framework\TestCase;
use Algolia\AlgoliaSearch\SearchClient;
use Laravel\Scout\Engines\AlgoliaEngine;
use Laravel\Scout\Tests\Fixtures\SearchableModel;
use Illuminate\Database\Eloquent\Collection;
use Laravel\Scout\Tests\Fixtures\EmptyTestModel;
use Laravel\Scout\Tests\Fixtures\AlgoliaEngineTestModel;
use Laravel\Scout\Tests\Fixtures\AlgoliaEngineTestCustomKeyModel;

class AlgoliaEngineTest extends TestCase
{
Expand All @@ -20,51 +20,50 @@ public function tearDown()

public function test_update_adds_objects_to_index()
{
$client = m::mock('Algolia\AlgoliaSearch\SearchClient');
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock('StdClass'));
$client = m::mock(SearchClient::class);
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock(stdClass::class));
$index->shouldReceive('saveObjects')->with([[
'id' => 1,
'objectID' => 1,
]]);

$engine = new AlgoliaEngine($client);
$engine->update(Collection::make([new AlgoliaEngineTestModel]));
$engine->update(Collection::make([new SearchableModel]));
}

public function test_delete_removes_objects_to_index()
{
$client = m::mock('Algolia\AlgoliaSearch\SearchClient');
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock('StdClass'));
$client = m::mock(SearchClient::class);
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock(stdClass::class));
$index->shouldReceive('deleteObjects')->with([1]);

$engine = new AlgoliaEngine($client);
$engine->delete(Collection::make([new AlgoliaEngineTestModel]));
$engine->delete(Collection::make([new SearchableModel(['id' => 1])]));
}

public function test_search_sends_correct_parameters_to_algolia()
{
$client = m::mock('Algolia\AlgoliaSearch\SearchClient');
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock('StdClass'));
$client = m::mock(SearchClient::class);
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock(stdClass::class));
$index->shouldReceive('search')->with('zonda', [
'numericFilters' => ['foo=1'],
]);

$engine = new AlgoliaEngine($client);
$builder = new Builder(new AlgoliaEngineTestModel, 'zonda');
$builder = new Builder(new SearchableModel, 'zonda');
$builder->where('foo', 1);
$engine->search($builder);
}

public function test_map_correctly_maps_results_to_models()
{
$client = m::mock('Algolia\AlgoliaSearch\SearchClient');
$client = m::mock(SearchClient::class);
$engine = new AlgoliaEngine($client);

$model = m::mock('StdClass');
$model->shouldReceive('newQuery')->andReturn($model);
$model->shouldReceive('getKeyName')->andReturn('id');
$model->shouldReceive('getScoutModelsByIds')->andReturn($models = Collection::make([new AlgoliaEngineTestModel]));
$model->shouldReceive('newCollection')->andReturn($models);
$model = m::mock(stdClass::class);
$model->shouldReceive('getScoutModelsByIds')->andReturn($models = Collection::make([
new SearchableModel(['id' => 1]),
]));

$builder = m::mock(Builder::class);

Expand All @@ -75,46 +74,88 @@ public function test_map_correctly_maps_results_to_models()
$this->assertEquals(1, count($results));
}

public function test_map_method_respects_order()
{
$client = m::mock(SearchClient::class);
$engine = new AlgoliaEngine($client);

$model = m::mock(stdClass::class);
$model->shouldReceive('getScoutModelsByIds')->andReturn($models = Collection::make([
new SearchableModel(['id' => 1]),
new SearchableModel(['id' => 2]),
new SearchableModel(['id' => 3]),
new SearchableModel(['id' => 4]),
]));

$builder = m::mock(Builder::class);

$results = $engine->map($builder, ['nbHits' => 4, 'hits' => [
['objectID' => 1, 'id' => 1],
['objectID' => 2, 'id' => 2],
['objectID' => 4, 'id' => 4],
['objectID' => 3, 'id' => 3],
]], $model);

$this->assertEquals(4, count($results));
$this->assertEquals([1, 2, 4, 3], $results->pluck('id')->all());
}

public function test_a_model_is_indexed_with_a_custom_algolia_key()
{
$client = m::mock('Algolia\AlgoliaSearch\SearchClient');
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock('StdClass'));
$client = m::mock(SearchClient::class);
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock(stdClass::class));
$index->shouldReceive('saveObjects')->with([[
'id' => 1,
'objectID' => 'my-algolia-key.1',
]]);

$engine = new AlgoliaEngine($client);
$engine->update(Collection::make([new AlgoliaEngineTestCustomKeyModel]));
$engine->update(Collection::make([new CustomKeySearchableModel]));
}

public function test_a_model_is_removed_with_a_custom_algolia_key()
{
$client = m::mock('Algolia\AlgoliaSearch\SearchClient');
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock('StdClass'));
$client = m::mock(SearchClient::class);
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock(stdClass::class));
$index->shouldReceive('deleteObjects')->with(['my-algolia-key.1']);

$engine = new AlgoliaEngine($client);
$engine->delete(Collection::make([new AlgoliaEngineTestCustomKeyModel]));
$engine->delete(Collection::make([new CustomKeySearchableModel(['id' => 1])]));
}

public function test_flush_a_model()
public function test_flush_a_model_with_a_custom_algolia_key()
{
$client = m::mock('Algolia\AlgoliaSearch\SearchClient');
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock('StdClass'));
$client = m::mock(SearchClient::class);
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock(stdClass::class));
$index->shouldReceive('clearObjects');

$engine = new AlgoliaEngine($client);
$engine->flush(new AlgoliaEngineTestCustomKeyModel);
$engine->flush(new CustomKeySearchableModel);
}

public function test_update_empty_searchable_array_does_not_add_objects_to_index()
{
$client = m::mock('Algolia\AlgoliaSearch\SearchClient');
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock('StdClass'));
$client = m::mock(SearchClient::class);
$client->shouldReceive('initIndex')->with('table')->andReturn($index = m::mock(stdClass::class));
$index->shouldNotReceive('saveObjects');

$engine = new AlgoliaEngine($client);
$engine->update(Collection::make([new EmptyTestModel]));
$engine->update(Collection::make([new EmptySearchableModel]));
}
}

class CustomKeySearchableModel extends SearchableModel
{
public function getScoutKey()
{
return 'my-algolia-key.'.$this->getKey();
}
}

class EmptySearchableModel extends SearchableModel
{
public function toSearchableArray()
{
return [];
}
}
11 changes: 0 additions & 11 deletions tests/Fixtures/AlgoliaEngineTestCustomKeyModel.php

This file was deleted.

8 changes: 0 additions & 8 deletions tests/Fixtures/AlgoliaEngineTestModel.php

This file was deleted.

11 changes: 0 additions & 11 deletions tests/Fixtures/EmptyTestModel.php

This file was deleted.

28 changes: 28 additions & 0 deletions tests/Fixtures/SearchableModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Laravel\Scout\Tests\Fixtures;

use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;

class SearchableModel extends Model
{
use Searchable;

/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['id'];

public function searchableAs()
{
return 'table';
}

public function scoutMetadata()
{
return [];
}
}
10 changes: 0 additions & 10 deletions tests/Fixtures/SearchableTestModel.php

This file was deleted.

39 changes: 0 additions & 39 deletions tests/Fixtures/TestModel.php

This file was deleted.

15 changes: 8 additions & 7 deletions tests/SearchableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

use Mockery as m;
use PHPUnit\Framework\TestCase;
use Laravel\Scout\Tests\Fixtures\SearchableTestModel;
use Illuminate\Database\Eloquent\Builder;
use Laravel\Scout\Tests\Fixtures\SearchableModel;

class SearchableTest extends TestCase
{
Expand All @@ -19,7 +20,7 @@ public function test_searchable_using_update_is_called_on_collection()
$collection->shouldReceive('isEmpty')->andReturn(false);
$collection->shouldReceive('first->searchableUsing->update')->with($collection);

$model = new SearchableTestModel;
$model = new SearchableModel();
$model->queueMakeSearchable($collection);
}

Expand All @@ -29,7 +30,7 @@ public function test_searchable_using_update_is_not_called_on_empty_collection()
$collection->shouldReceive('isEmpty')->andReturn(true);
$collection->shouldNotReceive('first->searchableUsing->update');

$model = new SearchableTestModel;
$model = new SearchableModel;
$model->queueMakeSearchable($collection);
}

Expand All @@ -39,7 +40,7 @@ public function test_searchable_using_delete_is_called_on_collection()
$collection->shouldReceive('isEmpty')->andReturn(false);
$collection->shouldReceive('first->searchableUsing->delete')->with($collection);

$model = new SearchableTestModel;
$model = new SearchableModel;
$model->queueRemoveFromSearch($collection);
}

Expand All @@ -49,7 +50,7 @@ public function test_searchable_using_delete_is_not_called_on_empty_collection()
$collection->shouldReceive('isEmpty')->andReturn(true);
$collection->shouldNotReceive('first->searchableUsing->delete');

$model = new SearchableTestModel;
$model = new SearchableModel;
$model->queueRemoveFromSearch($collection);
}

Expand All @@ -59,11 +60,11 @@ public function test_make_all_searchable_uses_order_by()
}
}

class ModelStubForMakeAllSearchable extends SearchableTestModel
class ModelStubForMakeAllSearchable extends SearchableModel
{
public function newQuery()
{
$mock = \Mockery::mock('Illuminate\Database\Eloquent\Builder');
$mock = m::mock(Builder::class);

$mock->shouldReceive('orderBy')
->with('id')
Expand Down