Permalink
Browse files

Made it work with Rails 2.3.2, at least for MySQL and PostgreSQL adap…

…ters. Avoid require'ing of adapters; add new functionality by included modules instead of re-opening classes.
  • Loading branch information...
1 parent 9ea8a5a commit 89c2b0043a137ee32a63bb4c6f623b686ac0803a @mschuerig mschuerig committed Apr 7, 2009
View
3 .gitignore
@@ -1 +1,2 @@
-pkg/*
+pkg/*
+*~
View
4 TODO
@@ -0,0 +1,4 @@
+
+- Fix SchemaDumperTest#test_view for PostgreSQL
+- Don't rewrite ./test/schema.#{adapter}.out.rb all the time
+- Use pre-existing Adapter#supports_views? where possible
View
20 lib/core_ext/module.rb
@@ -1,11 +1,13 @@
# This is required for 1.1.6 support
-class Module
- def alias_method_chain(target, feature)
- # Strip out punctuation on predicates or bang methods since
- # e.g. target?_without_feature is not a valid method name.
- aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
- yield(aliased_target, punctuation) if block_given?
- alias_method "#{aliased_target}_without_#{feature}#{punctuation}", target
- alias_method target, "#{aliased_target}_with_#{feature}#{punctuation}"
+unless Module.respond_to?(:alias_method_chain)
+ class Module
+ def alias_method_chain(target, feature)
+ # Strip out punctuation on predicates or bang methods since
+ # e.g. target?_without_feature is not a valid method name.
+ aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
+ yield(aliased_target, punctuation) if block_given?
+ alias_method "#{aliased_target}_without_#{feature}#{punctuation}", target
+ alias_method target, "#{aliased_target}_with_#{feature}#{punctuation}"
+ end
end
-end
+end
View
22 lib/rails_sql_views.rb
@@ -31,12 +31,22 @@
require 'rails_sql_views/connection_adapters/abstract/schema_definitions'
require 'rails_sql_views/connection_adapters/abstract/schema_statements'
require 'rails_sql_views/connection_adapters/abstract_adapter'
-require 'rails_sql_views/connection_adapters/mysql_adapter'
-require 'rails_sql_views/connection_adapters/postgresql_adapter'
-require 'rails_sql_views/connection_adapters/sqlserver_adapter'
-require 'rails_sql_views/connection_adapters/sqlite_adapter'
require 'rails_sql_views/schema_dumper'
-class ActiveRecord::ConnectionAdapters::AbstractAdapter
+ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
include RailsSqlViews::ConnectionAdapters::SchemaStatements
-end
+end
+
+ActiveRecord::SchemaDumper.class_eval do
+ include RailsSqlViews::SchemaDumper
+end
+
+%w( Mysql PostgreSQL SQLServer SQLite ).each do |db|
+ if ActiveRecord::ConnectionAdapters.const_defined?("#{db}Adapter")
+ require "rails_sql_views/connection_adapters/#{db.downcase}_adapter"
+ ActiveRecord::ConnectionAdapters.const_get("#{db}Adapter").class_eval do
+ include RailsSqlViews::ConnectionAdapters::AbstractAdapter
+ include RailsSqlViews::ConnectionAdapters.const_get("#{db}Adapter")
+ end
+ end
+end
View
3 lib/rails_sql_views/connection_adapters/abstract/schema_definitions.rb
@@ -17,6 +17,7 @@ def column(name)
end
def to_sql
+ ### TODO quote
@columns * ', '
end
@@ -60,4 +61,4 @@ def view_cols
end
end
end
-end
+end
View
15 lib/rails_sql_views/connection_adapters/abstract/schema_statements.rb
@@ -1,7 +1,10 @@
module RailsSqlViews
module ConnectionAdapters # :nodoc:
module SchemaStatements
-
+ def self.included(base)
+ base.alias_method_chain :drop_table, :cascade
+ end
+
# Create a view.
# The +options+ hash can include the following keys:
# [<tt>:check_option</tt>]
@@ -18,7 +21,7 @@ def create_view(name, select_query, options={})
end
create_sql = "CREATE VIEW "
- create_sql << "#{name} "
+ create_sql << "#{quote_table_name(name)} "
if supports_view_columns_definition? && !view_definition.to_sql.blank?
create_sql << "("
create_sql << view_definition.to_sql
@@ -47,11 +50,17 @@ def create_mapping_view(old_name, new_name, options = {})
view_sql = "CREATE VIEW #{new_name} "
if supports_view_columns_definition?
+ ### TODO quote
view_sql << "(#{mapper.view_cols.join(', ')}) "
end
+ ### TODO quote
view_sql << "AS SELECT #{mapper.select_cols.join(', ')} FROM #{old_name}"
execute view_sql
end
+
+ def drop_table_with_cascade(table_name, options = {})
+ execute "DROP TABLE #{quote_table_name(table_name)} CASCADE"
+ end
# Drop a view.
# The +options+ hash can include the following keys:
@@ -67,4 +76,4 @@ def drop_view(name, options={})
end
end
end
-end
+end
View
6 lib/rails_sql_views/connection_adapters/abstract_adapter.rb
@@ -1,6 +1,6 @@
-module ActiveRecord
+module RailsSqlViews
module ConnectionAdapters
- class AbstractAdapter
+ module AbstractAdapter
# Subclasses should override and return true if they support views.
def supports_views?
return false
@@ -21,4 +21,4 @@ def view_select_statement(view, name=nil)
end
end
end
-end
+end
View
10 lib/rails_sql_views/connection_adapters/mysql_adapter.rb
@@ -1,6 +1,12 @@
-module ActiveRecord
+module RailsSqlViews
module ConnectionAdapters
- class MysqlAdapter
+ module MysqlAdapter
+ def self.included(base)
+ if base.private_method_defined?(:supports_views?)
+ base.send(:public, :supports_views?)
+ end
+ end
+
# Returns true as this adapter supports views.
def supports_views?
true
View
6 lib/rails_sql_views/connection_adapters/oci_adapter.rb
@@ -1,6 +1,6 @@
-module ActiveRecord
+module RailsSqlViews
module ConnectionAdapters
- class OciAdapter
+ module OciAdapter
# Returns true as this adapter supports views.
def supports_views?
true
@@ -29,4 +29,4 @@ def view_select_statement(view, name=nil)
end
end
-end
+end
View
6 lib/rails_sql_views/connection_adapters/oracle_adapter.rb
@@ -1,6 +1,6 @@
-module ActiveRecord
+module RailsSqlViews
module ConnectionAdapters
- class OracleAdapter
+ module OracleAdapter
# Returns true as this adapter supports views.
def supports_views?
true
@@ -29,4 +29,4 @@ def view_select_statement(view, name=nil)
end
end
-end
+end
View
20 lib/rails_sql_views/connection_adapters/postgresql_adapter.rb
@@ -1,17 +1,31 @@
-module ActiveRecord
+module RailsSqlViews
module ConnectionAdapters
- class PostgreSQLAdapter
+ module PostgreSQLAdapter
+ def self.included(base)
+ base.alias_method_chain :tables, :views_included
+ end
# Returns true as this adapter supports views.
def supports_views?
true
end
+ def tables_with_views_included(name = nil)
+ q = <<-SQL
+ SELECT table_name, table_type
+ FROM information_schema.tables
+ WHERE table_schema IN (#{schemas})
+ AND table_type IN ('BASE TABLE', 'VIEW')
+ SQL
+
+ query(q, name).map { |row| row[0] }
+ end
+
def nonview_tables(name = nil)
q = <<-SQL
SELECT table_name, table_type
FROM information_schema.tables
WHERE table_schema IN (#{schemas})
- AND table_type = 'BASE_TABLE'
+ AND table_type = 'BASE TABLE'
SQL
query(q, name).map { |row| row[0] }
View
6 lib/rails_sql_views/connection_adapters/sqlite_adapter.rb
@@ -1,6 +1,6 @@
-module ActiveRecord
+module RailsSqlViews
module ConnectionAdapters
- class SQLiteAdapter
+ module SQLiteAdapter
def supports_views?
true
end
@@ -58,4 +58,4 @@ def supports_view_columns_definition?
end
end
-end
+end
View
6 lib/rails_sql_views/connection_adapters/sqlserver_adapter.rb
@@ -1,6 +1,6 @@
-module ActiveRecord
+module RailsSqlViews
module ConnectionAdapters
- class SQLServerAdapter
+ module SQLServerAdapter
# Returns true as this adapter supports views.
def supports_views?
true
@@ -39,4 +39,4 @@ def convert_statement(s)
end
end
end
-end
+end
View
25 lib/rails_sql_views/schema_dumper.rb
@@ -1,16 +1,20 @@
-module ActiveRecord
- class SchemaDumper
-
- # A list of views which should not be dumped to the schema.
- # Acceptable values are strings as well as regexp.
- # This setting is only used if ActiveRecord::Base.schema_format == :ruby
- cattr_accessor :ignore_views
- @@ignore_views = []
+module RailsSqlViews
+ module SchemaDumper
+ def self.included(base)
+ base.alias_method_chain :trailer, :views
+ base.alias_method_chain :dump, :views
+ base.alias_method_chain :tables, :views_excluded
+
+ # A list of views which should not be dumped to the schema.
+ # Acceptable values are strings as well as regexp.
+ # This setting is only used if ActiveRecord::Base.schema_format == :ruby
+ base.cattr_accessor :ignore_views
+ base.ignore_views = []
+ end
def trailer_with_views(stream)
# do nothing...we'll call this later
end
- alias_method_chain :trailer, :views
# Add views to the end of the dump stream
def dump_with_views(stream)
@@ -29,7 +33,6 @@ def dump_with_views(stream)
trailer_without_views(stream)
stream
end
- alias_method_chain :dump, :views
# Add views to the stream
def views(stream)
@@ -77,7 +80,7 @@ def view(view, stream)
stream
end
- def tables(stream)
+ def tables_with_views_excluded(stream)
@connection.nonview_tables.sort.each do |tbl|
next if [ActiveRecord::Migrator.schema_migrations_table_name, ignore_tables].flatten.any? do |ignored|
case ignored
View
0 init.rb → rails/init.rb
File renamed without changes.
View
12 test/adapter_test.rb
@@ -8,11 +8,15 @@ def test_current_database
end
def test_tables
create_view
- assert_equal ["people", "people2", "places","v_person"], ActiveRecord::Base.connection.tables
+ found = ActiveRecord::Base.connection.tables.sort
+ found.delete(ActiveRecord::Migrator.schema_migrations_table_name)
+ assert_equal ["people", "people2", "places", "v_person"], found
end
def test_nonview_tables
create_view
- assert_equal ["people", "people2", "places"], ActiveRecord::Base.connection.nonview_tables
+ found = ActiveRecord::Base.connection.nonview_tables.sort
+ found.delete(ActiveRecord::Migrator.schema_migrations_table_name)
+ assert_equal ["people", "people2", "places"], found
end
def test_views
create_view
@@ -54,7 +58,8 @@ def test_old_name_not_found_error_during_mapping
private
def create_view
- ActiveRecord::Base.connection.create_view(:v_person, 'select * from people', :force => true) do |v|
+# ActiveRecord::Base.connection.create_view(:v_person, 'select * from people', :force => true) do |v|
+ ActiveRecord::Base.connection.create_view(:v_person, 'select first_name, last_name, ssn from people', :force => true) do |v|
v.column :f_name
v.column :l_name
v.column :social_security
@@ -63,6 +68,7 @@ def create_view
def create_mapping
ActiveRecord::Base.connection.create_mapping_view(:people, :v_person, :force => true) do |v|
+ v.map_column :id, nil
v.map_column :first_name, :f_name
v.map_column :last_name, :l_name
v.map_column :ssn, nil
View
11 test/connection/native_mysql/schema.sql
@@ -1,19 +1,22 @@
drop table if exists people;
create table people (
+ id int(11) DEFAULT NULL auto_increment PRIMARY KEY,
first_name char(255),
last_name char(255),
ssn char(64)
);
drop table if exists people2;
create table people2 (
+ id int(11) DEFAULT NULL auto_increment PRIMARY KEY,
first_name char(255),
last_name char(255),
ssn char(64)
);
drop table if exists places;
create table places (
- address text,
- city char(255),
- state char(255),
- country char(2)
+ id int(11) DEFAULT NULL auto_increment PRIMARY KEY,
+ address text,
+ city char(255),
+ cstate char(255),
+ country char(2)
);
View
17 test/connection/native_postgresql/schema.sql
@@ -1,19 +1,22 @@
-drop table people CASCADE;
+drop table if exists people CASCADE;
create table people (
+ id serial primary key,
first_name char(255),
last_name char(255),
ssn char(64)
);
-drop table people2 CASCADE;
+drop table if exists people2 CASCADE;
create table people2 (
+ id serial primary key,
first_name char(255),
last_name char(255),
ssn char(64)
);
-drop table places CASCADE;
+drop table if exists places CASCADE;
create table places (
- address text,
- city char(255),
- state char(255),
- country char(2)
+ id serial primary key,
+ address text,
+ city char(255),
+ cstate char(255),
+ country char(2)
);
View
39 test/schema.native_mysql.out.rb
@@ -1,26 +1,33 @@
-# This file is autogenerated. Instead of editing this file, please use the
-# migrations feature of ActiveRecord to incrementally modify your database, and
+# This file is auto-generated from the current state of the database. Instead of editing this file,
+# please use the migrations feature of Active Record to incrementally modify your database, and
# then regenerate this schema definition.
+#
+# Note that this schema.rb definition is the authoritative source for your database schema. If you need
+# to create the application database on another system, you should be using db:schema:load, not running
+# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
+# you'll amass, the slower it'll run and the greater likelihood for issues).
+#
+# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define() do
+ActiveRecord::Schema.define(:version => 0) do
- create_table "people", :id => false, :force => true do |t|
- t.column "first_name", :string
- t.column "last_name", :string
- t.column "ssn", :string, :limit => 64
+ create_table "people", :force => true do |t|
+ t.string "first_name"
+ t.string "last_name"
+ t.string "ssn", :limit => 64
end
- create_table "people2", :id => false, :force => true do |t|
- t.column "first_name", :string
- t.column "last_name", :string
- t.column "ssn", :string, :limit => 64
+ create_table "people2", :force => true do |t|
+ t.string "first_name"
+ t.string "last_name"
+ t.string "ssn", :limit => 64
end
- create_table "places", :id => false, :force => true do |t|
- t.column "address", :text
- t.column "city", :string
- t.column "state", :string
- t.column "country", :string, :limit => 2
+ create_table "places", :force => true do |t|
+ t.text "address"
+ t.string "city"
+ t.string "cstate"
+ t.string "country", :limit => 2
end
create_view "v_person", "select `people`.`first_name` AS `f_name`,`people`.`last_name` AS `l_name`,`people`.`ssn` AS `social_security` from `people`", :force => true do |v|
View
45 test/schema.native_postgresql.out.rb
@@ -1,26 +1,39 @@
-# This file is autogenerated. Instead of editing this file, please use the
-# migrations feature of ActiveRecord to incrementally modify your database, and
+# This file is auto-generated from the current state of the database. Instead of editing this file,
+# please use the migrations feature of Active Record to incrementally modify your database, and
# then regenerate this schema definition.
+#
+# Note that this schema.rb definition is the authoritative source for your database schema. If you need
+# to create the application database on another system, you should be using db:schema:load, not running
+# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
+# you'll amass, the slower it'll run and the greater likelihood for issues).
+#
+# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define() do
+ActiveRecord::Schema.define(:version => 0) do
- create_table "people", :id => false, :force => true do |t|
- t.column "first_name", :string
- t.column "last_name", :string
- t.column "ssn", :string, :limit => 64
+ create_table "people", :force => true do |t|
+ t.string "first_name"
+ t.string "last_name"
+ t.string "ssn", :limit => 64
end
- create_table "places", :id => false, :force => true do |t|
- t.column "address", :text
- t.column "city", :string
- t.column "state", :string
- t.column "country", :string, :limit => 2
+ create_table "people2", :force => true do |t|
+ t.string "first_name"
+ t.string "last_name"
+ t.string "ssn", :limit => 64
end
- create_view "v_person", "SELECT people.first_name AS f_name, people.last_name AS l_name, people.ssn AS social_security FROM people;", :force => true do |v|
- v.column :f_name
- v.column :l_name
- v.column :social_security
+ create_table "places", :force => true do |t|
+ t.text "address"
+ t.string "city"
+ t.string "cstate"
+ t.string "country", :limit => 2
+ end
+
+ create_view "v_profile", "SELECT people.first_name, people.last_name, people.ssn FROM people UNION SELECT people2.first_name, people2.last_name, people2.ssn FROM people2;", :force => true do |v|
+ v.column :first_name
+ v.column :last_name
+ v.column :ssn
end
end
View
5 test/schema_dumper_test.rb
@@ -17,7 +17,10 @@ def test_dump_and_load
def test_union
Person.create(:first_name => 'Joe', :last_name => 'User', :ssn => '123456789')
Person2.create(:first_name => 'Jane', :last_name => 'Doe', :ssn => '222334444')
- ActiveRecord::Base.connection.create_view(:v_profile, "(select * from people) UNION (select * from people2)", :force => true) do |v|
+ ActiveRecord::Base.connection.create_view(:v_profile,
+ "(select first_name, last_name, ssn from people) " +
+ " UNION " +
+ "(select first_name, last_name, ssn from people2)", :force => true) do |v|
v.column :first_name
v.column :last_name
v.column :ssn
View
9 test/test_helper.rb
@@ -1,24 +1,27 @@
$:.unshift(File.dirname(__FILE__) + '/../lib')
$:.unshift(File.dirname(__FILE__))
+require 'rubygems'
require 'test/unit'
require 'pp'
-require 'rails_sql_views'
require 'flexmock/test_unit'
+require 'active_record'
$connection = (ENV['DB'] || 'native_mysql')
require "connection/#{$connection}/connection"
+require 'rails_sql_views'
require 'models/person'
require 'models/person2'
require 'models/v_person'
class Test::Unit::TestCase
def create_person_view
- ActiveRecord::Base.connection.create_view(:v_person, 'select * from people', :force => true) do |v|
+ ActiveRecord::Base.connection.create_view(:v_person,
+ 'select first_name, last_name, ssn from people', :force => true) do |v|
v.column :f_name
v.column :l_name
v.column :social_security
end
end
-end
+end
View
8 test/view_test.rb
@@ -4,7 +4,8 @@ class ViewTest < Test::Unit::TestCase
def test_create_view
Person.create(:first_name => 'John', :last_name => 'Doe', :ssn => '123456789')
assert_nothing_raised do
- ActiveRecord::Base.connection.create_view(:v_person, 'select * from people', :force => true) do |v|
+ ActiveRecord::Base.connection.create_view(:v_person,
+ 'select first_name, last_name, ssn from people', :force => true) do |v|
v.column :f_name
v.column :l_name
v.column :social_security
@@ -16,7 +17,8 @@ def test_create_view
end
def test_drop_view
assert_nothing_raised do
- ActiveRecord::Base.connection.create_view(:v_place, 'select * from places', :force => true) do |v|
+ ActiveRecord::Base.connection.create_view(:v_place,
+ 'select address, city, cstate, country from places', :force => true) do |v|
v.column :v_address
v.column :v_city
v.column :v_state
@@ -31,4 +33,4 @@ def test_drop_view
def test_no_view_raises_error
assert_raises(RuntimeError) { ActiveRecord::Base.connection.view_select_statement('foo') }
end
-end
+end

0 comments on commit 89c2b00

Please sign in to comment.