The scheduler command ran every minute and loaded all active automations, then filtered by trigger_type in PHP because that value lived buried in the nodes JSON array — effectively a full-table scan plus a JSON decode per row each minute, discarding every non-schedule automation. Derive trigger_type into a real, indexed column on save (recomputed in the existing saving() hook so it can never drift from nodes) and filter on it in SQL. Applies to both the schedule firer and the post-trigger dispatcher.
60 lines
2.2 KiB
PHP
60 lines
2.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Enums\Automation\Status;
|
|
use App\Models\Automation;
|
|
use App\Models\AutomationNodeRun;
|
|
use App\Models\AutomationRun;
|
|
use App\Models\AutomationTriggerItem;
|
|
use Illuminate\Database\UniqueConstraintViolationException;
|
|
|
|
it('persists automation with json columns and enum cast', function () {
|
|
$automation = Automation::factory()->withScheduleTrigger()->create();
|
|
|
|
expect($automation->status)->toBe(Status::Draft);
|
|
expect($automation->nodes)->toBeArray();
|
|
expect($automation->nodes[0]['type'])->toBe('trigger');
|
|
});
|
|
|
|
it('derives the trigger_type column from the trigger node on save', function () {
|
|
$automation = Automation::factory()->withScheduleTrigger()->create();
|
|
|
|
expect($automation->trigger_type)->toBe('schedule');
|
|
|
|
$automation->update([
|
|
'nodes' => [
|
|
['id' => 'trigger_1', 'type' => 'trigger', 'position' => ['x' => 0, 'y' => 0],
|
|
'data' => ['trigger_type' => 'post_published']],
|
|
],
|
|
]);
|
|
|
|
expect($automation->fresh()->trigger_type)->toBe('post_published');
|
|
});
|
|
|
|
it('nulls the trigger_type column when there is no trigger node', function () {
|
|
$automation = Automation::factory()->create(['nodes' => []]);
|
|
|
|
expect($automation->trigger_type)->toBeNull();
|
|
});
|
|
|
|
it('relates trigger items, runs and node runs', function () {
|
|
$automation = Automation::factory()->create();
|
|
$item = AutomationTriggerItem::factory()->for($automation)->create();
|
|
$run = AutomationRun::factory()->for($automation)->create(['trigger_item_id' => $item->id]);
|
|
$nodeRun = AutomationNodeRun::factory()->for($run, 'run')->create();
|
|
|
|
expect($automation->triggerItems)->toHaveCount(1);
|
|
expect($automation->runs)->toHaveCount(1);
|
|
expect($run->triggerItem->id)->toBe($item->id);
|
|
expect($run->nodeRuns)->toHaveCount(1);
|
|
expect($nodeRun->run->id)->toBe($run->id);
|
|
});
|
|
|
|
it('enforces unique item_key per automation', function () {
|
|
$automation = Automation::factory()->create();
|
|
AutomationTriggerItem::factory()->for($automation)->create(['item_key' => 'abc']);
|
|
|
|
expect(fn () => AutomationTriggerItem::factory()->for($automation)->create(['item_key' => 'abc']))
|
|
->toThrow(UniqueConstraintViolationException::class);
|
|
});
|