class Breathing::Trigger

Attributes

log_table_name[R]
model[R]

Public Class Methods

new(model, log_table_name) click to toggle source
# File lib/breathing/trigger.rb, line 8
def initialize(model, log_table_name)
  @model          = model
  @log_table_name = log_table_name
end

Public Instance Methods

create() click to toggle source
# File lib/breathing/trigger.rb, line 13
def create
  exists_trigger_names = ActiveRecord::Base.connection.triggers.keys

  trigger_name = "#{log_table_name}_insert_#{model.table_name}"
  create_insert_trigger(trigger_name, model) if exists_trigger_names.exclude?(trigger_name)

  trigger_name = "#{log_table_name}_update_#{model.table_name}"
  create_update_trigger(trigger_name, model) if exists_trigger_names.exclude?(trigger_name)

  trigger_name = "#{log_table_name}_delete_#{model.table_name}"
  create_delete_trigger(trigger_name, model) if exists_trigger_names.exclude?(trigger_name)
end
drop() click to toggle source
# File lib/breathing/trigger.rb, line 26
def drop
  trigger_names = %w[insert update delete].map { |action| "#{log_table_name}_#{action}_#{model.table_name}" }

  trigger_names.each do |trigger_name|
    begin
      sql = "DROP TRIGGER IF EXISTS #{trigger_name}"
      if postgresql?
        sql << " ON #{model.table_name} CASCADE;"
        sql << " DROP FUNCTION IF EXISTS #{trigger_name} CASCADE;"
      end
      puts sql
      ActiveRecord::Base.connection.execute(sql)
    rescue StandardError => e
      puts "#{e.message} trigger_name:#{trigger_name}"
    end
  end
end

Private Instance Methods

create_delete_trigger(trigger_name, model) click to toggle source
# File lib/breathing/trigger.rb, line 77
    def create_delete_trigger(trigger_name, model)
      create_trigger(trigger_name).on(model.table_name).after(:delete) do
        <<-SQL
           INSERT INTO #{log_table_name} (created_at, action, table_name, transaction_id, before_data, after_data)
           VALUES (CURRENT_TIMESTAMP, 'DELETE', '#{model.table_name}', OLD.id,
                  #{row_to_json(model.columns, 'OLD')},
                  '{}');
        SQL
      end
    end
create_insert_trigger(trigger_name, model) click to toggle source
# File lib/breathing/trigger.rb, line 55
    def create_insert_trigger(trigger_name, model)
      create_trigger(trigger_name).on(model.table_name).after(:insert) do
        <<-SQL
          INSERT INTO #{log_table_name} (created_at, action, table_name, transaction_id, before_data, after_data)
          VALUES (CURRENT_TIMESTAMP, 'INSERT', '#{model.table_name}', NEW.id,
                  '{}',
                  #{row_to_json(model.columns, 'NEW')});
        SQL
      end
    end
create_trigger(name) click to toggle source
# File lib/breathing/trigger.rb, line 50
def create_trigger(name)
  puts "CREATE TRIGGER #{name}"
  ActiveRecord::Base.connection.create_trigger(name) # hairtrigger gem
end
create_update_trigger(trigger_name, model) click to toggle source
# File lib/breathing/trigger.rb, line 66
    def create_update_trigger(trigger_name, model)
      create_trigger(trigger_name).on(model.table_name).before(:update).of(:updated_at) do
        <<-SQL
          INSERT INTO #{log_table_name} (created_at, action, table_name, transaction_id, before_data, after_data)
              VALUES (CURRENT_TIMESTAMP, 'UPDATE', '#{model.table_name}', NEW.id,
                      #{row_to_json(model.columns, 'OLD')},
                      #{row_to_json(model.columns, 'NEW')});
        SQL
      end
    end
postgresql?() click to toggle source
# File lib/breathing/trigger.rb, line 46
def postgresql?
  ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
end
row_to_json(columns, state) click to toggle source
# File lib/breathing/trigger.rb, line 88
def row_to_json(columns, state)
  if postgresql?
    "row_to_json(#{state}.*)"
  else
    json_object_values = columns.each.with_object([]) do |column, array|
      array << "'#{column.name}'"
      array << "#{state}.#{column.name}"
    end
    "JSON_OBJECT(#{json_object_values.join(',')})"
  end
end