7
7
use DateTimeImmutable ;
8
8
use Illuminate \Database \Eloquent \Collection as EloquentCollection ;
9
9
use Laravel \Scout \Builder ;
10
+ use Laravel \Scout \Jobs \RemoveFromSearch ;
11
+ use Laravel \Scout \Tests \Unit \AlgoliaEngineTest ;
10
12
use Mockery as m ;
11
13
use MongoDB \BSON \Document ;
12
14
use MongoDB \BSON \Regex ;
20
22
use MongoDB \Model \BSONDocument ;
21
23
use PHPUnit \Framework \Attributes \DataProvider ;
22
24
25
+ use function serialize ;
26
+ use function unserialize ;
27
+
23
28
/** Unit tests that do not require an Atlas Search cluster */
24
29
class ScoutEngineTest extends TestCase
25
30
{
31
+ private const EXPECTED_SEARCH_OPTIONS = ['allowDiskUse ' => true , 'typeMap ' => ['root ' => 'object ' , 'document ' => 'array ' , 'array ' => 'array ' ]];
32
+
26
33
/** @param callable(): Builder $builder */
27
34
#[DataProvider('provideSearchPipelines ' )]
28
35
public function testSearch (Closure $ builder , array $ expectedPipeline ): void
@@ -36,8 +43,7 @@ public function testSearch(Closure $builder, array $expectedPipeline): void
36
43
$ cursor = m::mock (CursorInterface::class);
37
44
$ cursor ->shouldReceive ('toArray ' )->once ()->with ()->andReturn ($ data );
38
45
39
- $ options = ['allowDiskUse ' => true , 'typeMap ' => ['root ' => 'object ' , 'document ' => 'array ' , 'array ' => 'array ' ]];
40
- $ collection ->shouldReceive ('aggregate ' )->once ()->with ($ expectedPipeline , $ options )->andReturn ($ cursor );
46
+ $ collection ->shouldReceive ('aggregate ' )->once ()->with ($ expectedPipeline , self ::EXPECTED_SEARCH_OPTIONS )->andReturn ($ cursor );
41
47
42
48
$ engine = new ScoutEngine ($ database , softDelete: false , prefix: '' );
43
49
$ result = $ engine ->search ($ builder ());
@@ -157,6 +163,66 @@ function () {
157
163
158
164
public function testPaginate ()
159
165
{
166
+ $ perPage = 5 ;
167
+ $ page = 3 ;
168
+
169
+ $ database = m::mock (Database::class);
170
+ $ collection = m::mock (Collection::class);
171
+ $ cursor = m::mock (CursorInterface::class);
172
+ $ database ->shouldReceive ('selectCollection ' )
173
+ ->with ('table_searchable ' )
174
+ ->andReturn ($ collection );
175
+ $ collection ->shouldReceive ('aggregate ' )
176
+ ->once ()
177
+ ->withArgs (function (...$ args ) {
178
+ self ::assertSame ([
179
+ [
180
+ '$search ' => [
181
+ 'index ' => 'scout ' ,
182
+ 'text ' => [
183
+ 'query ' => 'mustang ' ,
184
+ 'path ' => [
185
+ 'wildcard ' => '* ' ,
186
+ ],
187
+ 'fuzzy ' => [
188
+ 'maxEdits ' => 2 ,
189
+ ],
190
+ ],
191
+ 'count ' => [
192
+ 'type ' => 'lowerBound ' ,
193
+ ],
194
+ 'sort ' => [
195
+ 'name ' => -1 ,
196
+ ],
197
+ ],
198
+ ],
199
+ [
200
+ '$addFields ' => [
201
+ 'search_meta ' => '$$SEARCH_META ' ,
202
+ ],
203
+ ],
204
+ [
205
+ '$limit ' => 5 ,
206
+ ],
207
+ [
208
+ '$skip ' => 10 ,
209
+ ],
210
+ ], $ args [0 ]);
211
+
212
+ $ this ->assertSame (self ::EXPECTED_SEARCH_OPTIONS , $ args [1 ]);
213
+
214
+ return true ;
215
+ })
216
+ ->andReturn ($ cursor );
217
+ $ cursor ->shouldReceive ('toArray ' )
218
+ ->once ()
219
+ ->with ()
220
+ ->andReturn ([['_id ' => 'key_1 ' ], ['_id ' => 'key_2 ' ]]);
221
+
222
+ $ engine = new ScoutEngine ($ database , softDelete: false , prefix: '' );
223
+ $ builder = new Builder (new SearchableModel (), 'mustang ' );
224
+ $ builder ->orderBy ('name ' , 'desc ' );
225
+ $ engine ->paginate ($ builder , $ perPage , $ page );
160
226
}
161
227
162
228
#[DataProvider('provideResultsForMapIds ' )]
@@ -254,18 +320,17 @@ public function testUpdateWithSoftDelete(): void
254
320
[
255
321
'updateOne ' => [
256
322
['_id ' => 'key_1 ' ],
257
- ['$setOnInsert ' => ['_id ' => 'key_1 ' ], '$set ' => ['id ' => 1 , ' date ' => new UTCDateTime ( $ date ) ]],
323
+ ['$setOnInsert ' => ['_id ' => 'key_1 ' ], '$set ' => ['id ' => 1 ]],
258
324
['upsert ' => true ],
259
325
],
260
326
],
261
327
]);
262
328
329
+ $ model = new SearchableModel (['id ' => 1 ]);
330
+ $ model ->delete ();
331
+
263
332
$ engine = new ScoutEngine ($ database , softDelete: false , prefix: '' );
264
- $ engine ->update (EloquentCollection::make ([
265
- (new SearchableModel ([
266
- 'id ' => 1 ,
267
- ])),
268
- ]));
333
+ $ engine ->update (EloquentCollection::make ([$ model ]));
269
334
}
270
335
271
336
public function testDelete (): void
@@ -286,6 +351,28 @@ public function testDelete(): void
286
351
]));
287
352
}
288
353
354
+ /** @see AlgoliaEngineTest::test_delete_with_removeable_scout_collection_using_custom_search_key */
355
+ public function testDeleteWithRemoveableScoutCollection (): void
356
+ {
357
+ $ job = new RemoveFromSearch (EloquentCollection::make ([
358
+ new SearchableModel (['id ' => 5 , 'scout_key ' => 'key_5 ' ]),
359
+ ]));
360
+
361
+ $ job = unserialize (serialize ($ job ));
362
+
363
+ $ database = m::mock (Database::class);
364
+ $ collection = m::mock (Collection::class);
365
+ $ database ->shouldReceive ('selectCollection ' )
366
+ ->with ('table_indexable ' )
367
+ ->andReturn ($ collection );
368
+ $ collection ->shouldReceive ('deleteMany ' )
369
+ ->once ()
370
+ ->with (['_id ' => ['$in ' => ['key_5 ' ]]]);
371
+
372
+ $ engine = new ScoutEngine ($ database , softDelete: false , prefix: 'ignored_prefix_ ' );
373
+ $ engine ->delete ($ job ->models );
374
+ }
375
+
289
376
public function testDeleteAll (): void
290
377
{
291
378
$ collectionNames = ['scout-prefix-table1 ' , 'scout-prefix-table2 ' ];
0 commit comments