diff --git a/migrations/2026_08_31_000000_add_report_execution_statistics_columns.php b/migrations/2026_08_31_000000_add_report_execution_statistics_columns.php new file mode 100644 index 00000000..ad43896b --- /dev/null +++ b/migrations/2026_08_31_000000_add_report_execution_statistics_columns.php @@ -0,0 +1,60 @@ +unsignedInteger('execution_count')->default(0)->after('row_count'); + + // A mean of integer millisecond timings, so it needs somewhere for the + // fraction to go — `execution_time` is an integer because it holds one + // measurement rather than an average of several. + $table->float('average_execution_time')->nullable()->comment('Mean execution time in milliseconds across all runs')->after('execution_count'); + + $table->integer('last_result_count')->nullable()->after('average_execution_time'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('reports', function (Blueprint $table) { + $table->dropColumn([ + 'execution_count', + 'average_execution_time', + 'last_result_count', + ]); + }); + } +}; diff --git a/tests/Unit/Models/ReportExecutionColumnsTest.php b/tests/Unit/Models/ReportExecutionColumnsTest.php new file mode 100644 index 00000000..cad064e5 --- /dev/null +++ b/tests/Unit/Models/ReportExecutionColumnsTest.php @@ -0,0 +1,63 @@ +[A-Za-z]+\(\s*'([a-z0-9_]+)'/", $block, $found); + $columns = array_merge($columns, $found[1]); + } + } + + return array_unique($columns); +} + +it('has a column for every execution statistic the report model writes', function () { + $columns = reportsTableColumns(); + + expect($columns)->not->toBeEmpty('no reports blueprints were found to read'); + + foreach (['execution_count', 'average_execution_time', 'last_result_count', 'last_executed_at'] as $column) { + expect($columns)->toContain($column); + } +}); + +it('still has the per-run columns the api resource exposes', function () { + // execution_time and row_count describe the last run and are returned by the Report + // resource; the statistics above accumulate across runs. Both sets must exist — + // adding one must not be mistaken for replacing the other. + $columns = reportsTableColumns(); + + expect($columns)->toContain('execution_time') + ->and($columns)->toContain('row_count'); +});