lib/hypershield.rb in hypershield-0.1.1 vs lib/hypershield.rb in hypershield-0.2.0
- old
+ new
@@ -8,28 +8,29 @@
# integrations
require "hypershield/engine" if defined?(Rails)
module Hypershield
class << self
- attr_accessor :schemas, :log_sql
+ attr_accessor :enabled, :log_sql, :schemas
end
+ self.enabled = true
+ self.log_sql = false
self.schemas = {
hypershield: {
hide: %w(encrypted password token secret),
show: []
}
}
- self.log_sql = false
class << self
def drop_view(view)
schemas.each do |schema, _|
execute("DROP VIEW IF EXISTS #{quote_ident(schema)}.#{quote_ident(view)}")
end
end
- def refresh
+ def refresh(dry_run: false)
if adapter_name =~ /sqlite/i
raise "Adapter not supported: #{adapter_name}"
end
quiet_logging do
@@ -37,36 +38,45 @@
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"
- statements << "DROP VIEW IF EXISTS #{quote_ident(schema)}.#{quote_ident(table)} CASCADE"
-
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 statements.any?
- connection.transaction do
- if mysql?
- statements.each do |statement|
- execute(statement)
- end
- else
- execute(statements.join(";\n"))
- 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
@@ -95,18 +105,21 @@
def mysql?
adapter_name =~ /mysql/i
end
- def tables
- # TODO make schema configurable
- schema =
- if mysql?
- "database()"
- else
- "'public'"
- end
+ 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,
@@ -129,9 +142,13 @@
connection.select_all(sql).to_a
end
def execute(sql)
connection.execute(sql)
+ end
+
+ def quote(literal)
+ connection.quote(literal)
end
def quote_ident(ident)
connection.quote_table_name(ident.to_s)
end