Skip to content
This repository was archived by the owner on Jun 13, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,20 @@ module SchemaPlus::Compatibility
module ActiveRecord
module ConnectionAdapters
module AbstractAdapter
@@internal_tables = []
@@internal_tables << ::ActiveRecord::InternalMetadata.table_name if defined? ::ActiveRecord::InternalMetadata

def user_tables_only
t = tables_only
t.delete ::ActiveRecord::InternalMetadata.table_name if defined? ::ActiveRecord::InternalMetadata
t.delete_if {|table_name| @@internal_tables.include? table_name}
t
end

def user_views_only
# Out of the currently supported databases, only PostgreSQL has internal views.
# Postgres can override this function, but the rest of the adapters can just return the views as is.
views if respond_to? :views
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module ActiveRecord
module ConnectionAdapters
module Mysql2Adapter
def tables_only
select_values("SHOW FULL TABLES WHERE table_type != 'VIEW'", "SCHEMA")
select_values("SHOW FULL TABLES WHERE table_type != 'VIEW'", 'SCHEMA')
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,37 @@ module ActiveRecord
module ConnectionAdapters
module PostgreSQLAdapter
def tables_only
select_values(<<-SQL, "SCHEMA")
_pg_relations(%w{r}) # (r)elation/table
end

def user_views_only
_pg_relations(%w{v m}, _filter_user_data_sources_sql) # (v)iew, (m)aterialized view
end

# Filter for user data sources
def _filter_user_data_sources_sql
sql = "c.relname NOT LIKE 'pg\\_%'"
sql += " AND n.nspname != 'postgis'" if adapter_name == 'PostGIS'
sql
end

def _pg_relations(rel_types, extra_sql = nil)
sql = _pg_relations_sql(rel_types)
if extra_sql
sql << "\nAND (#{extra_sql})"
end
select_values(sql, 'SCHEMA')
end

# This private method tries the model the way ActiveRecord queries PostgreSQL relations, but allow for modifications
# by middleware.
def _pg_relations_sql(rel_types)
rel_type_query = rel_types.map{|t| "'#{t}'"}.join(',')
<<-SQL
SELECT c.relname
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r') -- (r)elation/table
WHERE c.relkind IN (#{rel_type_query})
AND n.nspname = ANY (current_schemas(false))
SQL
end
Expand Down
2 changes: 1 addition & 1 deletion lib/schema_plus/compatibility/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module SchemaPlus
module Compatibility
VERSION = "0.2.0"
VERSION = "0.3.0"
end
end
103 changes: 103 additions & 0 deletions spec/data_sources_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# encoding: utf-8
require 'spec_helper'
require 'support/helpers'

describe 'tables_only' do
let(:connection) { ActiveRecord::Base.connection }

around(:each) do |example|
create_dummy_data_sources &example
end

it 'does not cause deprecation' do
expect(ActiveSupport::Deprecation).not_to receive(:warn)
connection.tables_only
end

let(:ar_internal_tables) {
if ActiveRecord::VERSION::MAJOR >= 5
[ActiveRecord::InternalMetadata.table_name]
else
[]
end
}

it 'lists all tables' do
expect(connection.tables_only).to match_array %w[t1 t2] + ar_internal_tables
end

it "user_tables_only doesn't list internal tables" do
expect(connection.user_tables_only).to match_array %w[t1 t2]
end

end

# Only test ActiveRecord versions which support views (5.0+)
if ActiveRecord::Base.connection.respond_to? :views
describe 'user_views_only' do
let(:connection) { ActiveRecord::Base.connection }

around(:each) do |example|
create_dummy_data_sources &example
end

if DataSourceHelpers.is_postgresql?
it 'lists all views and materialized views' do
expect(connection.user_views_only).to match_array %w[v1 v2 mv1 mv2]
end
else
it 'lists all views' do
expect(connection.user_views_only).to match_array %w[v1 v2]
end
end
end
end


if DataSourceHelpers.is_postgresql?
describe '_pg_relations' do
let(:connection) { ActiveRecord::Base.connection }

around(:each) do |example|
create_dummy_data_sources &example
end

it 'lists (r)elations (tables)' do
result = (connection._pg_relations(%w[r]))
expect(result).to include *%w[t1 t2]
expect(result).not_to include *%w[v1 v2]
expect(result).not_to include *%w[mv1 mv2]
end

it 'lists (v)iews' do
result = (connection._pg_relations(%w[v]))
expect(result).to include *%w[v1 v2]
expect(result).not_to include *%w[mv1 mv2]
expect(result).not_to include *%w[t1 t2]
end

it 'lists (m)aterialized views' do
result = (connection._pg_relations(%w[m]))
expect(result).to include *%w[mv1 mv2]
expect(result).not_to include *%w[v1 v2]
expect(result).not_to include *%w[t1 t2]
end

it 'lists (r)elations and (v)iews' do
result = (connection._pg_relations(%w[r v]))
expect(result).to include *%w[t1 t2 v1 v2]
expect(result).not_to include *%w[mv1 mv2]
end

it 'lists (r)elations, (v)iews and (m)aterialized views' do
result = (connection._pg_relations(%w[r v m]))
expect(result).to include *%w[t1 t2 v1 v2 mv1 mv2]
end

it 'supports extra SQL code' do
result = (connection._pg_relations(%w[r v m], "c.relname NOT LIKE '%2'"))
expect(result).to include *%w[t1 v1 mv1]
expect(result).not_to include *%w[t2 v2 mv2]
end
end
end
6 changes: 6 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@
require 'active_record'
require 'schema_plus_compatibility'
require 'schema_dev/rspec'
require 'support/helpers'

SchemaDev::Rspec.setup

RSpec.configure do |config|
config.include DataSourceHelpers
end

Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}

