From c98f4ee264a92b10c4f1cbcfcd982eb640184636 Mon Sep 17 00:00:00 2001 From: ronen barzel Date: Fri, 28 Aug 2015 10:47:05 +0100 Subject: [PATCH 01/11] =?UTF-8?q?remove=20=E2=80=98pry=E2=80=99=20dependen?= =?UTF-8?q?cy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/spec_helper.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ed212ad..12f3a99 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,6 +1,5 @@ require 'simplecov' require 'simplecov-gem-profile' -require 'pry' SimpleCov.start "gem" $LOAD_PATH.unshift(File.dirname(__FILE__)) From 51584b7157a70f981191cda10c6062316547ae6c Mon Sep 17 00:00:00 2001 From: ronen barzel Date: Fri, 28 Aug 2015 10:47:24 +0100 Subject: [PATCH 02/11] include schema_plus_foreign_keys development dependency --- schema_multiple_schemas.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/schema_multiple_schemas.gemspec b/schema_multiple_schemas.gemspec index 857639a..00c0f1d 100644 --- a/schema_multiple_schemas.gemspec +++ b/schema_multiple_schemas.gemspec @@ -26,4 +26,5 @@ Gem::Specification.new do |gem| gem.add_development_dependency "schema_dev", "~> 3.5", ">= 3.5.1" gem.add_development_dependency "simplecov" gem.add_development_dependency "simplecov-gem-profile" + gem.add_development_dependency "schema_plus_foreign_keys" end From 6f3f4e4218286350a6651568e08290b2605e48ad Mon Sep 17 00:00:00 2001 From: ronen barzel Date: Fri, 28 Aug 2015 11:09:51 +0100 Subject: [PATCH 03/11] move tables implementation into middleware --- lib/schema_plus_multischema.rb | 7 +--- .../connection_adapters/postgresql_adapter.rb | 30 ---------------- lib/schema_plus_multischema/middleware.rb | 36 +++++++++++++++++++ 3 files changed, 37 insertions(+), 36 deletions(-) delete mode 100644 lib/schema_plus_multischema/active_record/connection_adapters/postgresql_adapter.rb create mode 100644 lib/schema_plus_multischema/middleware.rb diff --git a/lib/schema_plus_multischema.rb b/lib/schema_plus_multischema.rb index 3aa9b04..0d7faed 100644 --- a/lib/schema_plus_multischema.rb +++ b/lib/schema_plus_multischema.rb @@ -1,11 +1,6 @@ require 'schema_plus/core' require_relative 'schema_plus_multischema/version' -require_relative 'schema_plus_multischema/active_record/connection_adapters/postgresql_adapter' - -module SchemaPlusMultischema - module ActiveRecord - end -end +require_relative 'schema_plus_multischema/middleware' SchemaMonkey.register SchemaPlusMultischema diff --git a/lib/schema_plus_multischema/active_record/connection_adapters/postgresql_adapter.rb b/lib/schema_plus_multischema/active_record/connection_adapters/postgresql_adapter.rb deleted file mode 100644 index 9cc06a6..0000000 --- a/lib/schema_plus_multischema/active_record/connection_adapters/postgresql_adapter.rb +++ /dev/null @@ -1,30 +0,0 @@ -module SchemaPlusMultischema - module ActiveRecord - module ConnectionAdapters - module PostgresqlAdapter - - # Returns the list of all tables in the schema search path or a specified schema. - def tables(name = nil) - select_tablenames_with_schemas <<-SQL - SELECT schemaname, tablename - FROM pg_tables - WHERE schemaname = ANY(current_schemas(false)) - SQL - end - - def select_tablenames_with_schemas(arel) - arel, binds = binds_from_relation arel, [] - sql = to_sql(arel, binds) - execute_and_clear(sql, 'SCHEMA', binds) do |result| - if result.nfields > 0 - rows = result.column_values(0).count - (0..(rows - 1)).map{ |i| "#{result.column_values(0)[i]}.#{result.column_values(1)[i]}" } - else - [] - end - end - end - end - end - end -end diff --git a/lib/schema_plus_multischema/middleware.rb b/lib/schema_plus_multischema/middleware.rb new file mode 100644 index 0000000..e321535 --- /dev/null +++ b/lib/schema_plus_multischema/middleware.rb @@ -0,0 +1,36 @@ +module SchemaPlusMultischema + module Middleware + + module PostgreSQL + + module Schema + module Tables + + def implement(env) + env.tables += select_tablenames_with_schemas env.connection, <<-SQL + SELECT schemaname, tablename + FROM pg_tables + WHERE schemaname = ANY(current_schemas(false)) + SQL + end + + private + + def select_tablenames_with_schemas(connection, arel) + arel, binds = connection.send :binds_from_relation, arel, [] + sql = connection.to_sql(arel, binds) + connection.send :execute_and_clear, sql, 'SCHEMA', binds do |result| + if result.nfields > 0 + rows = result.column_values(0).count + (0..(rows - 1)).map{ |i| "#{result.column_values(0)[i]}.#{result.column_values(1)[i]}" } + else + [] + end + end + end + + end + end + end + end +end From e2e4a8a5e98d104789f5fce4ad8ee48169442e0e Mon Sep 17 00:00:00 2001 From: ronen barzel Date: Fri, 28 Aug 2015 11:24:43 +0100 Subject: [PATCH 04/11] Simplify query code. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to go through arel and bindings since it’s hardwired SQL; use higher-level connection.exec_query method for simpler API --- lib/schema_plus_multischema/middleware.rb | 26 ++++++----------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/lib/schema_plus_multischema/middleware.rb b/lib/schema_plus_multischema/middleware.rb index e321535..9596ec7 100644 --- a/lib/schema_plus_multischema/middleware.rb +++ b/lib/schema_plus_multischema/middleware.rb @@ -7,26 +7,14 @@ module Schema module Tables def implement(env) - env.tables += select_tablenames_with_schemas env.connection, <<-SQL - SELECT schemaname, tablename - FROM pg_tables - WHERE schemaname = ANY(current_schemas(false)) + query = <<-SQL + SELECT schemaname, tablename + FROM pg_tables + WHERE schemaname = ANY(current_schemas(false)) SQL - end - - private - - def select_tablenames_with_schemas(connection, arel) - arel, binds = connection.send :binds_from_relation, arel, [] - sql = connection.to_sql(arel, binds) - connection.send :execute_and_clear, sql, 'SCHEMA', binds do |result| - if result.nfields > 0 - rows = result.column_values(0).count - (0..(rows - 1)).map{ |i| "#{result.column_values(0)[i]}.#{result.column_values(1)[i]}" } - else - [] - end - end + env.tables += env.connection.exec_query(query, 'SCHEMA').map { |row| + "#{row['schemaname']}.#{row['tablename']}" + } end end From dc71f751df32e9b8fd2c90e34df8642c3221ae58 Mon Sep 17 00:00:00 2001 From: ronen barzel Date: Fri, 28 Aug 2015 11:32:05 +0100 Subject: [PATCH 05/11] move suppress_messages into spec_helper --- spec/schema_dumper_spec.rb | 25 +++++++++++-------------- spec/spec_helper.rb | 5 +++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/spec/schema_dumper_spec.rb b/spec/schema_dumper_spec.rb index 021f361..b5726ec 100644 --- a/spec/schema_dumper_spec.rb +++ b/spec/schema_dumper_spec.rb @@ -2,29 +2,27 @@ describe 'Schema dump' do before(:each) do - ActiveRecord::Migration.suppress_messages do + ActiveRecord::Schema.define do + connection.schema_search_path='first,second' + connection.tables.each do |table| drop_table table, force: :cascade end - ActiveRecord::Schema.define do - connection.schema_search_path='first,second' - connection.tables.each do |table| drop_table table, force: :cascade end - - execute <<-SQL + execute <<-SQL CREATE SCHEMA IF NOT EXISTS first; CREATE TABLE first.dogs ( id INTEGER PRIMARY KEY ); - SQL + SQL - execute <<-SQL + execute <<-SQL CREATE SCHEMA IF NOT EXISTS second; CREATE TABLE second.dogs ( id INTEGER PRIMARY KEY ); - SQL + SQL - execute <<-SQL + execute <<-SQL CREATE SCHEMA IF NOT EXISTS second; CREATE TABLE first.owners ( @@ -35,16 +33,15 @@ ALTER TABLE ONLY first.owners ADD CONSTRAINT fk_first_owners_dog_id FOREIGN KEY (dog_id) REFERENCES second.dogs(id) ON DELETE CASCADE; - SQL + SQL - execute <<-SQL + execute <<-SQL CREATE SCHEMA IF NOT EXISTS second; CREATE TABLE no_schema_prefix ( id INTEGER PRIMARY KEY ); - SQL - end + SQL end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 12f3a99..941474d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -17,6 +17,11 @@ RSpec.configure do |config| config.warnings = true + config.around(:each) do |example| + ActiveRecord::Migration.suppress_messages do + example.run + end + end end From ef79d64b81d0a4e812464fb85b9d20d28ebb5128 Mon Sep 17 00:00:00 2001 From: ronen barzel Date: Fri, 28 Aug 2015 12:06:11 +0100 Subject: [PATCH 06/11] Spec cleanup: add (multi)schema support methods. In particular, with_schemas([names]) is a wrapper creates the schemas and sets the search path, and cleans up after itself: removes all tables in those schemas as well as the schema definitions themselves --- spec/schema_dumper_spec.rb | 12 ++++++------ spec/spec_helper.rb | 1 + spec/support/schema.rb | 29 +++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 spec/support/schema.rb diff --git a/spec/schema_dumper_spec.rb b/spec/schema_dumper_spec.rb index b5726ec..0ce923f 100644 --- a/spec/schema_dumper_spec.rb +++ b/spec/schema_dumper_spec.rb @@ -1,13 +1,16 @@ require 'spec_helper' describe 'Schema dump' do + around(:each) do |example| + with_schemas %w[first second] do + example.run + end + end + before(:each) do ActiveRecord::Schema.define do - connection.schema_search_path='first,second' - connection.tables.each do |table| drop_table table, force: :cascade end execute <<-SQL - CREATE SCHEMA IF NOT EXISTS first; CREATE TABLE first.dogs ( id INTEGER PRIMARY KEY @@ -15,7 +18,6 @@ SQL execute <<-SQL - CREATE SCHEMA IF NOT EXISTS second; CREATE TABLE second.dogs ( id INTEGER PRIMARY KEY @@ -23,7 +25,6 @@ SQL execute <<-SQL - CREATE SCHEMA IF NOT EXISTS second; CREATE TABLE first.owners ( id INTEGER PRIMARY KEY, @@ -36,7 +37,6 @@ SQL execute <<-SQL - CREATE SCHEMA IF NOT EXISTS second; CREATE TABLE no_schema_prefix ( id INTEGER PRIMARY KEY diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 941474d..8b5964a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -20,6 +20,7 @@ config.around(:each) do |example| ActiveRecord::Migration.suppress_messages do example.run + drop_all_tables end end end diff --git a/spec/support/schema.rb b/spec/support/schema.rb new file mode 100644 index 0000000..99abd66 --- /dev/null +++ b/spec/support/schema.rb @@ -0,0 +1,29 @@ +def with_schemas(names) + connection = ActiveRecord::Base.connection + begin + previous_schemas = connection.schema_search_path + names.each do |name| + connection.execute "CREATE SCHEMA IF NOT EXISTS #{name}" + end + connection.schema_search_path = names.join(',') + yield + ensure + drop_all_tables + names.each do |name| + connection.execute "DROP SCHEMA IF EXISTS #{name}" + end + connection.schema_search_path = previous_schemas + end +end + +def schema_definitions(&block) + ActiveRecord::Schema.define &block +end + +def drop_all_tables + ActiveRecord::Base.connection.tables.each do |table| + ActiveRecord::Base.connection.drop_table table, force: :cascade + end +end + + From 7e972bccabfeb0a738efc079a6e847fd49b3c8a6 Mon Sep 17 00:00:00 2001 From: ronen barzel Date: Fri, 28 Aug 2015 12:38:03 +0100 Subject: [PATCH 07/11] Spec cleanup: Make separate schema definitions for each context rather than one global schema for all examples. --- spec/schema_dumper_spec.rb | 86 +++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 48 deletions(-) diff --git a/spec/schema_dumper_spec.rb b/spec/schema_dumper_spec.rb index 0ce923f..de8ec41 100644 --- a/spec/schema_dumper_spec.rb +++ b/spec/schema_dumper_spec.rb @@ -1,69 +1,59 @@ require 'spec_helper' describe 'Schema dump' do + let(:connection) { ActiveRecord::Base.connection } + around(:each) do |example| with_schemas %w[first second] do example.run end end - before(:each) do - ActiveRecord::Schema.define do - - execute <<-SQL - CREATE TABLE first.dogs - ( - id INTEGER PRIMARY KEY - ); - SQL - - execute <<-SQL - CREATE TABLE second.dogs - ( - id INTEGER PRIMARY KEY - ); - SQL + context 'with a table that is created without a schema prefix' do + before(:each) do + schema_definitions do + create_table 'no_schema_prefix' + end + end + it 'includes schema prefix in dump' do + expect(dump_schema).to include('create_table "first.no_schema_prefix"') + end + end - execute <<-SQL - CREATE TABLE first.owners - ( - id INTEGER PRIMARY KEY, - dog_id INTEGER NOT NULL - ); - CREATE INDEX fk__first_owners_second_dogs ON first.owners USING btree (dog_id); + context 'tables with same name in different schemas' do + before(:each) do + schema_definitions do + create_table 'first.dogs' + create_table 'second.dogs' + end + end - ALTER TABLE ONLY first.owners - ADD CONSTRAINT fk_first_owners_dog_id FOREIGN KEY (dog_id) REFERENCES second.dogs(id) ON DELETE CASCADE; - SQL + it 'includes both tables with schema prefixes' do + expect(dump_schema).to include('create_table "first.dogs"') + expect(dump_schema).to include('create_table "second.dogs"') + end - execute <<-SQL - CREATE TABLE no_schema_prefix - ( - id INTEGER PRIMARY KEY - ); - SQL + context 'with schema_plus_foreign_keys support' do + before(:each) do + schema_definitions do + create_table 'first.owners' do |t| + t.integer :dog_id, null: false, references: 'second.dogs' + end + end + end + + it 'includes foreign key references with schema prefixes' do + expect(dump_schema).to include('foreign_key: {references: "second.dogs", name: "fk_first_owners_dog_id"') + end end end - def dump_schema(opts={}) + private + + def dump_schema stream = StringIO.new - ActiveRecord::SchemaDumper.ignore_tables = Array.wrap(opts[:ignore]) || [] ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream) stream.string end - it 'should dump tables which are created without schema prefix' do - expect(dump_schema).to include('create_table "first.no_schema_prefix"') - end - - it 'should dump tables with same names from different schemas' do - expect(dump_schema).to include('create_table "first.dogs"') - expect(dump_schema).to include('create_table "second.dogs"') - end - - context 'when foreign key schema plus gem required' do - it 'should dump foreign key references with schema names' do - expect(dump_schema).to include('foreign_key: {references: "second.dogs", name: "fk_first_owners_dog_id"') - end - end end From a759df771149788ee23628ec2ed1965f5b0e6f96 Mon Sep 17 00:00:00 2001 From: ronen barzel Date: Fri, 28 Aug 2015 12:38:16 +0100 Subject: [PATCH 08/11] Add spec for connection.tables --- spec/tables_spec.rb | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 spec/tables_spec.rb diff --git a/spec/tables_spec.rb b/spec/tables_spec.rb new file mode 100644 index 0000000..75c8052 --- /dev/null +++ b/spec/tables_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe 'tables' do + + let(:connection) { ActiveRecord::Base.connection } + + around(:each) do |example| + with_schemas %w[first second] do + example.run + end + end + + context 'with a table that is created without a schema prefix' do + before(:each) do + schema_definitions do + create_table 'no_schema_prefix' + end + end + it 'includes schema prefix in table name' do + expect(connection.tables).to eq %W[first.no_schema_prefix] + end + end + + context 'with tables with same name in different schemas' do + before(:each) do + schema_definitions do + create_table 'first.dogs' + create_table 'second.dogs' + end + end + + it 'includes schema prefix in table names' do + expect(connection.tables.sort).to eq %W[first.dogs second.dogs] + end + end + +end From 651d4b58e1d67de7cc24bdff136c422b643ddfb4 Mon Sep 17 00:00:00 2001 From: ronen barzel Date: Fri, 28 Aug 2015 13:12:55 +0100 Subject: [PATCH 09/11] =?UTF-8?q?don=E2=80=99t=20add=20prefix=20when=20usi?= =?UTF-8?q?ng=20default=20schema=20path?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/schema_plus_multischema/middleware.rb | 9 ++++- spec/tables_spec.rb | 48 +++++++++++++++-------- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/lib/schema_plus_multischema/middleware.rb b/lib/schema_plus_multischema/middleware.rb index 9596ec7..1066af5 100644 --- a/lib/schema_plus_multischema/middleware.rb +++ b/lib/schema_plus_multischema/middleware.rb @@ -6,14 +6,21 @@ module PostgreSQL module Schema module Tables + DEFAULT_SCHEMA_SEARCH_PATH = %q{"$user",public} + def implement(env) + use_prefix = (env.connection.schema_search_path != DEFAULT_SCHEMA_SEARCH_PATH) query = <<-SQL SELECT schemaname, tablename FROM pg_tables WHERE schemaname = ANY(current_schemas(false)) SQL env.tables += env.connection.exec_query(query, 'SCHEMA').map { |row| - "#{row['schemaname']}.#{row['tablename']}" + if use_prefix + "#{row['schemaname']}.#{row['tablename']}" + else + row['tablename'] + end } end diff --git a/spec/tables_spec.rb b/spec/tables_spec.rb index 75c8052..5f1f975 100644 --- a/spec/tables_spec.rb +++ b/spec/tables_spec.rb @@ -4,33 +4,49 @@ let(:connection) { ActiveRecord::Base.connection } - around(:each) do |example| - with_schemas %w[first second] do - example.run + context "with multiple schemas" do + + around(:each) do |example| + with_schemas %w[first second] do + example.run + end end - end - context 'with a table that is created without a schema prefix' do - before(:each) do - schema_definitions do - create_table 'no_schema_prefix' + context 'with a table that is created without a schema prefix' do + before(:each) do + schema_definitions do + create_table 'no_schema_prefix' + end + end + it 'includes schema prefix in table name' do + expect(connection.tables).to eq %w[first.no_schema_prefix] end end - it 'includes schema prefix in table name' do - expect(connection.tables).to eq %W[first.no_schema_prefix] + + context 'with tables with same name in different schemas' do + before(:each) do + schema_definitions do + create_table 'first.dogs' + create_table 'second.dogs' + end + end + + it 'includes schema prefix in table names' do + expect(connection.tables.sort).to eq %w[first.dogs second.dogs] + end end + end - context 'with tables with same name in different schemas' do - before(:each) do + context "without multiple schemas" do + before(:each) do schema_definitions do - create_table 'first.dogs' - create_table 'second.dogs' + create_table 'dogs' end end - it 'includes schema prefix in table names' do - expect(connection.tables.sort).to eq %W[first.dogs second.dogs] + it 'does not include schema_prefix in table names' do + expect(connection.tables).to eq %w[dogs] end end From 3ab67a8b5412070ee508e0e349b7e502bac6ab62 Mon Sep 17 00:00:00 2001 From: ronen barzel Date: Fri, 28 Aug 2015 16:03:34 +0100 Subject: [PATCH 10/11] Added schema creation and search path --- lib/schema_plus_multischema/middleware.rb | 18 +++++- spec/schema_dumper_spec.rb | 74 ++++++++++++++--------- 2 files changed, 61 insertions(+), 31 deletions(-) diff --git a/lib/schema_plus_multischema/middleware.rb b/lib/schema_plus_multischema/middleware.rb index 1066af5..253ba82 100644 --- a/lib/schema_plus_multischema/middleware.rb +++ b/lib/schema_plus_multischema/middleware.rb @@ -2,12 +2,11 @@ module SchemaPlusMultischema module Middleware module PostgreSQL + DEFAULT_SCHEMA_SEARCH_PATH = %q{"$user",public} module Schema module Tables - DEFAULT_SCHEMA_SEARCH_PATH = %q{"$user",public} - def implement(env) use_prefix = (env.connection.schema_search_path != DEFAULT_SCHEMA_SEARCH_PATH) query = <<-SQL @@ -26,6 +25,21 @@ def implement(env) end end + + module Dumper + module Initial + + def after(env) + if (path = env.connection.schema_search_path) != DEFAULT_SCHEMA_SEARCH_PATH + path.split(',').each do |name| + env.initial << %Q{ connection.execute "CREATE SCHEMA IF NOT EXISTS #{name}"} + end + env.initial << %Q{ connection.schema_search_path = #{path.inspect}} + end + end + + end + end end end end diff --git a/spec/schema_dumper_spec.rb b/spec/schema_dumper_spec.rb index de8ec41..4463535 100644 --- a/spec/schema_dumper_spec.rb +++ b/spec/schema_dumper_spec.rb @@ -3,51 +3,67 @@ describe 'Schema dump' do let(:connection) { ActiveRecord::Base.connection } - around(:each) do |example| - with_schemas %w[first second] do - example.run - end - end + context "with multiple schemas" do - context 'with a table that is created without a schema prefix' do - before(:each) do - schema_definitions do - create_table 'no_schema_prefix' + around(:each) do |example| + with_schemas %w[first second] do + example.run end end - it 'includes schema prefix in dump' do - expect(dump_schema).to include('create_table "first.no_schema_prefix"') - end - end - context 'tables with same name in different schemas' do - before(:each) do - schema_definitions do - create_table 'first.dogs' - create_table 'second.dogs' - end + it "includes the schema definitions and path in the dump" do + expect(dump_schema).to include('CREATE SCHEMA IF NOT EXISTS first') + expect(dump_schema).to include('CREATE SCHEMA IF NOT EXISTS second') + expect(dump_schema).to include('schema_search_path = "first,second"') end - it 'includes both tables with schema prefixes' do - expect(dump_schema).to include('create_table "first.dogs"') - expect(dump_schema).to include('create_table "second.dogs"') + context 'with a table that is created without a schema prefix' do + before(:each) do + schema_definitions do + create_table 'no_schema_prefix' + end + end + it 'includes schema prefix in dump' do + expect(dump_schema).to include('create_table "first.no_schema_prefix"') + end end - context 'with schema_plus_foreign_keys support' do - before(:each) do + context 'tables with same name in different schemas' do + before(:each) do schema_definitions do - create_table 'first.owners' do |t| - t.integer :dog_id, null: false, references: 'second.dogs' - end + create_table 'first.dogs' + create_table 'second.dogs' end end - it 'includes foreign key references with schema prefixes' do - expect(dump_schema).to include('foreign_key: {references: "second.dogs", name: "fk_first_owners_dog_id"') + it 'includes both tables with schema prefixes' do + expect(dump_schema).to include('create_table "first.dogs"') + expect(dump_schema).to include('create_table "second.dogs"') + end + + context 'with schema_plus_foreign_keys support' do + before(:each) do + schema_definitions do + create_table 'first.owners' do |t| + t.integer :dog_id, null: false, references: 'second.dogs' + end + end + end + + it 'includes foreign key references with schema prefixes' do + expect(dump_schema).to include('foreign_key: {references: "second.dogs", name: "fk_first_owners_dog_id"') + end end end end + context "without multiple schemas" do + it "does not include schema setup" do + expect(dump_schema).not_to include('CREATE SCHEMA') + expect(dump_schema).not_to include('schema_search_path') + end + end + private def dump_schema From fb9ee2c51598e1769cc13ce00af89b96960f8e8e Mon Sep 17 00:00:00 2001 From: ronen barzel Date: Fri, 28 Aug 2015 21:43:25 +0100 Subject: [PATCH 11/11] Update doc to describe change to connection.tables, and including the schema setup in the dump. --- README.md | 69 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 5a04bfa..0ee0530 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,17 @@ [![Gem Version](https://badge.fury.io/rb/schema_plus_multischema.svg)](http://badge.fury.io/rb/schema_plus_multischema) [![Build Status](https://secure.travis-ci.org/SchemaPlus/schema_plus_multischema.svg)](http://travis-ci.org/SchemaPlus/schema_plus_multischema) [![Coverage Status](https://img.shields.io/coveralls/SchemaPlus/schema_plus_multischema.svg)](https://coveralls.io/r/SchemaPlus/schema_plus_multischema) -[![Dependency Status](https://gemnasium.com/lomba/schema_plus_multischema.svg)](https://gemnasium.com/SchemaPlus/schema_plus_multischema) + # SchemaPlusMultischema -Schema plus multischema is a schema plus extension for postgresql that adds support for multiple schemas for schema dumps. +SchemaPlusMultischema adds support for using multiple schemas with ActiveRecord. The new features are currently: + +* `ActiveRecord::Connection#tables` returns each table name in the form `"schema.table"` if there if the current search path isn't the DBMS default. + +* Schema dump includes the schema definitions and search path and creates each table in its appropriate schema, if the current search path isn't the DBMS default. + +Support is currently limited to Postgresql. See details below. SchemaPlusMultischema is part of the [SchemaPlus](https://github.com/SchemaPlus/) family of Ruby on Rails ActiveRecord extension gems. @@ -32,43 +38,50 @@ SchemaPlusMultischema is tested on: -## Usage +SchemaPlusMultischema should be a no-op if used with sqlite3 or mysql. -Using schema plus multiple schemas is easy - simply require it before you do a schema dump. If everything works, then the schema dump should include schema names before table names +## Background -For example, lets say we have a table ```wallets``` in schema ```private``` and table ```users``` in schema ```public```. Each user has 1 wallet. Without this gem, the schemadump would look like this: +Your PostgreSQL database might have multiple schemas, that provide namespaces for tables. For example, you could define: -``` -create_table 'wallets' do -end + connection.execute "CREATE SCHEMA first" + connection.execute "CREATE SCHEMA second" -create_table 'users' do |t| - t.integer :wallet_id -end -``` +ActiveRecord's PostgreSQL connection adapter lets you set PostgreSQL's search_path to choose which schemas to look at: -With this gem, the schemadump will look like this: + connection.schema_search_path = "first,second" + +And ActiveRecord let you use schema names in migrations, such as -``` -create_table 'private.wallets' do -end + create_table 'first.my_table' do ... + create_table 'second.my_table' do ... + +But without SchemaPlusMultishema, ActiveRecord's introspection doesn't handle them properly. It *does* find all tables that are in the current search path, but it *doesn't* prefix them with their schema names. And the schema dump `schema/dump.rb` doesn't take into account the schemas at all, so it's invalid. -create_table 'public.users' do |t| - t.integer :wallet_id, null: false -end +## Features -``` +With SchemaPlusMultischema installed, the following features are automatically in place. -The schema plus multischema also works with schema plus foreign keys. If schema plus foreign keys is enabled, the output will look like this: +### `connection.tables` -``` -create_table 'private.wallets' do -end +SchemaPlusMultischema modifies the output of ActiveRecord's `connection.tables` method. If the current search path is different from PostgreSQL's default (`"$user",public`), then each table name is prefixed with its schema. E.g. -create_table 'public.users' do |t| - t.integer :wallet_id, null: false, foreign_key: {references: "private.wallets", name: "fk_public_users_wallet_id", on_update: :no_action, on_delete: :cascade} -end -``` + connection.tables # => ["first.my_table", "second.my_table"] + +If the current search path is the same as the default, the table names are not prefixed, i.e. the behavior is the same as pure ActiveRecord. + +### Schema dump + +If the current search path isn't the default, the schema dump (`db/schema.rb`) will include the schema setup, and the table definitions will be prefixed with their schemas. E.g. + + connection.execute "CREATE SCHEMA IF NOT EXISTS first" + connection.execute "CREATE SCHEMA IF NOT EXISTS second" + connection.schema_search_path = "first,second" + + create_table "first.my_table" do ... + create_table "second.my_table" do ... + +If the current search path is the same as the default, no schema_setup is included and the table names are not prefixed, i.e. the behavior is the same as pure ActiveRecord. ## History