pg_sql_triggers 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.erb_lint.yml +0 -0
  3. data/.rspec +0 -0
  4. data/.rubocop.yml +6 -16
  5. data/AGENTS.md +8 -0
  6. data/CHANGELOG.md +354 -0
  7. data/COVERAGE.md +39 -41
  8. data/LICENSE +0 -0
  9. data/README.md +44 -26
  10. data/RELEASE.md +0 -0
  11. data/Rakefile +5 -0
  12. data/app/assets/javascripts/pg_sql_triggers/application.js +0 -0
  13. data/app/assets/javascripts/pg_sql_triggers/trigger_actions.js +0 -0
  14. data/app/assets/stylesheets/pg_sql_triggers/application.css +0 -0
  15. data/app/controllers/concerns/pg_sql_triggers/error_handling.rb +0 -0
  16. data/app/controllers/concerns/pg_sql_triggers/kill_switch_protection.rb +0 -0
  17. data/app/controllers/concerns/pg_sql_triggers/permission_checking.rb +6 -5
  18. data/app/controllers/pg_sql_triggers/application_controller.rb +0 -0
  19. data/app/controllers/pg_sql_triggers/audit_logs_controller.rb +81 -64
  20. data/app/controllers/pg_sql_triggers/dashboard_controller.rb +111 -34
  21. data/app/controllers/pg_sql_triggers/migrations_controller.rb +13 -14
  22. data/app/controllers/pg_sql_triggers/tables_controller.rb +8 -0
  23. data/app/controllers/pg_sql_triggers/triggers_controller.rb +1 -0
  24. data/app/helpers/pg_sql_triggers/dashboard_helper.rb +19 -0
  25. data/app/helpers/pg_sql_triggers/permissions_helper.rb +3 -2
  26. data/app/models/pg_sql_triggers/application_record.rb +0 -0
  27. data/app/models/pg_sql_triggers/audit_log.rb +29 -47
  28. data/app/models/pg_sql_triggers/trigger_registry.rb +137 -74
  29. data/app/views/layouts/pg_sql_triggers/application.html.erb +0 -1
  30. data/app/views/pg_sql_triggers/audit_logs/index.html.erb +9 -5
  31. data/app/views/pg_sql_triggers/dashboard/index.html.erb +107 -27
  32. data/app/views/pg_sql_triggers/shared/_confirmation_modal.html.erb +0 -0
  33. data/app/views/pg_sql_triggers/shared/_kill_switch_status.html.erb +0 -0
  34. data/app/views/pg_sql_triggers/tables/index.html.erb +27 -18
  35. data/app/views/pg_sql_triggers/tables/show.html.erb +0 -2
  36. data/app/views/pg_sql_triggers/triggers/_drop_modal.html.erb +0 -0
  37. data/app/views/pg_sql_triggers/triggers/_re_execute_modal.html.erb +0 -0
  38. data/app/views/pg_sql_triggers/triggers/show.html.erb +33 -0
  39. data/config/initializers/pg_sql_triggers.rb +0 -0
  40. data/config/routes.rb +0 -14
  41. data/db/migrate/{20251222000001_create_pg_sql_triggers_tables.rb → 20251222104327_create_pg_sql_triggers_tables.rb} +0 -0
  42. data/db/migrate/20251229071916_add_timing_to_pg_sql_triggers_registry.rb +0 -0
  43. data/db/migrate/{20260103000001_create_pg_sql_triggers_audit_log.rb → 20260103114508_create_pg_sql_triggers_audit_log.rb} +0 -0
  44. data/db/migrate/20260228162233_add_for_each_to_pg_sql_triggers_registry.rb +8 -0
  45. data/db/migrate/20260412185841_add_constraint_deferral_to_pg_sql_triggers_registry.rb +9 -0
  46. data/docs/README.md +3 -0
  47. data/docs/api-reference.md +176 -152
  48. data/docs/audit-trail.md +1 -1
  49. data/docs/configuration.md +196 -3
  50. data/docs/getting-started.md +31 -16
  51. data/docs/kill-switch.md +0 -0
  52. data/docs/permissions.md +6 -9
  53. data/docs/troubleshooting.md +0 -0
  54. data/docs/ui-guide.md +0 -0
  55. data/docs/usage-guide.md +112 -67
  56. data/docs/web-ui.md +3 -103
  57. data/lib/generators/pg_sql_triggers/install_generator.rb +0 -0
  58. data/lib/generators/pg_sql_triggers/templates/README +0 -0
  59. data/lib/generators/pg_sql_triggers/templates/create_pg_sql_triggers_tables.rb +0 -0
  60. data/lib/generators/pg_sql_triggers/templates/initializer.rb +14 -0
  61. data/lib/generators/pg_sql_triggers/templates/trigger_dsl.rb.tt +11 -0
  62. data/lib/generators/pg_sql_triggers/templates/trigger_migration.rb.erb +0 -0
  63. data/lib/generators/pg_sql_triggers/templates/trigger_migration_full.rb.tt +29 -0
  64. data/lib/generators/pg_sql_triggers/trigger_generator.rb +83 -0
  65. data/lib/generators/pg_sql_triggers/trigger_migration_generator.rb +0 -0
  66. data/lib/pg_sql_triggers/alerting.rb +77 -0
  67. data/lib/pg_sql_triggers/database_introspection.rb +0 -0
  68. data/lib/pg_sql_triggers/deferral_checksum.rb +54 -0
  69. data/lib/pg_sql_triggers/drift/db_queries.rb +26 -13
  70. data/lib/pg_sql_triggers/drift/detector.rb +59 -38
  71. data/lib/pg_sql_triggers/drift/reporter.rb +0 -0
  72. data/lib/pg_sql_triggers/drift.rb +5 -0
  73. data/lib/pg_sql_triggers/dsl/trigger_definition.rb +68 -20
  74. data/lib/pg_sql_triggers/dsl.rb +0 -0
  75. data/lib/pg_sql_triggers/engine.rb +49 -0
  76. data/lib/pg_sql_triggers/errors.rb +0 -0
  77. data/lib/pg_sql_triggers/events_checksum.rb +114 -0
  78. data/lib/pg_sql_triggers/migration.rb +5 -6
  79. data/lib/pg_sql_triggers/migrator/pre_apply_comparator.rb +85 -82
  80. data/lib/pg_sql_triggers/migrator/pre_apply_diff_reporter.rb +0 -0
  81. data/lib/pg_sql_triggers/migrator/safety_validator.rb +34 -12
  82. data/lib/pg_sql_triggers/migrator.rb +137 -94
  83. data/lib/pg_sql_triggers/permissions/checker.rb +12 -15
  84. data/lib/pg_sql_triggers/permissions.rb +1 -0
  85. data/lib/pg_sql_triggers/rake_development_boot.rb +65 -0
  86. data/lib/pg_sql_triggers/registry/manager.rb +60 -21
  87. data/lib/pg_sql_triggers/registry/validator.rb +287 -6
  88. data/lib/pg_sql_triggers/registry.rb +0 -0
  89. data/lib/pg_sql_triggers/schema_dumper_extension.rb +32 -0
  90. data/lib/pg_sql_triggers/sql/kill_switch.rb +154 -275
  91. data/lib/pg_sql_triggers/sql.rb +0 -6
  92. data/lib/pg_sql_triggers/testing/dry_run.rb +0 -0
  93. data/lib/pg_sql_triggers/testing/function_tester.rb +97 -107
  94. data/lib/pg_sql_triggers/testing/safe_executor.rb +0 -0
  95. data/lib/pg_sql_triggers/testing/syntax_validator.rb +0 -0
  96. data/lib/pg_sql_triggers/testing.rb +0 -0
  97. data/lib/pg_sql_triggers/trigger_structure_dumper.rb +111 -0
  98. data/lib/pg_sql_triggers/version.rb +1 -1
  99. data/lib/pg_sql_triggers.rb +21 -1
  100. data/lib/tasks/trigger_migrations.rake +235 -152
  101. data/rakelib/pg_sql_triggers_environment.rake +9 -0
  102. data/scripts/generate_coverage_report.rb +4 -1
  103. data/sig/pg_sql_triggers.rbs +0 -0
  104. metadata +68 -22
  105. data/Goal.md +0 -742
  106. data/app/controllers/pg_sql_triggers/generator_controller.rb +0 -213
  107. data/app/controllers/pg_sql_triggers/sql_capsules_controller.rb +0 -161
  108. data/app/views/pg_sql_triggers/generator/new.html.erb +0 -388
  109. data/app/views/pg_sql_triggers/generator/preview.html.erb +0 -305
  110. data/app/views/pg_sql_triggers/sql_capsules/new.html.erb +0 -81
  111. data/app/views/pg_sql_triggers/sql_capsules/show.html.erb +0 -85
  112. data/lib/generators/trigger/migration_generator.rb +0 -60
  113. data/lib/pg_sql_triggers/generator/form.rb +0 -80
  114. data/lib/pg_sql_triggers/generator/service.rb +0 -339
  115. data/lib/pg_sql_triggers/generator.rb +0 -8
  116. data/lib/pg_sql_triggers/sql/capsule.rb +0 -79
  117. data/lib/pg_sql_triggers/sql/executor.rb +0 -200
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f8d9043692145293beaf91342280ca01702979a6e50190fd5930d8578170291
4
- data.tar.gz: 18e9eaaa03de9932f9916bcc2110e9896a271c555a3b94f13348baf1e37c584c
3
+ metadata.gz: 7adcec137e32ecf9e1013a7dbb98a16844a5f8082b0d910a7380903cd2151678
4
+ data.tar.gz: b285ecac25cf7806a56f0205fca527a158b48c7f26b99adb4c1c304b3b2d17d7
5
5
  SHA512:
