lunks-rails_sql_views 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +22 -0
- data/LICENSE +7 -0
- data/README +51 -0
- data/Rakefile +78 -0
- data/TODO +2 -0
- data/lib/active_record/view.rb +76 -0
- data/lib/core_ext/module.rb +13 -0
- data/lib/ctreatma-rails_sql_views.rb +51 -0
- data/lib/rails_sql_views/connection_adapters/abstract/schema_definitions.rb +63 -0
- data/lib/rails_sql_views/connection_adapters/abstract/schema_statements.rb +71 -0
- data/lib/rails_sql_views/connection_adapters/abstract_adapter.rb +36 -0
- data/lib/rails_sql_views/connection_adapters/mysql_adapter.rb +66 -0
- data/lib/rails_sql_views/connection_adapters/oci_adapter.rb +33 -0
- data/lib/rails_sql_views/connection_adapters/oracle_adapter.rb +33 -0
- 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 +65 -0
- data/lib/rails_sql_views/connection_adapters/postgresql_adapter.rb.orig +69 -0
- data/lib/rails_sql_views/connection_adapters/sqlite_adapter.rb +62 -0
- data/lib/rails_sql_views/connection_adapters/sqlserver_adapter.rb +43 -0
- data/lib/rails_sql_views/loader.rb +20 -0
- data/lib/rails_sql_views/schema_dumper.rb +112 -0
- data/lib/rails_sql_views/version.rb +9 -0
- metadata +82 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
0.1.0 - Released Dec 27, 2006
|
2
|
+
* Initial release
|
3
|
+
|
4
|
+
0.5.0 - Released Dec 29, 2006
|
5
|
+
* Added support for PostgreSQL (Michael Schuerig)
|
6
|
+
* Fixed the schema dumper
|
7
|
+
|
8
|
+
0.5.1 - Released Jan 10, 2007
|
9
|
+
* Patch by Clifford T. Matthews to use String.dump to dump out the view select statement
|
10
|
+
|
11
|
+
0.6.0 - Released May 9, 2007
|
12
|
+
* Added support for SQL Server (Seth Ladd)-
|
13
|
+
* Added support for using views to map non-friendly database field names to AR-friendly names (Nathan Vack)
|
14
|
+
* Added support for Oracle (Alistair Davidson)
|
15
|
+
|
16
|
+
0.6.1 - Released June 6, 2007
|
17
|
+
* Added test for union support
|
18
|
+
* Updated tests to include new table to support union test
|
19
|
+
|
20
|
+
0.7.0
|
21
|
+
* Updated dependency versions to get on ActiveRecord 2.x. May not be compatible with Rails versions less than 2.x.
|
22
|
+
* Add nonview_tables support to *all* of the adapters (was missing from Postgres and SQLServer)
|
data/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2006-2008 Anthony Eden
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
== Rails SQL Views
|
2
|
+
|
3
|
+
Library which adds SQL Views to Rails. Adds create_view and drop_view to the ActiveRecord::ConnectionAdapters::AbstractAdapter (which makes them available to migrations) and adds support for dumping views in the ActiveRecord::SchemaDumper.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
To install:
|
8
|
+
|
9
|
+
gem install rails_sql_views
|
10
|
+
|
11
|
+
Then add the following to your Rails config/environment.rb:
|
12
|
+
|
13
|
+
require_gem 'rails_sql_views'
|
14
|
+
require 'rails_sql_views'
|
15
|
+
|
16
|
+
== Usage
|
17
|
+
|
18
|
+
You can then use create_view and drop_view in your migrations. For example:
|
19
|
+
|
20
|
+
class CreatePersonView < ActiveRecord::Migration
|
21
|
+
def self.up
|
22
|
+
create_view :v_people, "select * from people" do |t|
|
23
|
+
t.column :id
|
24
|
+
t.column :name
|
25
|
+
t.column :social_security
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.down
|
30
|
+
drop_view :v_people
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
This extension also adds support for views in the ActiveRecord::SchemaDumper class.
|
35
|
+
|
36
|
+
The following drivers are supported:
|
37
|
+
|
38
|
+
MySQL
|
39
|
+
PostgreSQL (Native and Pure Ruby)
|
40
|
+
Oracle
|
41
|
+
SQL Server
|
42
|
+
|
43
|
+
== Known Issues
|
44
|
+
|
45
|
+
* Drivers not mentioned above are not supported.
|
46
|
+
|
47
|
+
If you find any issues please send an email to anthonyeden@gmail.com .
|
48
|
+
|
49
|
+
== Contributing
|
50
|
+
|
51
|
+
If you would like to implement view support for other adapters then please drop me an email. Better yet, write up the adapter modifications and send them to me. :-)
|
data/Rakefile
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/packagetask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
require File.join(File.dirname(__FILE__), 'lib/rails_sql_views', 'version')
|
8
|
+
|
9
|
+
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
10
|
+
PKG_NAME = 'rails_sql_views'
|
11
|
+
PKG_VERSION = RailsSqlViews::VERSION::STRING + PKG_BUILD
|
12
|
+
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
13
|
+
PKG_DESTINATION = ENV["PKG_DESTINATION"] || "../#{PKG_NAME}"
|
14
|
+
|
15
|
+
RELEASE_NAME = "REL #{PKG_VERSION}"
|
16
|
+
|
17
|
+
RUBY_FORGE_PROJECT = "activewarehouse"
|
18
|
+
RUBY_FORGE_USER = "aeden"
|
19
|
+
|
20
|
+
desc 'Default: run unit tests.'
|
21
|
+
task :default => :test
|
22
|
+
|
23
|
+
desc 'Test the library.'
|
24
|
+
Rake::TestTask.new(:test) do |t|
|
25
|
+
t.libs << 'lib'
|
26
|
+
t.pattern = 'test/**/*_test.rb'
|
27
|
+
t.verbose = true
|
28
|
+
end
|
29
|
+
|
30
|
+
namespace :rcov do
|
31
|
+
desc 'Measures test coverage'
|
32
|
+
task :test do
|
33
|
+
rm_f 'coverage.data'
|
34
|
+
mkdir 'coverage' unless File.exist?('coverage')
|
35
|
+
rcov = "rcov --aggregate coverage.data --text-summary -Ilib"
|
36
|
+
system("#{rcov} test/*_test.rb test/**/*_test.rb")
|
37
|
+
system("open coverage/index.html") if PLATFORM['darwin']
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Generate documentation library.'
|
42
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
43
|
+
rdoc.rdoc_dir = 'rdoc'
|
44
|
+
rdoc.title = 'Rails SQL Views'
|
45
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
46
|
+
rdoc.rdoc_files.include('README')
|
47
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
48
|
+
end
|
49
|
+
|
50
|
+
begin
|
51
|
+
require 'jeweler'
|
52
|
+
Jeweler::Tasks.new do |s|
|
53
|
+
s.name = "ctreatma-rails_sql_views"
|
54
|
+
s.summary = "Library which adds SQL Views to ActiveRecord."
|
55
|
+
s.email = "charles.treatman@gmail.com"
|
56
|
+
s.homepage = "http://github.com/ctreatma/rails_sql_views"
|
57
|
+
s.description = "Adds support for using SQL views within ActiveRecord"
|
58
|
+
s.authors = ["Charles Treatman", "Anthony Eden"]
|
59
|
+
s.files = FileList[
|
60
|
+
"CHANGELOG",
|
61
|
+
"README",
|
62
|
+
"Rakefile",
|
63
|
+
"{bin,lib}/**/*"
|
64
|
+
]
|
65
|
+
s.add_dependency 'activerecord'
|
66
|
+
s.add_development_dependency 'flexmock'
|
67
|
+
s.add_development_dependency 'pg'
|
68
|
+
s.add_development_dependency 'mysql'
|
69
|
+
s.add_development_dependency 'mysql2'
|
70
|
+
end
|
71
|
+
rescue LoadError
|
72
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
73
|
+
end
|
74
|
+
|
75
|
+
desc "Publish the API documentation"
|
76
|
+
task :pdoc => [:rdoc] do
|
77
|
+
Rake::SshDirPublisher.new("aeden@rubyforge.org", "/var/www/gforge-projects/activewarehouse/rails_sql_views/rdoc", "rdoc").upload
|
78
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
|
2
|
+
# A base class for database views.
|
3
|
+
# It is primarily useful for views that are centered around a single table/model.
|
4
|
+
module ActiveRecord # :nodoc:
|
5
|
+
class View < Base
|
6
|
+
self.abstract_class = true
|
7
|
+
|
8
|
+
def readonly?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
# Clones all applicable associations from +model+ to this view
|
14
|
+
# and provides an instance method
|
15
|
+
# <tt>to_<em>model</em></tt>
|
16
|
+
# that casts a view object to an object of the kind view is
|
17
|
+
# based on. This latter object may be missing attributes; to fill
|
18
|
+
# them in, call #reload.
|
19
|
+
def based_on(model)
|
20
|
+
define_method("to_#{model.name.demodulize.underscore}") do
|
21
|
+
becomes(model)
|
22
|
+
end
|
23
|
+
|
24
|
+
model.reflect_on_all_associations.each do |assoc|
|
25
|
+
clone_association(model, assoc)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Clone one or more associations from +model+ to this view class.
|
30
|
+
#
|
31
|
+
# NOTE: Currently only <tt>belongs_to</tt>, <tt>has_many</tt> (withouth
|
32
|
+
# <tt>:through</tt>), and <tt>has_and_belongs_to_many</tt> associations
|
33
|
+
# are supported.
|
34
|
+
def clone_association(model, *associations)
|
35
|
+
associations.each do |association|
|
36
|
+
r = case association
|
37
|
+
when String, Symbol
|
38
|
+
model.reflect_on_association(association.to_sym)
|
39
|
+
when ActiveRecord::Reflection::AssociationReflection
|
40
|
+
association
|
41
|
+
else
|
42
|
+
raise ArgumentError, "Unrecognized association #{association.inspect}; must be a Symbol, String, or AssociationReflection."
|
43
|
+
end
|
44
|
+
case r.macro
|
45
|
+
when :belongs_to
|
46
|
+
if self.column_names.include?(r.primary_key_name.to_s)
|
47
|
+
if !r.options[:foreign_type] || self.column_names.include?(r.options[:foreign_type])
|
48
|
+
options = r.options.merge(
|
49
|
+
:class_name => r.class_name,
|
50
|
+
:foreign_key => r.primary_key_name
|
51
|
+
)
|
52
|
+
belongs_to r.name, options
|
53
|
+
end
|
54
|
+
end
|
55
|
+
when :has_many
|
56
|
+
### TODO :through assocications
|
57
|
+
options = r.options.merge(
|
58
|
+
:class_name => r.class_name,
|
59
|
+
:foreign_key => r.primary_key_name
|
60
|
+
)
|
61
|
+
has_many r.name, options
|
62
|
+
when :has_and_belongs_to_many
|
63
|
+
options = r.options.merge(
|
64
|
+
:class_name => r.class_name,
|
65
|
+
:foreign_key => r.primary_key_name,
|
66
|
+
:association_foreign_key => r.association_foreign_key
|
67
|
+
)
|
68
|
+
has_and_belongs_to_many r.name, options
|
69
|
+
when :has_one
|
70
|
+
### TODO
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# This is required for 1.1.6 support
|
2
|
+
unless Module.respond_to?(:alias_method_chain)
|
3
|
+
class Module
|
4
|
+
def alias_method_chain(target, feature)
|
5
|
+
# Strip out punctuation on predicates or bang methods since
|
6
|
+
# e.g. target?_without_feature is not a valid method name.
|
7
|
+
aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
|
8
|
+
yield(aliased_target, punctuation) if block_given?
|
9
|
+
alias_method "#{aliased_target}_without_#{feature}#{punctuation}", target
|
10
|
+
alias_method target, "#{aliased_target}_with_#{feature}#{punctuation}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006 Anthony Eden
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
$:.unshift(File.dirname(__FILE__))
|
25
|
+
|
26
|
+
require 'active_record'
|
27
|
+
|
28
|
+
require 'core_ext/module'
|
29
|
+
|
30
|
+
require 'rails_sql_views/connection_adapters/abstract/schema_definitions'
|
31
|
+
require 'rails_sql_views/connection_adapters/abstract/schema_statements'
|
32
|
+
require 'rails_sql_views/connection_adapters/abstract_adapter'
|
33
|
+
require 'rails_sql_views/schema_dumper'
|
34
|
+
require 'rails_sql_views/loader'
|
35
|
+
|
36
|
+
$rails_sql_views_included = false
|
37
|
+
|
38
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
|
39
|
+
include RailsSqlViews::ConnectionAdapters::SchemaStatements
|
40
|
+
def self.inherited(sub)
|
41
|
+
unless $rails_sql_views_included && (Rails.env.test? || Rails.env.cucumber?)
|
42
|
+
RailsSqlViews::Loader.load_extensions
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
ActiveRecord::SchemaDumper.class_eval do
|
48
|
+
include RailsSqlViews::SchemaDumper
|
49
|
+
end
|
50
|
+
|
51
|
+
RailsSqlViews::Loader.load_extensions
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module RailsSqlViews
|
2
|
+
module ConnectionAdapters #:nodoc:
|
3
|
+
# Abstract definition of a View
|
4
|
+
class ViewDefinition
|
5
|
+
attr_accessor :columns, :select_query
|
6
|
+
|
7
|
+
def initialize(base, select_query)
|
8
|
+
@columns = []
|
9
|
+
@base = base
|
10
|
+
@select_query = select_query
|
11
|
+
end
|
12
|
+
|
13
|
+
def column(name)
|
14
|
+
column = name.to_s
|
15
|
+
@columns << column unless @columns.include? column
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_sql
|
20
|
+
@columns.collect { |c| @base.quote_column_name(c) } * ', '
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
class MappingDefinition
|
26
|
+
|
27
|
+
# Generates a hash of the form :old_column => :new_column
|
28
|
+
# Initially, it'll map column names to themselves.
|
29
|
+
# use map_column to modify the list.
|
30
|
+
def initialize(columns)
|
31
|
+
@columns = columns
|
32
|
+
@map = Hash.new()
|
33
|
+
columns.each do |c|
|
34
|
+
@map[c] = c
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
# Create a mapping from an old column name to a new one.
|
40
|
+
# If the new name is nil, specify that the old column shouldn't
|
41
|
+
# appear in this new view.
|
42
|
+
def map_column(old_name, new_name)
|
43
|
+
unless @map.include?(old_name)
|
44
|
+
raise ActiveRecord::ActiveRecordError, "column #{old_name} not found, can't be mapped"
|
45
|
+
end
|
46
|
+
if new_name.nil?
|
47
|
+
@map.delete old_name
|
48
|
+
@columns.delete old_name
|
49
|
+
else
|
50
|
+
@map[old_name] = new_name
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def select_cols
|
55
|
+
@columns
|
56
|
+
end
|
57
|
+
|
58
|
+
def view_cols
|
59
|
+
@columns.map { |c| @map[c] }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module RailsSqlViews
|
2
|
+
module ConnectionAdapters # :nodoc:
|
3
|
+
module SchemaStatements
|
4
|
+
# Create a view.
|
5
|
+
# The +options+ hash can include the following keys:
|
6
|
+
# [<tt>:check_option</tt>]
|
7
|
+
# Specify restrictions for inserts or updates in updatable views. ANSI SQL 92 defines two check option
|
8
|
+
# values: CASCADED and LOCAL. See your database documentation for allowed values.
|
9
|
+
def create_view(name, select_query, options={})
|
10
|
+
if supports_views?
|
11
|
+
view_definition = ViewDefinition.new(self, select_query)
|
12
|
+
|
13
|
+
if block_given?
|
14
|
+
yield view_definition
|
15
|
+
end
|
16
|
+
|
17
|
+
if options[:force]
|
18
|
+
drop_view(name) rescue nil
|
19
|
+
end
|
20
|
+
|
21
|
+
create_sql = "CREATE VIEW "
|
22
|
+
create_sql << "#{quote_table_name(name)} "
|
23
|
+
if supports_view_columns_definition? && !view_definition.to_sql.blank?
|
24
|
+
create_sql << "("
|
25
|
+
create_sql << view_definition.to_sql
|
26
|
+
create_sql << ") "
|
27
|
+
end
|
28
|
+
create_sql << "AS #{view_definition.select_query}"
|
29
|
+
create_sql << " WITH #{options[:check_option]} CHECK OPTION" if options[:check_option]
|
30
|
+
execute create_sql
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Also creates a view, with the specific purpose of remapping column names
|
35
|
+
# to make non-ActiveRecord tables friendly with the naming
|
36
|
+
# conventions, while maintaining legacy app compatibility.
|
37
|
+
def create_mapping_view(old_name, new_name, options = {})
|
38
|
+
return unless supports_views?
|
39
|
+
|
40
|
+
col_names = columns(old_name).collect { |col| col.name.to_sym }
|
41
|
+
mapper = MappingDefinition.new(col_names)
|
42
|
+
|
43
|
+
yield mapper
|
44
|
+
|
45
|
+
if options[:force]
|
46
|
+
drop_view(new_name) rescue nil
|
47
|
+
end
|
48
|
+
|
49
|
+
view_sql = "CREATE VIEW #{new_name} "
|
50
|
+
if supports_view_columns_definition?
|
51
|
+
view_sql << "(#{mapper.view_cols.collect { |c| quote_column_name(c) }.join(', ')}) "
|
52
|
+
end
|
53
|
+
view_sql << "AS SELECT #{mapper.select_cols.collect { |c| quote_column_name(c) }.join(', ')} FROM #{old_name}"
|
54
|
+
execute view_sql
|
55
|
+
end
|
56
|
+
|
57
|
+
# Drop a view.
|
58
|
+
# The +options+ hash can include the following keys:
|
59
|
+
# [<tt>:drop_behavior</tt>]
|
60
|
+
# Specify the drop behavior. ANSI SQL 92 defines two drop behaviors, CASCADE and RESTRICT. See your
|
61
|
+
# database documentation to determine what drop behaviors are available.
|
62
|
+
def drop_view(name, options={})
|
63
|
+
if supports_views?
|
64
|
+
drop_sql = "DROP VIEW #{quote_table_name(name)}"
|
65
|
+
drop_sql << " #{options[:drop_behavior]}" if options[:drop_behavior]
|
66
|
+
execute drop_sql
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RailsSqlViews
|
2
|
+
module ConnectionAdapters
|
3
|
+
module AbstractAdapter
|
4
|
+
def self.included(base)
|
5
|
+
base.alias_method_chain :disable_referential_integrity, :views_excluded
|
6
|
+
end
|
7
|
+
|
8
|
+
# Subclasses should override and return true if they support views.
|
9
|
+
def supports_views?
|
10
|
+
return false
|
11
|
+
end
|
12
|
+
|
13
|
+
def disable_referential_integrity_with_views_excluded(&block)
|
14
|
+
self.class.send(:alias_method, :original_tables_method, :tables)
|
15
|
+
self.class.send(:alias_method, :tables, :base_tables)
|
16
|
+
disable_referential_integrity_without_views_excluded(&block)
|
17
|
+
ensure
|
18
|
+
self.class.send(:alias_method, :tables, :original_tables_method)
|
19
|
+
end
|
20
|
+
|
21
|
+
def supports_view_columns_definition?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
# Get a list of all views for the current database
|
26
|
+
def views(name = nil)
|
27
|
+
raise NotImplementedError, "views is an abstract method"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Get the select statement for the specified view
|
31
|
+
def view_select_statement(view, name=nil)
|
32
|
+
raise NotImplementedError, "view_select_statement is an abstract method"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module RailsSqlViews
|
2
|
+
module ConnectionAdapters
|
3
|
+
module MysqlAdapter
|
4
|
+
REQUIRED_METHODS = [:supports_views?]
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.class_eval do
|
8
|
+
def self.method_added(method)
|
9
|
+
public(method) if REQUIRED_METHODS.include?(method) && !self.public_method_defined?(method)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns true as this adapter supports views.
|
15
|
+
def supports_views?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def base_tables(name = nil) #:nodoc:
|
20
|
+
tables = []
|
21
|
+
execute("SHOW FULL TABLES WHERE TABLE_TYPE='BASE TABLE'").each{|row| tables << row[0]}
|
22
|
+
tables
|
23
|
+
end
|
24
|
+
alias nonview_tables base_tables
|
25
|
+
|
26
|
+
def views(name = nil) #:nodoc:
|
27
|
+
views = []
|
28
|
+
execute("SHOW FULL TABLES WHERE TABLE_TYPE='VIEW'").each{|row| views << row[0]}
|
29
|
+
views
|
30
|
+
end
|
31
|
+
|
32
|
+
def tables_with_views_included(name = nil)
|
33
|
+
nonview_tables(name) + views(name)
|
34
|
+
end
|
35
|
+
|
36
|
+
def structure_dump
|
37
|
+
structure = ""
|
38
|
+
base_tables.each do |table|
|
39
|
+
structure += select_one("SHOW CREATE TABLE #{quote_table_name(table)}")["Create Table"] + ";\n\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
views.each do |view|
|
43
|
+
structure += select_one("SHOW CREATE VIEW #{quote_table_name(view)}")["Create View"] + ";\n\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
return structure
|
47
|
+
end
|
48
|
+
|
49
|
+
# Get the view select statement for the specified table.
|
50
|
+
def view_select_statement(view, name=nil)
|
51
|
+
begin
|
52
|
+
row = execute("SHOW CREATE VIEW #{view}", name).each do |row|
|
53
|
+
return convert_statement(row[1]) if row[0] == view
|
54
|
+
end
|
55
|
+
rescue ActiveRecord::StatementInvalid => e
|
56
|
+
raise "No view called #{view} found"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def convert_statement(s)
|
62
|
+
s.gsub!(/.* AS (select .*)/, '\1')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RailsSqlViews
|
2
|
+
module ConnectionAdapters
|
3
|
+
module OciAdapter
|
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
|
+
execute("SELECT TABLE_NAME FROM USER_TABLES", name).each { |row| tables << row[0] }
|
12
|
+
tables
|
13
|
+
end
|
14
|
+
alias nonview_tables base_tables
|
15
|
+
|
16
|
+
def views(name = nil) #:nodoc:
|
17
|
+
views = []
|
18
|
+
execute("SELECT VIEW_NAME FROM USER_VIEWS", name).each { |row| views << row[0] }
|
19
|
+
views
|
20
|
+
end
|
21
|
+
|
22
|
+
# Get the view select statement for the specified table.
|
23
|
+
def view_select_statement(view, name=nil)
|
24
|
+
row = execute("SELECT TEXT FROM USER_VIEWS WHERE VIEW_NAME = '#{view}'", name).each do |row|
|
25
|
+
return row[0]
|
26
|
+
end
|
27
|
+
raise "No view called #{view} found"
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RailsSqlViews
|
2
|
+
module ConnectionAdapters
|
3
|
+
module OracleAdapter
|
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
|
+
execute("SELECT TABLE_NAME FROM USER_TABLES", name).each { |row| tables << row[0] }
|
12
|
+
tables
|
13
|
+
end
|
14
|
+
alias nonview_tables base_tables
|
15
|
+
|
16
|
+
def views(name = nil) #:nodoc:
|
17
|
+
views = []
|
18
|
+
execute("SELECT VIEW_NAME FROM USER_VIEWS", name).each { |row| views << row[0] }
|
19
|
+
views
|
20
|
+
end
|
21
|
+
|
22
|
+
# Get the view select statement for the specified table.
|
23
|
+
def view_select_statement(view, name=nil)
|
24
|
+
row = execute("SELECT TEXT FROM USER_VIEWS WHERE VIEW_NAME = '#{view}'", name).each do |row|
|
25
|
+
return row[0]
|
26
|
+
end
|
27
|
+
raise "No view called #{view} found"
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
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 ALL_TABLES WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'", 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 ALL_VIEWS WHERE owner = SYS_CONTEXT('userenv', 'current_schema')", 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 ALL_VIEWS WHERE VIEW_NAME = '#{view}' AND owner = SYS_CONTEXT('userenv', 'current_schema')", 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
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module RailsSqlViews
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQLAdapter
|
4
|
+
def self.included(base)
|
5
|
+
base.alias_method_chain :tables, :views_included unless method_defined?(:tables_with_views_included)
|
6
|
+
end
|
7
|
+
# Returns true as this adapter supports views.
|
8
|
+
def supports_views?
|
9
|
+
true
|
10
|
+
end
|
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
|
+
|
35
|
+
def views(name = nil) #:nodoc:
|
36
|
+
q = <<-SQL
|
37
|
+
SELECT table_name, table_type
|
38
|
+
FROM information_schema.tables
|
39
|
+
WHERE table_schema IN (#{schemas})
|
40
|
+
AND table_type = 'VIEW'
|
41
|
+
SQL
|
42
|
+
|
43
|
+
query(q, name).map { |row| row[0] }
|
44
|
+
end
|
45
|
+
|
46
|
+
def view_select_statement(view, name = nil)
|
47
|
+
q = <<-SQL
|
48
|
+
SELECT view_definition
|
49
|
+
FROM information_schema.views
|
50
|
+
WHERE table_catalog = (SELECT catalog_name FROM information_schema.information_schema_catalog_name)
|
51
|
+
AND table_schema IN (#{schemas})
|
52
|
+
AND table_name = '#{view}'
|
53
|
+
SQL
|
54
|
+
|
55
|
+
select_value(q, name) or raise "No view called #{view} found"
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def schemas
|
61
|
+
schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -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,62 @@
|
|
1
|
+
module RailsSqlViews
|
2
|
+
module ConnectionAdapters
|
3
|
+
module SQLiteAdapter
|
4
|
+
def supports_views?
|
5
|
+
true
|
6
|
+
end
|
7
|
+
|
8
|
+
def tables(name = nil) #:nodoc:
|
9
|
+
sql = <<-SQL
|
10
|
+
SELECT name
|
11
|
+
FROM sqlite_master
|
12
|
+
WHERE (type = 'table' OR type = 'view') AND NOT name = 'sqlite_sequence'
|
13
|
+
SQL
|
14
|
+
|
15
|
+
execute(sql, name).map do |row|
|
16
|
+
row[0]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def base_tables(name = nil)
|
21
|
+
sql = <<-SQL
|
22
|
+
SELECT name
|
23
|
+
FROM sqlite_master
|
24
|
+
WHERE (type = 'table') AND NOT name = 'sqlite_sequence'
|
25
|
+
SQL
|
26
|
+
|
27
|
+
execute(sql, name).map do |row|
|
28
|
+
row[0]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
alias nonview_tables base_tables
|
32
|
+
|
33
|
+
def views(name = nil)
|
34
|
+
sql = <<-SQL
|
35
|
+
SELECT name
|
36
|
+
FROM sqlite_master
|
37
|
+
WHERE type = 'view' AND NOT name = 'sqlite_sequence'
|
38
|
+
SQL
|
39
|
+
|
40
|
+
execute(sql, name).map do |row|
|
41
|
+
row[0]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get the view select statement for the specified table.
|
46
|
+
def view_select_statement(view, name = nil)
|
47
|
+
sql = <<-SQL
|
48
|
+
SELECT sql
|
49
|
+
FROM sqlite_master
|
50
|
+
WHERE name = '#{view}' AND NOT name = 'sqlite_sequence'
|
51
|
+
SQL
|
52
|
+
|
53
|
+
(select_value(sql, name).gsub("CREATE VIEW #{view} AS ", "")) or raise "No view called #{view} found"
|
54
|
+
end
|
55
|
+
|
56
|
+
def supports_view_columns_definition?
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module RailsSqlViews
|
2
|
+
module ConnectionAdapters
|
3
|
+
module SQLServerAdapter
|
4
|
+
# Returns true as this adapter supports views.
|
5
|
+
def supports_views?
|
6
|
+
true
|
7
|
+
end
|
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
|
+
|
16
|
+
# Returns all the view names from the currently connected schema.
|
17
|
+
def views(name = nil)
|
18
|
+
select_values("SELECT table_name FROM information_schema.views", name)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Get the view select statement for the specified view.
|
22
|
+
def view_select_statement(view, name=nil)
|
23
|
+
q =<<-ENDSQL
|
24
|
+
SELECT view_definition FROM information_schema.views
|
25
|
+
WHERE table_name = '#{view}'
|
26
|
+
ENDSQL
|
27
|
+
|
28
|
+
view_def = select_value(q, name)
|
29
|
+
|
30
|
+
if view_def
|
31
|
+
return convert_statement(view_def)
|
32
|
+
else
|
33
|
+
raise "No view called #{view} found"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def convert_statement(s)
|
39
|
+
s.sub(/^CREATE.* AS (select .*)/i, '\1').gsub(/\n/, '')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
module RailsSqlViews
|
3
|
+
module Loader
|
4
|
+
SUPPORTED_ADAPTERS = %w( Mysql Mysql2 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
|
+
# prevent reloading extension when the environment is reloaded
|
14
|
+
$rails_sql_views_included = true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,112 @@
|
|
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
|
20
|
+
|
21
|
+
def trailer_with_views(stream)
|
22
|
+
# do nothing...we'll call this later
|
23
|
+
end
|
24
|
+
|
25
|
+
# Add views to the end of the dump stream
|
26
|
+
def dump_with_views(stream)
|
27
|
+
dump_without_views(stream)
|
28
|
+
begin
|
29
|
+
if @connection.supports_views?
|
30
|
+
views(stream)
|
31
|
+
end
|
32
|
+
rescue => e
|
33
|
+
if ActiveRecord::Base.logger
|
34
|
+
ActiveRecord::Base.logger.error "Unable to dump views: #{e}"
|
35
|
+
else
|
36
|
+
raise e
|
37
|
+
end
|
38
|
+
end
|
39
|
+
trailer_without_views(stream)
|
40
|
+
stream
|
41
|
+
end
|
42
|
+
|
43
|
+
# Add views to the stream
|
44
|
+
def views(stream)
|
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|
|
55
|
+
case ignored
|
56
|
+
when String then v == ignored
|
57
|
+
when Symbol then v == ignored.to_s
|
58
|
+
when Regexp then v =~ ignored
|
59
|
+
else
|
60
|
+
raise StandardError, 'ActiveRecord::SchemaDumper.ignore_views accepts an array of String and / or Regexp values.'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
view(v, stream)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Add the specified view to the stream
|
68
|
+
def view(view, stream)
|
69
|
+
columns = @connection.columns(view).collect { |c| c.name }
|
70
|
+
begin
|
71
|
+
v = StringIO.new
|
72
|
+
|
73
|
+
v.print " create_view #{view.inspect}"
|
74
|
+
v.print ", #{@connection.view_select_statement(view).dump}"
|
75
|
+
v.print ", :force => true"
|
76
|
+
v.puts " do |v|"
|
77
|
+
|
78
|
+
columns.each do |column|
|
79
|
+
v.print " v.column :#{column}"
|
80
|
+
v.puts
|
81
|
+
end
|
82
|
+
|
83
|
+
v.puts " end"
|
84
|
+
v.puts
|
85
|
+
|
86
|
+
v.rewind
|
87
|
+
stream.print v.read
|
88
|
+
rescue => e
|
89
|
+
stream.puts "# Could not dump view #{view.inspect} because of following #{e.class}"
|
90
|
+
stream.puts "# #{e.message}"
|
91
|
+
stream.puts
|
92
|
+
end
|
93
|
+
|
94
|
+
stream
|
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
|
+
|
111
|
+
end
|
112
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lunks-rails_sql_views
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Charles Treatman
|
9
|
+
- Anthony Eden
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-04-12 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activerecord
|
17
|
+
requirement: &70363715386660 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *70363715386660
|
26
|
+
description: Adds support for using SQL views within ActiveRecord
|
27
|
+
email: charles.treatman@gmail.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files:
|
31
|
+
- LICENSE
|
32
|
+
- README
|
33
|
+
- TODO
|
34
|
+
files:
|
35
|
+
- CHANGELOG
|
36
|
+
- README
|
37
|
+
- Rakefile
|
38
|
+
- lib/active_record/view.rb
|
39
|
+
- lib/core_ext/module.rb
|
40
|
+
- lib/ctreatma-rails_sql_views.rb
|
41
|
+
- lib/rails_sql_views/connection_adapters/abstract/schema_definitions.rb
|
42
|
+
- lib/rails_sql_views/connection_adapters/abstract/schema_statements.rb
|
43
|
+
- lib/rails_sql_views/connection_adapters/abstract_adapter.rb
|
44
|
+
- lib/rails_sql_views/connection_adapters/mysql_adapter.rb
|
45
|
+
- lib/rails_sql_views/connection_adapters/oci_adapter.rb
|
46
|
+
- lib/rails_sql_views/connection_adapters/oracle_adapter.rb
|
47
|
+
- lib/rails_sql_views/connection_adapters/oracleenhanced_adapter.rb
|
48
|
+
- lib/rails_sql_views/connection_adapters/oracleenhanced_adapter.rb.orig
|
49
|
+
- lib/rails_sql_views/connection_adapters/postgresql_adapter.rb
|
50
|
+
- lib/rails_sql_views/connection_adapters/postgresql_adapter.rb.orig
|
51
|
+
- lib/rails_sql_views/connection_adapters/sqlite_adapter.rb
|
52
|
+
- lib/rails_sql_views/connection_adapters/sqlserver_adapter.rb
|
53
|
+
- lib/rails_sql_views/loader.rb
|
54
|
+
- lib/rails_sql_views/schema_dumper.rb
|
55
|
+
- lib/rails_sql_views/version.rb
|
56
|
+
- LICENSE
|
57
|
+
- TODO
|
58
|
+
homepage: http://github.com/lunks/rails_sql_views
|
59
|
+
licenses: []
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
requirements: []
|
77
|
+
rubyforge_project:
|
78
|
+
rubygems_version: 1.8.15
|
79
|
+
signing_key:
|
80
|
+
specification_version: 3
|
81
|
+
summary: Library which adds SQL Views to ActiveRecord.
|
82
|
+
test_files: []
|