schema_test.rb 21.8 KB
Newer Older
1
require "cases/helper"
2
require 'models/default'
3
require 'support/schema_dumping_helper'
4

5 6 7
module PGSchemaHelper
  def with_schema_search_path(schema_search_path)
    @connection.schema_search_path = schema_search_path
8
    @connection.schema_cache.clear!
9 10 11
    yield if block_given?
  ensure
    @connection.schema_search_path = "'$user', public"
12
    @connection.schema_cache.clear!
13 14 15
  end
end

16
class SchemaTest < ActiveRecord::PostgreSQLTestCase
17
  include PGSchemaHelper
18
  self.use_transactional_tests = false
19

20
  SCHEMA_NAME = 'test_schema'
21
  SCHEMA2_NAME = 'test_schema2'
22
  TABLE_NAME = 'things'
23
  CAPITALIZED_TABLE_NAME = 'Things'
24 25
  INDEX_A_NAME = 'a_index_things_on_name'
  INDEX_B_NAME = 'b_index_things_on_different_columns_in_each_schema'
26
  INDEX_C_NAME = 'c_index_full_text_search'
27
  INDEX_D_NAME = 'd_index_things_on_description_desc'
D
doabit 已提交
28
  INDEX_E_NAME = 'e_index_things_on_name_vector'
29 30 31
  INDEX_A_COLUMN = 'name'
  INDEX_B_COLUMN_S1 = 'email'
  INDEX_B_COLUMN_S2 = 'moment'
32
  INDEX_C_COLUMN = %q{(to_tsvector('english', coalesce(things.name, '')))}
33
  INDEX_D_COLUMN = 'description'
D
doabit 已提交
34
  INDEX_E_COLUMN = 'name_vector'
35 36 37
  COLUMNS = [
    'id integer',
    'name character varying(50)',
38
    'email character varying(50)',
39
    'description character varying(100)',
D
doabit 已提交
40
    'name_vector tsvector',
41 42
    'moment timestamp without time zone default now()'
  ]
43
  PK_TABLE_NAME = 'table_with_pk'
44 45
  UNMATCHED_SEQUENCE_NAME = 'unmatched_primary_key_default_value_seq'
  UNMATCHED_PK_TABLE_NAME = 'table_with_unmatched_sequence_for_pk'
46

47
  class Thing1 < ActiveRecord::Base
48
    self.table_name = "test_schema.things"
49 50 51
  end

  class Thing2 < ActiveRecord::Base
52
    self.table_name = "test_schema2.things"
53 54 55
  end

  class Thing3 < ActiveRecord::Base
56
    self.table_name = 'test_schema."things.table"'
57 58
  end

59
  class Thing4 < ActiveRecord::Base
60
    self.table_name = 'test_schema."Things"'
61 62
  end

63
  class Thing5 < ActiveRecord::Base
64
    self.table_name = 'things'
65 66
  end

67 68 69 70 71 72 73 74 75 76
  class Song < ActiveRecord::Base
    self.table_name = "music.songs"
    has_and_belongs_to_many :albums
  end

  class Album < ActiveRecord::Base
    self.table_name = "music.albums"
    has_and_belongs_to_many :songs
  end

77 78 79
  def setup
    @connection = ActiveRecord::Base.connection
    @connection.execute "CREATE SCHEMA #{SCHEMA_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})"
80
    @connection.execute "CREATE TABLE #{SCHEMA_NAME}.\"#{TABLE_NAME}.table\" (#{COLUMNS.join(',')})"
81
    @connection.execute "CREATE TABLE #{SCHEMA_NAME}.\"#{CAPITALIZED_TABLE_NAME}\" (#{COLUMNS.join(',')})"