6
- metadata.gz: 8ed71a10f16385f318a4a596a444c07d2cb00a7d07119043c921cf43b1d2199db6d36cc30b5ea523bcbb527a817b97fbe7c507ac81a4cec3931f887c2a4606ca
7
- data.tar.gz: af0162bab6005904e1649619e5a68e1c1f36733e4f8d34f0306c9a64af07356e9f19165dda1a60f19606b36b517ee1ad34224a50b479b02b0b8efd340175f1fc
6
+ metadata.gz: 0aeb0cb7beee89da7f9c8993fd166b569c4cacb684e1b82222c104d083c970b9878da4ae368449aeeda63839c991522148e6dc4996c0ffce79ca04e49063b1e0
7
+ data.tar.gz: 0d0034cf4c0ee07dc9f868fa44924a9fd737861ac1d067c67b189ae5f08172af8f9596fc625b029f5dce8d36fe00ec287e0bbb2ace5a4725ce43eabdfe66907a
data/.erb_lint.yml CHANGED
File without changes
data/.rspec CHANGED
File without changes
data/.rubocop.yml CHANGED
@@ -1,9 +1,7 @@
1
- require:
2
- - rubocop-rspec
3
- - rubocop-rspec_rails
4
-
5
1
  plugins:
6
2
  - rubocop-rails
3
+ - rubocop-rspec
4
+ - rubocop-rspec_rails
7
5
  - rubocop-capybara
8
6
  - rubocop-factory_bot
9
7
 
@@ -24,18 +22,14 @@ Metrics/AbcSize:
24
22
  Max: 65
25
23
  Exclude:
26
24
  - 'spec/**/*'
27
- - 'app/controllers/**/*'
28
- - 'lib/generators/**/*'
29
25
  - 'lib/pg_sql_triggers/testing/**/*'
30
26
 
31
27
  Metrics/BlockLength:
32
28
  Max: 50
33
29
  Exclude:
34
30
  - 'spec/**/*'
35
- - 'config/routes.rb'
36
31
  - '*.gemspec'
37
- - 'lib/tasks/**/*'
38
-
32
+
39
33
  Metrics/ClassLength:
40
34
  Max: 200
41
35
  Exclude:
@@ -44,21 +38,17 @@ Metrics/ClassLength:
44
38
  Metrics/CyclomaticComplexity:
45
39
  Max: 18
46
40
  Exclude:
47
- - 'app/controllers/**/*'
48
41
  - 'lib/pg_sql_triggers/testing/**/*'
49
42
 
50
43
  Metrics/MethodLength:
51
44
  Max: 55
52
45
  Exclude:
53
46
  - 'spec/**/*'
54
- - 'app/controllers/**/*'
55
- - 'lib/generators/**/*'
56
47
  - 'lib/pg_sql_triggers/testing/**/*'
57
48
 
58
49
  Metrics/PerceivedComplexity:
59
50
  Max: 15
60
51
  Exclude:
61
- - 'app/controllers/**/*'
62
52
  - 'lib/pg_sql_triggers/testing/**/*'
63
53
 
64
54
  # Style
@@ -97,9 +87,6 @@ RSpec/ExampleLength:
97
87
  Exclude:
98
88
  - 'spec/**/*_spec.rb'
99
89
 
100
- RSpec/FilePath:
101
- Enabled: false
102
-
103
90
  RSpec/InstanceVariable:
104
91
  Enabled: false
105
92
 
@@ -115,6 +102,9 @@ RSpec/MultipleDescribes:
115
102
  RSpec/MultipleExpectations:
116
103
  Max: 10
117
104
 
105
+ RSpec/MultipleMemoizedHelpers:
106
+ Max: 8
107
+
118
108
  RSpec/SpecFilePathFormat:
119
109
  Enabled: false
120
110
 
