Class: IronTrail::DbFunctions

Inherits:
Object
  • Object
show all
Defined in:
lib/iron_trail/db_functions.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connection) ⇒ DbFunctions

Returns a new instance of DbFunctions.



7
8
9
# File 'lib/iron_trail/db_functions.rb', line 7

def initialize(connection)
  @connection = connection
end

Instance Attribute Details

#connectionObject (readonly)

Returns the value of attribute connection.



5
6
7
# File 'lib/iron_trail/db_functions.rb', line 5

def connection
  @connection
end

Instance Method Details

#collect_all_tables(schema: 'public') ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/iron_trail/db_functions.rb', line 64

def collect_all_tables(schema: 'public')
  # query pg_class rather than information schema because this way
  # we can get only regular tables and ignore partitions.
  stmt = <<~SQL
    SELECT c.relname AS "table"
    FROM "pg_class" c INNER JOIN "pg_namespace" ns
    ON (ns.oid = c.relnamespace)
    WHERE ns.nspname=#{connection.quote(schema)}
      AND c.relkind IN ('r', 'p')
      AND NOT c.relispartition
    ORDER BY "table" ASC;
  SQL

  connection.execute(stmt).map { |row| row['table'] }
end

#collect_tables_tracking_statusObject



98
99
100
101
102
103
104
105
106
107
108
# File 'lib/iron_trail/db_functions.rb', line 98

def collect_tables_tracking_status
  ignored_tables = OWN_TABLES + (IronTrail.config.ignored_tables || [])

  all_tables = collect_all_tables - ignored_tables
  tracked_tables = collect_tracked_table_names - ignored_tables

  {
    tracked: tracked_tables,
    missing: all_tables - tracked_tables
  }
end

#collect_tracked_table_namesObject

Queries the database information schema and returns an array with all table names that have the “iron_trail_log_changes” trigger enabled.

This effectively returns all tables which are currently being tracked by IronTrail.



28
29
30
31
32
33
34
35
36
37
# File 'lib/iron_trail/db_functions.rb', line 28

def collect_tracked_table_names
  stmt = <<~SQL
    SELECT DISTINCT("event_object_table") AS "table"
    FROM "information_schema"."triggers"
    WHERE "trigger_name"='iron_trail_log_changes' AND "event_object_schema"='public'
    ORDER BY "table" ASC;
  SQL

  connection.execute(stmt).map { |row| row['table'] }
end

#disable_for_all_ignored_tablesObject



86
87
88
89
90
91
92
93
94
95
96
# File 'lib/iron_trail/db_functions.rb', line 86

def disable_for_all_ignored_tables
  affected_tables = collect_tracked_table_names & (
    OWN_TABLES + (IronTrail.config.ignored_tables || [])
  )

  affected_tables.each do |table_name|
    disable_tracking_for_table(table_name)
  end

  affected_tables
end

#disable_tracking_for_table(table_name) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/iron_trail/db_functions.rb', line 110

def disable_tracking_for_table(table_name)
  # Note: will disable even if table is ignored as this allows
  # one to fix ignored tables mnore easily. Since the table is already
  # ignored, it is an expected destructive operation.

  stmt = <<~SQL
    DROP TRIGGER "iron_trail_log_changes" ON
    #{connection.quote_table_name(table_name)}
  SQL

  connection.execute(stmt)
end

#enable_for_all_missing_tablesObject



80
81
82
83
84
# File 'lib/iron_trail/db_functions.rb', line 80

def enable_for_all_missing_tables
  collect_tables_tracking_status[:missing].each do |table_name|
    enable_tracking_for_table(table_name)
  end
end

#enable_tracking_for_table(table_name) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
# File 'lib/iron_trail/db_functions.rb', line 123

def enable_tracking_for_table(table_name)
  return false if IronTrail.ignore_table?(table_name)

  stmt = <<~SQL
    CREATE TRIGGER "iron_trail_log_changes" AFTER INSERT OR UPDATE OR DELETE ON
    #{connection.quote_table_name(table_name)}
    FOR EACH ROW EXECUTE FUNCTION irontrail_log_row();
  SQL

  connection.execute(stmt)
end

#function_present?(function: 'irontrail_log_row', schema: 'public') ⇒ Boolean

Returns:

  • (Boolean)


39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/iron_trail/db_functions.rb', line 39

def function_present?(function: 'irontrail_log_row', schema: 'public')
  stmt = <<~SQL
    SELECT 1 FROM "pg_proc" p
    INNER JOIN "pg_namespace" ns
    ON (ns.oid = p.pronamespace)
    WHERE p."proname"=#{connection.quote(function)}
      AND ns."nspname"=#{connection.quote(schema)}
    LIMIT 1;
  SQL

  connection.execute(stmt).to_a.count > 0
end

#install_functionsObject

Creates the SQL functions in the DB. It will not run the function or create any triggers.



13
14
15
16
# File 'lib/iron_trail/db_functions.rb', line 13

def install_functions
  sql = irontrail_log_row_function
  connection.execute(sql)
end

#irontrail_log_row_functionObject



18
19
20
21
# File 'lib/iron_trail/db_functions.rb', line 18

def irontrail_log_row_function
  path = File.expand_path('irontrail_log_row_function.sql', __dir__)
  File.read(path)
end

#remove_functions(cascade:) ⇒ Object



52
53
54
55
56
57
# File 'lib/iron_trail/db_functions.rb', line 52

def remove_functions(cascade:)
  query = +"DROP FUNCTION irontrail_log_row"
  query << " CASCADE" if cascade

  connection.execute(query)
end

#trigger_errors_countObject



59
60
61
62
# File 'lib/iron_trail/db_functions.rb', line 59

def trigger_errors_count
  stmt = 'SELECT COUNT(*) AS c FROM "irontrail_trigger_errors"'
  connection.execute(stmt).first['c']
end