pg_sql_triggers 1.3.0 → 1.4.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +253 -1
  3. data/GEM_ANALYSIS.md +368 -0
  4. data/README.md +20 -23
  5. data/app/models/pg_sql_triggers/trigger_registry.rb +42 -6
  6. data/app/views/layouts/pg_sql_triggers/application.html.erb +0 -1
  7. data/app/views/pg_sql_triggers/dashboard/index.html.erb +1 -4
  8. data/app/views/pg_sql_triggers/tables/index.html.erb +1 -4
  9. data/app/views/pg_sql_triggers/tables/show.html.erb +0 -2
  10. data/config/routes.rb +0 -14
  11. data/db/migrate/20260228000001_add_for_each_to_pg_sql_triggers_registry.rb +8 -0
  12. data/docs/api-reference.md +44 -153
  13. data/docs/configuration.md +24 -3
  14. data/docs/getting-started.md +17 -16
  15. data/docs/usage-guide.md +38 -67
  16. data/docs/web-ui.md +3 -103
  17. data/lib/generators/pg_sql_triggers/templates/trigger_dsl.rb.tt +11 -0
  18. data/lib/generators/pg_sql_triggers/templates/trigger_migration_full.rb.tt +29 -0
  19. data/lib/generators/pg_sql_triggers/trigger_generator.rb +83 -0
  20. data/lib/pg_sql_triggers/drift/db_queries.rb +12 -8
  21. data/lib/pg_sql_triggers/drift/detector.rb +51 -38
  22. data/lib/pg_sql_triggers/dsl/trigger_definition.rb +17 -23
  23. data/lib/pg_sql_triggers/engine.rb +14 -0
  24. data/lib/pg_sql_triggers/migrator/pre_apply_comparator.rb +8 -9
  25. data/lib/pg_sql_triggers/migrator/safety_validator.rb +32 -12
  26. data/lib/pg_sql_triggers/migrator.rb +53 -6
  27. data/lib/pg_sql_triggers/registry/manager.rb +36 -11
  28. data/lib/pg_sql_triggers/registry/validator.rb +62 -5
  29. data/lib/pg_sql_triggers/sql/kill_switch.rb +153 -275
  30. data/lib/pg_sql_triggers/sql.rb +0 -6
  31. data/lib/pg_sql_triggers/version.rb +1 -1
  32. data/lib/pg_sql_triggers.rb +4 -1
  33. data/pg_sql_triggers.gemspec +53 -0
  34. metadata +7 -13
  35. data/app/controllers/pg_sql_triggers/generator_controller.rb +0 -213
  36. data/app/controllers/pg_sql_triggers/sql_capsules_controller.rb +0 -161
  37. data/app/views/pg_sql_triggers/generator/new.html.erb +0 -388
  38. data/app/views/pg_sql_triggers/generator/preview.html.erb +0 -305
  39. data/app/views/pg_sql_triggers/sql_capsules/new.html.erb +0 -81
  40. data/app/views/pg_sql_triggers/sql_capsules/show.html.erb +0 -85
  41. data/lib/generators/trigger/migration_generator.rb +0 -60
  42. data/lib/pg_sql_triggers/generator/form.rb +0 -80
  43. data/lib/pg_sql_triggers/generator/service.rb +0 -339
  44. data/lib/pg_sql_triggers/generator.rb +0 -8
  45. data/lib/pg_sql_triggers/sql/capsule.rb +0 -79
  46. data/lib/pg_sql_triggers/sql/executor.rb +0 -200
@@ -45,9 +45,19 @@ After installation, you should have:
45
45
 
46
46
  ## Quick Start Example
47
47
 
48
- ### 1. Create Your First Trigger Definition
48
+ ### 1. Scaffold a Trigger (DSL + Migration)
49
49
 
