Skip to content

Commit db92b40

Browse files
committed
Add ability to enter custom range via --min and --max options
1 parent 26b58e9 commit db92b40

2 files changed

Lines changed: 152 additions & 11 deletions

File tree

src/Console/QueueCommand.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class QueueCommand extends Command
1616
*/
1717
protected $signature = 'scout:queue
1818
{model : Class name of model to bulk queue}
19+
{--min= : The minimum ID to start queuing from}
20+
{--max= : The maximum ID to queue up to}
1921
{--c|chunk= : The number of records to queue in a single job (Defaults to configuration value: `scout.chunk.searchable`)}';
2022

2123
/**
@@ -38,8 +40,10 @@ public function handle()
3840

3941
$query = $model::makeAllSearchableQuery();
4042

41-
$min = $query->min($model->getScoutKeyName());
42-
$max = $query->max($model->getScoutKeyName());
43+
$min = $this->option('min') ?? $query->min($model->getScoutKeyName());
44+
$max = $this->option('max') ?? $query->max($model->getScoutKeyName());
45+
46+
$chunk = max(1, (int) ($this->option('chunk') ?? config('scout.chunk.searchable', 500)));
4347

4448
if (! $min || ! $max) {
4549
$this->info('No records found for ['.$class.']');
@@ -53,12 +57,8 @@ public function handle()
5357
return;
5458
}
5559

56-
$chunkSize = $this->option('chunk') ?? config('scout.chunk.searchable', 500);
57-
58-
$chunkSize = max(1, (int) $chunkSize);
59-
60-
for ($start = $min; $start <= $max; $start += $chunkSize) {
61-
$end = min($start + $chunkSize - 1, $max);
60+
for ($start = $min; $start <= $max; $start += $chunk) {
61+
$end = min($start + $chunk - 1, $max);
6262

6363
dispatch(new MakeRangeSearchable($model, $start, $end))
6464
->onQueue($model->syncWithSearchUsingQueue())

tests/Feature/Commands/QueueCommandTest.php

Lines changed: 144 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ public function test_it_uses_custom_chunk_size()
5151
{
5252
Queue::fake();
5353

54-
// Create test users
5554
SearchableUserFactory::new()->count(10)->create();
5655

5756
$parameters = [
@@ -190,7 +189,6 @@ public function test_it_handles_chunk_size_larger_than_dataset()
190189
{
191190
Queue::fake();
192191

193-
// Create 3 users but use chunk size of 10
194192
SearchableUserFactory::new()->count(3)->create();
195193

196194
$parameters = [
@@ -211,7 +209,6 @@ public function test_it_handles_chunk_size_of_one()
211209
{
212210
Queue::fake();
213211

214-
// Create 3 users with chunk size of 1
215212
SearchableUserFactory::new()->count(3)->create();
216213

217214
$parameters = [
@@ -279,4 +276,148 @@ public function test_it_handles_zero_chunk_size()
279276
// Should still dispatch jobs (using default chunk size)
280277
Queue::assertPushed(MakeRangeSearchable::class);
281278
}
279+
280+
public function test_it_accepts_custom_min_option()
281+
{
282+
Queue::fake();
283+
284+
SearchableUserFactory::new()->count(10)->create();
285+
286+
$this->artisan('scout:queue', [
287+
'model' => SearchableUser::class,
288+
'--min' => 5
289+
])
290+
->expectsOutputToContain('models up to ID: 10')
291+
->expectsOutputToContain('records have been queued')
292+
->assertSuccessful();
293+
294+
// Should dispatch one job for range 5-10
295+
Queue::assertPushed(MakeRangeSearchable::class, function ($job) {
296+
return $job->start === 5 && $job->end === 10;
297+
});
298+
}
299+
300+
public function test_it_accepts_custom_max_option()
301+
{
302+
Queue::fake();
303+
304+
SearchableUserFactory::new()->count(10)->create();
305+
306+
$this->artisan('scout:queue', [
307+
'model' => SearchableUser::class,
308+
'--max' => 5
309+
])
310+
->expectsOutputToContain('models up to ID: 5')
311+
->expectsOutputToContain('records have been queued')
312+
->assertSuccessful();
313+
314+
// Should dispatch one job for range 1-5
315+
Queue::assertPushed(MakeRangeSearchable::class, function ($job) {
316+
return $job->start === 1 && $job->end === 5;
317+
});
318+
}
319+
320+
public function test_it_accepts_both_min_and_max_options()
321+
{
322+
Queue::fake();
323+
324+
SearchableUserFactory::new()->count(10)->create();
325+
326+
$this->artisan('scout:queue', [
327+
'model' => SearchableUser::class,
328+
'--min' => 3,
329+
'--max' => 7
330+
])
331+
->expectsOutputToContain('models up to ID: 7')
332+
->expectsOutputToContain('records have been queued')
333+
->assertSuccessful();
334+
335+
// Should dispatch one job for range 3-7
336+
Queue::assertPushed(MakeRangeSearchable::class, function ($job) {
337+
return $job->start === 3 && $job->end === 7;
338+
});
339+
}
340+
341+
public function test_it_chunks_custom_range_correctly()
342+
{
343+
Queue::fake();
344+
345+
SearchableUserFactory::new()->count(10)->create();
346+
347+
$this->artisan('scout:queue', [
348+
'model' => SearchableUser::class,
349+
'--min' => 2,
350+
'--max' => 8,
351+
'--chunk' => 3
352+
])
353+
->expectsOutputToContain('models up to ID: 4')
354+
->expectsOutputToContain('models up to ID: 7')
355+
->expectsOutputToContain('models up to ID: 8')
356+
->expectsOutputToContain('records have been queued')
357+
->assertSuccessful();
358+
359+
// Should dispatch 3 jobs: [2-4], [5-7], [8]
360+
Queue::assertPushed(MakeRangeSearchable::class, 3);
361+
}
362+
363+
public function test_it_handles_min_greater_than_max()
364+
{
365+
Queue::fake();
366+
367+
SearchableUserFactory::new()->count(5)->create();
368+
369+
$this->artisan('scout:queue', [
370+
'model' => SearchableUser::class,
371+
'--min' => 5,
372+
'--max' => 2
373+
])
374+
->expectsOutputToContain('records have been queued')
375+
->assertSuccessful();
376+
377+
// Should not dispatch any jobs since the range is invalid (start > end in loop)
378+
Queue::assertNothingPushed();
379+
}
380+
381+
public function test_it_handles_negative_min_option()
382+
{
383+
Queue::fake();
384+
385+
SearchableUserFactory::new()->count(3)->create();
386+
387+
$this->artisan('scout:queue', [
388+
'model' => SearchableUser::class,
389+
'--min' => -5,
390+
'--max' => 2
391+
])
392+
->expectsOutputToContain('models up to ID: 2')
393+
->expectsOutputToContain('records have been queued')
394+
->assertSuccessful();
395+
396+
// Should dispatch one job for range -5 to 2
397+
Queue::assertPushed(MakeRangeSearchable::class, function ($job) {
398+
return $job->start === -5 && $job->end === 2;
399+
});
400+
}
401+
402+
public function test_it_can_accept_all_options()
403+
{
404+
Queue::fake();
405+
406+
SearchableUserFactory::new()->count(20)->create();
407+
408+
$this->artisan('scout:queue', [
409+
'model' => SearchableUser::class,
410+
'--min' => 5,
411+
'--max' => 15,
412+
'--chunk' => 4
413+
])
414+
->expectsOutputToContain('models up to ID: 8')
415+
->expectsOutputToContain('models up to ID: 12')
416+
->expectsOutputToContain('models up to ID: 15')
417+
->expectsOutputToContain('records have been queued')
418+
->assertSuccessful();
419+
420+
// Should dispatch 3 jobs: [5-8], [9-12], [13-15]
421+
Queue::assertPushed(MakeRangeSearchable::class, 3);
422+
}
282423
}

0 commit comments

Comments
 (0)