data/AGENTS.md ADDED
@@ -0,0 +1,8 @@
1
+ # Agent / contributor notes
2
+
3
+ ## This repository
4
+
5
+ - Run Ruby tooling (**bundle**, **rubocop**, **rspec**) via **WSL** with **asdf** (use a login shell, e.g. `wsl bash -lic '…'`).
6
+ - **PostgreSQL** is expected in **Docker**; for local tests use **`aswin` / `aswin`** (`TEST_DB_USER`, `TEST_DB_PASSWORD`, or `DATABASE_URL` as appropriate).
7
+
8
+ More detail and example commands: `.cursor/rules/dev-environment.mdc`.
data/CHANGELOG.md CHANGED
@@ -7,6 +7,360 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ No changes yet.
11
+
12
+ ## [1.5.0] - 2026-04-15
13
+
14
+ These notes follow the phased gap analysis in [`IMPLEMENTATION_PLAN.md`](IMPLEMENTATION_PLAN.md)
15
+ (baseline **v1.4.0**). This release ships Phase 0 cleanup, Phase 1 routing-test hardening,
16
+ Phase 2 production readiness (drift alerting, dashboard search/filter/pagination), Phase 3
17
+ PostgreSQL feature parity (column-level `UPDATE OF`, constraint triggers with deferral,
18
+ `schema.rb` / `structure.sql` integration), and Phase 4 trigger ordering hints.
19
+
20
+ ### Added
21
+
22
+ - **Drift alerting** — Configurable `PgSqlTriggers.drift_notifier` for external notification when
23
+ drift detection finds drifted, dropped, or unknown triggers; `PgSqlTriggers::Alerting` module;
24
+ `PgSqlTriggers::Drift.check_and_notify`; Rake task `trigger:check_drift` with optional
25
+ `FAIL_ON_DRIFT=1`; `ActiveSupport::Notifications` event `pg_sql_triggers.drift_check`.
26
+ The gem’s root `Rakefile` loads `rakelib/pg_sql_triggers_environment.rake` and
27
+ `lib/tasks/trigger_migrations.rake` so `bundle exec rake trigger:*` works when developing the
28
+ gem (not only from a host app).
29
+ ([lib/pg_sql_triggers/alerting.rb](lib/pg_sql_triggers/alerting.rb),
30
+ [lib/tasks/trigger_migrations.rake](lib/tasks/trigger_migrations.rake),
31
+ [lib/pg_sql_triggers/rake_development_boot.rb](lib/pg_sql_triggers/rake_development_boot.rb),
32
+ [docs/configuration.md](docs/configuration.md))
33
+
34
+ - **Column-level `UPDATE OF` triggers** — DSL method `on_update_of(*columns)` sets the event to
35
+ `update` and records column names; SQL generation and checksums use `EventsChecksum` so
36
+ `UPDATE OF "col1", "col2"` is represented consistently in drift detection. Registry validation
37
+ rejects column lists unless an update event is present.
38
+ ([lib/pg_sql_triggers/dsl/trigger_definition.rb](lib/pg_sql_triggers/dsl/trigger_definition.rb),
39
+ [lib/pg_sql_triggers/events_checksum.rb](lib/pg_sql_triggers/events_checksum.rb),
40
+ [lib/pg_sql_triggers/registry/validator.rb](lib/pg_sql_triggers/registry/validator.rb))
41
+
42
+ - **Constraint triggers and deferral** — DSL supports `constraint_trigger!` with `deferrable` /
43
+ `initially` (constraint triggers only). Registry migration
44
+ `20260412185841_add_constraint_deferral_to_pg_sql_triggers_registry.rb` adds `constraint_trigger`,
45
+ `deferrable`, and `initially` columns. Validator and drift checksum paths normalize deferral using
46
+ catalog fields such as `tgdeferrable` / `tginitdeferred` where applicable.
47
+ ([db/migrate/20260412185841_add_constraint_deferral_to_pg_sql_triggers_registry.rb](db/migrate/20260412185841_add_constraint_deferral_to_pg_sql_triggers_registry.rb),
48
+ [lib/pg_sql_triggers/dsl/trigger_definition.rb](lib/pg_sql_triggers/dsl/trigger_definition.rb),
49
+ [lib/pg_sql_triggers/registry/validator.rb](lib/pg_sql_triggers/registry/validator.rb))
50
+
51
+ - **Trigger ordering hints (`depends_on`)** — Optional `depends_on(*names)` on the DSL records
52
+ intended ordering relative to PostgreSQL’s alphabetical firing order. `Registry::Validator` checks
53
+ same-table scope, timing/`FOR EACH` consistency, absence of cycles, and name ordering; Rake task
54
+ `trigger:validate_order` runs the same rules from the CLI.
55
+ ([lib/pg_sql_triggers/dsl/trigger_definition.rb](lib/pg_sql_triggers/dsl/trigger_definition.rb),
56
+ [lib/pg_sql_triggers/registry/validator.rb](lib/pg_sql_triggers/registry/validator.rb),
57
+ [lib/tasks/trigger_migrations.rake](lib/tasks/trigger_migrations.rake))
58
+
59
+ - **Dashboard search, filters, and pagination** — Trigger index supports query parameters
60
+ (`table`, `state`, `source`, `q`) with offset/limit pagination for large registries.
61
+ ([app/controllers/pg_sql_triggers/dashboard_controller.rb](app/controllers/pg_sql_triggers/dashboard_controller.rb))
62
+
63
+ - **`schema.rb` awareness and trigger SQL snapshots** — `ActiveRecord::SchemaDumper` is prepended
64
+ with `SchemaDumperExtension` to append optional comments pointing at trigger workflows when
65
+ `PgSqlTriggers.append_trigger_notes_to_schema_dump` is true (default). Rake tasks `trigger:dump`
66
+ and `trigger:load` round-trip `db/trigger_structure.sql` via `TriggerStructureDumper`; path is
67
+ configurable with `PgSqlTriggers.trigger_structure_sql_path`. When
68
+ `PgSqlTriggers.migrate_triggers_after_schema_load` is true (default), `db:schema:load` can chain
69
+ to `trigger:migrate` (skippable with `SKIP_TRIGGER_MIGRATE_AFTER_SCHEMA_LOAD`).
70
+ ([lib/pg_sql_triggers/schema_dumper_extension.rb](lib/pg_sql_triggers/schema_dumper_extension.rb),
71
+ [lib/pg_sql_triggers/trigger_structure_dumper.rb](lib/pg_sql_triggers/trigger_structure_dumper.rb),
72
+ [lib/pg_sql_triggers/engine.rb](lib/pg_sql_triggers/engine.rb),
73
+ [lib/tasks/trigger_migrations.rake](lib/tasks/trigger_migrations.rake),
74
+ [lib/pg_sql_triggers.rb](lib/pg_sql_triggers.rb))
75
+
76
+ - **Engine routing coverage** — Declarative routing specs for the mountable engine.
77
+ ([spec/routing/pg_sql_triggers_routes_spec.rb](spec/routing/pg_sql_triggers_routes_spec.rb))
78
+
79
+ ### Changed
80
+
81
+ - **SQL permission helper naming** — View and controller helpers use `can_execute_sql_operations?`
82
+ instead of capsule-era `can_execute_sql?`, with comments aligned to migration-style SQL execution.
83
+ ([app/helpers/pg_sql_triggers/permissions_helper.rb](app/helpers/pg_sql_triggers/permissions_helper.rb),
84
+ [app/controllers/concerns/pg_sql_triggers/permission_checking.rb](app/controllers/concerns/pg_sql_triggers/permission_checking.rb))
85
+
86
+ - **`TriggerRegistry#recreate_trigger`** — Uses an explicit `source == "dsl"` branch before the
87
+ `function_body` path so DSL re-execution is obvious to readers.
88
+ ([app/models/pg_sql_triggers/trigger_registry.rb](app/models/pg_sql_triggers/trigger_registry.rb))
89
+
90
+ ### Fixed
91
+
92
+ - **`can_generate_triggers?` permission alignment** — Helper and concern both use the
93
+ `:generate_trigger` action so UI and controller authorization stay consistent.
94
+ ([app/helpers/pg_sql_triggers/permissions_helper.rb](app/helpers/pg_sql_triggers/permissions_helper.rb),
95
+ [app/controllers/concerns/pg_sql_triggers/permission_checking.rb](app/controllers/concerns/pg_sql_triggers/permission_checking.rb))
96
+
97
+ ### Planned
98
+
99
+ - **Documentation accuracy** — Regenerate [`COVERAGE.md`](COVERAGE.md) from the current tree with
100
+ SimpleCov (plan §1.1); keep user-facing docs in sync with removed v1.4.0 features where files
101
+ still exist.
102
+
103
+ - **Test hardening** — Additional request/controller specs for migration error paths and
104
+ permission edge cases (plan §4.2–4.3); extend coverage for notifier and dashboard filter
105
+ behaviour where gaps remain (plan Phase 1–2).
106
+
107
+ - **Optional (Phase 4)** — Kill-switch time-window auto-lock; trigger definition export/import
108
+ (JSON/YAML) and related Rake tasks.
109
+
110
+ ## [1.4.0] - 2026-03-01
111
+
112
+ ### Added
113
+
114
+ - **[Feature 4.1] `FOR EACH ROW` / `FOR EACH STATEMENT` DSL support** — Every PostgreSQL trigger
115
+ requires a row-level or statement-level execution granularity, but the gem previously hard-coded
116
+ `FOR EACH ROW` with no way for callers to change it. Two new DSL methods, `for_each_row` and
117
+ `for_each_statement`, let trigger definitions declare the desired granularity explicitly. The
118
+ value defaults to `"row"` so all existing definitions continue to produce `FOR EACH ROW` triggers
119
+ without modification. The field is stored in a new `for_each` column on the registry table
120
+ (migration `20260228162233_add_for_each_to_pg_sql_triggers_registry.rb`), included in all three
121
+ checksum computations (`TriggerRegistry#calculate_checksum`, `Registry::Manager#calculate_checksum`,
122
+ and `Drift::Detector#calculate_db_checksum`), extracted from live trigger definitions via a new
123
+ `extract_trigger_for_each` helper, and validated by `Registry::Validator` (only `"row"` and
124
+ `"statement"` are accepted). The SQL reconstructed by `TriggerRegistry#build_trigger_sql_from_definition`
125
+ during `re_execute!` now honours the stored `for_each` value.
126
+ ([lib/pg_sql_triggers/dsl/trigger_definition.rb](lib/pg_sql_triggers/dsl/trigger_definition.rb),
127
+ [lib/pg_sql_triggers/registry/manager.rb](lib/pg_sql_triggers/registry/manager.rb),
128
+ [lib/pg_sql_triggers/registry/validator.rb](lib/pg_sql_triggers/registry/validator.rb),
129
+ [lib/pg_sql_triggers/drift/detector.rb](lib/pg_sql_triggers/drift/detector.rb),
130
+ [app/models/pg_sql_triggers/trigger_registry.rb](app/models/pg_sql_triggers/trigger_registry.rb),
131
+ [db/migrate/20260228162233_add_for_each_to_pg_sql_triggers_registry.rb](db/migrate/20260228162233_add_for_each_to_pg_sql_triggers_registry.rb))
132
+
133
+ ### Changed
134
+
135
+ - **[Refactor 5.1] `SQL::KillSwitch` reduced from 329 to 166 lines** — The module was inflated by
136
+ four separate single-purpose log helpers (`log_allowed`, `log_override`, `log_blocked`,
137
+ `format_actor`), a `raise_blocked_error` method whose two heredocs (`message` and `recovery`)
138
+ duplicated each other across 30 lines, verbose per-method comments, and a
139
+ `rubocop:disable Metrics/ModuleLength` suppressor. Collapsed the four log helpers into one
140
+ private `log(level, status, op, env, actor, extra = nil)` method; inlined `raise_blocked_error`
141
+ as a concise 5-line `raise` call; removed all comment padding; renamed `detect_environment` →
142
+ `resolve_environment` for clarity. All three-layer semantics (config → ENV override → explicit
143
+ confirmation), public API (`active?`, `check!`, `override`, `validate_confirmation!`), log
144
+ message formats, and error message content are unchanged — all existing specs continue to pass.
145
+ ([lib/pg_sql_triggers/sql/kill_switch.rb](lib/pg_sql_triggers/sql/kill_switch.rb))
146
+
147
+ - **[Design] Eliminated N+1 queries in drift detection** — `Drift::Detector.detect_all` and
148
+ `detect_for_table` previously called `detect(trigger_name)` per registry entry, which issued a
149
+ `TriggerRegistry.find_by` and a `DbQueries.find_trigger` DB query for every row (N+1 pattern).
150
+ These methods now build an `index_by` hash from the bulk-fetched result of `DbQueries.all_triggers`
151
+ and map over pre-loaded registry entries, eliminating all per-entry lookups. A new private method
152
+ `detect_with_preloaded(registry_entry, db_trigger)` performs state computation with zero
153
+ additional queries.
154
+ ([lib/pg_sql_triggers/drift/detector.rb](lib/pg_sql_triggers/drift/detector.rb))
155
+
156
+ - **[Design] Thread-safe registry cache** — `Registry::Manager._registry_cache` was stored in a
157
+ class-level instance variable mutated without synchronisation, creating a race condition on
158
+ multi-threaded Puma servers. A `REGISTRY_CACHE_MUTEX = Mutex.new` constant now guards all reads
159
+ and writes to `@_registry_cache` via `REGISTRY_CACHE_MUTEX.synchronize`.
160
+ ([lib/pg_sql_triggers/registry/manager.rb](lib/pg_sql_triggers/registry/manager.rb))
161
+
162
+ - **[Design] Configurable PostgreSQL schema** — Every SQL query in `Drift::DbQueries` hard-coded
163
+ `n.nspname = 'public'`, making the gem unusable in applications that manage triggers in
164
+ non-public schemas. A new configuration attribute `PgSqlTriggers.db_schema` (default: `"public"`)
165
+ replaces all hard-coded schema literals; the value is passed as a bind parameter via a private
166
+ `schema_name` helper. Override in an initialiser:
167
+ `PgSqlTriggers.db_schema = "app"`.
168
+ ([lib/pg_sql_triggers.rb](lib/pg_sql_triggers.rb),
169
+ [lib/pg_sql_triggers/drift/db_queries.rb](lib/pg_sql_triggers/drift/db_queries.rb))
170
+
171
+ - **[Design] Idiomatic DSL accessor methods** — `TriggerDefinition#version`, `#enabled`, and
172
+ `#timing` used a dual-purpose getter/setter pattern (`def version(v = nil)`) that silently
173
+ returned the current value when called with no argument, making typos invisible. Replaced with
174
+ standard `attr_accessor :version, :enabled` and a custom `timing=(val)` writer that converts to
175
+ string, matching the Ruby/Rails `attr_accessor` convention. DSL block syntax changes from
176
+ `version 1` to `self.version = 1` and `enabled true` to `self.enabled = true`.
177
+ ([lib/pg_sql_triggers/dsl/trigger_definition.rb](lib/pg_sql_triggers/dsl/trigger_definition.rb))
178
+
179
+ - **[Design] `capture_state` now includes `function_body`** — The audit snapshot captured by
180
+ `TriggerRegistry#capture_state` (used in before/after diffs for all audit log entries) omitted
181
+ `function_body`, making it impossible to see the actual function content in audit trail diffs.
182
+ The field is now included in all captured state hashes.
183
+ ([app/models/pg_sql_triggers/trigger_registry.rb](app/models/pg_sql_triggers/trigger_registry.rb))
184
+
185
+ - **[Design 5.4] `Migrator#run_migration` reduced from three migration instances to two** —
186
+ `run_migration` previously instantiated the migration class three times: once for
187
+ `SafetyValidator`, once for `PreApplyComparator`, and once for actual execution. This meant
188
+ the migration code ran twice before execution, making the behaviour unpredictable if the
189
+ migration had side effects that escaped the `execute` override. A new private
190
+ `capture_migration_sql(instance, direction)` helper (wrapped in a rolled-back transaction)
191
+ captures SQL once from a single inspection instance. `SafetyValidator.validate_sql!` and
192
+ `PreApplyComparator.compare_sql` are new entry points that accept pre-captured SQL directly,
193
+ avoiding a second run of the migration code. Execution still uses a fresh instance. The
194
+ existing `validate!` and `compare` instance-based APIs are retained for backward compatibility
195
+ with specs.
196
+ ([lib/pg_sql_triggers/migrator.rb](lib/pg_sql_triggers/migrator.rb),
197
+ [lib/pg_sql_triggers/migrator/safety_validator.rb](lib/pg_sql_triggers/migrator/safety_validator.rb),
198
+ [lib/pg_sql_triggers/migrator/pre_apply_comparator.rb](lib/pg_sql_triggers/migrator/pre_apply_comparator.rb))
199
+
200
+ ### Deprecated
201
+
202
+ - **`DSL::TriggerDefinition#when_env`** — Environment-specific trigger declarations cause schema
203
+ drift between environments and make triggers impossible to test fully outside production.
204
+ `when_env` now emits a `warn`-level deprecation message on every call and will be removed in a
205
+ future major version. Use application-level configuration to gate trigger behaviour by
206
+ environment instead.
207
+ ([lib/pg_sql_triggers/dsl/trigger_definition.rb](lib/pg_sql_triggers/dsl/trigger_definition.rb))
208
+
209
+ ### Removed
210
+
211
+ - **[Refactor 5.3] Web UI trigger generator removed; replaced with Rails CLI generator** —
212
+ `GeneratorController` provided a browser form for generating trigger DSL files and migrations
213
+ at runtime, writing files directly to the server's filesystem. This is a security and
214
+ auditability concern in production (server-side file writes, no code review gate). The
215
+ controller, its two views (`new`, `preview`), the `/generator` routes, `Generator::Service`,
216
+ `Generator::Form`, and all related specs have been removed. Code generation is now a local,
217
+ CLI-driven action via a new `pg_sql_triggers:trigger` Rails generator:
218
+ ```
219
+ rails generate pg_sql_triggers:trigger TRIGGER_NAME TABLE_NAME [EVENTS...] [--timing before|after] [--function fn_name]
220
+ ```
221
+ The generator produces `app/triggers/TRIGGER_NAME.rb` (DSL stub) and
222
+ `db/triggers/TIMESTAMP_TRIGGER_NAME.rb` (migration with function + trigger SQL) directly into
223
+ the working tree, where they go through version control and code review like any other source
224
+ file. The `autoload :Generator` entry is also removed from `PgSqlTriggers`.
225
+ ([lib/generators/pg_sql_triggers/trigger_generator.rb](lib/generators/pg_sql_triggers/trigger_generator.rb),
226
+ [config/routes.rb](config/routes.rb))
227
+
228
+ - **[Refactor 5.2] `SQL::Capsule` and `SQL::Executor` removed** — These classes implemented a
229
+ named-SQL-snippet execution system ("SQL capsules") for emergency operations. The feature is a
230
+ general-purpose dangerous-SQL runner that has nothing specifically to do with trigger management;
231
+ bundling it in this gem conflated concerns and enlarged the web UI's attack surface. Removed:
232
+ `lib/pg_sql_triggers/sql/capsule.rb`, `lib/pg_sql_triggers/sql/executor.rb`,
233
+ `app/controllers/pg_sql_triggers/sql_capsules_controller.rb`, the two associated views, the
234
+ `/sql_capsules` routes, and all related specs. `SQL::KillSwitch` is retained — it continues to
235
+ gate trigger re-execution and migration operations. The `PgSqlTriggers::SQL.execute_capsule`
236
+ convenience method is also removed.
237
+ ([lib/pg_sql_triggers/sql.rb](lib/pg_sql_triggers/sql.rb),
238
+ [config/routes.rb](config/routes.rb))
239
+
240
+ - **Duplicate `trigger:migration` generator namespace** — Two generator namespaces existed for the
241
+ same task: `rails g pg_sql_triggers:trigger_migration` and `rails g trigger:migration`. The
242
+ `Trigger::Generators::MigrationGenerator` (`lib/generators/trigger/`) has been removed; use
243
+ `rails g pg_sql_triggers:trigger_migration` exclusively.
244
+ ([lib/generators/trigger/migration_generator.rb](lib/generators/trigger/migration_generator.rb))
245
+
246
+ ### Security
247
+
248
+ - **[High] Production warning when no `permission_checker` is configured** — The gem's default
249
+ behaviour is to allow all actions (including admin-level operations such as `drop_trigger`,
250
+ `execute_sql`, and `override_drift`) when no `permission_checker` is set. A newly deployed
251
+ application with no extra configuration silently granted every actor full admin access.
252
+ The engine now emits a `Rails.logger.warn` at startup when the app boots in production and
253
+ `PgSqlTriggers.permission_checker` is still `nil`, making the misconfiguration visible in
254
+ production logs immediately on deploy.
255
+ ([lib/pg_sql_triggers/engine.rb](lib/pg_sql_triggers/engine.rb))
256
+
257
+ - **[High] `Registry::Validator` was a no-op stub** — `Validator.validate!` returned `true`
258
+ unconditionally, meaning malformed DSL definitions (missing `table_name`, empty or invalid
259
+ `events`, missing `function_name`, unrecognised `timing` values) silently passed validation
260
+ and were written to the registry. Replaced the stub with real validation: every `source: "dsl"`
261
+ entry in the registry has its stored `definition` JSON parsed and checked against required
262
+ fields and allowed values (`insert / update / delete / truncate` for events;
263
+ `before / after / instead_of` for timing). All errors are collected across all triggers and
264
+ surfaced in a single `ValidationError` listing every violation. Non-DSL entries are not
265
+ validated. Unparseable JSON is treated as an empty definition, which itself fails validation.
266
+ ([lib/pg_sql_triggers/registry/validator.rb](lib/pg_sql_triggers/registry/validator.rb))
267
+
268
+ ### Fixed
269
+ - **[High] `enabled: false` DSL option was cosmetic — trigger still fired in PostgreSQL** —
270
+ The `enabled` field was stored in the registry and surfaced in drift reports, but no
271
+ `ALTER TABLE … DISABLE TRIGGER` was ever issued across three code paths, so the trigger
272
+ continued to fire regardless of the DSL flag.
273
+
274
+ *Gap 1 — `Registry::Manager#register`*: A new private `sync_postgresql_enabled_state` helper
275
+ is called after every create or update that affects the `enabled` field. On **create**, the
276
+ helper fires only when `definition.enabled` is falsy (a newly created PostgreSQL trigger is
277
+ always enabled by default). On **update**, `enabled_changed` is captured before the `update!`
278
+ call so the comparison is always against the old value; the sync fires only when `enabled`
279
+ actually flipped. The helper checks `DatabaseIntrospection#trigger_exists?` before issuing
280
+ any SQL, making it safe to call at app boot before migrations have run, and rescues any error
281
+ with a `Rails.logger.warn` so a transient DB issue cannot crash the registration path.
282
+
283
+ *Gap 2 — `Migrator#run_migration` (`:up`)*: `CREATE TRIGGER` always leaves the trigger
284
+ enabled in PostgreSQL. A new private `enforce_disabled_triggers` method is called after each
285
+ `:up` migration transaction commits; it iterates over all `TriggerRegistry.disabled` entries
286
+ and issues `ALTER TABLE … DISABLE TRIGGER` for any that exist in the database. A per-iteration
287
+ `rescue` ensures one failure does not block the rest.
288
+
289
+ *Gap 3 — `TriggerRegistry#update_registry_after_re_execute`*: `re_execute!` drops and
290
+ recreates the trigger, leaving it always enabled in PostgreSQL. The method previously also
291
+ forced `enabled: true` into the registry `update!` call, overwriting any previously stored
292
+ `false` value. The `enabled: true` is removed from the `update!` so the stored state is
293
+ preserved; if `enabled` is `false`, an `ALTER TABLE … DISABLE TRIGGER` is issued immediately
294
+ after the registry update, within the same transaction.
295
+
296
+ Spec coverage added for all three gaps:
297
+ - `registry_spec.rb` — four cases in a new `"with PostgreSQL enabled state sync"` context:
298
+ create with `enabled: false` when trigger exists in DB, create when trigger not yet in DB
299
+ (no SQL, no error), update `true → false`, and update `false → true`.
300
+ - `trigger_registry_spec.rb` — new `"when registry entry has enabled: false"` context inside
301
+ `#re_execute!`: verifies `enabled` is not flipped to `true` and that `DISABLE TRIGGER` SQL
302
+ is issued after recreation.
303
+ - `migrator_spec.rb` — new `".run_migration with enforce_disabled_triggers"` describe block:
304
+ runs a real migration that creates a trigger, confirms `tgenabled = 'D'` in `pg_trigger`
305
+ afterward.
306
+
307
+ ([lib/pg_sql_triggers/registry/manager.rb](lib/pg_sql_triggers/registry/manager.rb),
308
+ [lib/pg_sql_triggers/migrator.rb](lib/pg_sql_triggers/migrator.rb),
309
+ [app/models/pg_sql_triggers/trigger_registry.rb](app/models/pg_sql_triggers/trigger_registry.rb),
310
+ [spec/pg_sql_triggers/registry_spec.rb](spec/pg_sql_triggers/registry_spec.rb),
311
+ [spec/pg_sql_triggers/trigger_registry_spec.rb](spec/pg_sql_triggers/trigger_registry_spec.rb),
312
+ [spec/pg_sql_triggers/migrator_spec.rb](spec/pg_sql_triggers/migrator_spec.rb))
313
+
314
+ - **[Medium] `enabled` defaulted to `false` in the DSL** — Every newly declared trigger had
315
+ `@enabled = false`, meaning triggers were silently disabled unless the author explicitly added
316
+ `self.enabled = true`. Deployments that omitted the flag would register a disabled trigger that
317
+ appears in the registry but never fires, with no warning. Changed the default to `true` so
318
+ triggers are active unless explicitly disabled.
319
+ ([lib/pg_sql_triggers/dsl/trigger_definition.rb](lib/pg_sql_triggers/dsl/trigger_definition.rb))
320
+
321
+ - **[Critical] Drift detector checksum excluded `timing` field** — `Drift::Detector#calculate_db_checksum`
322
+ was hashing without the `timing` attribute, while `TriggerRegistry#calculate_checksum` and
323
+ `Registry::Manager#calculate_checksum` both include it. Any trigger with a non-default timing
324
+ value (`"after"`) permanently showed as `DRIFTED` even when fully in sync.
325
+ ([lib/pg_sql_triggers/drift/detector.rb](lib/pg_sql_triggers/drift/detector.rb))
326
+
327
+ - **[Critical] `extract_function_body` returned the full `CREATE FUNCTION` statement** —
328
+ `pg_get_functiondef()` returns the complete DDL including the `CREATE OR REPLACE FUNCTION`
329
+ header and language clause. The detector was hashing that entire string while the registry
330
+ stores only the PL/pgSQL body, so checksums never matched and every trigger appeared `DRIFTED`.
331
+ Fixed by extracting only the content between dollar-quote delimiters (`$$` / `$function$`).
332
+ ([lib/pg_sql_triggers/drift/detector.rb](lib/pg_sql_triggers/drift/detector.rb))
333
+
334
+ - **[Critical] DSL triggers stored `"placeholder"` as checksum causing permanent false drift** —
335
+ `Registry::Manager#calculate_checksum` returned the literal string `"placeholder"` whenever
336
+ `function_body` was blank (the normal case for DSL-defined triggers). The drift detector then
337
+ computed a real SHA256 hash and compared it to `"placeholder"`, so all DSL triggers always
338
+ appeared `DRIFTED`. Fixed by computing a real checksum using `""` for `function_body`, and
339
+ teaching the detector to also use `""` for `function_body` when the registry source is `"dsl"`.
340
+ ([lib/pg_sql_triggers/registry/manager.rb](lib/pg_sql_triggers/registry/manager.rb),
341
+ [lib/pg_sql_triggers/drift/detector.rb](lib/pg_sql_triggers/drift/detector.rb))
342
+
343
+ - **[Critical] `re_execute!` always raised for DSL-defined triggers** —
344
+ `TriggerRegistry#re_execute!` raised `StandardError` immediately when `function_body` was
345
+ blank, which is always the case for DSL triggers (the primary use path). Added a
346
+ `build_trigger_sql_from_definition` private helper that reconstructs a valid `CREATE TRIGGER`
347
+ SQL statement from the stored DSL definition JSON (`function_name`, `timing`, `events`,
348
+ `condition`). `re_execute!` now falls back to this reconstructed SQL when `function_body` is
349
+ absent, making the method functional for DSL triggers.
350
+ ([app/models/pg_sql_triggers/trigger_registry.rb](app/models/pg_sql_triggers/trigger_registry.rb))
351
+
352
+ - **[High] `SafetyValidator#capture_sql` executed migration side effects during capture** —
353
+ `capture_sql` monkey-patched only the `execute` method, so any ActiveRecord migration helpers
354
+ (`add_column`, `create_table`, etc.) called by the migration ran for real as a side effect of
355
+ the safety check. Wrapped the migration invocation in
356
+ `ActiveRecord::Base.transaction { …; raise ActiveRecord::Rollback }` so all schema changes
357
+ are rolled back after SQL capture.
358
+ ([lib/pg_sql_triggers/migrator/safety_validator.rb](lib/pg_sql_triggers/migrator/safety_validator.rb))
359
+
360
+ - **[Low] Dead `trigger_name` expression in `drop!`** — A bare `trigger_name` expression inside
361
+ the `drop!` transaction block was a no-op whose return value was silently discarded. Removed.
362
+ ([app/models/pg_sql_triggers/trigger_registry.rb](app/models/pg_sql_triggers/trigger_registry.rb))
363
+
10
364
  ## [1.3.0] - 2026-01-05
