diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 49473dc92a..7600ac34ca 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,9 @@ ## Rails 4.0.0 (unreleased) ## +* Support for PostgreSQL's ltree data type. + + *Rob Worley* + * Fix undefined method `to_i` when calling `new` on a scope that uses an Array. Fixes #8718, #8734. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb index 0a69e062f0..02c295983f 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb @@ -276,6 +276,7 @@ module ActiveRecord register_type 'circle', OID::Identity.new register_type 'hstore', OID::Hstore.new register_type 'json', OID::Json.new + register_type 'ltree', OID::Identity.new register_type 'int4range', OID::IntRange.new alias_type 'int8range', 'int4range' diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index d62a375470..c106215bd5 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -173,6 +173,8 @@ module ActiveRecord :decimal when 'hstore' :hstore + when 'ltree' + :ltree # Network address types when 'inet' :inet @@ -275,6 +277,10 @@ module ActiveRecord column(name, 'hstore', options) end + def ltree(name, options = {}) + column(name, 'ltree', options) + end + def inet(name, options = {}) column(name, 'inet', options) end @@ -340,7 +346,8 @@ module ActiveRecord macaddr: { name: "macaddr" }, uuid: { name: "uuid" }, json: { name: "json" }, - intrange: { name: "int4range" } + intrange: { name: "int4range" }, + ltree: { name: "ltree" } } include Quoting diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb index c7ce43d71e..06e0983780 100644 --- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb +++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb @@ -30,6 +30,9 @@ end class PostgresqlUUID < ActiveRecord::Base end +class PostgresqlLtree < ActiveRecord::Base +end + class PostgresqlDataTypeTest < ActiveRecord::TestCase self.use_transactional_fixtures = false @@ -97,7 +100,6 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase 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 diff --git a/activerecord/test/cases/adapters/postgresql/ltree_test.rb b/activerecord/test/cases/adapters/postgresql/ltree_test.rb new file mode 100644 index 0000000000..20228d1fc4 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/ltree_test.rb @@ -0,0 +1,44 @@ +# 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 + self.table_name = 'ltrees' + end + + def setup + @connection = ActiveRecord::Base.connection + begin + @connection.transaction do + @connection.create_table('ltrees') do |t| + t.ltree 'path' + end + end + rescue ActiveRecord::StatementInvalid + return skip "do not test on PG without ltree" + end + @column = Ltree.columns.find { |c| c.name == 'path' } + end + + def teardown + @connection.execute 'drop table if exists ltrees' + end + + def test_column + assert_equal :ltree, @column.type + end + + def test_write + x = Ltree.new(:path => '1.2.3.4') + assert x.save! + end + + def test_select + @connection.execute "insert into ltrees (path) VALUES ('1.2.3')" + x = Ltree.first + assert_equal('1.2.3', x.path) + end +end diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 907b7bec30..cae12e0e3a 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -280,6 +280,13 @@ class SchemaDumperTest < ActiveRecord::TestCase end end + def test_schema_dump_includes_ltrees_shorthand_definition + output = standard_dump + if %r{create_table "postgresql_ltrees"} =~ output + assert_match %r[t.ltree "path"], output + end + end + def test_schema_dump_includes_arrays_shorthand_definition output = standard_dump if %r{create_table "postgresql_arrays"} =~ output diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb index 96fef3a831..ae13f2cd8a 100644 --- a/activerecord/test/schema/postgresql_specific_schema.rb +++ b/activerecord/test/schema/postgresql_specific_schema.rb @@ -1,6 +1,6 @@ ActiveRecord::Schema.define do - %w(postgresql_tsvectors postgresql_hstores postgresql_arrays postgresql_moneys postgresql_numbers postgresql_times postgresql_network_addresses postgresql_bit_strings postgresql_uuids + %w(postgresql_tsvectors postgresql_hstores postgresql_arrays postgresql_moneys postgresql_numbers postgresql_times postgresql_network_addresses postgresql_bit_strings postgresql_uuids postgresql_ltrees postgresql_oids postgresql_xml_data_type defaults geometrics postgresql_timestamp_with_zones postgresql_partitioned_table postgresql_partitioned_table_parent postgresql_json_data_type postgresql_intrange_data_type).each do |table_name| execute "DROP TABLE IF EXISTS #{quote_table_name table_name}" end @@ -89,6 +89,15 @@ _SQL _SQL end + if 't' == select_value("select 'ltree'=ANY(select typname from pg_type)") + execute <<_SQL + CREATE TABLE postgresql_ltrees ( + id SERIAL PRIMARY KEY, + path ltree + ); +_SQL + end + if 't' == select_value("select 'json'=ANY(select typname from pg_type)") execute <<_SQL CREATE TABLE postgresql_json_data_type (