From fddaa66512764fb1d0f38b4ac66f91781d830135 Mon Sep 17 00:00:00 2001 From: lapaliv Date: Sun, 4 Jun 2023 22:30:33 +0200 Subject: [PATCH 1/2] feat: added method `Bulk::withTrashed()` --- README.md | 7 +++++++ src/Bulk.php | 15 +++++++++++++++ .../MarkNonexistentRowsAsSkippedFeature.php | 2 ++ src/Features/SelectExistingRowsFeature.php | 3 ++- src/Scenarios/CreateScenario.php | 8 +++++++- src/Scenarios/UpdateScenario.php | 3 ++- src/Scenarios/UpsertScenario.php | 4 +++- .../CreateBeforeWritingEventDependenciesTest.php | 2 +- .../UpdateBeforeWritingEventDependenciesTest.php | 3 +++ 9 files changed, 42 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2fb28e2..d578fb4 100644 --- a/README.md +++ b/README.md @@ -528,6 +528,13 @@ class Bulk { */ public function updateAllExcept(array $attributes): static; + /** + * Enables soft deleted rows into select. + * + * @return $this + */ + public function withTrashed(): static; + /** * Creates the rows. * @param iterable|object> $rows diff --git a/src/Bulk.php b/src/Bulk.php index f782eb8..e40c6fb 100644 --- a/src/Bulk.php +++ b/src/Bulk.php @@ -95,6 +95,7 @@ class Bulk * @var string[] */ private array $updateExcept = []; + private bool $withTrashed = false; /** * @param class-string|TModel $model @@ -642,6 +643,18 @@ public function saveAccumulated(): static ->upsertAccumulated(); } + /** + * Adds soft deleted rows to queries. + * + * @return $this + */ + public function withTrashed(): static + { + $this->withTrashed = true; + + return $this; + } + /** * Accumulates the rows to the storage. * @@ -865,6 +878,7 @@ private function runUpdateScenario(BulkAccumulationEntity $accumulation, array $ $this->getDateFields(), $this->getSelectColumns($columns, $accumulation->uniqueBy), $this->getDeletedAtColumn(), + $this->withTrashed, ); unset($scenario); @@ -899,6 +913,7 @@ private function runUpsertScenario(BulkAccumulationEntity $accumulation, array $ $this->getDateFields(), $this->getSelectColumns($columns, $accumulation->uniqueBy), $this->getDeletedAtColumn(), + $this->withTrashed, ); unset($scenario); diff --git a/src/Features/MarkNonexistentRowsAsSkippedFeature.php b/src/Features/MarkNonexistentRowsAsSkippedFeature.php index e11c4e6..05bd1c5 100644 --- a/src/Features/MarkNonexistentRowsAsSkippedFeature.php +++ b/src/Features/MarkNonexistentRowsAsSkippedFeature.php @@ -24,6 +24,7 @@ public function handle( BulkAccumulationEntity $data, array $selectColumns, ?string $deletedAtColumn, + bool $withTrashed, ): void { $nonexistent = new BulkAccumulationEntity($data->uniqueBy); @@ -43,6 +44,7 @@ public function handle( $data->uniqueBy, $selectColumns, $deletedAtColumn, + $withTrashed, ) ); } diff --git a/src/Features/SelectExistingRowsFeature.php b/src/Features/SelectExistingRowsFeature.php index e7cdd67..cc00a05 100644 --- a/src/Features/SelectExistingRowsFeature.php +++ b/src/Features/SelectExistingRowsFeature.php @@ -22,12 +22,13 @@ public function handle( array $uniqueBy, array $selectColumns, ?string $deletedAtColumn = null, + bool $withTrashed = false, ): Collection { $builder = $eloquent->newQuery() ->select($selectColumns) ->limit($collection->count()); - if ($deletedAtColumn !== null) { + if ($withTrashed && $deletedAtColumn !== null) { call_user_func([$builder, 'withTrashed']); } diff --git a/src/Scenarios/CreateScenario.php b/src/Scenarios/CreateScenario.php index fa979ab..a760e8d 100644 --- a/src/Scenarios/CreateScenario.php +++ b/src/Scenarios/CreateScenario.php @@ -23,6 +23,8 @@ */ class CreateScenario { + private bool $hasDeletingRows = false; + public function __construct( private GetInsertBuilderFeature $getInsertBuilderFeature, private BulkDriverManager $driverManager, @@ -112,7 +114,8 @@ public function handle( $data->getNotSkippedModels('skipCreating'), $data->uniqueBy, $selectColumns, - $deletedAtColumn + $deletedAtColumn, + withTrashed: $this->hasDeletingRows, ); } @@ -220,6 +223,8 @@ private function dispatchDeletingEvents( BulkEventDispatcher $eventDispatcher, string $deletedAtColumn ): void { + $this->hasDeletingRows = false; + if (!$eventDispatcher->hasListeners(BulkEventEnum::delete())) { return; } @@ -237,6 +242,7 @@ private function dispatchDeletingEvents( } $accumulatedRow->isDeleting = true; + $this->hasDeletingRows = true; if ($eventDispatcher->dispatch(BulkEventEnum::DELETING, $accumulatedRow->model) === false) { $accumulatedRow->skipDeleting = true; diff --git a/src/Scenarios/UpdateScenario.php b/src/Scenarios/UpdateScenario.php index 135c204..6d4aff2 100644 --- a/src/Scenarios/UpdateScenario.php +++ b/src/Scenarios/UpdateScenario.php @@ -34,12 +34,13 @@ public function handle( array $dateFields, array $selectColumns, ?string $deletedAtColumn, + bool $withTrashed, ): void { if (empty($data->rows)) { return; } - $this->markNonexistentRowsAsSkipped->handle($eloquent, $data, $selectColumns, $deletedAtColumn); + $this->markNonexistentRowsAsSkipped->handle($eloquent, $data, $selectColumns, $deletedAtColumn, $withTrashed); if ($eventDispatcher->hasListeners(BulkEventEnum::saving()) || $eventDispatcher->hasListeners(BulkEventEnum::updating()) diff --git a/src/Scenarios/UpsertScenario.php b/src/Scenarios/UpsertScenario.php index 3cb6547..11fa2b7 100644 --- a/src/Scenarios/UpsertScenario.php +++ b/src/Scenarios/UpsertScenario.php @@ -27,12 +27,13 @@ public function handle( array $dateFields, array $selectColumns, ?string $deletedAtColumn, + bool $withTrashed, ): void { if (empty($data->rows)) { return; } - $this->markNonexistentRowsAsSkipped->handle($eloquent, $data, $selectColumns, $deletedAtColumn); + $this->markNonexistentRowsAsSkipped->handle($eloquent, $data, $selectColumns, $deletedAtColumn, $withTrashed); $this->create($eloquent, $data, $eventDispatcher, $dateFields, $selectColumns, $deletedAtColumn); @@ -43,6 +44,7 @@ public function handle( $dateFields, $selectColumns, $deletedAtColumn, + $withTrashed ); } diff --git a/tests/Unit/Bulk/Create/CreateBeforeWritingEventDependenciesTest.php b/tests/Unit/Bulk/Create/CreateBeforeWritingEventDependenciesTest.php index 544bfdb..b4020c2 100644 --- a/tests/Unit/Bulk/Create/CreateBeforeWritingEventDependenciesTest.php +++ b/tests/Unit/Bulk/Create/CreateBeforeWritingEventDependenciesTest.php @@ -29,7 +29,7 @@ final class CreateBeforeWritingEventDependenciesTest extends TestCase use UserTestTrait; /** - * When one of model events sometimes returns false then its dependencies have not been called. + * When one of model's events return false then its dependencies have not been called. * * @param class-string $model * @param Closure $data diff --git a/tests/Unit/Bulk/Update/UpdateBeforeWritingEventDependenciesTest.php b/tests/Unit/Bulk/Update/UpdateBeforeWritingEventDependenciesTest.php index 9497d2d..fa48123 100644 --- a/tests/Unit/Bulk/Update/UpdateBeforeWritingEventDependenciesTest.php +++ b/tests/Unit/Bulk/Update/UpdateBeforeWritingEventDependenciesTest.php @@ -70,6 +70,7 @@ public function testModelEventReturnsFalseSometimes( $sut = $model::query() ->bulk() + ->withTrashed() ->uniqueBy(['id']); // act @@ -143,6 +144,7 @@ public function testModelEventReturnsFalseAlways( $sut = $model::query() ->bulk() + ->withTrashed() ->uniqueBy(['id']); // act @@ -200,6 +202,7 @@ public function testCollectionEventReturnsFalse( $sut = $model::query() ->bulk() + ->withTrashed() ->uniqueBy(['id']); // act From 9c52cf328be7d304883a6feb41a681618f32eac4 Mon Sep 17 00:00:00 2001 From: lapaliv Date: Sun, 4 Jun 2023 22:43:34 +0200 Subject: [PATCH 2/2] fix: fix the problem when models didn't find --- src/Scenarios/CreateScenario.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Scenarios/CreateScenario.php b/src/Scenarios/CreateScenario.php index a760e8d..c1443aa 100644 --- a/src/Scenarios/CreateScenario.php +++ b/src/Scenarios/CreateScenario.php @@ -310,6 +310,9 @@ function (Model $model) use ($data): string { ) { $row->model->wasRecentlyCreated = $startedAt < $existingRow->getAttribute($createdAtColumn); } + } else { + $row->skipSaving = true; + $row->skipCreating = true; } } }