From d26545fca7ac5620725986de42d718f90dc29099 Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 15:37:52 -0300 Subject: [PATCH 01/14] feat: start a sequence at a predefined value --- config/config.php | 1 + src/Traits/Sequenceable.php | 30 ++++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/config/config.php b/config/config.php index 76ed05d..201d046 100644 --- a/config/config.php +++ b/config/config.php @@ -2,4 +2,5 @@ return [ 'column_name' => 'position', + 'initial_value' => 1, ]; diff --git a/src/Traits/Sequenceable.php b/src/Traits/Sequenceable.php index 247d086..0b4a93b 100644 --- a/src/Traits/Sequenceable.php +++ b/src/Traits/Sequenceable.php @@ -27,7 +27,7 @@ public static function bootSequenceable(): void static::creating(function ($model) { $model->handleSequenceableCreate(); }); - + static::updating(function ($model) { $model->handleSequenceableUpdate(); }); @@ -81,7 +81,7 @@ protected function handleSequenceableUpdate(): void return; } - + $value = $this->getSequenceValue(); if (! $this->isDirty(static::getSequenceColumnName()) || is_null($value)) { @@ -107,12 +107,12 @@ protected function handleSequenceableDelete(): void return; } - + $columnName = static::getSequenceColumnName(); $objects = $this->getSequence() ->where($columnName, '>', $this->getSequenceValue()); - + static::decrementSequenceValues($objects); } @@ -180,7 +180,7 @@ public function getSequenceValue(): ?int return is_numeric($value) ? (int) $value : null; } - + /** * Get original sequence value. * @@ -239,7 +239,7 @@ protected function isMovingUpInSequence(): bool protected function isMovingDownInSequence(): bool { $originalValue = $this->getOriginalSequenceValue(); - + return $originalValue && $originalValue > $this->getSequenceValue(); } @@ -286,7 +286,9 @@ public static function getSequenceColumnName(): string */ protected function getLastSequenceValue(): int { - return $this->getSequence()->count(); + return $this->isSequenceEmpty() + ? 0 + : $this->getSequence()->count() + static::getInitialSequenceValue() - 1; } /** @@ -296,7 +298,9 @@ protected function getLastSequenceValue(): int */ public function getNextSequenceValue(): int { - return $this->getLastSequenceValue() + 1; + return $this->isSequenceEmpty() + ? static::getInitialSequenceValue() + : $this->getLastSequenceValue() + 1; } /** @@ -375,4 +379,14 @@ protected function getSequenceKeys(): array ? static::$sequenceableKeys : []; } + + protected static function getInitialSequenceValue(): int + { + return (int) config('eloquentsequencer.initial_value', 1); + } + + protected function isSequenceEmpty(): bool + { + return $this->getSequence()->count() === 0; + } } From 1c64ad2fcc2bba37c22721e14c98a1479230bf6a Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 15:38:09 -0300 Subject: [PATCH 02/14] test: ensure the sequence starts at a predefined value --- tests/Unit/InitialSequenceValueTest.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/Unit/InitialSequenceValueTest.php diff --git a/tests/Unit/InitialSequenceValueTest.php b/tests/Unit/InitialSequenceValueTest.php new file mode 100644 index 0000000..2bf38eb --- /dev/null +++ b/tests/Unit/InitialSequenceValueTest.php @@ -0,0 +1,25 @@ + 10]); + + $group = Factory::of('Group')->create(); + + $firstItem = Factory::of('Item')->create(['group_id' => $group->id]); + $secondItem = Factory::of('Item')->create(['group_id' => $group->id]); + $thirdItem = Factory::of('Item')->create(['group_id' => $group->id]); + + $this->assertEquals(10, $firstItem->position); + $this->assertEquals(11, $secondItem->position); + $this->assertEquals(12, $thirdItem->position); + } +} From f931f380274cb344c4e6aedbf57b8b1939b50e84 Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 15:38:59 -0300 Subject: [PATCH 03/14] chore: add idea folder to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c53c4c4..7bab5ef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.idea .phpunit.result.cache build composer.lock From 6e541e500e978f163e3b88b06f78a0b37e9c04dd Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 15:44:37 -0300 Subject: [PATCH 04/14] test: ensure it throws an exception when the value is smaller than the initial value --- ...eateObjectWithSequenceValueOutOfBoundsTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Unit/CreateObjectWithSequenceValueOutOfBoundsTest.php b/tests/Unit/CreateObjectWithSequenceValueOutOfBoundsTest.php index c1d03b9..ca59630 100644 --- a/tests/Unit/CreateObjectWithSequenceValueOutOfBoundsTest.php +++ b/tests/Unit/CreateObjectWithSequenceValueOutOfBoundsTest.php @@ -49,4 +49,19 @@ public function it_throws_an_exception_when_the_object_created_has_a_sequence_va 'group_id' => $group->id, ]); } + + /** @test */ + public function it_throws_an_exception_when_the_object_created_has_a_sequence_value_smaller_than_the_initial_value() + { + config(['eloquentsequencer.initial_vaue' => 10]); + + $group = Factory::of('Group')->create(); + + $this->expectException(SequenceValueOutOfBoundsException::class); + + Factory::of('Item')->create([ + 'position' => 9, + 'group_id' => $group->id, + ]); + } } From f46a4059732e88c57d506ab905e0b8498f149e46 Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 16:08:45 -0300 Subject: [PATCH 05/14] refactor: remove variables --- src/Traits/Sequenceable.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Traits/Sequenceable.php b/src/Traits/Sequenceable.php index 0b4a93b..7f2558d 100644 --- a/src/Traits/Sequenceable.php +++ b/src/Traits/Sequenceable.php @@ -202,9 +202,6 @@ protected function getOriginalSequenceValue(): ?int protected static function updateSequenceablesAffectedBy(Model $model): void { DB::transaction(function () use ($model) { - $value = $model->getSequenceValue(); - $originalValue = $model->getOriginalSequenceValue(); - $modelsToUpdate = $model->getSequence() ->where('id', '!=', $model->id) ->filter(function ($sequenceModel) use ($model) { From b69152118068d601012973b286ddf6b358762a0c Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 16:10:36 -0300 Subject: [PATCH 06/14] feat: ensure an exception is thrown when the updated value is smaller than the initial value --- src/Traits/Sequenceable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Traits/Sequenceable.php b/src/Traits/Sequenceable.php index 7f2558d..58e8753 100644 --- a/src/Traits/Sequenceable.php +++ b/src/Traits/Sequenceable.php @@ -138,7 +138,7 @@ protected function isUpdatedSequenceValueOutOfBounds(): bool $newValue = $this->getSequenceValue(); $originalValue = $this->getOriginalSequenceValue(); - return $newValue <= 0 + return $newValue < static::getInitialSequenceValue() || ! is_null($originalValue) && $newValue > $this->getLastSequenceValue() || is_null($originalValue) && $newValue > $this->getNextSequenceValue(); } From 414f9fd86da57fe7862c6b7f91c86dde001a2d8b Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 16:10:41 -0300 Subject: [PATCH 07/14] test: ensure an exception is thrown when the updated value is smaller than the initial value --- ...pdateObjectWithSequenceValueOutOfBoundsTest.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/Unit/UpdateObjectWithSequenceValueOutOfBoundsTest.php b/tests/Unit/UpdateObjectWithSequenceValueOutOfBoundsTest.php index 8aff845..dec9e13 100644 --- a/tests/Unit/UpdateObjectWithSequenceValueOutOfBoundsTest.php +++ b/tests/Unit/UpdateObjectWithSequenceValueOutOfBoundsTest.php @@ -91,4 +91,18 @@ public function it_does_not_throw_an_exception_when_the_updated_object_has_a_seq $this->assertEquals(2, $item->refresh()->position); } + + /** @test */ + public function it_throws_an_exception_when_the_updated_object_has_a_sequence_value_smaller_than_the_initial_value() + { + config(['eloquentsequencer.initial_value' => 10]); + + $group = Factory::of('Group')->create(); + + $item = Factory::of('Item')->create(['group_id' => $group->id]); + + $this->expectException(SequenceValueOutOfBoundsException::class); + + $item->update(['position' => 9]); + } } From 70a39fb04d6348f8dbfb412155928c5682be232e Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 16:20:28 -0300 Subject: [PATCH 08/14] test: ensure updated sequences start at the initial value --- tests/Unit/InitialSequenceValueTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/Unit/InitialSequenceValueTest.php b/tests/Unit/InitialSequenceValueTest.php index 2bf38eb..a6e5096 100644 --- a/tests/Unit/InitialSequenceValueTest.php +++ b/tests/Unit/InitialSequenceValueTest.php @@ -22,4 +22,22 @@ public function it_starts_a_sequence_at_a_predefined_value() $this->assertEquals(11, $secondItem->position); $this->assertEquals(12, $thirdItem->position); } + + /** @test */ + public function when_a_sequence_is_updated_the_first_object_will_have_the_initial_value() + { + config(['eloquentsequencer.initial_value' => 10]); + + $group = Factory::of('Group')->create(); + + $firstItem = Factory::of('Item')->create(['group_id' => $group->id]); + $secondItem = Factory::of('Item')->create(['group_id' => $group->id]); + $thirdItem = Factory::of('Item')->create(['group_id' => $group->id]); + + $firstItem->update(['position' => 12]); + + $this->assertEquals(10, $secondItem->refresh()->position); + $this->assertEquals(11, $thirdItem->refresh()->position); + $this->assertEquals(12, $firstItem->refresh()->position); + } } From 990419b62f0db8400ed2225f5926b8bc000909fe Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 16:27:42 -0300 Subject: [PATCH 09/14] docs: describe isSequenceEmpty --- src/Traits/Sequenceable.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Traits/Sequenceable.php b/src/Traits/Sequenceable.php index 58e8753..14dd994 100644 --- a/src/Traits/Sequenceable.php +++ b/src/Traits/Sequenceable.php @@ -382,6 +382,11 @@ protected static function getInitialSequenceValue(): int return (int) config('eloquentsequencer.initial_value', 1); } + /** + * Determine if the sequence if empty. + * + * @return bool + */ protected function isSequenceEmpty(): bool { return $this->getSequence()->count() === 0; From baab916c1511df647a0f4a55d22be0540b5ecb7d Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 16:27:55 -0300 Subject: [PATCH 10/14] docs: describe getInitialSequenceValue --- src/Traits/Sequenceable.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Traits/Sequenceable.php b/src/Traits/Sequenceable.php index 14dd994..4704d19 100644 --- a/src/Traits/Sequenceable.php +++ b/src/Traits/Sequenceable.php @@ -377,6 +377,11 @@ protected function getSequenceKeys(): array : []; } + /** + * Get the value that sequences should start at. + * + * @return int + */ protected static function getInitialSequenceValue(): int { return (int) config('eloquentsequencer.initial_value', 1); From 586079b2eede13995e71ed556783fa44762aa372 Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 16:35:19 -0300 Subject: [PATCH 11/14] docs: update README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f819d9b..20ccdc3 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,12 @@ php artisan vendor:publish --provider="Gurgentil\LaravelEloquentSequencer\Larave ### Configuration parameters -You can change the default colum name in `config/eloquentsequencer.php`: +You can change the default colum name and the initial value for the sequences in `config/eloquentsequencer.php`: ```php return [ 'column_name' => 'position', + 'initial_value' => 1, ]; ``` From 88d569dde6e336b91acd6b1427ed8e00bcf88265 Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 16:39:53 -0300 Subject: [PATCH 12/14] refactor: remove conditional --- src/Traits/Sequenceable.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Traits/Sequenceable.php b/src/Traits/Sequenceable.php index 4704d19..4014e89 100644 --- a/src/Traits/Sequenceable.php +++ b/src/Traits/Sequenceable.php @@ -283,9 +283,7 @@ public static function getSequenceColumnName(): string */ protected function getLastSequenceValue(): int { - return $this->isSequenceEmpty() - ? 0 - : $this->getSequence()->count() + static::getInitialSequenceValue() - 1; + return $this->getSequence()->count() + static::getInitialSequenceValue() - 1; } /** From 0d9f63efab2e5d60750f1f41f828a0b4e9329162 Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 16:42:18 -0300 Subject: [PATCH 13/14] refactor: simplify getNextSequenceValue --- src/Traits/Sequenceable.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Traits/Sequenceable.php b/src/Traits/Sequenceable.php index 4014e89..0d2f2d6 100644 --- a/src/Traits/Sequenceable.php +++ b/src/Traits/Sequenceable.php @@ -283,7 +283,7 @@ public static function getSequenceColumnName(): string */ protected function getLastSequenceValue(): int { - return $this->getSequence()->count() + static::getInitialSequenceValue() - 1; + return $this->getNextSequenceValue() - 1; } /** @@ -293,9 +293,7 @@ protected function getLastSequenceValue(): int */ public function getNextSequenceValue(): int { - return $this->isSequenceEmpty() - ? static::getInitialSequenceValue() - : $this->getLastSequenceValue() + 1; + return static::getInitialSequenceValue() + $this->getSequence()->count(); } /** From dae42a8f19ea64cc2d5379a5bfe6b80e3ab38cf5 Mon Sep 17 00:00:00 2001 From: Gustavo Gentil Date: Sat, 4 Jul 2020 16:42:25 -0300 Subject: [PATCH 14/14] refactor: remove method --- src/Traits/Sequenceable.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Traits/Sequenceable.php b/src/Traits/Sequenceable.php index 0d2f2d6..067d187 100644 --- a/src/Traits/Sequenceable.php +++ b/src/Traits/Sequenceable.php @@ -382,14 +382,4 @@ protected static function getInitialSequenceValue(): int { return (int) config('eloquentsequencer.initial_value', 1); } - - /** - * Determine if the sequence if empty. - * - * @return bool - */ - protected function isSequenceEmpty(): bool - { - return $this->getSequence()->count() === 0; - } }