50
- Create a trigger definition file:
50
+ Use the CLI generator to create both files at once:
51
+
52
+ ```bash
53
+ rails generate pg_sql_triggers:trigger users_email_validation users insert update --timing before --function validate_user_email
54
+ ```
55
+
56
+ This creates:
57
+ - `app/triggers/users_email_validation.rb` — DSL stub
58
+ - `db/triggers/TIMESTAMP_users_email_validation.rb` — migration with function + trigger SQL
59
+
60
+ Edit the DSL stub to match your requirements:
51
61
 
52
62
  ```ruby
53
63
  # app/triggers/users_email_validation.rb
@@ -56,21 +66,12 @@ PgSqlTriggers::DSL.pg_sql_trigger "users_email_validation" do
56
66
  on :insert, :update
57
67
  function :validate_user_email
58
68
 
59
- version 1
60
- enabled false
61
-
62
- when_env :production
69
+ self.version = 1
70
+ self.enabled = true
71
+ timing :before
63
72
  end
64
73
  ```
65
74
 
66
- ### 2. Generate a Migration
67
-
68
- Create a trigger migration to implement the function:
69
-
70
- ```bash
71
- rails generate trigger:migration add_email_validation
72
- ```
73
-
74
75
  Edit the generated migration in `db/triggers/`:
75
76
 
76
77
  ```ruby
@@ -104,7 +105,7 @@ class AddEmailValidation < PgSqlTriggers::Migration
104
105
  end
105
106
  ```
106
107
 
107
- ### 3. Run the Migration
108
+ ### 2. Run the Migration
108
109
 
109
110
  Apply the trigger migration:
110
111
 
@@ -112,7 +113,7 @@ Apply the trigger migration:
112
113
  rake trigger:migrate
113
114
  ```
114
115
 
115
- ### 4. Access the Web UI
116
+ ### 3. Access the Web UI
116
117
 
117
118
  Open your browser and navigate to:
118
119
 
data/docs/usage-guide.md CHANGED
@@ -15,7 +15,7 @@ PgSqlTriggers provides a Ruby DSL for defining triggers. Trigger definitions are
15
15
 
16
16
  ### Basic Trigger Definition
17
17
 
18
- Create trigger definition files in `app/triggers/`:
18
+ Create trigger definition files in `app/triggers/` (or scaffold them with the CLI generator — see below):
19
19
 
20
20
  ```ruby
21
21
  # app/triggers/users_email_validation.rb
@@ -24,11 +24,9 @@ PgSqlTriggers::DSL.pg_sql_trigger "users_email_validation" do
24
24
  on :insert, :update
25
25
  function :validate_user_email
26
26
 
27
- version 1
28
- enabled false
27
+ self.version = 1
28
+ self.enabled = true
29
29
  timing :before
30
-
31
- when_env :production
32
30
  end
33
31
  ```
34
32
 
@@ -61,25 +59,30 @@ function :validate_user_email
61
59
  Version number for tracking changes:
62
60
 
63
61
  ```ruby
64
- version 1 # Increment when trigger logic changes
62
+ self.version = 1 # Increment when trigger logic changes
65
63
  ```
66
64
 
67
65
  #### `enabled`
68
- Initial state of the trigger:
66
+ Initial state of the trigger (defaults to `true`):
69
67
 
70
68
  ```ruby
71
- enabled true # Trigger is active
72
- enabled false # Trigger is inactive
69
+ self.enabled = true # Trigger is active (default)
70
+ self.enabled = false # Trigger is inactive
73
71
  ```
74
72
 
75
- #### `when_env`
76
- Environment-specific activation:
73
+ #### `for_each_row` / `for_each_statement`
74
+ PostgreSQL execution granularity (defaults to row-level):
77
75
 
78
76
  ```ruby
