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

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

14
class SchemaTest < ActiveRecord::PostgreSQLTestCase
15
  include PGSchemaHelper
16
  self.use_transactional_tests = false
17

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

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

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

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

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

61
  class Thing5 < ActiveRecord::Base
62
    self.table_name = 'things'
63 64
  end

65 66 67 68 69 70 71 72 73 74
  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

75 76 77
  def setup
    @connection = ActiveRecord::Base.connection
    @connection.execute "CREATE SCHEMA #{SCHEMA_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})"
78
    @connection.execute "CREATE TABLE #{SCHEMA_NAME}.\"#{TABLE_NAME}.table\" (#{COLUMNS.join(',')})"
79
    @connection.execute "CREATE TABLE #{SCHEMA_NAME}.\"#{CAPITALIZED_TABLE_NAME}\" (#{COLUMNS.join(',')})"
80 81 82 83 84
    @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});"
85 86
    @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});"
87 88
    @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 已提交
89 90
    @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});"
91
    @connection.execute "CREATE TABLE #{SCHEMA_NAME}.#{PK_TABLE_NAME} (id serial primary key)"
92 93
    @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))"
94 95
  end

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

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

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
  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 已提交
127
      @connection.create_schema "test_schema3"
128 129 130 131 132 133
    ensure
      @connection.drop_schema "test_schema3"
    end
    assert !@connection.schema_names.include?("test_schema3")
  end

134 135 136 137 138 139 140
  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

141
  def test_habtm_table_name_with_schema
142 143
    ActiveRecord::Base.connection.drop_schema "music", if_exists: true
    ActiveRecord::Base.connection.create_schema "music"
144 145 146 147 148 149 150
    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
151
    Album.create
152 153
    assert_equal song, Song.includes(:albums).references(:albums).first
  ensure
154
    ActiveRecord::Base.connection.drop_schema "music", if_exists: true
155 156
  end

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

    assert_nothing_raised do
      @connection.drop_schema "idontexist", if_exists: true
164 165 166
    end
  end

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

173
  def test_schema_change_with_prepared_stmt
J
Jon Leighton 已提交
174
    altered = false
S
Sean Griffin 已提交
175
    @connection.exec_query "select * from developers where id = $1", 'sql', [bind_param(1)]
176
    @connection.exec_query "alter table developers add column zomg int", 'sql', []
J
Jon Leighton 已提交
177
    altered = true
S
Sean Griffin 已提交
178
    @connection.exec_query "select * from developers where id = $1", 'sql', [bind_param(1)]
179
  ensure
J
Jon Leighton 已提交
180 181 182
    # 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
183 184
  end

185 186 187 188 189 190 191
  def test_table_exists?
    [Thing1, Thing2, Thing3, Thing4].each do |klass|
      name = klass.table_name
      assert @connection.table_exists?(name), "'#{name}' table should exist"
    end
  end

192 193 194 195 196 197 198 199 200 201 202 203
  def test_table_exists_when_on_schema_search_path
    with_schema_search_path(SCHEMA_NAME) do
      assert(@connection.table_exists?(TABLE_NAME), "table should exist and be found")
    end
  end

  def test_table_exists_when_not_on_schema_search_path
    with_schema_search_path('PUBLIC') do
      assert(!@connection.table_exists?(TABLE_NAME), "table exists but should not be found")
    end
  end

204 205 206 207
  def test_table_exists_wrong_schema
    assert(!@connection.table_exists?("foo.things"), "table should not exist")
  end

