Skip to content

Commit

Permalink
WIP tests
Browse files Browse the repository at this point in the history
  • Loading branch information
GromNaN committed Nov 14, 2024
1 parent 3ee6cf1 commit 6b3524a
Show file tree
Hide file tree
Showing 4 changed files with 390 additions and 40 deletions.
64 changes: 49 additions & 15 deletions src/Scout/ScoutEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use MongoDB\Exception\Exception;
use MongoDB\Exception\RuntimeException;
use Traversable;
use TypeError;

use function array_column;
use function array_filter;
Expand All @@ -32,9 +33,13 @@
use function assert;
use function call_user_func;
use function class_uses_recursive;
use function get_debug_type;
use function hrtime;
use function in_array;
use function is_array;
use function is_int;
use function is_iterable;
use function is_string;
use function iterator_to_array;
use function preg_quote;
use function sleep;
Expand Down Expand Up @@ -84,7 +89,7 @@ public function update($models)
return;
}

$collection = $this->getCollection($models);
$collection = $this->getIndexableCollection($models);

if ($this->softDelete && $this->usesSoftDelete($models)) {
$models->each->pushSoftDeleteMetadata();

Check failure

Code scanning / PHPStan

Call to an undefined method Illuminate\Support\HigherOrderCollectionProxy<(int|string), Illuminate\Database\Eloquent\Model>::pushSoftDeleteMetadata(). Error

Call to an undefined method Illuminate\Support\HigherOrderCollectionProxy<(int|string), Illuminate\Database\Eloquent\Model>::pushSoftDeleteMetadata().
Expand All @@ -102,8 +107,8 @@ public function update($models)
'updateOne' => [
['_id' => $model->getScoutKey()],
[
'$set' => array_merge($searchableData, $model->scoutMetadata()),
'$setOnInsert' => ['_id' => $model->getScoutKey()],
'$set' => array_merge($searchableData, $model->scoutMetadata()),
],
['upsert' => true],
],
Expand All @@ -123,15 +128,15 @@ public function update($models)
*/
public function delete($models): void
{
assert($models instanceof Collection, new TypeError(sprintf('Argument #1 ($models) must be of type %s, %s given', Collection::class, get_debug_type($models))));

if ($models->isEmpty()) {
return;
}

$collection = $this->mongodb->getCollection($models);
$ids = array_map(fn (Model $model) => $model->getScoutKey(), $models->toArray());
$collection->deleteMany([
'_id' => ['$in' => $ids],
]);
$collection = $this->getIndexableCollection($models);
$ids = $models->map(fn (Model $model) => $model->getScoutKey())->all();
$collection->deleteMany(['_id' => ['$in' => $ids]]);
}

/**
Expand All @@ -157,6 +162,9 @@ public function search(Builder $builder)
*/
public function paginate(Builder $builder, $perPage, $page)
{
assert(is_int($perPage), new TypeError(sprintf('Argument #2 ($perPage) must be of type int, %s given', get_debug_type($perPage))));
assert(is_int($page), new TypeError(sprintf('Argument #3 ($page) must be of type int, %s given', get_debug_type($page))));

return $this->performSearch($builder, array_filter([
'filters' => $this->filters($builder),
'limit' => (int) $perPage,
Expand All @@ -169,7 +177,7 @@ public function paginate(Builder $builder, $perPage, $page)
*/
protected function performSearch(Builder $builder, array $searchParams = []): array
{
$collection = $this->getCollection($builder->model);
$collection = $this->getSearchableCollection($builder->model);

if ($builder->callback) {
$result = call_user_func(
Expand Down Expand Up @@ -242,6 +250,8 @@ protected function filters(Builder $builder): array
*/
public function mapIds($results): Collection
{
assert(is_array($results), new TypeError(sprintf('Argument #1 ($results) must be of type array, %s given', get_debug_type($results))));

return new Collection(array_column($results, '_id'));
}

Expand All @@ -253,6 +263,9 @@ public function mapIds($results): Collection
*/
public function map(Builder $builder, $results, $model): Collection
{
assert(is_array($results), new TypeError(sprintf('Argument #2 ($results) must be of type array, %s given', get_debug_type($results))));
assert($model instanceof Model, new TypeError(sprintf('Argument #3 ($model) must be of type %s, %s given', Model::class, get_debug_type($model))));

if (! $results) {
return $model->newCollection();
}
Expand Down Expand Up @@ -287,22 +300,27 @@ public function getTotalCount($results): int
*/
public function flush($model): void
{
$collection = $this->getCollection($model);
assert($model instanceof Model, new TypeError(sprintf('Argument #1 ($model) must be of type %s, %s given', Model::class, get_debug_type($model))));

$collection = $this->getIndexableCollection($model);

$collection->deleteMany([]);
}

/**
* Map the given results to instances of the given model via a lazy collection.
*
* @param Builder $builder
* @param mixed $results
* @param Model $model
* @param Builder $builder
* @param array|Cursor $results
* @param Model $model
*
* @return LazyCollection
*/
public function lazyMap(Builder $builder, $results, $model)
public function lazyMap(Builder $builder, $results, $model): LazyCollection
{
assert($results instanceof Cursor || is_array($results), new TypeError(sprintf('Argument #2 ($results) must be of type %s|array, %s given', Cursor::class, get_debug_type($results))));
assert($model instanceof Model, new TypeError(sprintf('Argument #3 ($model) must be of type %s, %s given', Model::class, get_debug_type($model))));

if (! $results) {
return LazyCollection::make($model->newCollection());
}
Expand Down Expand Up @@ -341,6 +359,8 @@ public function lazyMap(Builder $builder, $results, $model)
*/
public function createIndex($name, array $options = []): void
{
assert(is_string($name), new TypeError(sprintf('Argument #1 ($name) must be of type string, %s given', get_debug_type($name))));

$this->performSearchIndexOperation(function () use ($name, $options) {
$this->mongodb->createCollection($name);
$collection = $this->mongodb->selectCollection($name);
Expand Down Expand Up @@ -375,6 +395,8 @@ public function createIndex($name, array $options = []): void
*/
public function deleteIndex($name): void
{
assert(is_string($name), new TypeError(sprintf('Argument #1 ($name) must be of type string, %s given', get_debug_type($name))));

$this->mongodb->selectCollection($name)->drop();
}

Expand All @@ -394,8 +416,8 @@ public function deleteAllIndexes()
}
}

/** Get the MongoDB collection used as search index for the provided model */
private function getCollection(Model|EloquentCollection $model): MongoDBCollection
/** Get the MongoDB collection used to search for the provided model */
private function getSearchableCollection(Model|EloquentCollection $model): MongoDBCollection
{
if ($model instanceof EloquentCollection) {
$model = $model->first();
Expand All @@ -406,6 +428,18 @@ private function getCollection(Model|EloquentCollection $model): MongoDBCollecti
return $this->mongodb->selectCollection($model->searchableAs());
}

/** Get the MongoDB collection used to index the provided model */
private function getIndexableCollection(Model|EloquentCollection $model): MongoDBCollection
{
if ($model instanceof EloquentCollection) {
$model = $model->first();
}

assert(in_array(Searchable::class, class_uses_recursive($model)), sprintf('Model "%s" must use "%s" trait', $model::class, Searchable::class));

return $this->mongodb->selectCollection($model->indexableAs());
}

private static function serialize(mixed $value): mixed
{
if ($value instanceof DateTimeInterface) {
Expand Down
34 changes: 34 additions & 0 deletions tests/Models/SearchableModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace MongoDB\Laravel\Tests\Models;

use Laravel\Scout\Searchable;
use MongoDB\Laravel\Eloquent\Model as Eloquent;
use MongoDB\Laravel\Eloquent\SoftDeletes;

class SearchableModel extends Eloquent
{
use Searchable;
use SoftDeletes;

protected $connection = 'sqlite';
protected $table = 'searchable';
protected static $unguarded = true;

public function searchableAs(): string
{
return 'table_searchable';
}

public function indexableAs(): string
{
return 'table_indexable';
}

public function getScoutKey(): string
{
return 'key_' . $this->id;
}
}
Loading

0 comments on commit 6b3524a

Please sign in to comment.