Class: Postspec::Render
- Inherits:
-
Object
- Object
- Postspec::Render
- Defined in:
- lib/postspec/render.rb
Constant Summary collapse
- READONLY_PRIORITY =
Is a string because it needs two digits not matter the value
"90"
- REGISTER_PRIORITY =
"91"
- READONLY_BUD_TRIGGER_NAME =
"p#{READONLY_PRIORITY}_postspec_readonly_bud_trg"
- READONLY_BT_TRIGGER_NAME =
"p#{READONLY_PRIORITY}_postspec_readonly_bt_stmt_trg"
- REGISTER_TRIGGER_FORMAT =
"p#{REGISTER_PRIORITY}_postspec_register_%s_b%s_trg"
Instance Attribute Summary collapse
-
#postspec ⇒ Object
readonly
Returns the value of attribute postspec.
Instance Method Summary collapse
-
#create_readonly_triggers(uids) ⇒ Object
Create readonly seed triggers.
- #delete_tables(arg) ⇒ Object
-
#delete_tables_new(arg) ⇒ Object
FIXME: doesn’t seem to be any improvement performance-wise.
- #drop_readonly_triggers ⇒ Object
- #execution_unit(tables, sql) ⇒ Object
-
#initialize(postspec) ⇒ Render
constructor
A new instance of Render.
- #postspec_schema(state) ⇒ Object
-
#readonly_triggers(state, uids = nil) ⇒ Object
Create/drop readonly triggers.
-
#register_triggers(state) ⇒ Object
Create triggers to register changes in the database.
- #reset_postspec_tables ⇒ Object
- #truncate_tables(uids) ⇒ Object
Constructor Details
Instance Attribute Details
#postspec ⇒ Object (readonly)
Returns the value of attribute postspec.
4 5 6 |
# File 'lib/postspec/render.rb', line 4 def postspec @postspec end |
Instance Method Details
#create_readonly_triggers(uids) ⇒ Object
Create readonly seed triggers. Readonly triggers are used to raise an error when seed data are updated, deleted, or truncated. They all call the common postspec.readonly_failure() function that raises a Postgres exception
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/postspec/render.rb', line 74 def create_readonly_triggers(uids) constrain uids, { String => [Integer, NilClass] } result = [] uids.map { |uid, id| bud_sql = <<~EOS1 create trigger #{READONLY_BUD_TRIGGER_NAME} before update or delete on #{uid} for each row when (OLD.id <= #{id}) execute function postspec.readonly_failure('#{uid}') EOS1 bt_sql = <<~EOS2 create trigger #{READONLY_BT_TRIGGER_NAME} before truncate on #{uid} execute function postspec.truncate_failure('#{uid}') EOS2 [ bud_sql.chomp, bt_sql.chomp, "insert into postspec.seeds (table_uid, record_id) values ('#{uid}', #{id})" ] }.flatten end |
#delete_tables(arg) ⇒ Object
113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/postspec/render.rb', line 113 def delete_tables(arg) constrain arg, Array, Hash uids = arg.is_a?(Array) ? arg.map { |uid| [uid, 0] }.to_h : arg sql = uids.map { |uid, id| "delete from #{uid}" + (id > 0 ? " where id > #{id}" : "") } + uids.select { |uid| uid =~ /^postspec\./ ? true : !postspec.type.dot(uid).sub_table? }.map { |uid, id| "alter table #{uid} alter column id restart" + (id > 0 ? " with #{id+1}" : "") } end |
#delete_tables_new(arg) ⇒ Object
FIXME: doesn’t seem to be any improvement performance-wise
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/postspec/render.rb', line 130 def delete_tables_new(arg) constrain arg, Array, Hash if arg.is_a?(Array) delete_all = arg delete_only = {} else delete_all = [] delete_only = {} arg.each { |uid, id| if id == 0 delete_all << uid else delete_only[uid] = id end } end table_alias_index = 0 if delete_all.empty? delete_all_sql = [] else delete_all_sql = [ "with " + delete_all.map { |uid| "t#{table_alias_index += 1} as (delete from #{uid} returning 1 as id)" }.join(", ") + " select " + (1...table_alias_index).map { |i| "t#{i}.id" }.join(", ") + " from " + (1...table_alias_index).map { |i| "t#{i}" }.join(", ") ] + delete_all.map { |uid| "alter table #{uid} alter column id restart" } end delete_only_sql = delete_only.map { |uid, id| "delete from #{uid}" + (id > 0 ? " > #{id}" : "") } + delete_only.map { |uid, id| "alter table #{uid} alter column id restart with #{id+1}" } sql = delete_all_sql + delete_only_sql # uids.map { |uid, id| "delete from #{uid}" + (id > 0 ? " > #{id}" : "") } + # uids.map { |uid, id| "alter table #{uid} alter column id restart" } end |
#drop_readonly_triggers ⇒ Object
61 62 63 64 65 66 67 68 |
# File 'lib/postspec/render.rb', line 61 def drop_readonly_triggers postspec.tables.map { |uid| [READONLY_BUD_TRIGGER_NAME, READONLY_BT_TRIGGER_NAME].map { |trigger| trigger_uid = "#{uid}.#{trigger}()" postspec..exist?(trigger_uid) ? "drop trigger #{trigger} on #{uid}" : nil }.compact }.flatten end |
#execution_unit(tables, sql) ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/postspec/render.rb', line 98 def execution_unit(tables, sql) return [] if sql.empty? materialized_views = tables.select { |uid| uid !~ /^postspec\./ }.map { |uid| postspec.type.dot(uid).depending_materialized_views }.flatten.map(&:uid).uniq sql = tables.map { |uid| "alter table #{uid} disable trigger all" } + sql + tables.map { |uid| "alter table #{uid} enable trigger all" } + materialized_views.map { |uid| "refresh materialized view #{uid}" } end |
#postspec_schema(state) ⇒ Object
20 |
# File 'lib/postspec/render.rb', line 20 def postspec_schema(state) raise NotYet end |
#readonly_triggers(state, uids = nil) ⇒ Object
Create/drop readonly triggers. The triggers can be disabled because the tests may occasionally modify seed data
52 53 54 55 56 57 58 59 |
# File 'lib/postspec/render.rb', line 52 def readonly_triggers(state, uids = nil) case state when :create; create_readonly_triggers(uids) when :drop; drop_readonly_triggers else raise ArgumentError, state.inspect end end |
#register_triggers(state) ⇒ Object
Create triggers to register changes in the database. It uses the postgres function register_EVENT to write the data to the postspec schema
It is supposed to be called only once and the triggers can’t be disabled
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/postspec/render.rb', line 27 def register_triggers(state) constrain state, lambda { |state| [:create, :drop].include?(state) } postspec.tables.map { |table| %w(insert update delete).map { |event| name = REGISTER_TRIGGER_FORMAT % [event, event[0]] exist = postspec..exist?("#{table.uid}.#{name}()") if state == :create && !exist ref = (event == "insert" ? "new" : "old") <<~EOS create trigger #{name} before #{event} on #{table.uid} for each row execute function postspec.register_#{event}() EOS elsif state == :drop && exist "drop trigger if exists #{name} on #{table.uid}" else nil end }.compact }.flatten end |
#reset_postspec_tables ⇒ Object
125 126 127 |
# File 'lib/postspec/render.rb', line 125 def reset_postspec_tables() delete_tables %w(postspec.runs postspec.seeds postspec.inserts postspec.updates postspec.deletes) end |
#truncate_tables(uids) ⇒ Object
111 |
# File 'lib/postspec/render.rb', line 111 def truncate_tables(uids) ["truncate #{uids.join(', ')} cascade"] end |