Skip to content
This repository has been archived by the owner on May 13, 2022. It is now read-only.

Basic support for PostgreSQL materialized views #154

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ def initialize_with_schema_plus(*args) #:nodoc:
# to first drop the view if it already exists.
def create_view(view_name, definition, options={})
definition = definition.to_sql if definition.respond_to? :to_sql
execute "DROP VIEW IF EXISTS #{quote_table_name(view_name)}" if options[:force]
execute "CREATE VIEW #{quote_table_name(view_name)} AS #{definition}"
execute "DROP #{options[:create_options] || ''} VIEW IF EXISTS #{quote_table_name(view_name)}" if options[:force]
execute "CREATE #{options[:create_options] || ''} VIEW #{quote_table_name(view_name)} AS #{definition}"
end

# Drop the named view
def drop_view(view_name)
execute "DROP VIEW #{quote_table_name(view_name)}"
execute "DROP #{view_create_options(view_name)} VIEW #{quote_table_name(view_name)}"
end


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ def view_definition(view_name, name = nil)
sql
end

def view_create_options(view_name)
return ""
end

module AddColumnOptions
def default_expr_valid?(expr)
false # only the TIMESTAMP column accepts SQL column defaults and rails uses DATETIME
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,29 +261,51 @@ def reverse_foreign_keys(table_name, name = nil) #:nodoc:
end

def views(name = nil) #:nodoc:
# This will not work if there are views and materialized views
# with the same name.
sql = <<-SQL
SELECT viewname
FROM pg_views
WHERE schemaname = ANY (current_schemas(false))
AND viewname NOT LIKE 'pg\_%'
UNION
SELECT matviewname
FROM pg_matviews
WHERE schemaname = ANY (current_schemas(false))
AND matviewname NOT LIKE 'pg\_%'
SQL
sql += " AND schemaname != 'postgis'" if adapter_name == 'PostGIS'
query(sql, name).map { |row| row[0] }
end

def view_create_options(view_name, name = nil) #:nodoc:
sql = <<-SQL
SELECT relkind
FROM pg_class
WHERE relname = '#{view_name}'
AND relkind IN ('v', 'm')
SQL
result = query(sql, name)
if result[0][0].eql?('m')
return "MATERIALIZED"
else
return ""
end
end

def view_definition(view_name, name = nil) #:nodoc:
result = query(<<-SQL, name)
SELECT pg_get_viewdef(oid)
FROM pg_class
WHERE relkind = 'v'
WHERE relkind IN ('v', 'm')
AND relname = '#{view_name}'
SQL
row = result.first
row.first.chomp(';') unless row.nil?
end

private

def namespace_sql(table_name)
(table_name.to_s =~ /(.*)[.]/) ? "'#{$1}'" : "ANY (current_schemas(false))"
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,16 @@ def reverse_foreign_keys(table_name, name = nil)
def views(name = nil)
execute("SELECT name FROM sqlite_master WHERE type='view'", name).collect{|row| row["name"]}
end

def view_definition(view_name, name = nil)
sql = execute("SELECT sql FROM sqlite_master WHERE type='view' AND name=#{quote(view_name)}", name).collect{|row| row["sql"]}.first
sql.sub(/^CREATE VIEW \S* AS\s+/im, '') unless sql.nil?
end

def view_create_options(view_name)
return ""
end

protected

def get_foreign_keys(table_name = nil, name = nil)
Expand Down
6 changes: 5 additions & 1 deletion lib/schema_plus/active_record/schema_dumper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def tables_with_schema_plus(stream) #:nodoc:
@connection.views.each do |view_name|
next if Array.wrap(::ActiveRecord::SchemaDumper.ignore_tables).any? {|pattern| view_name.match pattern}
definition = @connection.view_definition(view_name)
@table_dumps[view_name] = " create_view #{view_name.inspect}, #{definition.inspect}, :force => true\n"
@table_dumps[view_name] = " create_view #{view_name.inspect}, #{definition.inspect}, :force => true, :create_options => '#{@connection.view_create_options(view_name)}'\n"
end

re_view_referent = %r{(?:(?i)FROM|JOIN) \S*\b(#{(@table_dumps.keys).join('|')})\b}
Expand Down Expand Up @@ -89,6 +89,10 @@ def tables_with_schema_plus(stream) #:nodoc:
stream.puts dump_foreign_keys(@backref_fks[table], :inline => false)+"\n" if @backref_fks[table].any?
end

@connection.views.each do |view_name|
next if Array.wrap(::ActiveRecord::SchemaDumper.ignore_tables).any? {|pattern| view_name.match pattern}
indexes_without_schema_plus(view_name, stream)
end
end

def tsort_each_node(&block) #:nodoc:
Expand Down