82 83 84 85 86
    @connection.execute "CREATE SCHEMA #{SCHEMA2_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})"
    @connection.execute "CREATE INDEX #{INDEX_A_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME}  USING btree (#{INDEX_A_COLUMN});"
    @connection.execute "CREATE INDEX #{INDEX_A_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME}  USING btree (#{INDEX_A_COLUMN});"
    @connection.execute "CREATE INDEX #{INDEX_B_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME}  USING btree (#{INDEX_B_COLUMN_S1});"
    @connection.execute "CREATE INDEX #{INDEX_B_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME}  USING btree (#{INDEX_B_COLUMN_S2});"
87 88
    @connection.execute "CREATE INDEX #{INDEX_C_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME}  USING gin (#{INDEX_C_COLUMN});"
    @connection.execute "CREATE INDEX #{INDEX_C_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME}  USING gin (#{INDEX_C_COLUMN});"
89 90
    @connection.execute "CREATE INDEX #{INDEX_D_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME}  USING btree (#{INDEX_D_COLUMN} DESC);"
    @connection.execute "CREATE INDEX #{INDEX_D_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME}  USING btree (#{INDEX_D_COLUMN} DESC);"
D
doabit 已提交
91 92
    @connection.execute "CREATE INDEX #{INDEX_E_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME}  USING gin (#{INDEX_E_COLUMN});"
    @connection.execute "CREATE INDEX #{INDEX_E_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME}  USING gin (#{INDEX_E_COLUMN});"
93
    @connection.execute "CREATE TABLE #{SCHEMA_NAME}.#{PK_TABLE_NAME} (id serial primary key)"
94 95
    @connection.execute "CREATE SEQUENCE #{SCHEMA_NAME}.#{UNMATCHED_SEQUENCE_NAME}"
    @connection.execute "CREATE TABLE #{SCHEMA_NAME}.#{UNMATCHED_PK_TABLE_NAME} (id integer NOT NULL DEFAULT nextval('#{SCHEMA_NAME}.#{UNMATCHED_SEQUENCE_NAME}'::regclass), CONSTRAINT unmatched_pkey PRIMARY KEY (id))"
96 97
  end

G
Guo Xiang Tan 已提交
98
  teardown do
99 100
    @connection.drop_schema SCHEMA2_NAME, if_exists: true
    @connection.drop_schema SCHEMA_NAME, if_exists: true
101 102
  end

103
  def test_schema_names
104
    assert_equal ["public", "test_schema", "test_schema2"], @connection.schema_names
105 106
  end

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
  def test_create_schema
    begin
      @connection.create_schema "test_schema3"
      assert @connection.schema_names.include? "test_schema3"
    ensure
      @connection.drop_schema "test_schema3"
    end
  end

  def test_raise_create_schema_with_existing_schema
    begin
      @connection.create_schema "test_schema3"
      assert_raises(ActiveRecord::StatementInvalid) do
        @connection.create_schema "test_schema3"
      end
    ensure
      @connection.drop_schema "test_schema3"
    end
  end

  def test_drop_schema
    begin
D
dfens 已提交
129
      @connection.create_schema "test_schema3"
130 131 132 133 134 135
    ensure
      @connection.drop_schema "test_schema3"
    end
    assert !@connection.schema_names.include?("test_schema3")
  end

136 137 138 139 140 141 142
  def test_drop_schema_if_exists
    @connection.create_schema "some_schema"
    assert_includes @connection.schema_names, "some_schema"
    @connection.drop_schema "some_schema", if_exists: true
    assert_not_includes @connection.schema_names, "some_schema"
  end

143
  def test_habtm_table_name_with_schema
144 145
    ActiveRecord::Base.connection.drop_schema "music", if_exists: true
    ActiveRecord::Base.connection.create_schema "music"
146 147 148 149 150 151 152
    ActiveRecord::Base.connection.execute <<-SQL
      CREATE TABLE music.albums (id serial primary key);
      CREATE TABLE music.songs (id serial primary key);
      CREATE TABLE music.albums_songs (album_id integer, song_id integer);
    SQL

    song = Song.create
153
    Album.create
154 155
    assert_equal song, Song.includes(:albums).references(:albums).first
  ensure