11
365
 
12
366
  ### Added
data/COVERAGE.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Code Coverage Report
2
2
 
3
- **Total Coverage: 95.99%**
3
+ **Total Coverage: 96.04%**
4
4
 
5
- Covered: 2319 / 2416 lines
5
+ Covered: 2499 / 2602 lines
6
6
 
7
7
  ---
8
8
 
@@ -10,58 +10,56 @@ Covered: 2319 / 2416 lines
10
10
 
11
11
  | File | Coverage | Covered Lines | Missed Lines | Total Lines |
12
12
  |------|----------|---------------|--------------|-------------|
13
- | `lib/pg_sql_triggers/drift.rb` | 100.0% ✅ | 13 | 0 | 13 |
14
- | `lib/pg_sql_triggers/drift/db_queries.rb` | 100.0% ✅ | 24 | 0 | 24 |
15
- | `lib/pg_sql_triggers/dsl.rb` | 100.0% ✅ | 9 | 0 | 9 |
16
- | `lib/pg_sql_triggers/dsl/trigger_definition.rb` | 100.0% ✅ | 37 | 0 | 37 |
17
- | `lib/pg_sql_triggers/generator.rb` | 100.0% ✅ | 4 | 0 | 4 |
18
- | `lib/pg_sql_triggers/generator/form.rb` | 100.0% ✅ | 36 | 0 | 36 |
19
- | `lib/pg_sql_triggers/generator/service.rb` | 100.0% ✅ | 101 | 0 | 101 |
20
- | `lib/generators/pg_sql_triggers/install_generator.rb` | 100.0% ✅ | 18 | 0 | 18 |
21
- | `lib/generators/trigger/migration_generator.rb` | 100.0% ✅ | 27 | 0 | 27 |
22
13
  | `lib/pg_sql_triggers/migration.rb` | 100.0% ✅ | 4 | 0 | 4 |
