diff options
Diffstat (limited to 'activerecord/test/cases/adapters/postgresql')
23 files changed, 582 insertions, 244 deletions
diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb index c20030ca64..e03d83df59 100644 --- a/activerecord/test/cases/adapters/postgresql/array_test.rb +++ b/activerecord/test/cases/adapters/postgresql/array_test.rb @@ -1,7 +1,5 @@ # encoding: utf-8 require "cases/helper" -require 'active_record/base' -require 'active_record/connection_adapters/postgresql_adapter' class PostgresqlArrayTest < ActiveRecord::TestCase class PgArray < ActiveRecord::Base @@ -89,16 +87,7 @@ class PostgresqlArrayTest < ActiveRecord::TestCase end def test_type_cast_array - data = '{1,2,3}' - oid_type = @column.instance_variable_get('@oid_type').subtype - # we are getting the instance variable in this test, but in the - # normal use of string_to_array, it's called from the OID::Array - # class and will have the OID instance that will provide the type - # casting - array = @column.class.string_to_array data, oid_type - assert_equal(['1', '2', '3'], array) - assert_equal(['1', '2', '3'], @column.type_cast(data)) - + assert_equal(['1', '2', '3'], @column.type_cast('{1,2,3}')) assert_equal([], @column.type_cast('{}')) assert_equal([nil], @column.type_cast('{NULL}')) end diff --git a/activerecord/test/cases/adapters/postgresql/bit_string_test.rb b/activerecord/test/cases/adapters/postgresql/bit_string_test.rb new file mode 100644 index 0000000000..3a9397bc26 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/bit_string_test.rb @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +require "cases/helper" +require 'support/connection_helper' +require 'support/schema_dumping_helper' + +class PostgresqlBitStringTest < ActiveRecord::TestCase + include ConnectionHelper + include SchemaDumpingHelper + + class PostgresqlBitString < ActiveRecord::Base; end + + def setup + @connection = ActiveRecord::Base.connection + @connection.create_table('postgresql_bit_strings', :force => true) do |t| + t.bit :a_bit, default: "00000011", limit: 8 + t.bit_varying :a_bit_varying, default: "0011", limit: 4 + end + end + + def teardown + return unless @connection + @connection.execute 'DROP TABLE IF EXISTS postgresql_bit_strings' + end + + def test_bit_string_column + column = PostgresqlBitString.columns_hash["a_bit"] + assert_equal :bit, column.type + assert_equal "bit(8)", column.sql_type + assert_not column.text? + assert_not column.number? + assert_not column.binary? + assert_not column.array + end + + def test_bit_string_varying_column + column = PostgresqlBitString.columns_hash["a_bit_varying"] + assert_equal :bit_varying, column.type + assert_equal "bit varying(4)", column.sql_type + assert_not column.text? + assert_not column.number? + assert_not column.binary? + assert_not column.array + end + + def test_default + column = PostgresqlBitString.columns_hash["a_bit"] + assert_equal "00000011", column.default + assert_equal "00000011", PostgresqlBitString.new.a_bit + + column = PostgresqlBitString.columns_hash["a_bit_varying"] + assert_equal "0011", column.default + assert_equal "0011", PostgresqlBitString.new.a_bit_varying + end + + def test_schema_dumping + output = dump_table_schema("postgresql_bit_strings") + assert_match %r{t\.bit\s+"a_bit",\s+limit: 8,\s+default: "00000011"$}, output + assert_match %r{t\.bit_varying\s+"a_bit_varying",\s+limit: 4,\s+default: "0011"$}, output + end + + def test_assigning_invalid_hex_string_raises_exception + assert_raises(ActiveRecord::StatementInvalid) { PostgresqlBitString.create! a_bit: "FF" } + assert_raises(ActiveRecord::StatementInvalid) { PostgresqlBitString.create! a_bit_varying: "FF" } + end + + def test_roundtrip + PostgresqlBitString.create! a_bit: "00001010", a_bit_varying: "0101" + record = PostgresqlBitString.first + assert_equal "00001010", record.a_bit + assert_equal "0101", record.a_bit_varying + + record.a_bit = "11111111" + record.a_bit_varying = "0xF" + record.save! + + assert record.reload + assert_equal "11111111", record.a_bit + assert_equal "1111", record.a_bit_varying + end +end diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb index fadadfa57c..3f8a5d1062 100644 --- a/activerecord/test/cases/adapters/postgresql/bytea_test.rb +++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb @@ -1,8 +1,5 @@ # encoding: utf-8 - require "cases/helper" -require 'active_record/base' -require 'active_record/connection_adapters/postgresql_adapter' class PostgresqlByteaTest < ActiveRecord::TestCase class ByteaDataType < ActiveRecord::Base diff --git a/activerecord/test/cases/adapters/postgresql/citext_test.rb b/activerecord/test/cases/adapters/postgresql/citext_test.rb index 8493050726..90e837d426 100644 --- a/activerecord/test/cases/adapters/postgresql/citext_test.rb +++ b/activerecord/test/cases/adapters/postgresql/citext_test.rb @@ -1,8 +1,5 @@ # encoding: utf-8 - require 'cases/helper' -require 'active_record/base' -require 'active_record/connection_adapters/postgresql_adapter' if ActiveRecord::Base.connection.supports_extensions? class PostgresqlCitextTest < ActiveRecord::TestCase diff --git a/activerecord/test/cases/adapters/postgresql/composite_test.rb b/activerecord/test/cases/adapters/postgresql/composite_test.rb index 68b9e6daf7..a925263098 100644 --- a/activerecord/test/cases/adapters/postgresql/composite_test.rb +++ b/activerecord/test/cases/adapters/postgresql/composite_test.rb @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- require "cases/helper" require 'support/connection_helper' -require 'active_record/base' -require 'active_record/connection_adapters/postgresql_adapter' module PostgresqlCompositeBehavior include ConnectionHelper @@ -83,9 +81,8 @@ end class PostgresqlCompositeWithCustomOIDTest < ActiveRecord::TestCase include PostgresqlCompositeBehavior - class FullAddressType + class FullAddressType < ActiveRecord::Type::Value def type; :full_address end - def simplified_type(sql_type); type end def type_cast(value) if value =~ /\("?([^",]*)"?,"?([^",]*)"?\)/ @@ -94,6 +91,7 @@ class PostgresqlCompositeWithCustomOIDTest < ActiveRecord::TestCase end def type_cast_for_write(value) + return if value.nil? "(#{value.city},#{value.street})" end end @@ -103,15 +101,7 @@ class PostgresqlCompositeWithCustomOIDTest < ActiveRecord::TestCase def setup super - @registration = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID - @registration.register_type "full_address", FullAddressType.new - end - - def teardown - super - - # there is currently no clean way to unregister a OID::Type - @registration::NAMES.delete("full_address") + @connection.type_map.register_type "full_address", FullAddressType.new end def test_column @@ -131,7 +121,6 @@ class PostgresqlCompositeWithCustomOIDTest < ActiveRecord::TestCase assert_equal "Champs-Élysées", composite.address.street composite.address = FullAddress.new("Paris", "Rue Basse") - skip "Saving with custom OID type is currently not supported." composite.save! assert_equal 'Paris', composite.reload.address.city diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb index 897b603321..a0a34e4b87 100644 --- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb +++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb @@ -1,14 +1,6 @@ require "cases/helper" require 'support/ddl_helper' -class PostgresqlArray < ActiveRecord::Base -end - -class PostgresqlTsvector < ActiveRecord::Base -end - -class PostgresqlMoney < ActiveRecord::Base -end class PostgresqlNumber < ActiveRecord::Base end @@ -16,18 +8,9 @@ end class PostgresqlTime < ActiveRecord::Base end -class PostgresqlNetworkAddress < ActiveRecord::Base -end - -class PostgresqlBitString < ActiveRecord::Base -end - class PostgresqlOid < ActiveRecord::Base end -class PostgresqlTimestampWithZone < ActiveRecord::Base -end - class PostgresqlLtree < ActiveRecord::Base end @@ -36,16 +19,6 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase def setup @connection = ActiveRecord::Base.connection - @connection.execute("set lc_monetary = 'C'") - - @connection.execute("INSERT INTO postgresql_tsvectors (id, text_vector) VALUES (1, ' ''text'' ''vector'' ')") - - @first_tsvector = PostgresqlTsvector.find(1) - - @connection.execute("INSERT INTO postgresql_moneys (id, wealth) VALUES (1, '567.89'::money)") - @connection.execute("INSERT INTO postgresql_moneys (id, wealth) VALUES (2, '-567.89'::money)") - @first_money = PostgresqlMoney.find(1) - @second_money = PostgresqlMoney.find(2) @connection.execute("INSERT INTO postgresql_numbers (id, single, double) VALUES (1, 123.456, 123456.789)") @connection.execute("INSERT INTO postgresql_numbers (id, single, double) VALUES (2, '-Infinity', 'Infinity')") @@ -57,29 +30,12 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase @connection.execute("INSERT INTO postgresql_times (id, time_interval, scaled_time_interval) VALUES (1, '1 year 2 days ago', '3 weeks ago')") @first_time = PostgresqlTime.find(1) - @connection.execute("INSERT INTO postgresql_network_addresses (id, cidr_address, inet_address, mac_address) VALUES(1, '192.168.0/24', '172.16.1.254/32', '01:23:45:67:89:0a')") - @first_network_address = PostgresqlNetworkAddress.find(1) - - @connection.execute("INSERT INTO postgresql_bit_strings (id, bit_string, bit_string_varying) VALUES (1, B'00010101', X'15')") - @first_bit_string = PostgresqlBitString.find(1) - @connection.execute("INSERT INTO postgresql_oids (id, obj_id) VALUES (1, 1234)") @first_oid = PostgresqlOid.find(1) - - @connection.execute("INSERT INTO postgresql_timestamp_with_zones (id, time) VALUES (1, '2010-01-01 10:00:00-1')") end teardown do - [PostgresqlTsvector, PostgresqlMoney, PostgresqlNumber, PostgresqlTime, PostgresqlNetworkAddress, - PostgresqlBitString, PostgresqlOid, PostgresqlTimestampWithZone].each(&:delete_all) - end - - def test_data_type_of_tsvector_types - assert_equal :tsvector, @first_tsvector.column_for_attribute(:text_vector).type - end - - def test_data_type_of_money_types - assert_equal :decimal, @first_money.column_for_attribute(:wealth).type + [PostgresqlNumber, PostgresqlTime, PostgresqlOid].each(&:delete_all) end def test_data_type_of_number_types @@ -92,53 +48,14 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase assert_equal :string, @first_time.column_for_attribute(:scaled_time_interval).type end - def test_data_type_of_network_address_types - assert_equal :cidr, @first_network_address.column_for_attribute(:cidr_address).type - assert_equal :inet, @first_network_address.column_for_attribute(:inet_address).type - assert_equal :macaddr, @first_network_address.column_for_attribute(:mac_address).type - end - - def test_data_type_of_bit_string_types - assert_equal :string, @first_bit_string.column_for_attribute(:bit_string).type - assert_equal :string, @first_bit_string.column_for_attribute(:bit_string_varying).type - end - def test_data_type_of_oid_types assert_equal :integer, @first_oid.column_for_attribute(:obj_id).type end - def test_tsvector_values - assert_equal "'text' 'vector'", @first_tsvector.text_vector - end - - def test_money_values - assert_equal 567.89, @first_money.wealth - assert_equal(-567.89, @second_money.wealth) - end - - def test_money_type_cast - column = PostgresqlMoney.columns_hash['wealth'] - assert_equal(12345678.12, column.type_cast("$12,345,678.12")) - assert_equal(12345678.12, column.type_cast("$12.345.678,12")) - assert_equal(-1.15, column.type_cast("-$1.15")) - assert_equal(-2.25, column.type_cast("($2.25)")) - end - - def test_update_tsvector - new_text_vector = "'new' 'text' 'vector'" - @first_tsvector.text_vector = new_text_vector - assert @first_tsvector.save - assert @first_tsvector.reload - @first_tsvector.text_vector = new_text_vector - assert @first_tsvector.save - assert @first_tsvector.reload - assert_equal new_text_vector, @first_tsvector.text_vector - end - def test_number_values assert_equal 123.456, @first_number.single assert_equal 123456.789, @first_number.double - assert_equal -::Float::INFINITY, @second_number.single + assert_equal(-::Float::INFINITY, @second_number.single) assert_equal ::Float::INFINITY, @second_number.double assert_same ::Float::NAN, @third_number.double end @@ -148,32 +65,10 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase assert_equal '-21 days', @first_time.scaled_time_interval end - def test_network_address_values_ipaddr - cidr_address = IPAddr.new '192.168.0.0/24' - inet_address = IPAddr.new '172.16.1.254' - - assert_equal cidr_address, @first_network_address.cidr_address - assert_equal inet_address, @first_network_address.inet_address - assert_equal '01:23:45:67:89:0a', @first_network_address.mac_address - end - - def test_bit_string_values - assert_equal '00010101', @first_bit_string.bit_string - assert_equal '00010101', @first_bit_string.bit_string_varying - end - def test_oid_values assert_equal 1234, @first_oid.obj_id end - def test_update_money - new_value = BigDecimal.new('123.45') - @first_money.wealth = new_value - assert @first_money.save - assert @first_money.reload - assert_equal new_value, @first_money.wealth - end - def test_update_number new_single = 789.012 new_double = 789012.345 @@ -192,51 +87,6 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase assert_equal '2 years 00:03:00', @first_time.time_interval end - def test_update_network_address - new_inet_address = '10.1.2.3/32' - new_cidr_address = '10.0.0.0/8' - new_mac_address = 'bc:de:f0:12:34:56' - @first_network_address.cidr_address = new_cidr_address - @first_network_address.inet_address = new_inet_address - @first_network_address.mac_address = new_mac_address - assert @first_network_address.save - assert @first_network_address.reload - assert_equal @first_network_address.cidr_address, new_cidr_address - assert_equal @first_network_address.inet_address, new_inet_address - assert_equal @first_network_address.mac_address, new_mac_address - end - - def test_update_bit_string - new_bit_string = '11111111' - new_bit_string_varying = '0xFF' - @first_bit_string.bit_string = new_bit_string - @first_bit_string.bit_string_varying = new_bit_string_varying - assert @first_bit_string.save - assert @first_bit_string.reload - assert_equal new_bit_string, @first_bit_string.bit_string - assert_equal @first_bit_string.bit_string, @first_bit_string.bit_string_varying - end - - def test_invalid_hex_string - new_bit_string = 'FF' - @first_bit_string.bit_string = new_bit_string - assert_raise(ActiveRecord::StatementInvalid) { assert @first_bit_string.save } - end - - def test_invalid_network_address - @first_network_address.cidr_address = 'invalid addr' - assert_nil @first_network_address.cidr_address - assert_equal 'invalid addr', @first_network_address.cidr_address_before_type_cast - assert @first_network_address.save - - @first_network_address.reload - - @first_network_address.inet_address = 'invalid addr' - assert_nil @first_network_address.inet_address - assert_equal 'invalid addr', @first_network_address.inet_address_before_type_cast - assert @first_network_address.save - end - def test_update_oid new_value = 567890 @first_oid.obj_id = new_value @@ -244,32 +94,6 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase assert @first_oid.reload assert_equal new_value, @first_oid.obj_id end - - def test_timestamp_with_zone_values_with_rails_time_zone_support - with_timezone_config default: :utc, aware_attributes: true do - @connection.reconnect! - - @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1) - assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time - assert_instance_of Time, @first_timestamp_with_zone.time - end - ensure - @connection.reconnect! - end - - def test_timestamp_with_zone_values_without_rails_time_zone_support - with_timezone_config default: :local, aware_attributes: false do - @connection.reconnect! - # make sure to use a non-UTC time zone - @connection.execute("SET time zone 'America/Jamaica'", 'SCHEMA') - - @first_timestamp_with_zone = PostgresqlTimestampWithZone.find(1) - assert_equal Time.utc(2010,1,1, 11,0,0), @first_timestamp_with_zone.time - assert_instance_of Time, @first_timestamp_with_zone.time - end - ensure - @connection.reconnect! - end end class PostgresqlInternalDataTypeTest < ActiveRecord::TestCase diff --git a/activerecord/test/cases/adapters/postgresql/domain_test.rb b/activerecord/test/cases/adapters/postgresql/domain_test.rb index 5286a847a4..fd7fdecff1 100644 --- a/activerecord/test/cases/adapters/postgresql/domain_test.rb +++ b/activerecord/test/cases/adapters/postgresql/domain_test.rb @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- require "cases/helper" require 'support/connection_helper' -require 'active_record/base' -require 'active_record/connection_adapters/postgresql_adapter' class PostgresqlDomainTest < ActiveRecord::TestCase include ConnectionHelper diff --git a/activerecord/test/cases/adapters/postgresql/enum_test.rb b/activerecord/test/cases/adapters/postgresql/enum_test.rb index 4146b117f6..b809f1a79c 100644 --- a/activerecord/test/cases/adapters/postgresql/enum_test.rb +++ b/activerecord/test/cases/adapters/postgresql/enum_test.rb @@ -39,6 +39,17 @@ class PostgresqlEnumTest < ActiveRecord::TestCase assert_not column.array end + def test_enum_defaults + @connection.add_column 'postgresql_enums', 'good_mood', :mood, default: 'happy' + PostgresqlEnum.reset_column_information + column = PostgresqlEnum.columns_hash["good_mood"] + + assert_equal "happy", column.default + assert_equal "happy", PostgresqlEnum.new.good_mood + ensure + PostgresqlEnum.reset_column_information + end + def test_enum_mapping @connection.execute "INSERT INTO postgresql_enums VALUES (1, 'sad');" enum = PostgresqlEnum.first diff --git a/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb b/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb new file mode 100644 index 0000000000..7b99fcdda0 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/extension_migration_test.rb @@ -0,0 +1,63 @@ +require "cases/helper" + +class PostgresqlExtensionMigrationTest < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + class EnableHstore < ActiveRecord::Migration + def change + enable_extension "hstore" + end + end + + class DisableHstore < ActiveRecord::Migration + def change + disable_extension "hstore" + end + end + + def setup + super + + @connection = ActiveRecord::Base.connection + + unless @connection.supports_extensions? + return skip("no extension support") + end + + @old_schema_migration_tabel_name = ActiveRecord::SchemaMigration.table_name + @old_tabel_name_prefix = ActiveRecord::Base.table_name_prefix + @old_tabel_name_suffix = ActiveRecord::Base.table_name_suffix + + ActiveRecord::Base.table_name_prefix = "p_" + ActiveRecord::Base.table_name_suffix = "_s" + ActiveRecord::SchemaMigration.delete_all rescue nil + ActiveRecord::SchemaMigration.table_name = "p_schema_migrations_s" + ActiveRecord::Migration.verbose = false + end + + def teardown + ActiveRecord::Base.table_name_prefix = @old_tabel_name_prefix + ActiveRecord::Base.table_name_suffix = @old_tabel_name_suffix + ActiveRecord::SchemaMigration.delete_all rescue nil + ActiveRecord::Migration.verbose = true + ActiveRecord::SchemaMigration.table_name = @old_schema_migration_tabel_name + + super + end + + def test_enable_extension_migration_ignores_prefix_and_suffix + @connection.disable_extension("hstore") + + migrations = [EnableHstore.new(nil, 1)] + ActiveRecord::Migrator.new(:up, migrations).migrate + assert @connection.extension_enabled?("hstore"), "extension hstore should be enabled" + end + + def test_disable_extension_migration_ignores_prefix_and_suffix + @connection.enable_extension("hstore") + + migrations = [DisableHstore.new(nil, 1)] + ActiveRecord::Migrator.new(:up, migrations).migrate + assert_not @connection.extension_enabled?("hstore"), "extension hstore should not be enabled" + end +end diff --git a/activerecord/test/cases/adapters/postgresql/full_text_test.rb b/activerecord/test/cases/adapters/postgresql/full_text_test.rb new file mode 100644 index 0000000000..ec646de5e9 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/full_text_test.rb @@ -0,0 +1,27 @@ +# encoding: utf-8 +require "cases/helper" + +class PostgresqlFullTextTest < ActiveRecord::TestCase + class PostgresqlTsvector < ActiveRecord::Base; end + + def test_tsvector_column + column = PostgresqlTsvector.columns_hash["text_vector"] + assert_equal :tsvector, column.type + assert_equal "tsvector", column.sql_type + assert_not column.number? + assert_not column.text? + assert_not column.binary? + assert_not column.array + end + + def test_update_tsvector + PostgresqlTsvector.create text_vector: "'text' 'vector'" + tsvector = PostgresqlTsvector.first + assert_equal "'text' 'vector'", tsvector.text_vector + + tsvector.text_vector = "'new' 'text' 'vector'" + tsvector.save! + assert tsvector.reload + assert_equal "'new' 'text' 'vector'", tsvector.text_vector + end +end diff --git a/activerecord/test/cases/adapters/postgresql/geometric_test.rb b/activerecord/test/cases/adapters/postgresql/geometric_test.rb new file mode 100644 index 0000000000..2f106ee664 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/geometric_test.rb @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +require "cases/helper" +require 'support/connection_helper' +require 'support/schema_dumping_helper' + +class PostgresqlPointTest < ActiveRecord::TestCase + include ConnectionHelper + include SchemaDumpingHelper + + class PostgresqlPoint < ActiveRecord::Base; end + + def setup + @connection = ActiveRecord::Base.connection + @connection.transaction do + @connection.create_table('postgresql_points') do |t| + t.point :x + t.point :y, default: [12.2, 13.3] + t.point :z, default: "(14.4,15.5)" + end + end + end + + teardown do + @connection.execute 'DROP TABLE IF EXISTS postgresql_points' + end + + def test_column + column = PostgresqlPoint.columns_hash["x"] + assert_equal :point, column.type + assert_equal "point", column.sql_type + assert_not column.text? + assert_not column.number? + assert_not column.binary? + assert_not column.array + end + + def test_default + column = PostgresqlPoint.columns_hash["y"] + assert_equal [12.2, 13.3], column.default + assert_equal [12.2, 13.3], PostgresqlPoint.new.y + + column = PostgresqlPoint.columns_hash["z"] + assert_equal [14.4, 15.5], column.default + assert_equal [14.4, 15.5], PostgresqlPoint.new.z + end + + def test_schema_dumping + output = dump_table_schema("postgresql_points") + assert_match %r{t\.point\s+"x"$}, output + assert_match %r{t\.point\s+"y",\s+default: \[12\.2, 13\.3\]$}, output + assert_match %r{t\.point\s+"z",\s+default: \[14\.4, 15\.5\]$}, output + end + + def test_roundtrip + PostgresqlPoint.create! x: [10, 25.2] + record = PostgresqlPoint.first + assert_equal [10, 25.2], record.x + + record.x = [1.1, 2.2] + record.save! + assert record.reload + assert_equal [1.1, 2.2], record.x + end +end diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb index 67a610b459..1fef4899be 100644 --- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb +++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb @@ -142,6 +142,16 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase assert_equal "GMT", x.timezone end + def test_duplication_with_store_accessors + x = Hstore.new(language: "fr", timezone: "GMT") + assert_equal "fr", x.language + assert_equal "GMT", x.timezone + + y = x.dup + assert_equal "fr", y.language + assert_equal "GMT", y.timezone + end + def test_gen1 assert_equal(%q(" "=>""), @column.class.hstore_to_string({' '=>''})) end diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb index d25f8bf958..03b546119d 100644 --- a/activerecord/test/cases/adapters/postgresql/json_test.rb +++ b/activerecord/test/cases/adapters/postgresql/json_test.rb @@ -139,6 +139,14 @@ class PostgresqlJSONTest < ActiveRecord::TestCase assert_equal "640×1136", x.resolution end + def test_duplication_with_store_accessors + x = JsonDataType.new(resolution: "320×480") + assert_equal "320×480", x.resolution + + y = x.dup + assert_equal "320×480", y.resolution + end + def test_update_all json = JsonDataType.create! payload: { "one" => "two" } diff --git a/activerecord/test/cases/adapters/postgresql/ltree_test.rb b/activerecord/test/cases/adapters/postgresql/ltree_test.rb index 718f37a380..ddb7cd658c 100644 --- a/activerecord/test/cases/adapters/postgresql/ltree_test.rb +++ b/activerecord/test/cases/adapters/postgresql/ltree_test.rb @@ -1,7 +1,5 @@ # encoding: utf-8 require "cases/helper" -require 'active_record/base' -require 'active_record/connection_adapters/postgresql_adapter' class PostgresqlLtreeTest < ActiveRecord::TestCase class Ltree < ActiveRecord::Base diff --git a/activerecord/test/cases/adapters/postgresql/money_test.rb b/activerecord/test/cases/adapters/postgresql/money_test.rb new file mode 100644 index 0000000000..3e33477bff --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/money_test.rb @@ -0,0 +1,74 @@ +# encoding: utf-8 +require "cases/helper" +require 'support/schema_dumping_helper' + +class PostgresqlMoneyTest < ActiveRecord::TestCase + include SchemaDumpingHelper + + class PostgresqlMoney < ActiveRecord::Base; end + + setup do + @connection = ActiveRecord::Base.connection + @connection.execute("set lc_monetary = 'C'") + @connection.create_table('postgresql_moneys') do |t| + t.column "wealth", "money" + t.column "depth", "money", default: "150.55" + end + end + + teardown do + @connection.execute 'DROP TABLE IF EXISTS postgresql_moneys' + end + + def test_column + column = PostgresqlMoney.columns_hash["wealth"] + assert_equal :money, column.type + assert_equal "money", column.sql_type + assert_equal 2, column.scale + assert column.number? + assert_not column.text? + assert_not column.binary? + assert_not column.array + end + + def test_default + column = PostgresqlMoney.columns_hash["depth"] + assert_equal BigDecimal.new("150.55"), column.default + assert_equal BigDecimal.new("150.55"), PostgresqlMoney.new.depth + end + + def test_money_values + @connection.execute("INSERT INTO postgresql_moneys (id, wealth) VALUES (1, '567.89'::money)") + @connection.execute("INSERT INTO postgresql_moneys (id, wealth) VALUES (2, '-567.89'::money)") + + first_money = PostgresqlMoney.find(1) + second_money = PostgresqlMoney.find(2) + assert_equal 567.89, first_money.wealth + assert_equal(-567.89, second_money.wealth) + end + + def test_money_type_cast + column = PostgresqlMoney.columns_hash['wealth'] + assert_equal(12345678.12, column.type_cast("$12,345,678.12")) + assert_equal(12345678.12, column.type_cast("$12.345.678,12")) + assert_equal(-1.15, column.type_cast("-$1.15")) + assert_equal(-2.25, column.type_cast("($2.25)")) + end + + def test_schema_dumping + output = dump_table_schema("postgresql_moneys") + assert_match %r{t\.money\s+"wealth",\s+scale: 2$}, output + assert_match %r{t\.money\s+"depth",\s+scale: 2,\s+default: 150.55$}, output + end + + def test_create_and_update_money + money = PostgresqlMoney.create(wealth: "987.65") + assert_equal 987.65, money.wealth + + new_value = BigDecimal.new('123.45') + money.wealth = new_value + money.save! + money.reload + assert_equal new_value, money.wealth + end +end diff --git a/activerecord/test/cases/adapters/postgresql/network_test.rb b/activerecord/test/cases/adapters/postgresql/network_test.rb new file mode 100644 index 0000000000..32085cbb17 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/network_test.rb @@ -0,0 +1,74 @@ +# encoding: utf-8 +require "cases/helper" + +class PostgresqlNetworkTest < ActiveRecord::TestCase + class PostgresqlNetworkAddress < ActiveRecord::Base + end + + def test_cidr_column + column = PostgresqlNetworkAddress.columns_hash["cidr_address"] + assert_equal :cidr, column.type + assert_equal "cidr", column.sql_type + assert_not column.number? + assert_not column.text? + assert_not column.binary? + assert_not column.array + end + + def test_inet_column + column = PostgresqlNetworkAddress.columns_hash["inet_address"] + assert_equal :inet, column.type + assert_equal "inet", column.sql_type + assert_not column.number? + assert_not column.text? + assert_not column.binary? + assert_not column.array + end + + def test_macaddr_column + column = PostgresqlNetworkAddress.columns_hash["mac_address"] + assert_equal :macaddr, column.type + assert_equal "macaddr", column.sql_type + assert_not column.number? + assert_not column.text? + assert_not column.binary? + assert_not column.array + end + + def test_network_types + PostgresqlNetworkAddress.create(cidr_address: '192.168.0.0/24', + inet_address: '172.16.1.254/32', + mac_address: '01:23:45:67:89:0a') + + address = PostgresqlNetworkAddress.first + assert_equal IPAddr.new('192.168.0.0/24'), address.cidr_address + assert_equal IPAddr.new('172.16.1.254'), address.inet_address + assert_equal '01:23:45:67:89:0a', address.mac_address + + address.cidr_address = '10.1.2.3/32' + address.inet_address = '10.0.0.0/8' + address.mac_address = 'bc:de:f0:12:34:56' + + address.save! + assert address.reload + assert_equal IPAddr.new('10.1.2.3/32'), address.cidr_address + assert_equal IPAddr.new('10.0.0.0/8'), address.inet_address + assert_equal 'bc:de:f0:12:34:56', address.mac_address + end + + def test_invalid_network_address + invalid_address = PostgresqlNetworkAddress.new(cidr_address: 'invalid addr', + inet_address: 'invalid addr') + assert_nil invalid_address.cidr_address + assert_nil invalid_address.inet_address + assert_equal 'invalid addr', invalid_address.cidr_address_before_type_cast + assert_equal 'invalid addr', invalid_address.inet_address_before_type_cast + assert invalid_address.save + + invalid_address.reload + assert_nil invalid_address.cidr_address + assert_nil invalid_address.inet_address + assert_nil invalid_address.cidr_address_before_type_cast + assert_nil invalid_address.inet_address_before_type_cast + end +end diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index 49f5ec250f..cfff1f980b 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -134,18 +134,18 @@ module ActiveRecord end def test_default_sequence_name - assert_equal 'accounts_id_seq', + assert_equal PostgreSQL::Name.new('public', 'accounts_id_seq'), @connection.default_sequence_name('accounts', 'id') - assert_equal 'accounts_id_seq', + assert_equal PostgreSQL::Name.new('public', 'accounts_id_seq'), @connection.default_sequence_name('accounts') end def test_default_sequence_name_bad_table - assert_equal 'zomg_id_seq', + assert_equal PostgreSQL::Name.new(nil, 'zomg_id_seq'), @connection.default_sequence_name('zomg', 'id') - assert_equal 'zomg_id_seq', + assert_equal PostgreSQL::Name.new(nil, 'zomg_id_seq'), @connection.default_sequence_name('zomg') end @@ -216,7 +216,7 @@ module ActiveRecord ) seq = @connection.pk_and_sequence_for('ex').last - assert_equal 'ex_id_seq', seq + assert_equal PostgreSQL::Name.new("public", "ex_id_seq"), seq @connection.exec_query( "DELETE FROM pg_depend WHERE objid = 'ex2_id_seq'::regclass AND refobjid = 'ex'::regclass AND deptype = 'a'" @@ -353,6 +353,17 @@ module ActiveRecord assert_equal "posts.title, posts.updater_id AS alias_0", @connection.columns_for_distinct("posts.title", ["posts.updater_id desc nulls last"]) end + def test_columns_for_distinct_without_order_specifiers + assert_equal "posts.title, posts.updater_id AS alias_0", + @connection.columns_for_distinct("posts.title", ["posts.updater_id"]) + + assert_equal "posts.title, posts.updater_id AS alias_0", + @connection.columns_for_distinct("posts.title", ["posts.updater_id nulls last"]) + + assert_equal "posts.title, posts.updater_id AS alias_0", + @connection.columns_for_distinct("posts.title", ["posts.updater_id nulls first"]) + end + def test_raise_error_when_cannot_translate_exception assert_raise TypeError do @connection.send(:log, nil) { @connection.execute(nil) } diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb index 51846e22d9..218c59247e 100644 --- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb +++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb @@ -10,13 +10,13 @@ module ActiveRecord end def test_type_cast_true - c = PostgreSQLColumn.new(nil, 1, OID::Boolean.new, 'boolean') + c = PostgreSQLColumn.new(nil, 1, Type::Boolean.new, 'boolean') assert_equal 't', @conn.type_cast(true, nil) assert_equal 't', @conn.type_cast(true, c) end def test_type_cast_false - c = PostgreSQLColumn.new(nil, 1, OID::Boolean.new, 'boolean') + c = PostgreSQLColumn.new(nil, 1, Type::Boolean.new, 'boolean') assert_equal 'f', @conn.type_cast(false, nil) assert_equal 'f', @conn.type_cast(false, c) end @@ -47,9 +47,9 @@ module ActiveRecord def test_quote_cast_numeric fixnum = 666 - c = PostgreSQLColumn.new(nil, nil, OID::String.new, 'varchar') + c = PostgreSQLColumn.new(nil, nil, Type::String.new, 'varchar') assert_equal "'666'", @conn.quote(fixnum, c) - c = PostgreSQLColumn.new(nil, nil, OID::Text.new, 'text') + c = PostgreSQLColumn.new(nil, nil, Type::Text.new, 'text') assert_equal "'666'", @conn.quote(fixnum, c) end diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb index 060b17d071..4d9cfe55f5 100644 --- a/activerecord/test/cases/adapters/postgresql/range_test.rb +++ b/activerecord/test/cases/adapters/postgresql/range_test.rb @@ -1,7 +1,5 @@ require "cases/helper" require 'support/connection_helper' -require 'active_record/base' -require 'active_record/connection_adapters/postgresql_adapter' if ActiveRecord::Base.connection.supports_ranges? class PostgresqlRange < ActiveRecord::Base diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index 11ec7599a3..9e5fd17dc4 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -50,6 +50,16 @@ class SchemaTest < ActiveRecord::TestCase self.table_name = 'things' end + 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 + def setup @connection = ActiveRecord::Base.connection @connection.execute "CREATE SCHEMA #{SCHEMA_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})" @@ -109,6 +119,22 @@ class SchemaTest < ActiveRecord::TestCase assert !@connection.schema_names.include?("test_schema3") end + def test_habtm_table_name_with_schema + ActiveRecord::Base.connection.execute <<-SQL + DROP SCHEMA IF EXISTS music CASCADE; + CREATE SCHEMA music; + 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 + Album.create + assert_equal song, Song.includes(:albums).references(:albums).first + ensure + ActiveRecord::Base.connection.execute "DROP SCHEMA music CASCADE;" + end + def test_raise_drop_schema_with_nonexisting_schema assert_raises(ActiveRecord::StatementInvalid) do @connection.drop_schema "test_schema3" @@ -305,14 +331,15 @@ class SchemaTest < ActiveRecord::TestCase end def test_pk_and_sequence_for_with_schema_specified + pg_name = ActiveRecord::ConnectionAdapters::PostgreSQL::Name [ %("#{SCHEMA_NAME}"."#{PK_TABLE_NAME}"), %("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}") ].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}" - assert_equal "#{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 "#{UNMATCHED_SEQUENCE_NAME}", seq, "sequence name should be found when table referenced as #{given}" if given == %("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}") + 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}") end end @@ -352,6 +379,14 @@ class SchemaTest < ActiveRecord::TestCase end end + def test_reset_pk_sequence + sequence_name = "#{SCHEMA_NAME}.#{UNMATCHED_SEQUENCE_NAME}" + @connection.execute "SELECT setval('#{sequence_name}', 123)" + assert_equal "124", @connection.select_value("SELECT nextval('#{sequence_name}')") + @connection.reset_pk_sequence!("#{SCHEMA_NAME}.#{UNMATCHED_PK_TABLE_NAME}") + assert_equal "1", @connection.select_value("SELECT nextval('#{sequence_name}')") + end + private def columns(table_name) @connection.send(:column_definitions, table_name).map do |name, type, default| diff --git a/activerecord/test/cases/adapters/postgresql/timestamp_test.rb b/activerecord/test/cases/adapters/postgresql/timestamp_test.rb index 4d29a20e66..3614b29190 100644 --- a/activerecord/test/cases/adapters/postgresql/timestamp_test.rb +++ b/activerecord/test/cases/adapters/postgresql/timestamp_test.rb @@ -2,6 +2,47 @@ require 'cases/helper' require 'models/developer' require 'models/topic' +class PostgresqlTimestampTest < ActiveRecord::TestCase + class PostgresqlTimestampWithZone < ActiveRecord::Base; end + + self.use_transactional_fixtures = false + + setup do + @connection = ActiveRecord::Base.connection + @connection.execute("INSERT INTO postgresql_timestamp_with_zones (id, time) VALUES (1, '2010-01-01 10:00:00-1')") + end + + teardown do + PostgresqlTimestampWithZone.delete_all + end + + def test_timestamp_with_zone_values_with_rails_time_zone_support + with_timezone_config default: :utc, aware_attributes: true do + @connection.reconnect! + + timestamp = PostgresqlTimestampWithZone.find(1) + assert_equal Time.utc(2010,1,1, 11,0,0), timestamp.time + assert_instance_of Time, timestamp.time + end + ensure + @connection.reconnect! + end + + def test_timestamp_with_zone_values_without_rails_time_zone_support + with_timezone_config default: :local, aware_attributes: false do + @connection.reconnect! + # make sure to use a non-UTC time zone + @connection.execute("SET time zone 'America/Jamaica'", 'SCHEMA') + + timestamp = PostgresqlTimestampWithZone.find(1) + assert_equal Time.utc(2010,1,1, 11,0,0), timestamp.time + assert_instance_of Time, timestamp.time + end + ensure + @connection.reconnect! + end +end + class TimestampTest < ActiveRecord::TestCase fixtures :topics @@ -82,20 +123,32 @@ class TimestampTest < ActiveRecord::TestCase assert_equal date, Developer.find_by_name("aaron").updated_at end + def test_bc_timestamp_leap_year + date = Time.utc(-4, 2, 29) + Developer.create!(:name => "taihou", :updated_at => date) + assert_equal date, Developer.find_by_name("taihou").updated_at + end + + def test_bc_timestamp_year_zero + date = Time.utc(0, 4, 7) + Developer.create!(:name => "yahagi", :updated_at => date) + assert_equal date, Developer.find_by_name("yahagi").updated_at + end + private - def pg_datetime_precision(table_name, column_name) - results = ActiveRecord::Base.connection.execute("SELECT column_name, datetime_precision FROM information_schema.columns WHERE table_name ='#{table_name}'") - result = results.find do |result_hash| - result_hash["column_name"] == column_name - end - result && result["datetime_precision"] + def pg_datetime_precision(table_name, column_name) + results = ActiveRecord::Base.connection.execute("SELECT column_name, datetime_precision FROM information_schema.columns WHERE table_name ='#{table_name}'") + result = results.find do |result_hash| + result_hash["column_name"] == column_name end + result && result["datetime_precision"] + end - def activerecord_column_option(tablename, column_name, option) - result = ActiveRecord::Base.connection.columns(tablename).find do |column| - column.name == column_name - end - result && result.send(option) + def activerecord_column_option(tablename, column_name, option) + result = ActiveRecord::Base.connection.columns(tablename).find do |column| + column.name == column_name end + result && result.send(option) + end end diff --git a/activerecord/test/cases/adapters/postgresql/utils_test.rb b/activerecord/test/cases/adapters/postgresql/utils_test.rb index 9e7b08ef34..3fdb6888d9 100644 --- a/activerecord/test/cases/adapters/postgresql/utils_test.rb +++ b/activerecord/test/cases/adapters/postgresql/utils_test.rb @@ -1,9 +1,10 @@ require 'cases/helper' class PostgreSQLUtilsTest < ActiveSupport::TestCase - include ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::Utils + Name = ActiveRecord::ConnectionAdapters::PostgreSQL::Name + include ActiveRecord::ConnectionAdapters::PostgreSQL::Utils - def test_extract_schema_and_table + def test_extract_schema_qualified_name { %(table_name) => [nil,'table_name'], %("table.name") => [nil,'table.name'], @@ -14,7 +15,47 @@ class PostgreSQLUtilsTest < ActiveSupport::TestCase %("even spaces".table) => ['even spaces','table'], %(schema."table.name") => ['schema', 'table.name'] }.each do |given, expect| - assert_equal expect, extract_schema_and_table(given) + assert_equal Name.new(*expect), extract_schema_qualified_name(given) end end end + +class PostgreSQLNameTest < ActiveSupport::TestCase + Name = ActiveRecord::ConnectionAdapters::PostgreSQL::Name + + test "represents itself as schema.name" do + obj = Name.new("public", "articles") + assert_equal "public.articles", obj.to_s + end + + test "without schema, represents itself as name only" do + obj = Name.new(nil, "articles") + assert_equal "articles", obj.to_s + end + + test "quoted returns a string representation usable in a query" do + assert_equal %("articles"), Name.new(nil, "articles").quoted + assert_equal %("public"."articles"), Name.new("public", "articles").quoted + end + + test "prevents double quoting" do + name = Name.new('"quoted_schema"', '"quoted_table"') + assert_equal "quoted_schema.quoted_table", name.to_s + assert_equal %("quoted_schema"."quoted_table"), name.quoted + end + + test "equality based on state" do + assert_equal Name.new("access", "users"), Name.new("access", "users") + assert_equal Name.new(nil, "users"), Name.new(nil, "users") + assert_not_equal Name.new(nil, "users"), Name.new("access", "users") + assert_not_equal Name.new("access", "users"), Name.new("public", "users") + assert_not_equal Name.new("public", "users"), Name.new("public", "articles") + end + + test "can be used as hash key" do + hash = {Name.new("schema", "article_seq") => "success"} + assert_equal "success", hash[Name.new("schema", "article_seq")] + assert_equal nil, hash[Name.new("schema", "articles")] + assert_equal nil, hash[Name.new("public", "article_seq")] + end +end diff --git a/activerecord/test/cases/adapters/postgresql/xml_test.rb b/activerecord/test/cases/adapters/postgresql/xml_test.rb index c1c85f8c92..48c6eeb62c 100644 --- a/activerecord/test/cases/adapters/postgresql/xml_test.rb +++ b/activerecord/test/cases/adapters/postgresql/xml_test.rb @@ -1,8 +1,5 @@ # encoding: utf-8 - require 'cases/helper' -require 'active_record/base' -require 'active_record/connection_adapters/postgresql_adapter' class PostgresqlXMLTest < ActiveRecord::TestCase class XmlDataType < ActiveRecord::Base |