156
    ActiveRecord::Base.connection.drop_schema "music", if_exists: true
157 158
  end

159
  def test_drop_schema_with_nonexisting_schema
160
    assert_raises(ActiveRecord::StatementInvalid) do
161 162 163 164 165
      @connection.drop_schema "idontexist"
    end

    assert_nothing_raised do
      @connection.drop_schema "idontexist", if_exists: true
166 167 168
    end
  end

169 170
  def test_raise_wraped_exception_on_bad_prepare
    assert_raises(ActiveRecord::StatementInvalid) do
171
      @connection.exec_query "select * from developers where id = ?", 'sql', [bind_param(1)]
172 173 174
    end
  end

175
  def test_schema_change_with_prepared_stmt
J
Jon Leighton 已提交
176
    altered = false
S
Sean Griffin 已提交
177
    @connection.exec_query "select * from developers where id = $1", 'sql', [bind_param(1)]
178
    @connection.exec_query "alter table developers add column zomg int", 'sql', []
J
Jon Leighton 已提交
179
    altered = true
S
Sean Griffin 已提交
180
    @connection.exec_query "select * from developers where id = $1", 'sql', [bind_param(1)]
181
  ensure
J
Jon Leighton 已提交
182 183 184
    # We are not using DROP COLUMN IF EXISTS because that syntax is only
    # supported by pg 9.X
    @connection.exec_query("alter table developers drop column zomg", 'sql', []) if altered
185 186
  end

187
  def test_data_source_exists?
188 189
    [Thing1, Thing2, Thing3, Thing4].each do |klass|
      name = klass.table_name
190
      assert @connection.data_source_exists?(name), "'#{name}' data_source should exist"
191 192 193
    end
  end

194
  def test_data_source_exists_when_on_schema_search_path
195
    with_schema_search_path(SCHEMA_NAME) do
196
      assert(@connection.data_source_exists?(TABLE_NAME), "data_source should exist and be found")
197 198 199
    end
  end

200
  def test_data_source_exists_when_not_on_schema_search_path
201
    with_schema_search_path('PUBLIC') do
202
      assert(!@connection.data_source_exists?(TABLE_NAME), "data_source exists but should not be found")
203 204 205
    end
  end

206 207
  def test_data_source_exists_wrong_schema
    assert(!@connection.data_source_exists?("foo.things"), "data_source should not exist")
208 209
  end

210
  def test_data_source_exists_quoted_names
211
    [ %("#{SCHEMA_NAME}"."#{TABLE_NAME}"), %(#{SCHEMA_NAME}."#{TABLE_NAME}"), %(#{SCHEMA_NAME}."#{TABLE_NAME}")].each do |given|
212
      assert(@connection.data_source_exists?(given), "data_source should exist when specified as #{given}")
213 214 215
    end
    with_schema_search_path(SCHEMA_NAME) do
      given = %("#{TABLE_NAME}")
216
      assert(@connection.data_source_exists?(given), "data_source should exist when specified as #{given}")
217
    end
218 219
  end

220
  def test_data_source_exists_quoted_table
221
    with_schema_search_path(SCHEMA_NAME) do
222
      assert(@connection.data_source_exists?('"things.table"'), "data_source should exist")
223 224 225
    end
  end

226 227 228 229 230 231
  def test_with_schema_prefixed_table_name
    assert_nothing_raised do
      assert_equal COLUMNS, columns("#{SCHEMA_NAME}.#{TABLE_NAME}")
    end
  end

232 233 234 235 236 237
  def test_with_schema_prefixed_capitalized_table_name
    assert_nothing_raised do
      assert_equal COLUMNS, columns("#{SCHEMA_NAME}.#{CAPITALIZED_TABLE_NAME}")
    end
  end

238 239 240 241 242 243 244 245
  def test_with_schema_search_path
    assert_nothing_raised do
      with_schema_search_path(SCHEMA_NAME) do
        assert_equal COLUMNS, columns(TABLE_NAME)
      end
    end
  end

246 247 248 249 250 251 252 253 254 255 256 257 258
  def test_proper_encoding_of_table_name
    assert_equal '"table_name"', @connection.quote_table_name('table_name')
    assert_equal '"table.name"', @connection.quote_table_name('"table.name"')
    assert_equal '"schema_name"."table_name"', @connection.quote_table_name('schema_name.table_name')
    assert_equal '"schema_name"."table.name"', @connection.quote_table_name('schema_name."table.name"')
    assert_equal '"schema.name"."table_name"', @connection.quote_table_name('"schema.name".table_name')
    assert_equal '"schema.name"."table.name"', @connection.quote_table_name('"schema.name"."table.name"')
  end

  def test_classes_with_qualified_schema_name
    assert_equal 0, Thing1.count
    assert_equal 0, Thing2.count
    assert_equal 0, Thing3.count
259
    assert_equal 0, Thing4.count
260 261 262 263 264

    Thing1.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now)
    assert_equal 1, Thing1.count
    assert_equal 0, Thing2.count
    assert_equal 0, Thing3.count
265
    assert_equal 0, Thing4.count
266 267 268 269 270

    Thing2.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now)
    assert_equal 1, Thing1.count
    assert_equal 1, Thing2.count
    assert_equal 0, Thing3.count
