module Hypershield
Constants
- VERSION
Attributes
enabled[RW]
log_sql[RW]
schemas[RW]
Public Class Methods
drop_view(view)
click to toggle source
# File lib/hypershield.rb, line 25 def drop_view(view) schemas.each do |schema, _| execute("DROP VIEW IF EXISTS #{quote_ident(schema)}.#{quote_ident(view)}") end end
refresh(dry_run: false)
click to toggle source
# File lib/hypershield.rb, line 31 def refresh(dry_run: false) if adapter_name =~ /sqlite/i raise "Adapter not supported: #{adapter_name}" end quiet_logging do statements = [] schemas.each do |schema, config| hide = config[:hide].to_a show = config[:show].to_a hypershield_tables = tables(schema) tables.sort_by { |k, _| k }.each do |table, columns| next if table == "pg_stat_statements" columns.reject! do |column| hide.any? { |m| "#{table}.#{column}".include?(m) } && !show.any? { |m| "#{table}.#{column}".include?(m) } end # if the hypershield view has the same columns, assume it doesn't need updated # this may not necessarily be true if someone manually updates the view # we could check the view definition, but this is harder as the database normalizes it next if hypershield_tables[table] == columns statements << "DROP VIEW IF EXISTS #{quote_ident(schema)}.#{quote_ident(table)} CASCADE" if columns.any? statements << "CREATE VIEW #{quote_ident(schema)}.#{quote_ident(table)} AS SELECT #{columns.map { |c| quote_ident(c) }.join(", ")} FROM #{quote_ident(table)}" end end end if dry_run if statements.any? puts statements.map { |v| "#{v};" }.join("\n") end else # originally this was performed in a transaction # however, this appears to cause issues in certain situations - see #5 and #6 # this shouldn't be a huge issue now that we only update specific views # we already drop views outside of the transaction when migrations are run statements.each do |statement| execute(statement) end end end end
Private Class Methods
adapter_name()
click to toggle source
# File lib/hypershield.rb, line 102 def adapter_name connection.adapter_name end
connection()
click to toggle source
# File lib/hypershield.rb, line 98 def connection ActiveRecord::Base.connection end
execute(sql)
click to toggle source
# File lib/hypershield.rb, line 145 def execute(sql) connection.execute(sql) end
mysql?()
click to toggle source
# File lib/hypershield.rb, line 106 def mysql? adapter_name =~ /mysql/i end
quiet_logging() { || ... }
click to toggle source
# File lib/hypershield.rb, line 84 def quiet_logging if ActiveRecord::Base.logger && !log_sql previous_level = ActiveRecord::Base.logger.level begin ActiveRecord::Base.logger.level = Logger::INFO yield ensure ActiveRecord::Base.logger.level = previous_level end else yield end end
quote(literal)
click to toggle source
# File lib/hypershield.rb, line 149 def quote(literal) connection.quote(literal) end
quote_ident(ident)
click to toggle source
# File lib/hypershield.rb, line 153 def quote_ident(ident) connection.quote_table_name(ident.to_s) end
select_all(sql)
click to toggle source
# File lib/hypershield.rb, line 141 def select_all(sql) connection.select_all(sql).to_a end
tables(schema = nil)
click to toggle source
# File lib/hypershield.rb, line 110 def tables(schema = nil) if schema schema = quote(schema) else schema = if mysql? "database()" else "'public'" end end query = <<-SQL SELECT table_name, column_name, ordinal_position, data_type FROM information_schema.columns WHERE table_schema = #{schema} SQL select_all(query.squish) .map { |c| c.transform_keys(&:downcase) } .group_by { |c| c["table_name"] } .map { |t, cs| [t, cs.sort_by { |c| c["ordinal_position"].to_i }.map { |c| c["column_name"] }] } .to_h end