14
+ | `lib/pg_sql_triggers/migrator/pre_apply_comparator.rb` | 100.0% ✅ | 125 | 0 | 125 |
15
+ | `lib/generators/pg_sql_triggers/install_generator.rb` | 100.0% ✅ | 18 | 0 | 18 |
16
+ | `lib/pg_sql_triggers/dsl/trigger_definition.rb` | 100.0% ✅ | 60 | 0 | 60 |
17
+ | `lib/pg_sql_triggers/dsl.rb` | 100.0% ✅ | 9 | 0 | 9 |
23
18
  | `lib/pg_sql_triggers/migrator/pre_apply_diff_reporter.rb` | 100.0% ✅ | 75 | 0 | 75 |
24
- | `lib/pg_sql_triggers/migrator/safety_validator.rb` | 100.0% ✅ | 110 | 0 | 110 |
19
+ | `lib/pg_sql_triggers/sql.rb` | 100.0% ✅ | 7 | 0 | 7 |
20
+ | `lib/pg_sql_triggers/migrator/safety_validator.rb` | 100.0% ✅ | 120 | 0 | 120 |
21
+ | `lib/pg_sql_triggers/drift.rb` | 100.0% ✅ | 15 | 0 | 15 |
25
22
  | `lib/pg_sql_triggers/permissions.rb` | 100.0% ✅ | 11 | 0 | 11 |
