Lines
100.00%
33 / 33
Functions and Methods
100.00%
5 / 5
Classes and Traits
100.00%
1 / 1
| Name | Lines | Functions and Methods | CRAP | Classes and Traits | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| SeededHistory | 100.00% | 33 / 33 | 100.00% | 5 / 5 | 14 | 100.00% | 1 / 1 | |||
| recordState | 100.00% | 7 / 7 | 100.00% | 1 / 1 | 1 | |||||
| sliceForWindow | 100.00% | 16 / 16 | 100.00% | 1 / 1 | 7 | |||||
| dropRepeatedStates | 100.00% | 6 / 6 | 100.00% | 1 / 1 | 4 | |||||
| listStatesInOrder | 100.00% | 3 / 3 | 100.00% | 1 / 1 | 1 | |||||
| stripAttributes | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | |||||
| 1 | <?php | |
| 2 | ||
| 3 | declare(strict_types=1); | |
| 4 | ||
| 5 | namespace Stewart\Testing\HaContext; | |
| 6 | ||
| 7 | use Stewart\Contracts\Entity\EntityId; | |
| 8 | use Stewart\Contracts\History\Collection\HistoricalStateCollection; | |
| 9 | use Stewart\Contracts\History\EntityStateHistory; | |
| 10 | use Stewart\Contracts\History\HistoryDetail; | |
| 11 | use Stewart\Contracts\History\HistoryWindow; | |
| 12 | use Stewart\Contracts\State\EntityState; | |
| 13 | use Stewart\Contracts\Time\Instant; | |
| 14 | ||
| 15 | final class SeededHistory | |
| 16 | { | |
| 17 | /** @var array<string, list<EntityState>> */ | |
| 18 | private array $statesByEntityId = []; | |
| 19 | ||
| 20 | public function recordState(EntityState $state, Instant $changedAt): void | |
| 21 | { | |
| 22 | $this->statesByEntityId[$state->entityId->value][] = new EntityState( | |
| 23 | $state->entityId, | |
| 24 | $state->state, | |
| 25 | $state->attributes, | |
| 26 | $state->lastChangedAt ?? $changedAt, | |
| 27 | $state->lastUpdatedAt ?? $state->lastChangedAt ?? $changedAt, | |
| 28 | ); | |
| 29 | } | |
| 30 | ||
| 31 | public function sliceForWindow(EntityId $entityId, HistoryWindow $window, HistoryDetail $detail): EntityStateHistory | |
| 32 | { | |
| 33 | $startState = null; | |
| 34 | $inWindow = []; | |
| 35 | ||
| 36 | foreach ($this->listStatesInOrder($entityId) as $state) { | |
| 37 | $changedAt = $state->lastChangedAt ?? $window->startsAt; | |
| 38 | ||
| 39 | if (!$changedAt->isAfter($window->startsAt)) { | |
| 40 | $startState = new EntityState($entityId, $state->state, $state->attributes, $window->startsAt, $window->startsAt); | |
| 41 | } elseif (!$changedAt->isAfter($window->endsAt)) { | |
| 42 | $inWindow[] = $state; | |
| 43 | } | |
| 44 | } | |
| 45 | ||
| 46 | $states = $startState === null ? $inWindow : [$startState, ...$inWindow]; | |
| 47 | ||
| 48 | if (!$detail->includesAttributeOnlyChanges()) { | |
| 49 | $states = self::dropRepeatedStates($states); | |
| 50 | } | |
| 51 | ||
| 52 | return new EntityStateHistory( | |
| 53 | $entityId, | |
| 54 | $window, | |
| 55 | HistoricalStateCollection::fromList($detail->includesAttributes() ? $states : array_map(self::stripAttributes(...), $states)), | |
| 56 | ); | |
| 57 | } | |
| 58 | ||
| 59 | /** | |
| 60 | * @param list<EntityState> $states | |
| 61 | * @return list<EntityState> | |
| 62 | */ | |
| 63 | private static function dropRepeatedStates(array $states): array | |
| 64 | { | |
| 65 | $kept = []; | |
| 66 | ||
| 67 | foreach ($states as $state) { | |
| 68 | $previous = $kept[\count($kept) - 1] ?? null; | |
| 69 | ||
| 70 | if ($previous === null || $previous->state !== $state->state) { | |
| 71 | $kept[] = $state; | |
| 72 | } | |
| 73 | } | |
| 74 | ||
| 75 | return $kept; | |
| 76 | } | |
| 77 | ||
| 78 | /** @return list<EntityState> */ | |
| 79 | private function listStatesInOrder(EntityId $entityId): array | |
| 80 | { | |
| 81 | $states = $this->statesByEntityId[$entityId->value] ?? []; | |
| 82 | usort($states, static fn(EntityState $a, EntityState $b): int => $a->lastChangedAt?->toEpochMicroseconds() <=> $b->lastChangedAt?->toEpochMicroseconds()); | |
| 83 | ||
| 84 | return $states; | |
| 85 | } | |
| 86 | ||
| 87 | private static function stripAttributes(EntityState $state): EntityState | |
| 88 | { | |
| 89 | return new EntityState($state->entityId, $state->state, [], $state->lastChangedAt, $state->lastUpdatedAt); | |
| 90 | } | |
| 91 | } |