pg_sql_triggers 1.0.0 → 1.1.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.
- checksums.yaml +4 -4
- data/.erb_lint.yml +47 -0
- data/.rubocop.yml +4 -1
- data/CHANGELOG.md +112 -1
- data/COVERAGE.md +58 -0
- data/Goal.md +450 -123
- data/README.md +53 -215
- data/app/controllers/pg_sql_triggers/application_controller.rb +46 -0
- data/app/controllers/pg_sql_triggers/dashboard_controller.rb +4 -1
- data/app/controllers/pg_sql_triggers/generator_controller.rb +76 -8
- data/app/controllers/pg_sql_triggers/migrations_controller.rb +18 -0
- data/app/models/pg_sql_triggers/trigger_registry.rb +93 -12
- data/app/views/layouts/pg_sql_triggers/application.html.erb +34 -1
- data/app/views/pg_sql_triggers/dashboard/index.html.erb +70 -30
- data/app/views/pg_sql_triggers/generator/new.html.erb +22 -4
- data/app/views/pg_sql_triggers/generator/preview.html.erb +244 -16
- data/app/views/pg_sql_triggers/shared/_confirmation_modal.html.erb +221 -0
- data/app/views/pg_sql_triggers/shared/_kill_switch_status.html.erb +40 -0
- data/app/views/pg_sql_triggers/tables/index.html.erb +0 -2
- data/app/views/pg_sql_triggers/tables/show.html.erb +3 -4
- data/config/initializers/pg_sql_triggers.rb +69 -0
- data/db/migrate/20251222000001_create_pg_sql_triggers_tables.rb +3 -1
- data/db/migrate/20251229071916_add_timing_to_pg_sql_triggers_registry.rb +8 -0
- data/docs/README.md +66 -0
- data/docs/api-reference.md +681 -0
- data/docs/configuration.md +541 -0
- data/docs/getting-started.md +135 -0
- data/docs/kill-switch.md +586 -0
- data/docs/screenshots/.gitkeep +1 -0
- data/docs/screenshots/Generate Trigger.png +0 -0
- data/docs/screenshots/Triggers Page.png +0 -0
- data/docs/screenshots/kill error.png +0 -0
- data/docs/screenshots/kill modal for migration down.png +0 -0
- data/docs/usage-guide.md +493 -0
- data/docs/web-ui.md +353 -0
- data/lib/generators/pg_sql_triggers/templates/create_pg_sql_triggers_tables.rb +3 -1
- data/lib/generators/pg_sql_triggers/templates/initializer.rb +44 -2
- data/lib/pg_sql_triggers/drift/db_queries.rb +116 -0
- data/lib/pg_sql_triggers/drift/detector.rb +187 -0
- data/lib/pg_sql_triggers/drift/reporter.rb +179 -0
- data/lib/pg_sql_triggers/drift.rb +14 -11
- data/lib/pg_sql_triggers/dsl/trigger_definition.rb +15 -1
- data/lib/pg_sql_triggers/generator/form.rb +3 -1
- data/lib/pg_sql_triggers/generator/service.rb +82 -26
- data/lib/pg_sql_triggers/migration.rb +1 -1
- data/lib/pg_sql_triggers/migrator/pre_apply_comparator.rb +344 -0
- data/lib/pg_sql_triggers/migrator/pre_apply_diff_reporter.rb +143 -0
- data/lib/pg_sql_triggers/migrator/safety_validator.rb +258 -0
- data/lib/pg_sql_triggers/migrator.rb +85 -3
- data/lib/pg_sql_triggers/registry/manager.rb +100 -13
- data/lib/pg_sql_triggers/sql/kill_switch.rb +300 -0
- data/lib/pg_sql_triggers/testing/dry_run.rb +5 -7
- data/lib/pg_sql_triggers/testing/function_tester.rb +66 -24
- data/lib/pg_sql_triggers/testing/safe_executor.rb +23 -11
- data/lib/pg_sql_triggers/testing/syntax_validator.rb +24 -1
- data/lib/pg_sql_triggers/version.rb +1 -1
- data/lib/pg_sql_triggers.rb +24 -0
- data/lib/tasks/trigger_migrations.rake +33 -0
- data/scripts/generate_coverage_report.rb +129 -0
- metadata +45 -5
|
@@ -0,0 +1,681 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
Complete reference for using PgSqlTriggers programmatically from the Rails console or within your application code.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Registry API](#registry-api)
|
|
8
|
+
- [Migrator API](#migrator-api)
|
|
9
|
+
- [Kill Switch API](#kill-switch-api)
|
|
10
|
+
- [DSL API](#dsl-api)
|
|
11
|
+
- [TriggerRegistry Model](#triggerregistry-model)
|
|
12
|
+
|
|
13
|
+
## Registry API
|
|
14
|
+
|
|
15
|
+
The Registry API provides methods for inspecting and managing triggers.
|
|
16
|
+
|
|
17
|
+
### `PgSqlTriggers::Registry.list`
|
|
18
|
+
|
|
19
|
+
Returns all registered triggers.
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
triggers = PgSqlTriggers::Registry.list
|
|
23
|
+
# => [#<PgSqlTriggers::TriggerRegistry...>, ...]
|
|
24
|
+
|
|
25
|
+
triggers.each do |trigger|
|
|
26
|
+
puts "#{trigger.trigger_name} - #{trigger.status}"
|
|
27
|
+
end
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Returns**: Array of `TriggerRegistry` records
|
|
31
|
+
|
|
32
|
+
### `PgSqlTriggers::Registry.enabled`
|
|
33
|
+
|
|
34
|
+
Returns only enabled triggers.
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
enabled_triggers = PgSqlTriggers::Registry.enabled
|
|
38
|
+
# => [#<PgSqlTriggers::TriggerRegistry...>, ...]
|
|
39
|
+
|
|
40
|
+
puts "Enabled triggers: #{enabled_triggers.count}"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Returns**: Array of `TriggerRegistry` records
|
|
44
|
+
|
|
45
|
+
### `PgSqlTriggers::Registry.disabled`
|
|
46
|
+
|
|
47
|
+
Returns only disabled triggers.
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
disabled_triggers = PgSqlTriggers::Registry.disabled
|
|
51
|
+
# => [#<PgSqlTriggers::TriggerRegistry...>, ...]
|
|
52
|
+
|
|
53
|
+
disabled_triggers.each do |trigger|
|
|
54
|
+
puts "Disabled: #{trigger.trigger_name}"
|
|
55
|
+
end
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Returns**: Array of `TriggerRegistry` records
|
|
59
|
+
|
|
60
|
+
### `PgSqlTriggers::Registry.for_table(table_name)`
|
|
61
|
+
|
|
62
|
+
Returns triggers for a specific table.
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
user_triggers = PgSqlTriggers::Registry.for_table(:users)
|
|
66
|
+
# => [#<PgSqlTriggers::TriggerRegistry...>, ...]
|
|
67
|
+
|
|
68
|
+
user_triggers.each do |trigger|
|
|
69
|
+
puts trigger.trigger_name
|
|
70
|
+
end
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Parameters**:
|
|
74
|
+
- `table_name` (Symbol or String): The table name
|
|
75
|
+
|
|
76
|
+
**Returns**: Array of `TriggerRegistry` records
|
|
77
|
+
|
|
78
|
+
### `PgSqlTriggers::Registry.diff`
|
|
79
|
+
|
|
80
|
+
Checks for drift between DSL definitions and database state.
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
drift_info = PgSqlTriggers::Registry.diff
|
|
84
|
+
# => {
|
|
85
|
+
# in_sync: [...],
|
|
86
|
+
# drifted: [...],
|
|
87
|
+
# manual_override: [...],
|
|
88
|
+
# disabled: [...],
|
|
89
|
+
# dropped: [...],
|
|
90
|
+
# unknown: [...]
|
|
91
|
+
# }
|
|
92
|
+
|
|
93
|
+
drift_info[:drifted].each do |trigger|
|
|
94
|
+
puts "Drifted: #{trigger.trigger_name}"
|
|
95
|
+
end
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Returns**: Hash with drift categories
|
|
99
|
+
|
|
100
|
+
### `PgSqlTriggers::Registry.validate!`
|
|
101
|
+
|
|
102
|
+
Validates all triggers and raises an error if any are invalid.
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
begin
|
|
106
|
+
PgSqlTriggers::Registry.validate!
|
|
107
|
+
puts "All triggers valid"
|
|
108
|
+
rescue PgSqlTriggers::ValidationError => e
|
|
109
|
+
puts "Validation failed: #{e.message}"
|
|
110
|
+
end
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Raises**: `PgSqlTriggers::ValidationError` if validation fails
|
|
114
|
+
|
|
115
|
+
**Returns**: `true` if all triggers are valid
|
|
116
|
+
|
|
117
|
+
## Migrator API
|
|
118
|
+
|
|
119
|
+
The Migrator API manages trigger migrations programmatically.
|
|
120
|
+
|
|
121
|
+
### `PgSqlTriggers::Migrator.run_up(version = nil, confirmation: nil)`
|
|
122
|
+
|
|
123
|
+
Applies pending migrations.
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
# Apply all pending migrations
|
|
127
|
+
PgSqlTriggers::Migrator.run_up
|
|
128
|
+
|
|
129
|
+
# Apply up to a specific version
|
|
130
|
+
PgSqlTriggers::Migrator.run_up(20231215120000)
|
|
131
|
+
|
|
132
|
+
# With kill switch override
|
|
133
|
+
PgSqlTriggers::Migrator.run_up(nil, confirmation: "EXECUTE MIGRATOR_RUN_UP")
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Parameters**:
|
|
137
|
+
- `version` (Integer, optional): Target version to migrate to
|
|
138
|
+
- `confirmation` (String, optional): Kill switch confirmation text
|
|
139
|
+
|
|
140
|
+
**Returns**: Array of applied migration versions
|
|
141
|
+
|
|
142
|
+
### `PgSqlTriggers::Migrator.run_down(version = nil, confirmation: nil)`
|
|
143
|
+
|
|
144
|
+
Rolls back migrations.
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
# Rollback last migration
|
|
148
|
+
PgSqlTriggers::Migrator.run_down
|
|
149
|
+
|
|
150
|
+
# Rollback to a specific version
|
|
151
|
+
PgSqlTriggers::Migrator.run_down(20231215120000)
|
|
152
|
+
|
|
153
|
+
# With kill switch override
|
|
154
|
+
PgSqlTriggers::Migrator.run_down(nil, confirmation: "EXECUTE MIGRATOR_RUN_DOWN")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Parameters**:
|
|
158
|
+
- `version` (Integer, optional): Target version to rollback to
|
|
159
|
+
- `confirmation` (String, optional): Kill switch confirmation text
|
|
160
|
+
|
|
161
|
+
**Returns**: Array of rolled back migration versions
|
|
162
|
+
|
|
163
|
+
### `PgSqlTriggers::Migrator.redo(confirmation: nil)`
|
|
164
|
+
|
|
165
|
+
Rolls back and re-applies the last migration.
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
# Redo last migration
|
|
169
|
+
PgSqlTriggers::Migrator.redo
|
|
170
|
+
|
|
171
|
+
# With kill switch override
|
|
172
|
+
PgSqlTriggers::Migrator.redo(confirmation: "EXECUTE MIGRATOR_REDO")
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Parameters**:
|
|
176
|
+
- `confirmation` (String, optional): Kill switch confirmation text
|
|
177
|
+
|
|
178
|
+
**Returns**: Migration version that was redone
|
|
179
|
+
|
|
180
|
+
### `PgSqlTriggers::Migrator.pending_migrations`
|
|
181
|
+
|
|
182
|
+
Returns list of pending migrations.
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
pending = PgSqlTriggers::Migrator.pending_migrations
|
|
186
|
+
# => [#<PgSqlTriggers::Migration...>, ...]
|
|
187
|
+
|
|
188
|
+
pending.each do |migration|
|
|
189
|
+
puts "Pending: #{migration.name} (#{migration.version})"
|
|
190
|
+
end
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Returns**: Array of pending migration objects
|
|
194
|
+
|
|
195
|
+
### `PgSqlTriggers::Migrator.migration_status`
|
|
196
|
+
|
|
197
|
+
Returns status of all migrations.
|
|
198
|
+
|
|
199
|
+
```ruby
|
|
200
|
+
status = PgSqlTriggers::Migrator.migration_status
|
|
201
|
+
# => [
|
|
202
|
+
# { version: 20231215120000, name: "AddValidationTrigger", status: :up },
|
|
203
|
+
# { version: 20231216130000, name: "AddBillingTrigger", status: :down },
|
|
204
|
+
# ...
|
|
205
|
+
# ]
|
|
206
|
+
|
|
207
|
+
status.each do |migration|
|
|
208
|
+
puts "#{migration[:version]} - #{migration[:name]}: #{migration[:status]}"
|
|
209
|
+
end
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Returns**: Array of hashes with migration information
|
|
213
|
+
|
|
214
|
+
### `PgSqlTriggers::Migrator.current_version`
|
|
215
|
+
|
|
216
|
+
Returns the current migration version.
|
|
217
|
+
|
|
218
|
+
```ruby
|
|
219
|
+
version = PgSqlTriggers::Migrator.current_version
|
|
220
|
+
# => 20231215120000
|
|
221
|
+
|
|
222
|
+
puts "Current version: #{version}"
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Returns**: Integer (migration timestamp) or `nil` if no migrations applied
|
|
226
|
+
|
|
227
|
+
## Kill Switch API
|
|
228
|
+
|
|
229
|
+
The Kill Switch API provides methods for checking and overriding production protections.
|
|
230
|
+
|
|
231
|
+
### `PgSqlTriggers::SQL::KillSwitch.active?`
|
|
232
|
+
|
|
233
|
+
Checks if kill switch is currently active.
|
|
234
|
+
|
|
235
|
+
```ruby
|
|
236
|
+
if PgSqlTriggers::SQL::KillSwitch.active?
|
|
237
|
+
puts "Kill switch is enabled for this environment"
|
|
238
|
+
else
|
|
239
|
+
puts "Kill switch is not active"
|
|
240
|
+
end
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Returns**: Boolean
|
|
244
|
+
|
|
245
|
+
### `PgSqlTriggers::SQL::KillSwitch.protected_environment?`
|
|
246
|
+
|
|
247
|
+
Checks if current environment is protected.
|
|
248
|
+
|
|
249
|
+
```ruby
|
|
250
|
+
if PgSqlTriggers::SQL::KillSwitch.protected_environment?
|
|
251
|
+
puts "Current environment is protected"
|
|
252
|
+
else
|
|
253
|
+
puts "Current environment is not protected"
|
|
254
|
+
end
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**Returns**: Boolean
|
|
258
|
+
|
|
259
|
+
### `PgSqlTriggers::SQL::KillSwitch.environment`
|
|
260
|
+
|
|
261
|
+
Returns the current environment.
|
|
262
|
+
|
|
263
|
+
```ruby
|
|
264
|
+
env = PgSqlTriggers::SQL::KillSwitch.environment
|
|
265
|
+
# => "production"
|
|
266
|
+
|
|
267
|
+
puts "Current environment: #{env}"
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Returns**: String
|
|
271
|
+
|
|
272
|
+
### `PgSqlTriggers::SQL::KillSwitch.check!(operation:, actor:, confirmation: nil)`
|
|
273
|
+
|
|
274
|
+
Checks if an operation is allowed and raises an error if blocked.
|
|
275
|
+
|
|
276
|
+
```ruby
|
|
277
|
+
begin
|
|
278
|
+
PgSqlTriggers::SQL::KillSwitch.check!(
|
|
279
|
+
operation: :trigger_migrate,
|
|
280
|
+
actor: { type: 'console', user: 'admin@example.com' },
|
|
281
|
+
confirmation: "EXECUTE TRIGGER_MIGRATE"
|
|
282
|
+
)
|
|
283
|
+
# Operation is allowed
|
|
284
|
+
puts "Operation allowed"
|
|
285
|
+
rescue PgSqlTriggers::KillSwitchError => e
|
|
286
|
+
puts "Operation blocked: #{e.message}"
|
|
287
|
+
end
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Parameters**:
|
|
291
|
+
- `operation` (Symbol): The operation being performed
|
|
292
|
+
- `actor` (Hash): Information about who is performing the operation
|
|
293
|
+
- `confirmation` (String, optional): Confirmation text for override
|
|
294
|
+
|
|
295
|
+
**Raises**: `PgSqlTriggers::KillSwitchError` if operation is blocked
|
|
296
|
+
|
|
297
|
+
**Returns**: `true` if operation is allowed
|
|
298
|
+
|
|
299
|
+
### `PgSqlTriggers::SQL::KillSwitch.override(confirmation:, &block)`
|
|
300
|
+
|
|
301
|
+
Executes a block with kill switch override.
|
|
302
|
+
|
|
303
|
+
```ruby
|
|
304
|
+
PgSqlTriggers::SQL::KillSwitch.override(confirmation: "EXECUTE BATCH_ENABLE") do
|
|
305
|
+
# Operations in this block bypass kill switch
|
|
306
|
+
trigger = PgSqlTriggers::TriggerRegistry.find_by(trigger_name: "users_email_validation")
|
|
307
|
+
trigger.enable!
|
|
308
|
+
|
|
309
|
+
puts "Trigger enabled"
|
|
310
|
+
end
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
**Parameters**:
|
|
314
|
+
- `confirmation` (String): Confirmation text
|
|
315
|
+
- `block`: Code to execute with override
|
|
316
|
+
|
|
317
|
+
**Raises**: `PgSqlTriggers::KillSwitchError` if confirmation is invalid
|
|
318
|
+
|
|
319
|
+
**Returns**: Result of the block
|
|
320
|
+
|
|
321
|
+
## DSL API
|
|
322
|
+
|
|
323
|
+
The DSL API is used to define triggers in your application.
|
|
324
|
+
|
|
325
|
+
### `PgSqlTriggers::DSL.pg_sql_trigger(name, &block)`
|
|
326
|
+
|
|
327
|
+
Defines a trigger.
|
|
328
|
+
|
|
329
|
+
```ruby
|
|
330
|
+
PgSqlTriggers::DSL.pg_sql_trigger "users_email_validation" do
|
|
331
|
+
table :users
|
|
332
|
+
on :insert, :update
|
|
333
|
+
function :validate_user_email
|
|
334
|
+
version 1
|
|
335
|
+
enabled false
|
|
336
|
+
timing :before
|
|
337
|
+
when_env :production
|
|
338
|
+
end
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Parameters**:
|
|
342
|
+
- `name` (String): Unique trigger name
|
|
343
|
+
- `block`: DSL block defining the trigger
|
|
344
|
+
|
|
345
|
+
### DSL Methods
|
|
346
|
+
|
|
347
|
+
#### `table(table_name)`
|
|
348
|
+
|
|
349
|
+
Specifies the table for the trigger.
|
|
350
|
+
|
|
351
|
+
```ruby
|
|
352
|
+
table :users
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Parameters**:
|
|
356
|
+
- `table_name` (Symbol): Table name
|
|
357
|
+
|
|
358
|
+
#### `on(*events)`
|
|
359
|
+
|
|
360
|
+
Specifies trigger events.
|
|
361
|
+
|
|
362
|
+
```ruby
|
|
363
|
+
on :insert
|
|
364
|
+
on :insert, :update
|
|
365
|
+
on :insert, :update, :delete
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**Parameters**:
|
|
369
|
+
- `events` (Symbols): One or more of `:insert`, `:update`, `:delete`
|
|
370
|
+
|
|
371
|
+
#### `function(function_name)`
|
|
372
|
+
|
|
373
|
+
Specifies the PostgreSQL function to execute.
|
|
374
|
+
|
|
375
|
+
```ruby
|
|
376
|
+
function :validate_user_email
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
**Parameters**:
|
|
380
|
+
- `function_name` (Symbol): Function name
|
|
381
|
+
|
|
382
|
+
#### `version(number)`
|
|
383
|
+
|
|
384
|
+
Sets the trigger version.
|
|
385
|
+
|
|
386
|
+
```ruby
|
|
387
|
+
version 1
|
|
388
|
+
version 2
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
**Parameters**:
|
|
392
|
+
- `number` (Integer): Version number
|
|
393
|
+
|
|
394
|
+
#### `enabled(state)`
|
|
395
|
+
|
|
396
|
+
Sets the initial enabled state.
|
|
397
|
+
|
|
398
|
+
```ruby
|
|
399
|
+
enabled true
|
|
400
|
+
enabled false
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Parameters**:
|
|
404
|
+
- `state` (Boolean): Initial state
|
|
405
|
+
|
|
406
|
+
#### `when_env(*environments)`
|
|
407
|
+
|
|
408
|
+
Restricts trigger to specific environments.
|
|
409
|
+
|
|
410
|
+
```ruby
|
|
411
|
+
when_env :production
|
|
412
|
+
when_env :production, :staging
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**Parameters**:
|
|
416
|
+
- `environments` (Symbols): One or more environment names
|
|
417
|
+
|
|
418
|
+
#### `timing(timing_value)`
|
|
419
|
+
|
|
420
|
+
Specifies when the trigger fires relative to the event.
|
|
421
|
+
|
|
422
|
+
```ruby
|
|
423
|
+
timing :before # Trigger fires before constraint checks (default)
|
|
424
|
+
timing :after # Trigger fires after constraint checks
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
**Parameters**:
|
|
428
|
+
- `timing_value` (Symbol or String): Either `:before` or `:after`
|
|
429
|
+
|
|
430
|
+
**Returns**: Current timing value if called without argument
|
|
431
|
+
|
|
432
|
+
## TriggerRegistry Model
|
|
433
|
+
|
|
434
|
+
The `TriggerRegistry` ActiveRecord model represents a trigger in the registry.
|
|
435
|
+
|
|
436
|
+
### Attributes
|
|
437
|
+
|
|
438
|
+
```ruby
|
|
439
|
+
trigger = PgSqlTriggers::TriggerRegistry.first
|
|
440
|
+
|
|
441
|
+
trigger.trigger_name # => "users_email_validation"
|
|
442
|
+
trigger.table_name # => "users"
|
|
443
|
+
trigger.function_name # => "validate_user_email"
|
|
444
|
+
trigger.events # => ["insert", "update"]
|
|
445
|
+
trigger.version # => 1
|
|
446
|
+
trigger.enabled # => false
|
|
447
|
+
trigger.timing # => "before" or "after"
|
|
448
|
+
trigger.environments # => ["production"]
|
|
449
|
+
trigger.condition # => "NEW.status = 'active'" or nil
|
|
450
|
+
trigger.created_at # => 2023-12-15 12:00:00 UTC
|
|
451
|
+
trigger.updated_at # => 2023-12-15 12:00:00 UTC
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### Instance Methods
|
|
455
|
+
|
|
456
|
+
#### `enable!(confirmation: nil)`
|
|
457
|
+
|
|
458
|
+
Enables the trigger.
|
|
459
|
+
|
|
460
|
+
```ruby
|
|
461
|
+
trigger = PgSqlTriggers::TriggerRegistry.find_by(trigger_name: "users_email_validation")
|
|
462
|
+
trigger.enable!
|
|
463
|
+
|
|
464
|
+
# With kill switch override
|
|
465
|
+
trigger.enable!(confirmation: "EXECUTE TRIGGER_ENABLE")
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**Parameters**:
|
|
469
|
+
- `confirmation` (String, optional): Kill switch confirmation text
|
|
470
|
+
|
|
471
|
+
**Returns**: `true` on success
|
|
472
|
+
|
|
473
|
+
#### `disable!(confirmation: nil)`
|
|
474
|
+
|
|
475
|
+
Disables the trigger.
|
|
476
|
+
|
|
477
|
+
```ruby
|
|
478
|
+
trigger = PgSqlTriggers::TriggerRegistry.find_by(trigger_name: "users_email_validation")
|
|
479
|
+
trigger.disable!
|
|
480
|
+
|
|
481
|
+
# With kill switch override
|
|
482
|
+
trigger.disable!(confirmation: "EXECUTE TRIGGER_DISABLE")
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
**Parameters**:
|
|
486
|
+
- `confirmation` (String, optional): Kill switch confirmation text
|
|
487
|
+
|
|
488
|
+
**Returns**: `true` on success
|
|
489
|
+
|
|
490
|
+
#### `drop!(confirmation: nil)`
|
|
491
|
+
|
|
492
|
+
Drops the trigger from the database.
|
|
493
|
+
|
|
494
|
+
```ruby
|
|
495
|
+
trigger = PgSqlTriggers::TriggerRegistry.find_by(trigger_name: "users_email_validation")
|
|
496
|
+
trigger.drop!(confirmation: "EXECUTE TRIGGER_DROP")
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**Parameters**:
|
|
500
|
+
- `confirmation` (String, optional): Kill switch confirmation text
|
|
501
|
+
|
|
502
|
+
**Returns**: `true` on success
|
|
503
|
+
|
|
504
|
+
#### `drift_status`
|
|
505
|
+
|
|
506
|
+
Returns the drift status of the trigger.
|
|
507
|
+
|
|
508
|
+
```ruby
|
|
509
|
+
trigger = PgSqlTriggers::TriggerRegistry.first
|
|
510
|
+
status = trigger.drift_status
|
|
511
|
+
# => :in_sync, :drifted, :manual_override, :disabled, :dropped, or :unknown
|
|
512
|
+
|
|
513
|
+
case status
|
|
514
|
+
when :in_sync
|
|
515
|
+
puts "Trigger is synchronized"
|
|
516
|
+
when :drifted
|
|
517
|
+
puts "Trigger has drifted from DSL"
|
|
518
|
+
when :manual_override
|
|
519
|
+
puts "Trigger was manually modified"
|
|
520
|
+
end
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
**Returns**: Symbol representing drift state
|
|
524
|
+
|
|
525
|
+
#### `apply!(confirmation: nil)`
|
|
526
|
+
|
|
527
|
+
Applies the trigger definition from DSL to the database.
|
|
528
|
+
|
|
529
|
+
```ruby
|
|
530
|
+
trigger = PgSqlTriggers::TriggerRegistry.find_by(trigger_name: "users_email_validation")
|
|
531
|
+
trigger.apply!(confirmation: "EXECUTE TRIGGER_APPLY")
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
**Parameters**:
|
|
535
|
+
- `confirmation` (String, optional): Kill switch confirmation text
|
|
536
|
+
|
|
537
|
+
**Returns**: `true` on success
|
|
538
|
+
|
|
539
|
+
### Class Methods
|
|
540
|
+
|
|
541
|
+
#### `PgSqlTriggers::TriggerRegistry.find_by_name(name)`
|
|
542
|
+
|
|
543
|
+
Finds a trigger by name.
|
|
544
|
+
|
|
545
|
+
```ruby
|
|
546
|
+
trigger = PgSqlTriggers::TriggerRegistry.find_by_name("users_email_validation")
|
|
547
|
+
# => #<PgSqlTriggers::TriggerRegistry...>
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
**Parameters**:
|
|
551
|
+
- `name` (String): Trigger name
|
|
552
|
+
|
|
553
|
+
**Returns**: `TriggerRegistry` record or `nil`
|
|
554
|
+
|
|
555
|
+
#### `PgSqlTriggers::TriggerRegistry.for_environment(env)`
|
|
556
|
+
|
|
557
|
+
Returns triggers applicable to a specific environment.
|
|
558
|
+
|
|
559
|
+
```ruby
|
|
560
|
+
prod_triggers = PgSqlTriggers::TriggerRegistry.for_environment("production")
|
|
561
|
+
# => [#<PgSqlTriggers::TriggerRegistry...>, ...]
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
**Parameters**:
|
|
565
|
+
- `env` (String or Symbol): Environment name
|
|
566
|
+
|
|
567
|
+
**Returns**: Array of `TriggerRegistry` records
|
|
568
|
+
|
|
569
|
+
## Usage Examples
|
|
570
|
+
|
|
571
|
+
### Complete Workflow
|
|
572
|
+
|
|
573
|
+
```ruby
|
|
574
|
+
# 1. Check pending migrations
|
|
575
|
+
pending = PgSqlTriggers::Migrator.pending_migrations
|
|
576
|
+
puts "#{pending.count} pending migrations"
|
|
577
|
+
|
|
578
|
+
# 2. Apply migrations with override
|
|
579
|
+
PgSqlTriggers::SQL::KillSwitch.override(confirmation: "EXECUTE MIGRATOR_RUN_UP") do
|
|
580
|
+
PgSqlTriggers::Migrator.run_up
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
# 3. List all triggers
|
|
584
|
+
triggers = PgSqlTriggers::Registry.list
|
|
585
|
+
puts "Total triggers: #{triggers.count}"
|
|
586
|
+
|
|
587
|
+
# 4. Check for drift
|
|
588
|
+
drift = PgSqlTriggers::Registry.diff
|
|
589
|
+
puts "Drifted triggers: #{drift[:drifted].count}"
|
|
590
|
+
|
|
591
|
+
# 5. Enable specific trigger
|
|
592
|
+
trigger = PgSqlTriggers::TriggerRegistry.find_by(trigger_name: "users_email_validation")
|
|
593
|
+
trigger.enable!(confirmation: "EXECUTE TRIGGER_ENABLE") if trigger
|
|
594
|
+
|
|
595
|
+
# 6. Validate all triggers
|
|
596
|
+
begin
|
|
597
|
+
PgSqlTriggers::Registry.validate!
|
|
598
|
+
puts "All triggers valid"
|
|
599
|
+
rescue PgSqlTriggers::ValidationError => e
|
|
600
|
+
puts "Validation error: #{e.message}"
|
|
601
|
+
end
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### Batch Operations
|
|
605
|
+
|
|
606
|
+
```ruby
|
|
607
|
+
# Enable all disabled triggers
|
|
608
|
+
PgSqlTriggers::SQL::KillSwitch.override(confirmation: "EXECUTE BATCH_ENABLE") do
|
|
609
|
+
disabled_triggers = PgSqlTriggers::Registry.disabled
|
|
610
|
+
|
|
611
|
+
disabled_triggers.each do |trigger|
|
|
612
|
+
trigger.enable!
|
|
613
|
+
puts "Enabled: #{trigger.trigger_name}"
|
|
614
|
+
end
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
# Disable all triggers for a specific table
|
|
618
|
+
PgSqlTriggers::SQL::KillSwitch.override(confirmation: "EXECUTE BATCH_DISABLE") do
|
|
619
|
+
user_triggers = PgSqlTriggers::Registry.for_table(:users)
|
|
620
|
+
|
|
621
|
+
user_triggers.each do |trigger|
|
|
622
|
+
trigger.disable!
|
|
623
|
+
puts "Disabled: #{trigger.trigger_name}"
|
|
624
|
+
end
|
|
625
|
+
end
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Inspection and Reporting
|
|
629
|
+
|
|
630
|
+
```ruby
|
|
631
|
+
# Generate a drift report
|
|
632
|
+
drift = PgSqlTriggers::Registry.diff
|
|
633
|
+
|
|
634
|
+
puts "=== Drift Report ==="
|
|
635
|
+
puts "In Sync: #{drift[:in_sync].count}"
|
|
636
|
+
puts "Drifted: #{drift[:drifted].count}"
|
|
637
|
+
puts "Manual Override: #{drift[:manual_override].count}"
|
|
638
|
+
puts "Disabled: #{drift[:disabled].count}"
|
|
639
|
+
puts "Dropped: #{drift[:dropped].count}"
|
|
640
|
+
puts "Unknown: #{drift[:unknown].count}"
|
|
641
|
+
|
|
642
|
+
# List all triggers with details
|
|
643
|
+
triggers = PgSqlTriggers::Registry.list
|
|
644
|
+
|
|
645
|
+
puts "\n=== Trigger Inventory ==="
|
|
646
|
+
triggers.each do |trigger|
|
|
647
|
+
puts "#{trigger.trigger_name}:"
|
|
648
|
+
puts " Table: #{trigger.table_name}"
|
|
649
|
+
puts " Function: #{trigger.function_name}"
|
|
650
|
+
puts " Events: #{trigger.events.join(', ')}"
|
|
651
|
+
puts " Timing: #{trigger.timing}"
|
|
652
|
+
puts " Version: #{trigger.version}"
|
|
653
|
+
puts " Enabled: #{trigger.enabled}"
|
|
654
|
+
puts " Drift: #{trigger.drift_status}"
|
|
655
|
+
puts ""
|
|
656
|
+
end
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
### Error Handling
|
|
660
|
+
|
|
661
|
+
```ruby
|
|
662
|
+
begin
|
|
663
|
+
# Attempt operation without proper confirmation
|
|
664
|
+
trigger = PgSqlTriggers::TriggerRegistry.first
|
|
665
|
+
trigger.enable!
|
|
666
|
+
rescue PgSqlTriggers::KillSwitchError => e
|
|
667
|
+
puts "Kill switch blocked operation: #{e.message}"
|
|
668
|
+
# Extract required confirmation from error message
|
|
669
|
+
# Re-attempt with proper confirmation
|
|
670
|
+
trigger.enable!(confirmation: "EXECUTE TRIGGER_ENABLE")
|
|
671
|
+
rescue StandardError => e
|
|
672
|
+
puts "Unexpected error: #{e.message}"
|
|
673
|
+
puts e.backtrace.first(5)
|
|
674
|
+
end
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
## Next Steps
|
|
678
|
+
|
|
679
|
+
- [Usage Guide](usage-guide.md) - Learn the DSL and migration system
|
|
680
|
+
- [Kill Switch](kill-switch.md) - Production safety features
|
|
681
|
+
- [Configuration](configuration.md) - Configure advanced settings
|