208 209 210 211 212 213 214 215
  def test_table_exists_quoted_names
    [ %("#{SCHEMA_NAME}"."#{TABLE_NAME}"), %(#{SCHEMA_NAME}."#{TABLE_NAME}"), %(#{SCHEMA_NAME}."#{TABLE_NAME}")].each do |given|
      assert(@connection.table_exists?(given), "table should exist when specified as #{given}")
    end
    with_schema_search_path(SCHEMA_NAME) do
      given = %("#{TABLE_NAME}")
      assert(@connection.table_exists?(given), "table should exist when specified as #{given}")
    end
216 217
  end

218 219 220 221 222 223
  def test_table_exists_quoted_table
    with_schema_search_path(SCHEMA_NAME) do
        assert(@connection.table_exists?('"things.table"'), "table should exist")
    end
  end

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

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

236 237 238 239 240 241 242 243
  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

244 245 246 247 248 249 250 251 252 253 254 255 256
  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
257
    assert_equal 0, Thing4.count
258 259 260 261 262

    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
263
    assert_equal 0, Thing4.count
264 265 266 267 268

    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
269
    assert_equal 0, Thing4.count
270 271 272 273 274

    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
275 276 277 278 279 280 281
    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
282 283
  end

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

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

  def test_ignore_nil_schema_search_path
    assert_nothing_raised { with_schema_search_path nil }
  end

298 299 300 301 302 303 304 305 306 307 308 309
  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

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

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

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

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

G
Guo Xiang Tan 已提交
327 328 329
    with_schema_search_path SCHEMA_NAME do
      assert_nothing_raised { @connection.remove_index! "things", "things_Index"}
    end
330 331
  end

332
  def test_primary_key_with_schema_specified
333 334 335 336 337
    [
      %("#{SCHEMA_NAME}"."#{PK_TABLE_NAME}"),
      %(#{SCHEMA_NAME}."#{PK_TABLE_NAME}"),
      %(#{SCHEMA_NAME}.#{PK_TABLE_NAME})
    ].each do |given|
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
      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

356
  def test_pk_and_sequence_for_with_schema_specified
357
    pg_name = ActiveRecord::ConnectionAdapters::PostgreSQL::Name
358 359
    [
      %("#{SCHEMA_NAME}"."#{PK_TABLE_NAME}"),
360
      %("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}")
361 362 363
    ].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}"
364 365
      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}")
366 367 368
    end
  end

369 370
  def test_current_schema
    {
371 372
      %('$user',public)                        => 'public',
      SCHEMA_NAME                              => SCHEMA_NAME,
373 374 375 376 377 378 379
      %(#{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

380
  def test_prepared_statements_with_multiple_schemas
G
Guo Xiang Tan 已提交
381 382 383 384 385
    [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
386

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

394 395 396 397 398 399 400 401 402 403 404
  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

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

413 414 415 416
  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
417
    assert_equal 124, @connection.select_value("SELECT nextval('#{sequence_name}')")
418 419 420
    @connection.reset_pk_sequence! table_name
  end

421 422 423 424 425 426 427
  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 已提交
428
    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)
429
      with_schema_search_path(this_schema_name) do
430
        indexes = @connection.indexes(TABLE_NAME).sort_by(&:name)
D
doabit 已提交
431
        assert_equal 4,indexes.size
432 433 434

        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)
435
        do_dump_index_assertions_for_one_index(indexes[2], INDEX_D_NAME, third_index_column_name)
D
doabit 已提交
436
        do_dump_index_assertions_for_one_index(indexes[3], INDEX_E_NAME, fourth_index_column_name)
437

D
doabit 已提交
438 439 440 441
        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
442
        assert_equal :desc, indexes.select{|i| i.name == INDEX_D_NAME}[0].orders[INDEX_D_COLUMN]
443 444 445 446 447 448 449 450 451
      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 已提交
452 453 454 455

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

458
class SchemaForeignKeyTest < ActiveRecord::PostgreSQLTestCase
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
  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"
475
    assert_match %r{\s+add_foreign_key "wagons", "my_schema\.trains", column: "train_id"$}, output
476
  ensure
477 478
    @connection.drop_table "wagons", if_exists: true
    @connection.drop_table "my_schema.trains", if_exists: true
479
    @connection.drop_schema "my_schema", if_exists: true
480 481
  end
end
482

483
class DefaultsUsingMultipleSchemasAndDomainTest < ActiveRecord::PostgreSQLTestCase
484 485
  setup do
    @connection = ActiveRecord::Base.connection
486
    @connection.drop_schema "schema_1", if_exists: true
487 488 489 490 491 492 493 494 495 496
    @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"
497
      t.decimal "decimal_col", default: "3.14159265358979323846"
498 499 500 501 502 503
    end
    Default.reset_column_information
  end

  teardown do
    @connection.schema_search_path = @old_search_path
504
    @connection.drop_schema "schema_1", if_exists: true
505 506 507 508 509 510 511 512 513 514 515
    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

516 517 518 519
  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

520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
  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
536 537 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

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