271
    assert_equal 0, Thing4.count
272 273 274 275 276

    Thing3.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now)
    assert_equal 1, Thing1.count
    assert_equal 1, Thing2.count
    assert_equal 1, Thing3.count
277 278 279 280 281 282 283
    assert_equal 0, Thing4.count

    Thing4.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now)
    assert_equal 1, Thing1.count
    assert_equal 1, Thing2.count
    assert_equal 1, Thing3.count
    assert_equal 1, Thing4.count
284 285
  end

286
  def test_raise_on_unquoted_schema_name
287
    assert_raises(ActiveRecord::StatementInvalid) do
288 289 290 291 292
      with_schema_search_path '$user,public'
    end
  end

  def test_without_schema_search_path
293
    assert_raises(ActiveRecord::StatementInvalid) { columns(TABLE_NAME) }
294 295 296 297 298 299
  end

  def test_ignore_nil_schema_search_path
    assert_nothing_raised { with_schema_search_path nil }
  end

300 301 302 303 304 305 306 307 308 309 310 311
  def test_index_name_exists
    with_schema_search_path(SCHEMA_NAME) do
      assert @connection.index_name_exists?(TABLE_NAME, INDEX_A_NAME, true)
      assert @connection.index_name_exists?(TABLE_NAME, INDEX_B_NAME, true)
      assert @connection.index_name_exists?(TABLE_NAME, INDEX_C_NAME, true)
      assert @connection.index_name_exists?(TABLE_NAME, INDEX_D_NAME, true)
      assert @connection.index_name_exists?(TABLE_NAME, INDEX_E_NAME, true)
      assert @connection.index_name_exists?(TABLE_NAME, INDEX_E_NAME, true)
      assert_not @connection.index_name_exists?(TABLE_NAME, 'missing_index', true)
    end
  end

312
  def test_dump_indexes_for_schema_one
D
doabit 已提交
313
    do_dump_index_tests_for_schema(SCHEMA_NAME, INDEX_A_COLUMN, INDEX_B_COLUMN_S1, INDEX_D_COLUMN, INDEX_E_COLUMN)
314 315 316
  end

  def test_dump_indexes_for_schema_two
D
doabit 已提交
317
    do_dump_index_tests_for_schema(SCHEMA2_NAME, INDEX_A_COLUMN, INDEX_B_COLUMN_S2, INDEX_D_COLUMN, INDEX_E_COLUMN)
318 319
  end

320
  def test_dump_indexes_for_schema_multiple_schemas_in_search_path
D
doabit 已提交
321
    do_dump_index_tests_for_schema("public, #{SCHEMA_NAME}", INDEX_A_COLUMN, INDEX_B_COLUMN_S1, INDEX_D_COLUMN, INDEX_E_COLUMN)
