class Monocle::View
Attributes
dependants[RW]
name[R]
Public Class Methods
new(name)
click to toggle source
# File lib/monocle/view.rb, line 10 def initialize(name) @name = name @dependants = [] end
Public Instance Methods
create()
click to toggle source
# File lib/monocle/view.rb, line 27 def create debug "Creating #{name}..." execute create_command Migration.find_or_create_by version: slug dependants.each &:create true rescue ActiveRecord::StatementInvalid => e # We may have another new view coming that this view depend on # if the relation name is included on our list of views, we create # that first and then retry if e.message =~ /PG::UndefinedTable/ && e.message.scan(/relation \"(\w+)\" does not exist/) && list.keys.include?($1.to_sym) warn "Can't create #{name} because it depends on #{$1}, creating that first..." list.fetch($1.to_sym).create retry else fail e end end
create_command()
click to toggle source
# File lib/monocle/view.rb, line 88 def create_command @create_command ||= File.read(path_for_sql) end
drop()
click to toggle source
# File lib/monocle/view.rb, line 19 def drop debug "Dropping #{name}..." self.dependants = get_dependants_from_pg dependants.each &:drop execute drop_command true end
drop_command()
click to toggle source
# File lib/monocle/view.rb, line 83 def drop_command _materialized = 'MATERIALIZED' if materialized? "DROP #{_materialized} VIEW IF EXISTS #{name};" end
exists?()
click to toggle source
# File lib/monocle/view.rb, line 96 def exists? execute(check_if_view_exists_sql).entries.map(&:values).flatten.first end
materialized?()
click to toggle source
# File lib/monocle/view.rb, line 15 def materialized? !!(@materialized ||= create_command =~ /MATERIALIZED VIEW/i) end
migrate()
click to toggle source
# File lib/monocle/view.rb, line 48 def migrate if versions.include?(slug) debug "Skipping #{name} as it's already up to date." true else status = drop && create info "#{name} migrated to #{slug}!" status end end
path_for_sql()
click to toggle source
# File lib/monocle/view.rb, line 92 def path_for_sql @path_for_sql ||= File.join views_path, "#{name}.sql" end
refresh(concurrently: false)
click to toggle source
# File lib/monocle/view.rb, line 59 def refresh(concurrently: false) # We don't refresh normal views return false unless materialized? _concurrently = " CONCURRENTLY" if concurrently execute "REFRESH MATERIALIZED VIEW#{_concurrently} #{name}" true rescue ActiveRecord::StatementInvalid => e # This view is trying to select from a different view that hasn't been # populated. if e.message =~ /PG::ObjectNotInPrerequisiteState/ && e.message.scan(/materialized view \"(\w+)\" has not been populated/) && list.keys.include?($1.to_sym) warn "Can't refresh #{name} because it depends on #{$1} which hasn't been populated, refreshing that first..." list.fetch($1.to_sym).refresh retry else fail e end end
slug()
click to toggle source
# File lib/monocle/view.rb, line 79 def slug @slug ||= VersionGenerator.new(path_for_sql).generate end
Protected Instance Methods
check_if_view_exists_sql()
click to toggle source
# File lib/monocle/view.rb, line 102 def check_if_view_exists_sql <<-SQL SELECT count(*) > 0 FROM pg_catalog.pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind in ('m','v') AND n.nspname = 'public' AND c.relname = '#{name}'; SQL end
execute(sql)
click to toggle source
# File lib/monocle/view.rb, line 142 def execute(sql) ActiveRecord::Base.connection.execute(sql) end
find_dependants_sql()
click to toggle source
# File lib/monocle/view.rb, line 121 def find_dependants_sql <<-SQL WITH RECURSIVE vlist AS ( SELECT c.oid::REGCLASS AS view_name FROM pg_class c WHERE c.relname = '#{name}' UNION ALL SELECT DISTINCT r.ev_class::REGCLASS AS view_name FROM pg_depend d JOIN pg_rewrite r ON (r.oid = d.objid) JOIN vlist ON (vlist.view_name = d.refobjid) WHERE d.refobjsubid != 0 ) SELECT * FROM vlist; SQL end
get_dependants_from_error(e)
click to toggle source
# File lib/monocle/view.rb, line 138 def get_dependants_from_error(e) map_dependants e.message.scan(/(\w+) depends on.+view #{name}/).flatten end
get_dependants_from_pg()
click to toggle source
# File lib/monocle/view.rb, line 113 def get_dependants_from_pg map_dependants(execute(find_dependants_sql).entries.map(&:values).flatten - [name]) end
map_dependants(deps)
click to toggle source
# File lib/monocle/view.rb, line 117 def map_dependants(deps) deps.map { |d| list[d.to_sym] }.compact end