SimpleCov.command_name "[ruby#{RUBY_VERSION}-activerecord#{::ActiveRecord.version}-#{ActiveRecord::Base.connection.adapter_name}]"

55 changes: 24 additions & 31 deletions spec/tables_only_spec.rb → spec/support/helpers.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
# encoding: utf-8
require 'spec_helper'

describe "tables_only" do
let(:connection) { ActiveRecord::Base.connection }
module DataSourceHelpers
def create_dummy_view(v, t)
drop_dummy_view v
connection.execute "CREATE VIEW #{v} AS SELECT * FROM #{t}"
end

def drop_dummy_view(v)
connection.execute "DROP VIEW IF EXISTS #{v}"
end

def create_dummy_view(v, t)
drop_dummy_view v
connection.execute "CREATE VIEW #{v} AS SELECT * FROM #{t}"
def create_dummy_materialized_view(v, t)
if DataSourceHelpers.is_postgresql?
drop_dummy_materialized_view v
connection.execute "CREATE MATERIALIZED VIEW #{v} AS SELECT * FROM #{t}"
end
end

def drop_dummy_materialized_view(v)
if DataSourceHelpers.is_postgresql?
connection.execute "DROP MATERIALIZED VIEW IF EXISTS #{v}"
end
end

around(:each) do |example|
def create_dummy_data_sources
begin
connection.tables_only.each do |table|
connection.drop_table table, force: :cascade
Expand All @@ -23,35 +31,20 @@ def create_dummy_view(v, t)
connection.create_table :t2
create_dummy_view :v1, :t1
create_dummy_view :v2, :t2
example.run
create_dummy_materialized_view :mv1, :t1
create_dummy_materialized_view :mv2, :t2
yield
ensure
drop_dummy_view :v1
drop_dummy_view :v2
drop_dummy_materialized_view :mv1
drop_dummy_materialized_view :mv2
connection.drop_table :t1, if_exists: true
connection.drop_table :t2, if_exists: true
end
end

it "does not cause deprecation" do
expect(ActiveSupport::Deprecation).not_to receive(:warn)
connection.tables_only
end

let(:ar_internal_tables) {
if ActiveRecord::VERSION::MAJOR >= 5
[ActiveRecord::InternalMetadata.table_name]
else
[]
end
}

it "lists all tables" do
expect(connection.tables_only).to match_array %w[t1 t2] + ar_internal_tables
end

it "user_tables_only doesn't list internal tables" do
expect(connection.user_tables_only).to match_array %w[t1 t2]
def self.is_postgresql?
ActiveRecord::Base.connection.instance_of? ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
end


end