From d8bd2e874ac20f777718c68b6815de20b8d219db Mon Sep 17 00:00:00 2001 From: Gabor Ratky Date: Thu, 14 Oct 2010 16:42:40 +0200 Subject: [PATCH 1/7] Makes supports_views? public in MysqlAdapter when defined as private in AR - Fixes issue with Rails 3 schema dump [#5 state:fixed] --- .../connection_adapters/mysql_adapter.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/rails_sql_views/connection_adapters/mysql_adapter.rb b/lib/rails_sql_views/connection_adapters/mysql_adapter.rb index f41c9ed..4226a4d 100644 --- a/lib/rails_sql_views/connection_adapters/mysql_adapter.rb +++ b/lib/rails_sql_views/connection_adapters/mysql_adapter.rb @@ -1,9 +1,13 @@ module RailsSqlViews module ConnectionAdapters module MysqlAdapter + REQUIRED_METHODS = [:supports_views?] + def self.included(base) - if base.private_method_defined?(:supports_views?) - base.send(:public, :supports_views?) + base.class_eval do + def self.method_added(method) + public(method) if REQUIRED_METHODS.include?(method) && !self.public_method_defined?(method) + end end end @@ -18,7 +22,7 @@ def base_tables(name = nil) #:nodoc: tables end alias nonview_tables base_tables - + def views(name = nil) #:nodoc: views = [] execute("SHOW FULL TABLES WHERE TABLE_TYPE='VIEW'").each{|row| views << row[0]} @@ -28,7 +32,7 @@ def views(name = nil) #:nodoc: def tables_with_views_included(name = nil) nonview_tables(name) + views(name) end - + def structure_dump structure = "" base_tables.each do |table| @@ -52,7 +56,7 @@ def view_select_statement(view, name=nil) raise "No view called #{view} found" end end - + private def convert_statement(s) s.gsub!(/.* AS (select .*)/, '\1') From e7c2afeea20c369784b59d4e572fbc4ca499c666 Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Wed, 17 Nov 2010 16:10:08 +0100 Subject: [PATCH 2/7] added Mysql2 adapter --- .../connection_adapters/mysql2_adapter.rb | 62 +++++++++++++++++++ lib/rails_sql_views/loader.rb | 2 +- 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 lib/rails_sql_views/connection_adapters/mysql2_adapter.rb diff --git a/lib/rails_sql_views/connection_adapters/mysql2_adapter.rb b/lib/rails_sql_views/connection_adapters/mysql2_adapter.rb new file mode 100644 index 0000000..6a0fac0 --- /dev/null +++ b/lib/rails_sql_views/connection_adapters/mysql2_adapter.rb @@ -0,0 +1,62 @@ +module RailsSqlViews + module ConnectionAdapters + module Mysql2Adapter + 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 + end + + def base_tables(name = nil) #:nodoc: + tables = [] + execute("SHOW FULL TABLES WHERE TABLE_TYPE='BASE TABLE'").each{|row| tables << row[0]} + tables + end + alias nonview_tables base_tables + + def views(name = nil) #:nodoc: + views = [] + execute("SHOW FULL TABLES WHERE TABLE_TYPE='VIEW'").each{|row| views << row[0]} + views + end + + def tables_with_views_included(name = nil) + nonview_tables(name) + views(name) + end + + def structure_dump + structure = "" + base_tables.each do |table| + structure += select_one("SHOW CREATE TABLE #{quote_table_name(table)}")["Create Table"] + ";\n\n" + end + + views.each do |view| + structure += select_one("SHOW CREATE VIEW #{quote_table_name(view)}")["Create View"] + ";\n\n" + end + + return structure + end + + # Get the view select statement for the specified table. + def view_select_statement(view, name=nil) + begin + row = execute("SHOW CREATE VIEW #{view}", name).each do |row| + return convert_statement(row[1]) if row[0] == view + end + rescue ActiveRecord::StatementInvalid => e + raise "No view called #{view} found" + end + end + + private + def convert_statement(s) + s.gsub!(/.* AS (select .*)/, '\1') + end + end + end +end diff --git a/lib/rails_sql_views/loader.rb b/lib/rails_sql_views/loader.rb index 7c85018..2db2821 100644 --- a/lib/rails_sql_views/loader.rb +++ b/lib/rails_sql_views/loader.rb @@ -1,7 +1,7 @@ module RailsSqlViews module Loader - SUPPORTED_ADAPTERS = %w( Mysql PostgreSQL SQLServer SQLite OracleEnhanced ) + SUPPORTED_ADAPTERS = %w( Mysql Mysql2 PostgreSQL SQLServer SQLite OracleEnhanced ) def self.load_extensions SUPPORTED_ADAPTERS.each do |db| From da1b09b37b584c74538a4d5415e6ad75281eee01 Mon Sep 17 00:00:00 2001 From: nitay Date: Thu, 2 Dec 2010 08:10:51 +0000 Subject: [PATCH 3/7] Fix for error: undefined method `tables' for class `ActiveRecord::ConnectionAdapters::PostgreSQLAdapter'. See: - https://github.com/aeden/rails_sql_views/issues#issue/7 - https://github.com/aeden/rails_sql_views/commit/11231a1d2a56cf2e4b18ec9e6e408061a3b6d303 --- lib/rails_sql_views/connection_adapters/postgresql_adapter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rails_sql_views/connection_adapters/postgresql_adapter.rb b/lib/rails_sql_views/connection_adapters/postgresql_adapter.rb index 47033e7..4ec4d06 100644 --- a/lib/rails_sql_views/connection_adapters/postgresql_adapter.rb +++ b/lib/rails_sql_views/connection_adapters/postgresql_adapter.rb @@ -2,7 +2,7 @@ module RailsSqlViews module ConnectionAdapters module PostgreSQLAdapter def self.included(base) - base.alias_method_chain :tables, :views_included + base.alias_method_chain :tables, :views_included unless method_defined?(:tables_with_views_included) end # Returns true as this adapter supports views. def supports_views? From f78ab939dec6df903a8d485742dc7a88d5866d13 Mon Sep 17 00:00:00 2001 From: "Thies C. Arntzen" Date: Mon, 7 Mar 2011 08:39:02 +0100 Subject: [PATCH 4/7] take fix from https://github.com/aeden/rails_sql_views/commit/11231a1d2a56cf2e4b18ec9e6e408061a3b6d303 --- lib/rails_sql_views/connection_adapters/postgresql_adapter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rails_sql_views/connection_adapters/postgresql_adapter.rb b/lib/rails_sql_views/connection_adapters/postgresql_adapter.rb index 47033e7..4ec4d06 100644 --- a/lib/rails_sql_views/connection_adapters/postgresql_adapter.rb +++ b/lib/rails_sql_views/connection_adapters/postgresql_adapter.rb @@ -2,7 +2,7 @@ module RailsSqlViews module ConnectionAdapters module PostgreSQLAdapter def self.included(base) - base.alias_method_chain :tables, :views_included + base.alias_method_chain :tables, :views_included unless method_defined?(:tables_with_views_included) end # Returns true as this adapter supports views. def supports_views? From 957f46f0220220087fd9641d0b9b5b29016a450c Mon Sep 17 00:00:00 2001 From: Adam Bachman Date: Tue, 5 Apr 2011 14:17:08 -0400 Subject: [PATCH 5/7] updated development dependencies --- Rakefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Rakefile b/Rakefile index bdabf4f..dd280cb 100644 --- a/Rakefile +++ b/Rakefile @@ -63,6 +63,10 @@ begin "{bin,lib}/**/*" ] s.add_dependency 'activerecord' + s.add_development_dependency 'flexmock' + s.add_development_dependency 'pg' + s.add_development_dependency 'mysql' + s.add_development_dependency 'mysql2' end rescue LoadError puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com" From 0e1876ea7a5a9ce948ad18d61ebe701f0614f546 Mon Sep 17 00:00:00 2001 From: Adam Bachman Date: Tue, 5 Apr 2011 14:21:18 -0400 Subject: [PATCH 6/7] added mysql2 tests, fixed mysql test expectations --- test/connection/native_mysql2/connection.rb | 32 ++++++++++++ test/connection/native_mysql2/schema.sql | 33 ++++++++++++ test/schema.native_mysql.expected.rb | 6 +++ test/schema.native_mysql2.expected.rb | 57 +++++++++++++++++++++ 4 files changed, 128 insertions(+) create mode 100644 test/connection/native_mysql2/connection.rb create mode 100644 test/connection/native_mysql2/schema.sql create mode 100644 test/schema.native_mysql2.expected.rb diff --git a/test/connection/native_mysql2/connection.rb b/test/connection/native_mysql2/connection.rb new file mode 100644 index 0000000..78f46b4 --- /dev/null +++ b/test/connection/native_mysql2/connection.rb @@ -0,0 +1,32 @@ +print "Using native MySQL2\n" + +adapter_name = 'mysql2' +config = YAML.load_file(File.join(File.dirname(__FILE__), '/../../connection.yml'))[adapter_name] + +#require 'logger' +#ActiveRecord::Base.logger = Logger.new("debug.log") + +ActiveRecord::Base.silence do + ActiveRecord::Base.configurations = { + config['database'] => { + :adapter => adapter_name, + :username => config['username'], + :password => config['password'], + :host => config['host'], + :database => config['database'], + :encoding => config['encoding'], + :schema_file => config['schema_file'], + } + } + + ActiveRecord::Base.establish_connection config['database'] + ActiveRecord::Migration.verbose = false + + puts "Resetting database" + conn = ActiveRecord::Base.connection + conn.recreate_database(conn.current_database) + conn.reconnect! + lines = open(File.join(File.dirname(__FILE__), ActiveRecord::Base.configurations[config['database']][:schema_file])).readlines + lines.join.split(';').each { |line| conn.execute(line) } + conn.reconnect! +end diff --git a/test/connection/native_mysql2/schema.sql b/test/connection/native_mysql2/schema.sql new file mode 100644 index 0000000..f4a9897 --- /dev/null +++ b/test/connection/native_mysql2/schema.sql @@ -0,0 +1,33 @@ +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), + address_id integer +); +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 ( + id int(11) DEFAULT NULL auto_increment PRIMARY KEY, + address text, + city char(255), + cstate char(255), + country char(2) +); +drop table if exists items; +create table items ( + id int(11) DEFAULT NULL auto_increment PRIMARY KEY, + person_id int(11) +); +drop table if exists items_people; +create table items_people ( + person_id int(11), + item_id int(11) +); \ No newline at end of file diff --git a/test/schema.native_mysql.expected.rb b/test/schema.native_mysql.expected.rb index bb41c55..101f55f 100644 --- a/test/schema.native_mysql.expected.rb +++ b/test/schema.native_mysql.expected.rb @@ -48,4 +48,10 @@ v.column :address_id end + create_view "v_profile", "select `people`.`first_name` AS `first_name`,`people`.`last_name` AS `last_name`,`people`.`ssn` AS `ssn` from `people` union select `people2`.`first_name` AS `first_name`,`people2`.`last_name` AS `last_name`,`people2`.`ssn` AS `ssn` from `people2`", :force => true do |v| + v.column :first_name + v.column :last_name + v.column :ssn + end + end diff --git a/test/schema.native_mysql2.expected.rb b/test/schema.native_mysql2.expected.rb new file mode 100644 index 0000000..101f55f --- /dev/null +++ b/test/schema.native_mysql2.expected.rb @@ -0,0 +1,57 @@ +# 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(:version => 0) do + + create_table "items", :force => true do |t| + t.integer "person_id" + end + + create_table "items_people", :id => false, :force => true do |t| + t.integer "person_id" + t.integer "item_id" + end + + create_table "people", :force => true do |t| + t.string "first_name" + t.string "last_name" + t.string "ssn", :limit => 64 + t.integer "address_id" + end + + create_table "people2", :force => true do |t| + t.string "first_name" + t.string "last_name" + t.string "ssn", :limit => 64 + end + + 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_people", "select `people`.`id` AS `id`,`people`.`first_name` AS `f_name`,`people`.`last_name` AS `l_name`,`people`.`ssn` AS `social_security`,`people`.`address_id` AS `address_id` from `people`", :force => true do |v| + v.column :id + v.column :f_name + v.column :l_name + v.column :social_security + v.column :address_id + end + + create_view "v_profile", "select `people`.`first_name` AS `first_name`,`people`.`last_name` AS `last_name`,`people`.`ssn` AS `ssn` from `people` union select `people2`.`first_name` AS `first_name`,`people2`.`last_name` AS `last_name`,`people2`.`ssn` AS `ssn` from `people2`", :force => true do |v| + v.column :first_name + v.column :last_name + v.column :ssn + end + +end From 85dba61e1def16fa1ba89cc278783a86258f219a Mon Sep 17 00:00:00 2001 From: Adam Bachman Date: Tue, 5 Apr 2011 14:23:36 -0400 Subject: [PATCH 7/7] prevent repetition of method aliasing when environment reloads (e.g., when using database_cleaner gem for testing) --- lib/rails_sql_views.rb | 6 +++++- lib/rails_sql_views/loader.rb | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/rails_sql_views.rb b/lib/rails_sql_views.rb index 7850b3b..3f97bc7 100644 --- a/lib/rails_sql_views.rb +++ b/lib/rails_sql_views.rb @@ -33,10 +33,14 @@ require 'rails_sql_views/schema_dumper' require 'rails_sql_views/loader' +$rails_sql_views_included = false + ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do include RailsSqlViews::ConnectionAdapters::SchemaStatements def self.inherited(sub) - RailsSqlViews::Loader.load_extensions + unless $rails_sql_views_included && (Rails.env.test? || Rails.env.cucumber?) + RailsSqlViews::Loader.load_extensions + end end end diff --git a/lib/rails_sql_views/loader.rb b/lib/rails_sql_views/loader.rb index 2db2821..8f8f32b 100644 --- a/lib/rails_sql_views/loader.rb +++ b/lib/rails_sql_views/loader.rb @@ -10,6 +10,8 @@ def self.load_extensions ActiveRecord::ConnectionAdapters.const_get("#{db}Adapter").class_eval do include RailsSqlViews::ConnectionAdapters::AbstractAdapter include RailsSqlViews::ConnectionAdapters.const_get("#{db}Adapter") + # prevent reloading extension when the environment is reloaded + $rails_sql_views_included = true end end end