26
- | `lib/pg_sql_triggers/permissions/checker.rb` | 100.0% ✅ | 17 | 0 | 17 |
27
- | `lib/pg_sql_triggers/registry/validator.rb` | 100.0% ✅ | 5 | 0 | 5 |
28
- | `lib/pg_sql_triggers/sql/capsule.rb` | 100.0% ✅ | 28 | 0 | 28 |
29
- | `lib/pg_sql_triggers/sql/executor.rb` | 100.0% ✅ | 63 | 0 | 63 |
30
- | `lib/pg_sql_triggers/testing.rb` | 100.0% ✅ | 6 | 0 | 6 |
31
- | `lib/pg_sql_triggers/testing/syntax_validator.rb` | 100.0% ✅ | 58 | 0 | 58 |
23
+ | `lib/pg_sql_triggers/permissions/checker.rb` | 100.0% ✅ | 16 | 0 | 16 |
24
+ | `app/controllers/pg_sql_triggers/triggers_controller.rb` | 100.0% ✅ | 76 | 0 | 76 |
25
+ | `app/helpers/pg_sql_triggers/dashboard_helper.rb` | 100.0% ✅ | 7 | 0 | 7 |
26
+ | `app/controllers/pg_sql_triggers/dashboard_controller.rb` | 100.0% ✅ | 72 | 0 | 72 |
27
+ | `lib/pg_sql_triggers.rb` | 100.0% ✅ | 51 | 0 | 51 |
28
+ | `lib/pg_sql_triggers/errors.rb` | 100.0% ✅ | 83 | 0 | 83 |
32
29
  | `lib/pg_sql_triggers/testing/dry_run.rb` | 100.0% ✅ | 24 | 0 | 24 |