79
- when_env :production # Only in production
80
- when_env :staging, :production # Multiple environments
77
+ for_each_row # FOR EACH ROW (default)
78
+ for_each_statement # FOR EACH STATEMENT
81
79
  ```
82
80
 
81
+ #### `when_env`
82
+ **Deprecated.** Environment-specific trigger declarations cause schema drift between environments.
83
+ Use application-level configuration to gate trigger behaviour by environment instead.
84
+ Calling `when_env` emits a deprecation warning and will be removed in a future major version.
85
+
83
86
  #### `timing`
84
87
  Specifies when the trigger fires relative to the event (BEFORE or AFTER):
85
88
 
@@ -97,76 +100,44 @@ PgSqlTriggers::DSL.pg_sql_trigger "orders_billing_trigger" do
97
100
  on :insert, :update
98
101
  function :calculate_order_total
99
102
 
100
- version 2
101
- enabled true
103
+ self.version = 2
104
+ self.enabled = true
102
105
  timing :after
103
-
104
- when_env :production, :staging
106
+ for_each_row
105
107
  end
106
108
  ```
107
109
 
108
110
  ## Trigger Generator
109
111
 
110
- PgSqlTriggers provides a web-based generator and Rails generators for creating trigger definitions and migrations quickly.
112
+ PgSqlTriggers provides a CLI generator that scaffolds a DSL definition and migration together from the command line.
111
113
 
112
- ### Web UI Generator
114
+ ### CLI Generator
113
115
 
114
- The web UI generator provides a user-friendly interface for creating triggers:
115
-
116
- 1. Navigate to `/pg_sql_triggers/generator/new` in your browser
117
- 2. Fill in the trigger details:
118
- - **Trigger Name**: Lowercase letters, numbers, and underscores only
119
- - **Table Name**: The PostgreSQL table to attach the trigger to
120
- - **Function Name**: The PostgreSQL function name (must match the function body)
121
- - **Timing**: When the trigger fires - BEFORE (before constraint checks) or AFTER (after constraint checks)
122
- - **Events**: Select one or more events (INSERT, UPDATE, DELETE, TRUNCATE)
123
- - **Function Body**: The complete PostgreSQL function definition
124
- - **Version**: Starting version number (default: 1)
125
- - **Enabled**: Whether the trigger should be enabled initially
126
- - **Environments**: Optional environment restrictions
127
- - **Condition**: Optional WHEN condition for the trigger
128
- 3. Preview the generated DSL and migration code (includes timing and condition display)
129
- 4. Create the trigger files
130
-
131
- The generator creates:
132
- - A DSL definition file in `app/triggers/`
133
- - A migration file in `db/triggers/`
134
- - A registry entry in the database
135
-
136
- ### Rails Generators
116
+ ```bash
117
+ rails generate pg_sql_triggers:trigger TRIGGER_NAME TABLE_NAME [EVENTS...] [--timing before|after] [--function fn_name]
118
+ ```
137
119
 
138
- You can also use Rails generators to create trigger migrations:
120
+ Example:
139
121
 
140
122
  ```bash
141
- # Generate a trigger migration
142
- rails generate trigger:migration add_user_validation
143
-
144
- # Or using the full namespace
145
- rails generate pg_sql_triggers:trigger_migration add_user_validation
123
+ rails generate pg_sql_triggers:trigger users_email_validation users insert update --timing before --function validate_user_email
146
124
  ```
147
125
 
148
- This creates a migration file in `db/triggers/` that you can edit to add your trigger logic.
126
+ This creates:
127
+ - `app/triggers/users_email_validation.rb` — DSL stub
128
+ - `db/triggers/TIMESTAMP_users_email_validation.rb` — migration with function + trigger SQL
149
129
 
150
- ### Generator Features
130
+ Files are written directly into the working tree and go through version control and code review like any other source file.
151
131
 
