Skip to content

Commit

Permalink
feat: Move conditionalUpdate to regular query builder (#37)
Browse files Browse the repository at this point in the history
* feat: Add conditionalUpdate to regular query builder

* fix: Failing tests
  • Loading branch information
oprypkhantc authored Aug 28, 2024
1 parent 7c57285 commit 66f7fe9
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 41 deletions.
35 changes: 8 additions & 27 deletions src/Mixins/EloquentBuilderMixin.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,33 +174,6 @@ public function withSum(): callable
return fn ($relations, string $column) => $this->withAggregate($relations, new Expression("coalesce(sum({$column}), 0)"));
}

/**
* Used for mass update with switch cases
*/
public function conditionalUpdate(): callable
{
return function (string $changedField, string $caseField, array $cases) {
$this->whereIn($caseField, array_keys($cases));

$query = $this->getQuery();

$caseSql = $query->grammar->compileCase($cases, $caseField);

$sql = $query->grammar->compileUpdate($query, [
$changedField => new Expression($caseSql),
]);

$bindings = collect($cases)
->flatMap(static fn ($value, $key) => [$key, $value])
->all();

return $query->connection->update(
$sql,
$query->grammar->prepareBindingsForUpdate($query->bindings, $bindings)
);
};
}

/**
* @see QueryBuilderMixin::customWhereNested()
*/
Expand Down Expand Up @@ -333,4 +306,12 @@ public function setOnlyModel(): callable
return $this;
};
}

/**
* @see QueryBuilderMixin::conditionalUpdate()
*/
public function conditionalUpdate(): callable
{
return fn (string $changedField, string $caseField, array $cases) => $this->getQuery()->conditionalUpdate($changedField, $caseField, $cases);
}
}
25 changes: 25 additions & 0 deletions src/Mixins/QueryBuilderMixin.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,29 @@ public function whereSubOther(): callable
return $this;
};
}

/**
* Used for mass update with switch cases
*/
public function conditionalUpdate(): callable
{
return function (string $changedField, string $caseField, array $cases) {
$this->whereIn($caseField, array_keys($cases));

$caseSql = $this->grammar->compileCase($cases, $caseField);

$sql = $this->grammar->compileUpdate($this, [
$changedField => new Expression($caseSql),
]);

$bindings = collect($cases)
->flatMap(static fn ($value, $key) => [$key, $value])
->all();

return $this->connection->update(
$sql,
$this->grammar->prepareBindingsForUpdate($this->bindings, $bindings)
);
};
}
}
2 changes: 2 additions & 0 deletions testbench.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
providers:
- TenantCloud\Mixins\MixinsServiceProvider
3 changes: 2 additions & 1 deletion tests/Database/Factories/TestStubFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ class TestStubFactory extends Factory
public function definition()
{
return [
'name' => $this->faker->name,
'name' => $this->faker->name(),
'description' => $this->faker->text(),
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public function up(): void
$table->foreignIdFor(TestStub::class, 'parent_id')
->nullable();
$table->string('name');
$table->text('description');
$table->timestamps();
});
}
Expand Down
2 changes: 2 additions & 0 deletions tests/Database/Models/TestStub.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/**
* @property int $parent_id
* @property string $name
* @property string $description
* @property Carbon $updated_at
*/
class TestStub extends Model
Expand All @@ -17,6 +18,7 @@ class TestStub extends Model

protected $fillable = [
'name',
'description',
];

/**
Expand Down
6 changes: 3 additions & 3 deletions tests/EloquentBuilderMixin/Jobs/GenerateChunksJobTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use TenantCloud\Mixins\Jobs\HandleChunkJob;
use TenantCloud\Mixins\Jobs\SerializableBuilder;
use TenantCloud\Mixins\Queue\Handlers\Serializable\ChunkHandler;
use Tests\Database\Factories\TestStubFactory;
use Tests\Database\Models\TestStub;
use Tests\EloquentBuilderMixin\Stubs\HandlerStub;
use Tests\TestCase;
Expand Down Expand Up @@ -41,9 +42,8 @@ public function testChunkWorkerDoesNotFireIfNoItemsExists(): void
public function testCalculateMinMaxPrimaryKeyValue(): void
{
Queue::fake();
$model = new TestStub();
$model->name = $this->faker->name;
$model->save();

TestStubFactory::new()->create();

$serializedBuilder = new SerializableBuilder(TestStub::query());
$params = new ChunkParams(
Expand Down
14 changes: 4 additions & 10 deletions tests/EloquentBuilderMixin/Jobs/HandleChunkJobTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use TenantCloud\Mixins\Jobs\HandleChunkJob;
use TenantCloud\Mixins\Jobs\SerializableBuilder;
use TenantCloud\Mixins\Queue\Handlers\Serializable\ChunkHandler;
use Tests\Database\Factories\TestStubFactory;
use Tests\Database\Models\TestStub;
use Tests\EloquentBuilderMixin\Stubs\HandlerStub;
use Tests\TestCase;
Expand Down Expand Up @@ -48,9 +49,7 @@ public function testItShouldPassMockedClasses(): void

public function testFireHandleWithItem(): void
{
$model = new TestStub();
$model->name = $this->faker->name;
$model->save();
$model = TestStubFactory::new()->create();

$serializedBuilder = new SerializableBuilder(TestStub::query());

Expand All @@ -68,13 +67,8 @@ public function testFireHandleWithItem(): void

public function testFireHandleWithMultipleItems(): void
{
$model = new TestStub();
$model->name = $this->faker->name;
$model->save();

$model2 = new TestStub();
$model2->name = $this->faker->name;
$model2->save();
$model = TestStubFactory::new()->create();
$model2 = TestStubFactory::new()->create();

$serializedBuilder = new SerializableBuilder(TestStub::query());

Expand Down
40 changes: 40 additions & 0 deletions tests/QueryBuilderMixin/QueryBuilderConditionalUpdateTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Tests\QueryBuilderMixin;

use Illuminate\Foundation\Testing\RefreshDatabase;
use TenantCloud\Mixins\Mixins\QueryBuilderMixin;
use Tests\Database\Factories\TestStubFactory;
use Tests\Database\Models\TestStub;
use Tests\TestCase;

/** @see QueryBuilderMixin::conditionalUpdate() */
class QueryBuilderConditionalUpdateTest extends TestCase
{
use RefreshDatabase;

public function testUpdatesRecordsUsingAMap(): void
{
$stub1 = TestStubFactory::new()->create([
'name' => 'one',
]);
$stub2 = TestStubFactory::new()->create([
'name' => 'two',
'description' => 'unchanged',
]);
$stub3 = TestStubFactory::new()->create([
'name' => 'three',
]);

TestStub::query()
->getQuery()
->conditionalUpdate('description', 'name', [
'one' => 'one description',
'three' => 'three description',
]);

self::assertSame('one description', $stub1->fresh()->description);
self::assertSame('unchanged', $stub2->fresh()->description);
self::assertSame('three description', $stub3->fresh()->description);
}
}

0 comments on commit 66f7fe9

Please sign in to comment.