diff --git a/composer.json b/composer.json index bdd5486c..04555181 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ }, "require-dev": { "algolia/algoliasearch-client-php": "^3.2", - "typesense/typesense-php": "^4.9", + "typesense/typesense-php": "^4.9.2", "meilisearch/meilisearch-php": "^1.0", "mockery/mockery": "^1.0", "orchestra/testbench": "^7.31|^8.11|^9.0", diff --git a/src/Engines/TypesenseEngine.php b/src/Engines/TypesenseEngine.php index 943578c8..e4bedbab 100644 --- a/src/Engines/TypesenseEngine.php +++ b/src/Engines/TypesenseEngine.php @@ -11,8 +11,6 @@ use stdClass; use Typesense\Client as Typesense; use Typesense\Collection as TypesenseCollection; -use Typesense\Document; -use Typesense\Exceptions\ObjectNotFound; use Typesense\Exceptions\TypesenseClientError; class TypesenseEngine extends Engine @@ -66,7 +64,7 @@ public function update($models) $objects = $models->map(function ($model) { if (empty($searchableData = $model->toSearchableArray())) { - return; + return null; } return array_merge( @@ -86,7 +84,7 @@ public function update($models) /** * Import the given documents into the index. * - * @param \TypesenseCollection $collectionIndex + * @param TypesenseCollection $collectionIndex * @param array $documents * @param string $action * @return \Illuminate\Support\Collection @@ -156,7 +154,7 @@ public function delete($models) /** * Delete a document from the index. * - * @param \TypesenseCollection $collectionIndex + * @param TypesenseCollection $collectionIndex * @param mixed $modelId * @return array * @@ -487,7 +485,7 @@ public function deleteIndex($name) * Get collection from model or create new one. * * @param \Illuminate\Database\Eloquent\Model $model - * @return \TypesenseCollection + * @return TypesenseCollection * * @throws \Typesense\Exceptions\TypesenseClientError * @throws \Http\Client\Exception @@ -496,25 +494,23 @@ protected function getOrCreateCollectionFromModel($model): TypesenseCollection { $index = $this->typesense->getCollections()->{$model->searchableAs()}; - try { - $index->retrieve(); - + if ($index->exists() === true) { return $index; - } catch (ObjectNotFound $exception) { - $schema = config('scout.typesense.model-settings.'.get_class($model).'.collection-schema') ?? []; + } - if (method_exists($model, 'typesenseCollectionSchema')) { - $schema = $model->typesenseCollectionSchema(); - } + $schema = config('scout.typesense.model-settings.'.get_class($model).'.collection-schema') ?? []; - if (! isset($schema['name'])) { - $schema['name'] = $model->searchableAs(); - } - - $this->typesense->getCollections()->create($schema); + if (method_exists($model, 'typesenseCollectionSchema')) { + $schema = $model->typesenseCollectionSchema(); + } - return $this->typesense->getCollections()->{$model->searchableAs()}; + if (! isset($schema['name'])) { + $schema['name'] = $model->searchableAs(); } + + $this->typesense->getCollections()->create($schema); + + return $this->typesense->getCollections()->{$model->searchableAs()}; } /** diff --git a/tests/Integration/TypesenseSearchableTest.php b/tests/Integration/TypesenseSearchableTest.php new file mode 100644 index 00000000..30da065e --- /dev/null +++ b/tests/Integration/TypesenseSearchableTest.php @@ -0,0 +1,171 @@ +markTestSkipped(); + } + + $this->defineScoutEnvironment($app); + } + + /** + * Define database migrations. + * + * @return void + */ + protected function defineDatabaseMigrations() + { + $this->defineScoutDatabaseMigrations(); + } + + /** + * Perform any work that should take place once the database has finished refreshing. + * + * @return void + */ + protected function afterRefreshingDatabase() + { + $this->importScoutIndexFrom(User::class); + } + + public function test_it_can_use_basic_search() + { + $results = $this->itCanUseBasicSearch(); + + $this->assertSame([ + 11 => 'Larry Casper', + 1 => 'Laravel Framework', + 44 => 'Amos Larson Sr.', + 43 => 'Dana Larson Sr.', + 42 => 'Dax Larkin', + 41 => 'Gudrun Larkin', + 40 => 'Otis Larson MD', + 39 => 'Linkwood Larkin', + 20 => 'Prof. Larry Prosacco DVM', + 12 => 'Reta Larkin', + ], $results->pluck('name', 'id')->all()); + } + + public function test_it_can_use_basic_search_with_query_callback() + { + $results = $this->itCanUseBasicSearchWithQueryCallback(); + + $this->assertSame([ + 1 => 'Laravel Framework', + 44 => 'Amos Larson Sr.', + 43 => 'Dana Larson Sr.', + 42 => 'Dax Larkin', + 41 => 'Gudrun Larkin', + 40 => 'Otis Larson MD', + 12 => 'Reta Larkin', + ], $results->pluck('name', 'id')->all()); + } + + public function test_it_can_use_basic_search_to_fetch_keys() + { + $results = $this->itCanUseBasicSearchToFetchKeys(); + + $this->assertSame([ + '11', + '1', + '44', + '43', + '42', + '41', + '40', + '39', + '20', + '12', + ], $results->all()); + } + + public function test_it_can_use_basic_search_with_query_callback_to_fetch_keys() + { + $results = $this->itCanUseBasicSearchWithQueryCallbackToFetchKeys(); + + $this->assertSame([ + '11', + '1', + '44', + '43', + '42', + '41', + '40', + '39', + '20', + '12', + ], $results->all()); + } + + public function test_it_return_same_keys_with_query_callback() + { + $this->assertSame( + $this->itCanUseBasicSearchToFetchKeys()->all(), + $this->itCanUseBasicSearchWithQueryCallbackToFetchKeys()->all() + ); + } + + public function test_it_can_use_paginated_search() + { + [$page1, $page2] = $this->itCanUsePaginatedSearch(); + + $this->assertSame([ + 11 => 'Larry Casper', + 1 => 'Laravel Framework', + 44 => 'Amos Larson Sr.', + 43 => 'Dana Larson Sr.', + 42 => 'Dax Larkin', + ], $page1->pluck('name', 'id')->all()); + + $this->assertSame([ + 41 => 'Gudrun Larkin', + 40 => 'Otis Larson MD', + 39 => 'Linkwood Larkin', + 20 => 'Prof. Larry Prosacco DVM', + 12 => 'Reta Larkin', + ], $page2->pluck('name', 'id')->all()); + } + + public function test_it_can_use_paginated_search_with_query_callback() + { + [$page1, $page2] = $this->itCanUsePaginatedSearchWithQueryCallback(); + + $this->assertSame([ + 1 => 'Laravel Framework', + 44 => 'Amos Larson Sr.', + 43 => 'Dana Larson Sr.', + 42 => 'Dax Larkin', + ], $page1->pluck('name', 'id')->all()); + + $this->assertSame([ + 41 => 'Gudrun Larkin', + 40 => 'Otis Larson MD', + 12 => 'Reta Larkin', + ], $page2->pluck('name', 'id')->all()); + } + + protected static function scoutDriver(): string + { + return 'typesense'; + } +}