rails_sql_views 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +5 -1
- data/LICENSE +7 -0
- data/Rakefile +30 -72
- data/TODO +2 -0
- data/lib/active_record/view.rb +76 -0
- data/lib/core_ext/module.rb +11 -9
- data/lib/rails_sql_views.rb +16 -21
- data/lib/rails_sql_views/connection_adapters/abstract/schema_definitions.rb +2 -6
- data/lib/rails_sql_views/connection_adapters/abstract/schema_statements.rb +26 -9
- data/lib/rails_sql_views/connection_adapters/abstract_adapter.rb +24 -3
- data/lib/rails_sql_views/connection_adapters/mysql_adapter.rb +36 -9
- data/lib/rails_sql_views/connection_adapters/oci_adapter.rb +5 -4
- data/lib/rails_sql_views/connection_adapters/oracle_adapter.rb +5 -4
- data/lib/rails_sql_views/connection_adapters/oracleenhanced_adapter.rb +39 -0
- data/lib/rails_sql_views/connection_adapters/oracleenhanced_adapter.rb.orig +72 -0
- data/lib/rails_sql_views/connection_adapters/postgresql_adapter.rb +28 -2
- data/lib/rails_sql_views/connection_adapters/postgresql_adapter.rb.orig +69 -0
- data/lib/rails_sql_views/connection_adapters/sqlite_adapter.rb +66 -0
- data/lib/rails_sql_views/connection_adapters/sqlserver_adapter.rb +11 -4
- data/lib/rails_sql_views/loader.rb +18 -0
- data/lib/rails_sql_views/schema_dumper.rb +53 -16
- data/lib/rails_sql_views/version.rb +2 -2
- data/test/adapter_test.rb +82 -0
- data/test/connection/native_mysql/connection.rb +32 -0
- data/test/connection/native_postgresql/connection.rb +31 -0
- data/test/connection/oracle_enhanced/connection.rb +29 -0
- data/test/models/item.rb +4 -0
- data/test/models/person.rb +5 -0
- data/test/models/person2.rb +3 -0
- data/test/models/place.rb +2 -0
- data/test/models/v_person.rb +4 -0
- data/test/models/v_profile.rb +3 -0
- data/test/schema.native_mysql.expected.rb +51 -0
- data/test/schema.native_postgresql.expected.rb +51 -0
- data/test/schema.oracle_enhanced.expected.rb +51 -0
- data/test/schema_dumper_test.rb +117 -0
- data/test/test_helper.rb +30 -0
- data/test/view_model_test.rb +63 -0
- data/test/view_operations_test.rb +36 -0
- metadata +88 -57
@@ -1,16 +1,17 @@
|
|
1
|
-
module
|
1
|
+
module RailsSqlViews
|
2
2
|
module ConnectionAdapters
|
3
|
-
|
3
|
+
module OciAdapter
|
4
4
|
# Returns true as this adapter supports views.
|
5
5
|
def supports_views?
|
6
6
|
true
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
9
|
+
def base_tables(name = nil) #:nodoc:
|
10
10
|
tables = []
|
11
11
|
execute("SELECT TABLE_NAME FROM USER_TABLES", name).each { |row| tables << row[0] }
|
12
12
|
tables
|
13
13
|
end
|
14
|
+
alias nonview_tables base_tables
|
14
15
|
|
15
16
|
def views(name = nil) #:nodoc:
|
16
17
|
views = []
|
@@ -29,4 +30,4 @@ module ActiveRecord
|
|
29
30
|
|
30
31
|
end
|
31
32
|
end
|
32
|
-
end
|
33
|
+
end
|
@@ -1,16 +1,17 @@
|
|
1
|
-
module
|
1
|
+
module RailsSqlViews
|
2
2
|
module ConnectionAdapters
|
3
|
-
|
3
|
+
module OracleAdapter
|
4
4
|
# Returns true as this adapter supports views.
|
5
5
|
def supports_views?
|
6
6
|
true
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
9
|
+
def base_tables(name = nil) #:nodoc:
|
10
10
|
tables = []
|
11
11
|
execute("SELECT TABLE_NAME FROM USER_TABLES", name).each { |row| tables << row[0] }
|
12
12
|
tables
|
13
13
|
end
|
14
|
+
alias nonview_tables base_tables
|
14
15
|
|
15
16
|
def views(name = nil) #:nodoc:
|
16
17
|
views = []
|
@@ -29,4 +30,4 @@ module ActiveRecord
|
|
29
30
|
|
30
31
|
end
|
31
32
|
end
|
32
|
-
end
|
33
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module RailsSqlViews
|
2
|
+
module ConnectionAdapters
|
3
|
+
module OracleEnhancedAdapter
|
4
|
+
# Returns true as this adapter supports views.
|
5
|
+
def supports_views?
|
6
|
+
true
|
7
|
+
end
|
8
|
+
|
9
|
+
def base_tables(name = nil) #:nodoc:
|
10
|
+
tables = []
|
11
|
+
cursor = execute("SELECT TABLE_NAME FROM USER_TABLES", name)
|
12
|
+
while row = cursor.fetch
|
13
|
+
tables << row[0]
|
14
|
+
end
|
15
|
+
tables
|
16
|
+
end
|
17
|
+
alias nonview_tables base_tables
|
18
|
+
|
19
|
+
def views(name = nil) #:nodoc:
|
20
|
+
views = []
|
21
|
+
cursor = execute("SELECT VIEW_NAME FROM USER_VIEWS", name)
|
22
|
+
while row = cursor.fetch
|
23
|
+
views << row[0]
|
24
|
+
end
|
25
|
+
views
|
26
|
+
end
|
27
|
+
|
28
|
+
# Get the view select statement for the specified table.
|
29
|
+
def view_select_statement(view, name=nil)
|
30
|
+
cursor = execute("SELECT TEXT FROM USER_VIEWS WHERE VIEW_NAME = '#{view}'", name)
|
31
|
+
if row = cursor.fetch
|
32
|
+
return row[0]
|
33
|
+
else
|
34
|
+
raise "No view called #{view} found"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module RailsSqlViews
|
2
|
+
module ConnectionAdapters
|
3
|
+
module OracleEnhancedAdapter
|
4
|
+
<<<<<<< HEAD
|
5
|
+
def self.included(base)
|
6
|
+
base.alias_method_chain :tables, :views_included
|
7
|
+
end
|
8
|
+
=======
|
9
|
+
>>>>>>> Add support for oracle_enhanced adapter. Don't alias tables in PostgreSQL adapter if it's already been aliased.
|
10
|
+
# Returns true as this adapter supports views.
|
11
|
+
def supports_views?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
<<<<<<< HEAD
|
16
|
+
def tables_with_views_included(name = nil)
|
17
|
+
tables = []
|
18
|
+
sql = " SELECT TABLE_NAME FROM USER_TABLES
|
19
|
+
UNION
|
20
|
+
SELECT VIEW_NAME AS TABLE_NAME FROM USER_VIEWS"
|
21
|
+
cursor = execute(sql, name)
|
22
|
+
while row = cursor.fetch
|
23
|
+
tables << row[0].downcase
|
24
|
+
end
|
25
|
+
tables
|
26
|
+
end
|
27
|
+
|
28
|
+
=======
|
29
|
+
>>>>>>> Add support for oracle_enhanced adapter. Don't alias tables in PostgreSQL adapter if it's already been aliased.
|
30
|
+
def base_tables(name = nil) #:nodoc:
|
31
|
+
tables = []
|
32
|
+
cursor = execute("SELECT TABLE_NAME FROM USER_TABLES", name)
|
33
|
+
while row = cursor.fetch
|
34
|
+
<<<<<<< HEAD
|
35
|
+
tables << row[0].downcase
|
36
|
+
=======
|
37
|
+
tables << row[0]
|
38
|
+
>>>>>>> Add support for oracle_enhanced adapter. Don't alias tables in PostgreSQL adapter if it's already been aliased.
|
39
|
+
end
|
40
|
+
tables
|
41
|
+
end
|
42
|
+
alias nonview_tables base_tables
|
43
|
+
|
44
|
+
def views(name = nil) #:nodoc:
|
45
|
+
views = []
|
46
|
+
cursor = execute("SELECT VIEW_NAME FROM USER_VIEWS", name)
|
47
|
+
while row = cursor.fetch
|
48
|
+
<<<<<<< HEAD
|
49
|
+
views << row[0].downcase
|
50
|
+
=======
|
51
|
+
views << row[0]
|
52
|
+
>>>>>>> Add support for oracle_enhanced adapter. Don't alias tables in PostgreSQL adapter if it's already been aliased.
|
53
|
+
end
|
54
|
+
views
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get the view select statement for the specified table.
|
58
|
+
def view_select_statement(view, name=nil)
|
59
|
+
<<<<<<< HEAD
|
60
|
+
view.upcase!
|
61
|
+
=======
|
62
|
+
>>>>>>> Add support for oracle_enhanced adapter. Don't alias tables in PostgreSQL adapter if it's already been aliased.
|
63
|
+
cursor = execute("SELECT TEXT FROM USER_VIEWS WHERE VIEW_NAME = '#{view}'", name)
|
64
|
+
if row = cursor.fetch
|
65
|
+
return row[0]
|
66
|
+
else
|
67
|
+
raise "No view called #{view} found"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -1,11 +1,37 @@
|
|
1
|
-
module
|
1
|
+
module RailsSqlViews
|
2
2
|
module ConnectionAdapters
|
3
|
-
|
3
|
+
module PostgreSQLAdapter
|
4
|
+
def self.included(base)
|
5
|
+
base.alias_method_chain :tables, :views_included
|
6
|
+
end
|
4
7
|
# Returns true as this adapter supports views.
|
5
8
|
def supports_views?
|
6
9
|
true
|
7
10
|
end
|
8
11
|
|
12
|
+
def tables_with_views_included(name = nil)
|
13
|
+
q = <<-SQL
|
14
|
+
SELECT table_name, table_type
|
15
|
+
FROM information_schema.tables
|
16
|
+
WHERE table_schema IN (#{schemas})
|
17
|
+
AND table_type IN ('BASE TABLE', 'VIEW')
|
18
|
+
SQL
|
19
|
+
|
20
|
+
query(q, name).map { |row| row[0] }
|
21
|
+
end
|
22
|
+
|
23
|
+
def base_tables(name = nil)
|
24
|
+
q = <<-SQL
|
25
|
+
SELECT table_name, table_type
|
26
|
+
FROM information_schema.tables
|
27
|
+
WHERE table_schema IN (#{schemas})
|
28
|
+
AND table_type = 'BASE TABLE'
|
29
|
+
SQL
|
30
|
+
|
31
|
+
query(q, name).map { |row| row[0] }
|
32
|
+
end
|
33
|
+
alias nonview_tables base_tables
|
34
|
+
|
9
35
|
def views(name = nil) #:nodoc:
|
10
36
|
q = <<-SQL
|
11
37
|
SELECT table_name, table_type
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module RailsSqlViews
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQLAdapter
|
4
|
+
def self.included(base)
|
5
|
+
<<<<<<< HEAD
|
6
|
+
base.alias_method_chain :tables, :views_included unless method_defined?(:tables_with_views_included)
|
7
|
+
=======
|
8
|
+
base.alias_method_chain :tables, :views_included
|
9
|
+
>>>>>>> Make tests pass again for PostgreSQL and MySQL adapters.
|
10
|
+
end
|
11
|
+
# Returns true as this adapter supports views.
|
12
|
+
def supports_views?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def tables_with_views_included(name = nil)
|
17
|
+
q = <<-SQL
|
18
|
+
SELECT table_name, table_type
|
19
|
+
FROM information_schema.tables
|
20
|
+
WHERE table_schema IN (#{schemas})
|
21
|
+
AND table_type IN ('BASE TABLE', 'VIEW')
|
22
|
+
SQL
|
23
|
+
|
24
|
+
query(q, name).map { |row| row[0] }
|
25
|
+
end
|
26
|
+
|
27
|
+
def base_tables(name = nil)
|
28
|
+
q = <<-SQL
|
29
|
+
SELECT table_name, table_type
|
30
|
+
FROM information_schema.tables
|
31
|
+
WHERE table_schema IN (#{schemas})
|
32
|
+
AND table_type = 'BASE TABLE'
|
33
|
+
SQL
|
34
|
+
|
35
|
+
query(q, name).map { |row| row[0] }
|
36
|
+
end
|
37
|
+
alias nonview_tables base_tables
|
38
|
+
|
39
|
+
def views(name = nil) #:nodoc:
|
40
|
+
q = <<-SQL
|
41
|
+
SELECT table_name, table_type
|
42
|
+
FROM information_schema.tables
|
43
|
+
WHERE table_schema IN (#{schemas})
|
44
|
+
AND table_type = 'VIEW'
|
45
|
+
SQL
|
46
|
+
|
47
|
+
query(q, name).map { |row| row[0] }
|
48
|
+
end
|
49
|
+
|
50
|
+
def view_select_statement(view, name = nil)
|
51
|
+
q = <<-SQL
|
52
|
+
SELECT view_definition
|
53
|
+
FROM information_schema.views
|
54
|
+
WHERE table_catalog = (SELECT catalog_name FROM information_schema.information_schema_catalog_name)
|
55
|
+
AND table_schema IN (#{schemas})
|
56
|
+
AND table_name = '#{view}'
|
57
|
+
SQL
|
58
|
+
|
59
|
+
select_value(q, name) or raise "No view called #{view} found"
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def schemas
|
65
|
+
schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module RailsSqlViews
|
2
|
+
module ConnectionAdapters
|
3
|
+
module SQLiteAdapter
|
4
|
+
def supports_views?
|
5
|
+
true
|
6
|
+
end
|
7
|
+
|
8
|
+
def supports_drop_table_cascade?
|
9
|
+
return false
|
10
|
+
end
|
11
|
+
|
12
|
+
def tables(name = nil) #:nodoc:
|
13
|
+
sql = <<-SQL
|
14
|
+
SELECT name
|
15
|
+
FROM sqlite_master
|
16
|
+
WHERE (type = 'table' OR type = 'view') AND NOT name = 'sqlite_sequence'
|
17
|
+
SQL
|
18
|
+
|
19
|
+
execute(sql, name).map do |row|
|
20
|
+
row[0]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def base_tables(name = nil)
|
25
|
+
sql = <<-SQL
|
26
|
+
SELECT name
|
27
|
+
FROM sqlite_master
|
28
|
+
WHERE (type = 'table') AND NOT name = 'sqlite_sequence'
|
29
|
+
SQL
|
30
|
+
|
31
|
+
execute(sql, name).map do |row|
|
32
|
+
row[0]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
alias nonview_tables base_tables
|
36
|
+
|
37
|
+
def views(name = nil)
|
38
|
+
sql = <<-SQL
|
39
|
+
SELECT name
|
40
|
+
FROM sqlite_master
|
41
|
+
WHERE type = 'view' AND NOT name = 'sqlite_sequence'
|
42
|
+
SQL
|
43
|
+
|
44
|
+
execute(sql, name).map do |row|
|
45
|
+
row[0]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Get the view select statement for the specified table.
|
50
|
+
def view_select_statement(view, name = nil)
|
51
|
+
sql = <<-SQL
|
52
|
+
SELECT sql
|
53
|
+
FROM sqlite_master
|
54
|
+
WHERE name = '#{view}' AND NOT name = 'sqlite_sequence'
|
55
|
+
SQL
|
56
|
+
|
57
|
+
(select_value(sql, name).gsub("CREATE VIEW #{view} AS ", "")) or raise "No view called #{view} found"
|
58
|
+
end
|
59
|
+
|
60
|
+
def supports_view_columns_definition?
|
61
|
+
false
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -1,11 +1,18 @@
|
|
1
|
-
module
|
1
|
+
module RailsSqlViews
|
2
2
|
module ConnectionAdapters
|
3
|
-
|
3
|
+
module SQLServerAdapter
|
4
4
|
# Returns true as this adapter supports views.
|
5
5
|
def supports_views?
|
6
6
|
true
|
7
7
|
end
|
8
8
|
|
9
|
+
# Get all of the non-view tables from the currently connected schema
|
10
|
+
def base_tables(name = nil)
|
11
|
+
# this is untested
|
12
|
+
select_values("SELECT table_name FROM information_schema.tables", name)
|
13
|
+
end
|
14
|
+
alias nonview_tables base_tables
|
15
|
+
|
9
16
|
# Returns all the view names from the currently connected schema.
|
10
17
|
def views(name = nil)
|
11
18
|
select_values("SELECT table_name FROM information_schema.views", name)
|
@@ -29,8 +36,8 @@ module ActiveRecord
|
|
29
36
|
|
30
37
|
private
|
31
38
|
def convert_statement(s)
|
32
|
-
s.sub(/^CREATE.* AS (select .*)
|
39
|
+
s.sub(/^CREATE.* AS (select .*)/i, '\1').gsub(/\n/, '')
|
33
40
|
end
|
34
41
|
end
|
35
42
|
end
|
36
|
-
end
|
43
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
module RailsSqlViews
|
3
|
+
module Loader
|
4
|
+
SUPPORTED_ADAPTERS = %w( Mysql PostgreSQL SQLServer SQLite OracleEnhanced )
|
5
|
+
|
6
|
+
def self.load_extensions
|
7
|
+
SUPPORTED_ADAPTERS.each do |db|
|
8
|
+
if ActiveRecord::ConnectionAdapters.const_defined?("#{db}Adapter")
|
9
|
+
require "rails_sql_views/connection_adapters/#{db.downcase}_adapter"
|
10
|
+
ActiveRecord::ConnectionAdapters.const_get("#{db}Adapter").class_eval do
|
11
|
+
include RailsSqlViews::ConnectionAdapters::AbstractAdapter
|
12
|
+
include RailsSqlViews::ConnectionAdapters.const_get("#{db}Adapter")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,16 +1,26 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
module RailsSqlViews
|
2
|
+
module SchemaDumper
|
3
|
+
def self.included(base)
|
4
|
+
base.alias_method_chain :trailer, :views
|
5
|
+
base.alias_method_chain :dump, :views
|
6
|
+
base.alias_method_chain :tables, :views_excluded
|
7
|
+
|
8
|
+
# A list of views which should not be dumped to the schema.
|
9
|
+
# Acceptable values are strings as well as regexp.
|
10
|
+
# This setting is only used if ActiveRecord::Base.schema_format == :ruby
|
11
|
+
base.cattr_accessor :ignore_views
|
12
|
+
base.ignore_views = []
|
13
|
+
# Optional: specify the order that in which views are created.
|
14
|
+
# This allows views to depend on and include fields from other views.
|
15
|
+
# It is not necessary to specify all the view names, just the ones that
|
16
|
+
# need to be created first
|
17
|
+
base.cattr_accessor :view_creation_order
|
18
|
+
base.view_creation_order = []
|
19
|
+
end
|
9
20
|
|
10
21
|
def trailer_with_views(stream)
|
11
22
|
# do nothing...we'll call this later
|
12
23
|
end
|
13
|
-
alias_method_chain :trailer, :views
|
14
24
|
|
15
25
|
# Add views to the end of the dump stream
|
16
26
|
def dump_with_views(stream)
|
@@ -20,20 +30,32 @@ module ActiveRecord
|
|
20
30
|
views(stream)
|
21
31
|
end
|
22
32
|
rescue => e
|
23
|
-
ActiveRecord::Base.logger
|
33
|
+
if ActiveRecord::Base.logger
|
34
|
+
ActiveRecord::Base.logger.error "Unable to dump views: #{e}"
|
35
|
+
else
|
36
|
+
raise e
|
37
|
+
end
|
24
38
|
end
|
25
39
|
trailer_without_views(stream)
|
26
40
|
stream
|
27
41
|
end
|
28
|
-
alias_method_chain :dump, :views
|
29
42
|
|
30
43
|
# Add views to the stream
|
31
44
|
def views(stream)
|
32
|
-
|
33
|
-
|
45
|
+
if view_creation_order.empty?
|
46
|
+
sorted_views = @connection.views.sort
|
47
|
+
else
|
48
|
+
# set union, merge by joining arrays, removing dups
|
49
|
+
# this will float the view name sin view_creation_order to the top
|
50
|
+
# without requiring all the views to be specified
|
51
|
+
sorted_views = view_creation_order | @connection.views
|
52
|
+
end
|
53
|
+
sorted_views.each do |v|
|
54
|
+
next if [ActiveRecord::Migrator.schema_migrations_table_name, ignore_views].flatten.any? do |ignored|
|
34
55
|
case ignored
|
35
|
-
when String
|
36
|
-
when
|
56
|
+
when String then v == ignored
|
57
|
+
when Symbol then v == ignored.to_s
|
58
|
+
when Regexp then v =~ ignored
|
37
59
|
else
|
38
60
|
raise StandardError, 'ActiveRecord::SchemaDumper.ignore_views accepts an array of String and / or Regexp values.'
|
39
61
|
end
|
@@ -71,5 +93,20 @@ module ActiveRecord
|
|
71
93
|
|
72
94
|
stream
|
73
95
|
end
|
96
|
+
|
97
|
+
def tables_with_views_excluded(stream)
|
98
|
+
@connection.base_tables.sort.each do |tbl|
|
99
|
+
next if [ActiveRecord::Migrator.schema_migrations_table_name, ignore_tables].flatten.any? do |ignored|
|
100
|
+
case ignored
|
101
|
+
when String then tbl == ignored
|
102
|
+
when Regexp then tbl =~ ignored
|
103
|
+
else
|
104
|
+
raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
table(tbl, stream)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
74
111
|
end
|
75
|
-
end
|
112
|
+
end
|