152
- The generator handles:
153
- - **Function Name Formatting**: Automatically quotes function names with special characters
154
- - **Multiple Environments**: Supports multiple environment restrictions
155
- - **Condition Escaping**: Properly escapes quotes in WHEN conditions
156
- - **Event Combinations**: Handles single or multiple events (INSERT, UPDATE, DELETE, TRUNCATE)
157
- - **Migration Numbering**: Automatically generates sequential migration numbers
158
- - **Error Handling**: Graceful error handling with detailed error messages
132
+ ### Migration-Only Generator
159
133
 
160
- ### Generator Edge Cases
134
+ To generate a standalone trigger migration without a DSL stub:
135
+
136
+ ```bash
137
+ rails generate pg_sql_triggers:trigger_migration add_user_validation
138
+ ```
161
139
 
162
- The generator properly handles:
163
- - Function names with special characters (quoted vs unquoted)
164
- - Multiple environments in a single trigger
165
- - Complex WHEN conditions with quotes
166
- - All event type combinations
167
- - Standalone gem usage (without Rails context)
168
- - Migration number collisions
169
- - Blank events and environments (filtered automatically)
140
+ This creates a timestamped file in `db/triggers/` that you can edit to add your trigger logic.
170
141
 
171
142
  ## Trigger Migrations
172
143
 
@@ -177,7 +148,7 @@ Trigger migrations work similarly to Rails schema migrations but are specificall
177
148
  Create a new trigger migration:
178
149
 
179
150
  ```bash
180
- rails generate trigger:migration add_validation_trigger
151
+ rails generate pg_sql_triggers:trigger_migration add_validation_trigger
181
152
  ```
182
153
 
183
154
  This creates a timestamped file in `db/triggers/`:
data/docs/web-ui.md CHANGED
@@ -8,7 +8,6 @@ The PgSqlTriggers web interface provides a visual dashboard for managing trigger
8
8
  - [Dashboard Overview](#dashboard-overview)
9
9
  - [Managing Triggers](#managing-triggers)
10
10
  - [Migration Management](#migration-management)
11
- - [SQL Capsules](#sql-capsules)
12
11
  - [Audit Log](#audit-log)
13
12
  - [Permissions and Safety](#permissions-and-safety)
14
13
 
@@ -96,7 +95,7 @@ Each table row displays:
96
95
  - **Status**: Summary of enabled/disabled triggers
97
96
  - **Actions**:
98
97
  - "View Details" - Navigate to the table detail page
99
- - "Create Trigger" - Generate a new trigger for this table
98
+ - "Create Trigger" - Scaffold a new trigger for this table using the CLI generator (see [Trigger Generator](usage-guide.md#trigger-generator))
100
99
 
101
100
  ### Table Detail Page
102
101
 
@@ -303,83 +302,6 @@ After each migration action:
303
302
  - **Error**: Red flash message with error details
304
303
  - **Warnings**: Yellow flash message if issues occurred
305
304
 
306
- ## SQL Capsules
307
-
308
- SQL Capsules provide emergency escape hatches for executing SQL directly with comprehensive safety checks and audit logging.
309
-
310
- ### When to Use SQL Capsules
311
-
312
- Use SQL Capsules for:
313
- - Emergency fixes in production
314
- - Critical data corrections
315
- - Testing SQL functions
316
- - Debugging trigger behavior
317
- - One-off database operations
318
-
319
- ### Creating and Executing SQL Capsules
320
-
321
- 1. Navigate to "SQL Capsules" → "New SQL Capsule"
322
- 2. Fill in the capsule form:
323
- - **Name**: Unique identifier (alphanumeric, underscores, hyphens only)
324
- - **Environment**: Target environment (e.g., production, staging)
325
- - **Purpose**: Detailed explanation of what the SQL does and why (required for audit trail)
326
- - **SQL**: The SQL statement(s) to execute
327
- 3. Click "Create and Execute" or "Save for Later"
328
- 4. Review the capsule details on the confirmation page
329
- 5. In protected environments, enter confirmation text when prompted
330
- 6. Click "Execute" to run the SQL
331
- 7. Review the execution results
332
-
333
- ### Viewing Capsule History
334
-
335
- 1. Navigate to "SQL Capsules" → "History"
336
- 2. View list of previously executed capsules with:
337
- - Name and purpose
338
- - Environment and timestamp
339
- - SQL checksum
340
- - Execution status
341
- 3. Click on a capsule to view details
342
- 4. Re-execute historical capsules if needed
343
-
344
- ### Safety Features
345
-
346
- - **Admin Permission Required**: Only Admin users can create and execute SQL capsules
347
- - **Production Protection**: Requires typed confirmation in protected environments
348
- - **Kill Switch Integration**: All executions are protected by kill switch
349
- - **Comprehensive Logging**: All operations logged with actor, timestamp, and checksum
350
- - **Transactional Execution**: SQL runs in a transaction and rolls back on error
351
- - **Registry Storage**: All capsules are stored in the registry with checksums
352
- - **Purpose Tracking**: Required purpose field ensures all executions are documented
353
-
354
- ### Example SQL Capsules
355
-
356
- #### View All Triggers
357
- ```sql
358
- SELECT
359
- trigger_name,
360
- event_object_table,
361
- action_timing,
362
- event_manipulation
363
- FROM information_schema.triggers
364
- WHERE trigger_schema = 'public';
365
- ```
366
-
367
- #### Check Function Definitions
368
- ```sql
369
- SELECT
370
- routine_name,
371
- routine_type
372
- FROM information_schema.routines
373
- WHERE routine_schema = 'public'
374
- AND routine_name LIKE '%trigger%';
375
- ```
376
-
377
- #### Verify Trigger State
378
- ```sql
379
- SELECT * FROM pg_sql_triggers_registry
380
- WHERE trigger_name = 'users_email_validation';
381
- ```
382
-
383
305
  ## Audit Log
384
306
 
385
307
  The Audit Log provides a comprehensive view of all trigger operations performed through the web UI, console APIs, and CLI. This feature is essential for compliance, debugging, and tracking changes to your trigger ecosystem.
@@ -446,7 +368,6 @@ All of the following operations are logged to the audit log:
446
368
  - **Disable Trigger**: Success/failure, before/after state
447
369
  - **Drop Trigger**: Success/failure, reason, state changes
448
370
  - **Re-execute Trigger**: Success/failure, reason, drift diff information
449
- - **SQL Capsule Execution**: Success/failure, capsule details
450
371
  - **Migration Operations**: Up, down, and redo operations (infrastructure ready)
451
372
 
452
373
  Each log entry includes:
@@ -497,7 +418,6 @@ Cannot:
497
418
  #### Admin (Full Access)
498
419
  - All Operator permissions
499
420
  - Drop triggers
500
- - Execute SQL via capsules
501
421
  - Modify registry directly
502
422
 
503
423
  ### Kill Switch Protection
@@ -529,9 +449,9 @@ PgSqlTriggers.configure do |config|
529
449
  case action
530
450
  when :view_triggers, :view_diffs
531
451
  user.present? # Viewer level
532
- when :enable_trigger, :disable_trigger, :apply_trigger, :generate_trigger, :test_trigger, :dry_run_sql
452
+ when :enable_trigger, :disable_trigger, :apply_trigger, :test_trigger
533
453
  user.operator? || user.admin? # Operator level
534
- when :drop_trigger, :execute_sql, :override_drift
454
+ when :drop_trigger, :override_drift
535
455
  user.admin? # Admin level
536
456
  else
537
457
  false
@@ -550,32 +470,12 @@ end
550
470
  ### Main Dashboard
551
471
  ![Main Dashboard](screenshots/dashboard.png)
552
472
 
553
- ### Trigger Generator
554
-
555
- The trigger generator provides a comprehensive form for creating triggers:
556
-
557
- 1. **Basic Information**: Trigger name, table name, function name, and function body
558
- 2. **Trigger Events**: Select timing (BEFORE/AFTER) and events (INSERT, UPDATE, DELETE, TRUNCATE)
559
- 3. **Configuration**: Version, environments, WHEN condition, and enabled state
560
- 4. **Preview**: Review generated DSL and migration code with timing and condition information
561
-
562
- The preview page displays:
563
- - Generated DSL code with timing
564
- - Trigger configuration summary (timing, events, table, function, condition)
565
- - PL/pgSQL function body (editable)
566
- - SQL validation results
567
-
568
- ![Trigger Generator](screenshots/generator.png)
569
-
570
473
  ### Migration Management
571
474
  ![Migration Management](screenshots/migrations.png)
572
475
 
573
476
  ### Kill Switch Protection
574
477
  ![Kill Switch](screenshots/kill-switch.png)
575
478
 
576
- ### SQL Capsules
577
- ![SQL Capsules](screenshots/sql-capsules.png)
578
-
579
479
  ## Dashboard Enhancements (v1.3.0+)
580
480
 
581
481
  ### Last Applied Column
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ PgSqlTriggers::DSL.pg_sql_trigger "<%= trigger_name %>" do
4
+ table :<%= table_name %>
5
+ on <%= events_list %>
6
+ function :<%= function_name %>
7
+
8
+ version 1
9
+ enabled true
10
+ timing :<%= timing %>
11
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ class <%= trigger_class_name %> < PgSqlTriggers::Migration
4
+ def up
5
+ execute <<-SQL
6
+ CREATE OR REPLACE FUNCTION <%= function_name %>()
7
+ RETURNS TRIGGER AS $$
8
+ BEGIN
9
+ -- TODO: implement trigger logic
10
+ RETURN NEW;
11
+ END;
12
+ $$ LANGUAGE plpgsql;
13
+ SQL
14
+
15
+ execute <<-SQL
16
+ CREATE TRIGGER <%= trigger_name %>
17
+ <%= timing.upcase %> <%= events_sql %> ON <%= table_name %>
18
+ FOR EACH ROW
19
+ EXECUTE FUNCTION <%= function_name %>();
20
+ SQL
21
+ end
22
+
23
+ def down
24
+ execute <<-SQL
25
+ DROP TRIGGER IF EXISTS <%= trigger_name %> ON <%= table_name %>;
26
+ DROP FUNCTION IF EXISTS <%= function_name %>();
27
+ SQL
28
+ end
29
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/migration"
5
+ require "active_support/core_ext/string/inflections"
6
+
7
+ module PgSqlTriggers
8
+ module Generators
9
+ class TriggerGenerator < Rails::Generators::Base
10
+ include Rails::Generators::Migration
11
+
12
+ source_root File.expand_path("templates", __dir__)
13
+
14
+ desc "Generates a pg_sql_triggers DSL file and migration for a new trigger."
15
+
16
+ argument :trigger_name, type: :string,
17
+ desc: "Name of the trigger (e.g. notify_on_insert_users)"
18
+ argument :table_name, type: :string,
19
+ desc: "Database table the trigger attaches to (e.g. users)"
20
+ argument :events, type: :array, default: ["insert"], banner: "EVENT ...",
21
+ desc: "Trigger events: insert, update, delete (default: insert)"
22
+
23
+ class_option :timing, type: :string, default: "before",
24
+ desc: "Trigger timing: before or after (default: before)"
25
+ class_option :function, type: :string,
26
+ desc: "Function name (default: TRIGGER_NAME_function)"
27
+
28
+ def self.next_migration_number(_dirname)
29
+ existing = if Rails.root.join("db/triggers").exist?
30
+ Rails.root.glob("db/triggers/*.rb")
31
+ .map { |f| File.basename(f, ".rb").split("_").first.to_i }
32
+ .reject(&:zero?)
33
+ .max || 0
34
+ else
35
+ 0
36
+ end
37
+
38
+ now = Time.now.utc
39
+ base = now.strftime("%Y%m%d%H%M%S").to_i
40
+ base = existing + 1 if existing.positive? && base <= existing
41
+ base
42
+ end
43
+
44
+ def create_dsl_file
45
+ template "trigger_dsl.rb.tt", "app/triggers/#{trigger_name}.rb"
46
+ end
47
+
48
+ def create_migration_file
49
+ template "trigger_migration_full.rb.tt", "db/triggers/#{migration_file_name}.rb"
50
+ end
51
+
52
+ private
53
+
54
+ def function_name
55
+ options[:function].presence || "#{trigger_name}_function"
56
+ end
57
+
58
+ def timing
59
+ options[:timing]
60
+ end
61
+
62
+ def events_list
63
+ events.map { |e| ":#{e}" }.join(", ")
64
+ end
65
+
66
+ def events_sql
67
+ events.map(&:upcase).join(" OR ")
68
+ end
69
+
70
+ def trigger_class_name
71
+ "Add#{trigger_name.camelize}"
72
+ end
73
+
74
+ def migration_file_name
75
+ "#{migration_number}_#{trigger_name}"
76
+ end
77
+
78
+ def migration_number
79
+ self.class.next_migration_number(nil)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -22,12 +22,12 @@ module PgSqlTriggers
22
22
  JOIN pg_namespace n ON c.relnamespace = n.oid
23
23
  JOIN pg_proc p ON t.tgfoid = p.oid
24
24
  WHERE NOT t.tgisinternal
25
- AND n.nspname = 'public'
25
+ AND n.nspname = $1
26
26
  AND t.tgname NOT LIKE 'RI_%'
27
27
  ORDER BY c.relname, t.tgname;
28
28
  SQL
29
29
 
30
- execute_query(sql)
30
+ execute_query(sql, [schema_name])
31
31
  end
32
32
 
33
33
  # Fetch single trigger
@@ -49,10 +49,10 @@ module PgSqlTriggers
49
49
  JOIN pg_proc p ON t.tgfoid = p.oid
50
50
  WHERE t.tgname = $1
51
51
  AND NOT t.tgisinternal
52
- AND n.nspname = 'public';
52
+ AND n.nspname = $2;
53
53
  SQL
54
54
 
55
- result = execute_query(sql, [trigger_name])
55
+ result = execute_query(sql, [trigger_name, schema_name])
56
56
  result.first
57
57
  end
58
58
 
@@ -75,12 +75,12 @@ module PgSqlTriggers
75
75
  JOIN pg_proc p ON t.tgfoid = p.oid
76
76
  WHERE c.relname = $1
77
77
  AND NOT t.tgisinternal
78
- AND n.nspname = 'public'
78
+ AND n.nspname = $2
79
79
  AND t.tgname NOT LIKE 'RI_%'
80
80
  ORDER BY t.tgname;
81
81
  SQL
82
82
 
83
- execute_query(sql, [table_name])
83
+ execute_query(sql, [table_name, schema_name])
84
84
  end
85
85
 
86
86
  # Fetch function body by function name
@@ -92,15 +92,19 @@ module PgSqlTriggers
92
92
  FROM pg_proc p
93
93
  JOIN pg_namespace n ON p.pronamespace = n.oid
94
94
  WHERE p.proname = $1
95
- AND n.nspname = 'public';
95
+ AND n.nspname = $2;
96
96
  SQL
97
97
 
98
- result = execute_query(sql, [function_name])
98
+ result = execute_query(sql, [function_name, schema_name])
99
99
  result.first
100
100
  end
101
101
 
102
102
  private
103
103
 
104
+ def schema_name
105
+ PgSqlTriggers.db_schema.to_s
106
+ end
107
+
104
108
  def execute_query(sql, params = [])
105
109
  if params.any?
106
110
  # Use ActiveRecord's connection to execute parameterized queries