Module: Dagnabit::Migration
- Defined in:
- lib/dagnabit/migration.rb
Overview
Contains shorthand for setting up database triggers and constraints for maintaining dagnabit’s invariants. See the README for more information.
This module is intended to be extended by subclasses of ActiveRecord::Migration.
Instance Method Summary collapse
-
#create_cycle_check_function(edge_table) ⇒ void
Builds a PL/pgSQL function for performing cycle checks.
-
#create_cycle_check_trigger(edge_table) ⇒ void
Instantiates a cycle check trigger on ‘edge_table`.
-
#drop_cycle_check_function(edge_table) ⇒ void
Drops the function created by #create_cycle_check_function.
-
#drop_cycle_check_trigger(edge_table) ⇒ void
Drops a trigger created by #create_cycle_check_trigger.
Instance Method Details
#create_cycle_check_function(edge_table) ⇒ void
This method returns an undefined value.
Builds a PL/pgSQL function for performing cycle checks.
If the function already exists, then calling this method will overwrite it.
A ‘CREATE TRUSTED LANGUAGE plpgsql` declaration must have been made in the database prior to invocation of #create_cycle_check_function.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/dagnabit/migration.rb', line 50 def create_cycle_check_function(edge_table) execute %Q{ CREATE OR REPLACE FUNCTION #{function_name}_#{edge_table}() RETURNS trigger AS $#{function_name}$ DECLARE cyclic bool; BEGIN WITH RECURSIVE cycles(id, path, cycle) AS ( SELECT e.child_id, ARRAY[]::integer[], false FROM #{edge_table} e WHERE e.parent_id = NEW.parent_id UNION ALL SELECT e.child_id, c.path || c.id, c.id = ANY(c.path) FROM cycles c INNER JOIN #{edge_table} e ON e.parent_id = c.id AND NOT cycle ) SELECT true FROM cycles WHERE cycle = true INTO cyclic; IF cyclic = true THEN RAISE EXCEPTION 'Edge (%, %) introduces a cycle', NEW.child_id, NEW.parent_id; END IF; RETURN NULL; END; $#{function_name}$ LANGUAGE plpgsql; }.strip end |
#create_cycle_check_trigger(edge_table) ⇒ void
This method returns an undefined value.
Instantiates a cycle check trigger on ‘edge_table`. The trigger is executed on a per row basis for every insert or update.
17 18 19 20 21 22 23 24 |
# File 'lib/dagnabit/migration.rb', line 17 def create_cycle_check_trigger(edge_table) create_cycle_check_function(edge_table) execute %Q{ CREATE TRIGGER #{trigger_name} AFTER INSERT OR UPDATE ON #{edge_table} FOR EACH ROW EXECUTE PROCEDURE #{function_name}_#{edge_table}(); }.strip end |
#drop_cycle_check_function(edge_table) ⇒ void
This method returns an undefined value.
Drops the function created by #create_cycle_check_function.
It is safe to call this method if the function was not previously created.
82 83 84 85 86 |
# File 'lib/dagnabit/migration.rb', line 82 def drop_cycle_check_function(edge_table) execute %Q{ DROP FUNCTION IF EXISTS #{function_name}_#{edge_table}(); }.strip end |
#drop_cycle_check_trigger(edge_table) ⇒ void
This method returns an undefined value.
Drops a trigger created by #create_cycle_check_trigger.
31 32 33 34 35 36 37 |
# File 'lib/dagnabit/migration.rb', line 31 def drop_cycle_check_trigger(edge_table) execute %Q{ DROP TRIGGER #{trigger_name} ON #{edge_table}; }.strip drop_cycle_check_function(edge_table) end |