33
- | `app/models/pg_sql_triggers/audit_log.rb` | 100.0% ✅ | 28 | 0 | 28 |
34
- | `app/models/pg_sql_triggers/trigger_registry.rb` | 100.0% ✅ | 176 | 0 | 176 |
30
+ | `lib/pg_sql_triggers/testing/syntax_validator.rb` | 100.0% ✅ | 58 | 0 | 58 |
31
+ | `lib/pg_sql_triggers/testing.rb` | 100.0% ✅ | 6 | 0 | 6 |
32
+ | `config/initializers/pg_sql_triggers.rb` | 100.0% ✅ | 10 | 0 | 10 |
33
+ | `app/models/pg_sql_triggers/application_record.rb` | 100.0% ✅ | 3 | 0 | 3 |
34
+ | `app/models/pg_sql_triggers/audit_log.rb` | 100.0% ✅ | 32 | 0 | 32 |
35
35
  | `app/controllers/concerns/pg_sql_triggers/error_handling.rb` | 100.0% ✅ | 19 | 0 | 19 |
36
36
  | `app/controllers/concerns/pg_sql_triggers/kill_switch_protection.rb` | 100.0% ✅ | 17 | 0 | 17 |
37
- | `app/models/pg_sql_triggers/application_record.rb` | 100.0% ✅ | 3 | 0 | 3 |
37
+ | `app/controllers/concerns/pg_sql_triggers/permission_checking.rb` | 100.0% ✅ | 41 | 0 | 41 |
38
38
  | `app/controllers/pg_sql_triggers/application_controller.rb` | 100.0% ✅ | 13 | 0 | 13 |