322 323
  end

324
  def test_with_uppercase_index_name
G
Guo Xiang Tan 已提交
325
    @connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)"
326
    assert_nothing_raised { @connection.remove_index "things", name: "#{SCHEMA_NAME}.things_Index"}
G
Guo Xiang Tan 已提交
327
    @connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)"
328

G
Guo Xiang Tan 已提交
329
    with_schema_search_path SCHEMA_NAME do
330
      assert_nothing_raised { @connection.remove_index "things", name: "things_Index"}
G
Guo Xiang Tan 已提交
331
    end
332 333
  end

334
  def test_primary_key_with_schema_specified
335 336 337 338 339
    [
      %("#{SCHEMA_NAME}"."#{PK_TABLE_NAME}"),
      %(#{SCHEMA_NAME}."#{PK_TABLE_NAME}"),
      %(#{SCHEMA_NAME}.#{PK_TABLE_NAME})
    ].each do |given|
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
      assert_equal 'id', @connection.primary_key(given), "primary key should be found when table referenced as #{given}"
    end
  end

  def test_primary_key_assuming_schema_search_path
    with_schema_search_path(SCHEMA_NAME) do
      assert_equal 'id', @connection.primary_key(PK_TABLE_NAME), "primary key should be found"
    end
  end

  def test_primary_key_raises_error_if_table_not_found_on_schema_search_path
    with_schema_search_path(SCHEMA2_NAME) do
      assert_raises(ActiveRecord::StatementInvalid) do
        @connection.primary_key(PK_TABLE_NAME)
      end
    end
  end

358
  def test_pk_and_sequence_for_with_schema_specified
359
    pg_name = ActiveRecord::ConnectionAdapters::PostgreSQL::Name
360 361
    [
      %("#{SCHEMA_NAME}"."#{PK_TABLE_NAME}"),
362
      %("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}")
363 364 365
    ].each do |given|
      pk, seq = @connection.pk_and_sequence_for(given)
      assert_equal 'id', pk, "primary key should be found when table referenced as #{given}"
366 367
      assert_equal pg_name.new(SCHEMA_NAME, "#{PK_TABLE_NAME}_id_seq"), seq, "sequence name should be found when table referenced as #{given}" if given == %("#{SCHEMA_NAME}"."#{PK_TABLE_NAME}")
      assert_equal pg_name.new(SCHEMA_NAME, UNMATCHED_SEQUENCE_NAME), seq, "sequence name should be found when table referenced as #{given}" if given ==  %("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}")
368 369 370
    end
  end

371 372
  def test_current_schema
    {
373 374
      %('$user',public)                        => 'public',
      SCHEMA_NAME                              => SCHEMA_NAME,
375 376 377 378 379 380 381
      %(#{SCHEMA2_NAME},#{SCHEMA_NAME},public) => SCHEMA2_NAME,
      %(public,#{SCHEMA2_NAME},#{SCHEMA_NAME}) => 'public'
    }.each do |given,expect|
      with_schema_search_path(given) { assert_equal expect, @connection.current_schema }
    end
  end

382
  def test_prepared_statements_with_multiple_schemas
G
Guo Xiang Tan 已提交
383 384 385 386 387
    [SCHEMA_NAME, SCHEMA2_NAME].each do |schema_name|
      with_schema_search_path schema_name do
        Thing5.create(:id => 1, :name => "thing inside #{SCHEMA_NAME}", :email => "thing1@localhost", :moment => Time.now)
      end
    end
388

G
Guo Xiang Tan 已提交
389 390 391 392 393
    [SCHEMA_NAME, SCHEMA2_NAME].each do |schema_name|
      with_schema_search_path schema_name do
        assert_equal 1, Thing5.count
      end
    end
394 395
  end

396 397 398 399 400 401 402 403 404 405 406
  def test_schema_exists?
    {
      'public'     => true,
      SCHEMA_NAME  => true,
      SCHEMA2_NAME => true,
      'darkside'   => false
    }.each do |given,expect|
      assert_equal expect, @connection.schema_exists?(given)
    end
  end

407 408 409
  def test_reset_pk_sequence
    sequence_name = "#{SCHEMA_NAME}.#{UNMATCHED_SEQUENCE_NAME}"
    @connection.execute "SELECT setval('#{sequence_name}', 123)"
410
    assert_equal 124, @connection.select_value("SELECT nextval('#{sequence_name}')")
411
    @connection.reset_pk_sequence!("#{SCHEMA_NAME}.#{UNMATCHED_PK_TABLE_NAME}")
412
    assert_equal 1, @connection.select_value("SELECT nextval('#{sequence_name}')")
413 414
  end

415 416 417 418
  def test_set_pk_sequence
    table_name = "#{SCHEMA_NAME}.#{PK_TABLE_NAME}"
    _, sequence_name = @connection.pk_and_sequence_for table_name
    @connection.set_pk_sequence! table_name, 123
419
    assert_equal 124, @connection.select_value("SELECT nextval('#{sequence_name}')")
420 421 422
    @connection.reset_pk_sequence! table_name
  end

423 424 425 426 427 428 429
  private
    def columns(table_name)
      @connection.send(:column_definitions, table_name).map do |name, type, default|
        "#{name} #{type}" + (default ? " default #{default}" : '')
      end
    end

D
doabit 已提交
430
    def do_dump_index_tests_for_schema(this_schema_name, first_index_column_name, second_index_column_name, third_index_column_name, fourth_index_column_name)
431
      with_schema_search_path(this_schema_name) do
432
        indexes = @connection.indexes(TABLE_NAME).sort_by(&:name)
D
doabit 已提交
433
        assert_equal 4,indexes.size
434 435 436

        do_dump_index_assertions_for_one_index(indexes[0], INDEX_A_NAME, first_index_column_name)
        do_dump_index_assertions_for_one_index(indexes[1], INDEX_B_NAME, second_index_column_name)
437
        do_dump_index_assertions_for_one_index(indexes[2], INDEX_D_NAME, third_index_column_name)
D
doabit 已提交
438
        do_dump_index_assertions_for_one_index(indexes[3], INDEX_E_NAME, fourth_index_column_name)
439

D
doabit 已提交
440 441 442 443
        indexes.select{|i| i.name != INDEX_E_NAME}.each do |index|
           assert_equal :btree, index.using
        end
        assert_equal :gin, indexes.select{|i| i.name == INDEX_E_NAME}[0].using
444
        assert_equal :desc, indexes.select{|i| i.name == INDEX_D_NAME}[0].orders[INDEX_D_COLUMN]
445 446 447 448 449 450 451 452 453
      end
    end

    def do_dump_index_assertions_for_one_index(this_index, this_index_name, this_index_column)
      assert_equal TABLE_NAME, this_index.table
      assert_equal 1, this_index.columns.size
      assert_equal this_index_column, this_index.columns[0]
      assert_equal this_index_name, this_index.name
    end
S
Sean Griffin 已提交
454 455 456 457

    def bind_param(value)
      ActiveRecord::Relation::QueryAttribute.new(nil, value, ActiveRecord::Type::Value.new)
    end
458
end
459

460
class SchemaForeignKeyTest < ActiveRecord::PostgreSQLTestCase
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
  include SchemaDumpingHelper

  setup do
    @connection = ActiveRecord::Base.connection
  end

  def test_dump_foreign_key_targeting_different_schema
    @connection.create_schema "my_schema"
    @connection.create_table "my_schema.trains" do |t|
      t.string :name
    end
    @connection.create_table "wagons" do |t|
      t.integer :train_id
    end
    @connection.add_foreign_key "wagons", "my_schema.trains", column: "train_id"
    output = dump_table_schema "wagons"
477
    assert_match %r{\s+add_foreign_key "wagons", "my_schema\.trains", column: "train_id"$}, output
478
  ensure
479 480
    @connection.drop_table "wagons", if_exists: true
    @connection.drop_table "my_schema.trains", if_exists: true
481
    @connection.drop_schema "my_schema", if_exists: true
482 483
  end
end
484

485
class DefaultsUsingMultipleSchemasAndDomainTest < ActiveRecord::PostgreSQLTestCase
486 487
  setup do
    @connection = ActiveRecord::Base.connection
488
    @connection.drop_schema "schema_1", if_exists: true
489 490 491 492 493 494 495 496 497 498
    @connection.execute "CREATE SCHEMA schema_1"
    @connection.execute "CREATE DOMAIN schema_1.text AS text"
    @connection.execute "CREATE DOMAIN schema_1.varchar AS varchar"
    @connection.execute "CREATE DOMAIN schema_1.bpchar AS bpchar"

    @old_search_path = @connection.schema_search_path
    @connection.schema_search_path = "schema_1, pg_catalog"
    @connection.create_table "defaults" do |t|
      t.text "text_col", default: "some value"
      t.string "string_col", default: "some value"
499
      t.decimal "decimal_col", default: "3.14159265358979323846"
500 501 502 503 504 505
    end
    Default.reset_column_information
  end

  teardown do
    @connection.schema_search_path = @old_search_path
506
    @connection.drop_schema "schema_1", if_exists: true
507 508 509 510 511 512 513 514 515 516 517
    Default.reset_column_information
  end

  def test_text_defaults_in_new_schema_when_overriding_domain
    assert_equal "some value", Default.new.text_col, "Default of text column was not correctly parsed"
  end

  def test_string_defaults_in_new_schema_when_overriding_domain
    assert_equal "some value", Default.new.string_col, "Default of string column was not correctly parsed"
  end

518 519 520 521
  def test_decimal_defaults_in_new_schema_when_overriding_domain
    assert_equal BigDecimal.new("3.14159265358979323846"), Default.new.decimal_col, "Default of decimal column was not correctly parsed"
  end

522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
  def test_bpchar_defaults_in_new_schema_when_overriding_domain
    @connection.execute "ALTER TABLE defaults ADD bpchar_col bpchar DEFAULT 'some value'"
    Default.reset_column_information
    assert_equal "some value", Default.new.bpchar_col, "Default of bpchar column was not correctly parsed"
  end

  def test_text_defaults_after_updating_column_default
    @connection.execute "ALTER TABLE defaults ALTER COLUMN text_col SET DEFAULT 'some text'::schema_1.text"
    assert_equal "some text", Default.new.text_col, "Default of text column was not correctly parsed after updating default using '::text' since postgreSQL will add parens to the default in db"
  end

  def test_default_containing_quote_and_colons
    @connection.execute "ALTER TABLE defaults ALTER COLUMN string_col SET DEFAULT 'foo''::bar'"
    assert_equal "foo'::bar", Default.new.string_col
  end
end
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574

class SchemaWithDotsTest < ActiveRecord::PostgreSQLTestCase
  include PGSchemaHelper
  self.use_transactional_tests = false

  setup do
    @connection = ActiveRecord::Base.connection
    @connection.create_schema "my.schema"
  end

  teardown do
    @connection.drop_schema "my.schema", if_exists: true
  end

  test "rename_table" do
    with_schema_search_path('"my.schema"') do
      @connection.create_table :posts
      @connection.rename_table :posts, :articles
      assert_equal ["articles"], @connection.tables
    end
  end

  test "Active Record basics" do
    with_schema_search_path('"my.schema"') do
      @connection.create_table :articles do |t|
        t.string :title
      end
      article_class = Class.new(ActiveRecord::Base) do
        self.table_name = '"my.schema".articles'
      end

      article_class.create!(title: "zOMG, welcome to my blorgh!")
      welcome_article = article_class.last
      assert_equal "zOMG, welcome to my blorgh!", welcome_article.title
    end
  end
end