39
39
  | `app/helpers/pg_sql_triggers/permissions_helper.rb` | 100.0% ✅ | 16 | 0 | 16 |
40
- | `app/controllers/pg_sql_triggers/dashboard_controller.rb` | 100.0% ✅ | 26 | 0 | 26 |
41
- | `config/initializers/pg_sql_triggers.rb` | 100.0% ✅ | 10 | 0 | 10 |
42
- | `lib/pg_sql_triggers/errors.rb` | 100.0% ✅ | 83 | 0 | 83 |
43
- | `app/controllers/pg_sql_triggers/triggers_controller.rb` | 100.0% ✅ | 75 | 0 | 75 |
44
- | `lib/pg_sql_triggers.rb` | 100.0% ✅ | 40 | 0 | 40 |
45
- | `lib/pg_sql_triggers/migrator/pre_apply_comparator.rb` | 99.19% ✅ | 122 | 1 | 123 |
46
- | `lib/pg_sql_triggers/drift/detector.rb` | 98.48% ✅ | 65 | 1 | 66 |
47
- | `app/controllers/pg_sql_triggers/audit_logs_controller.rb` | 97.73% ✅ | 43 | 1 | 44 |
48
- | `app/controllers/pg_sql_triggers/sql_capsules_controller.rb` | 97.14% ✅ | 68 | 2 | 70 |
40
+ | `app/controllers/pg_sql_triggers/audit_logs_controller.rb` | 100.0% ✅ | 55 | 0 | 55 |
41
+ | `app/controllers/pg_sql_triggers/migrations_controller.rb` | 98.82% ✅ | 84 | 1 | 85 |
42
+ | `lib/pg_sql_triggers/registry/manager.rb` | 98.81% ✅ | 83 | 1 | 84 |
43
+ | `lib/pg_sql_triggers/events_checksum.rb` | 98.33% ✅ | 59 | 1 | 60 |
44
+ | `app/models/pg_sql_triggers/trigger_registry.rb` | 97.69% ✅ | 211 | 5 | 216 |
45
+ | `lib/pg_sql_triggers/sql/kill_switch.rb` | 96.51% ✅ | 83 | 3 | 86 |
49
46
  | `lib/generators/pg_sql_triggers/trigger_migration_generator.rb` | 96.3% ✅ | 26 | 1 | 27 |
50
- | `lib/pg_sql_triggers/sql/kill_switch.rb` | 96.04% ✅ | 97 | 4 | 101 |
51
- | `lib/pg_sql_triggers/migrator.rb` | 95.42% ✅ | 125 | 6 | 131 |
52
- | `lib/pg_sql_triggers/registry/manager.rb` | 95.08% ✅ | 58 | 3 | 61 |
53
- | `app/controllers/pg_sql_triggers/tables_controller.rb` | 94.74% ✅ | 18 | 1 | 19 |
47
+ | `lib/pg_sql_triggers/alerting.rb` | 96.3% ✅ | 26 | 1 | 27 |
48
+ | `lib/pg_sql_triggers/drift/db_queries.rb` | 96.15% ✅ | 25 | 1 | 26 |
49
+ | `lib/pg_sql_triggers/deferral_checksum.rb` | 96.0% ✅ | 24 | 1 | 25 |
50
+ | `lib/pg_sql_triggers/migrator.rb` | 95.78% ✅ | 159 | 7 | 166 |
51
+ | `lib/pg_sql_triggers/registry/validator.rb` | 94.83% ✅ | 165 | 9 | 174 |
54
52
  | `lib/pg_sql_triggers/database_introspection.rb` | 94.29% ✅ | 66 | 4 | 70 |
55
53
  | `lib/pg_sql_triggers/drift/reporter.rb` | 94.12% ✅ | 96 | 6 | 102 |
56
- | `lib/pg_sql_triggers/engine.rb` | 92.86% ✅ | 13 | 1 | 14 |
54
+ | `lib/pg_sql_triggers/drift/detector.rb` | 92.5% ✅ | 74 | 6 | 80 |
57
55
  | `lib/pg_sql_triggers/testing/safe_executor.rb` | 91.89% ✅ | 34 | 3 | 37 |
58
56
  | `lib/pg_sql_triggers/registry.rb` | 91.84% ✅ | 45 | 4 | 49 |
59
- | `app/controllers/pg_sql_triggers/generator_controller.rb` | 91.49% ✅ | 86 | 8 | 94 |
60
- | `lib/pg_sql_triggers/sql.rb` | 90.91% | 10 | 1 | 11 |
61
- | `lib/pg_sql_triggers/testing/function_tester.rb` | 89.71% ⚠️ | 61 | 7 | 68 |
62
- | `app/controllers/concerns/pg_sql_triggers/permission_checking.rb` | 85.37% ⚠️ | 35 | 6 | 41 |
63
- | `app/controllers/pg_sql_triggers/migrations_controller.rb` | 82.76% ⚠️ | 72 | 15 | 87 |
64
- | `config/routes.rb` | 12.0% ❌ | 3 | 22 | 25 |
57
+ | `lib/pg_sql_triggers/trigger_structure_dumper.rb` | 90.32% ✅ | 56 | 6 | 62 |
58
+ | `lib/pg_sql_triggers/testing/function_tester.rb` | 88.31% ⚠️ | 68 | 9 | 77 |
59
+ | `app/controllers/pg_sql_triggers/tables_controller.rb` | 83.78% ⚠️ | 31 | 6 | 37 |
60
+ | `lib/pg_sql_triggers/schema_dumper_extension.rb` | 73.33% ⚠️ | 11 | 4 | 15 |
61
+ | `lib/pg_sql_triggers/engine.rb` | 72.97% ⚠️ | 27 | 10 | 37 |
62
+ | `config/routes.rb` | 17.65% ❌ | 3 | 14 | 17 |
65
63
 
66
64
  ---
67
65
 
data/LICENSE CHANGED
File without changes