aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorlsylvester <lachlan.sylvester@hypothetical.com.au>2014-03-11 08:10:25 +1100
committerlsylvester <lachlan.sylvester@hypothetical.com.au>2014-03-11 08:14:03 +1100
commitb3e0da3062f809599fb4da9f9a29ed45aebd1ff6 (patch)
tree6bdc95ed7456bf88d9c90b6f10980ef71be15e12 /activerecord
parentd41154094a332a3dd797c4148894fbcd1e5ad5ff (diff)
downloadrails-b3e0da3062f809599fb4da9f9a29ed45aebd1ff6.tar.gz
rails-b3e0da3062f809599fb4da9f9a29ed45aebd1ff6.tar.bz2
rails-b3e0da3062f809599fb4da9f9a29ed45aebd1ff6.zip
register OID for PostgreSQL citex datatype [Troy Kruthoff & Lachlan Sylvester]
citext makes it possible to use AR Hash finders for case-insensitive matching as sql UPPER/LOWER functions are not needed.
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md5
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb9
-rw-r--r--activerecord/test/cases/adapters/postgresql/citext_test.rb58
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb7
-rw-r--r--activerecord/test/schema/postgresql_specific_schema.rb11
6 files changed, 89 insertions, 2 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 300c3761f1..2e4f653ea6 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,8 @@
+* Support for Postgres `citext` data type enabling case-insensitive where
+ values without needing to wrap in UPPER/LOWER sql functions.
+
+ *Troy Kruthoff*, *Lachlan Sylvester*
+
* Only save has_one associations if record has changes.
Previously after save related callbacks, such as `#after_commit`, were triggered when the has_one
object did not get saved to the db.
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
index 697915f3e9..5d32aaed50 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
@@ -375,6 +375,7 @@ This is not reliable and will be removed in the future.
register_type 'circle', OID::Text.new
register_type 'hstore', OID::Hstore.new
register_type 'json', OID::Json.new
+ register_type 'citext', OID::Text.new
register_type 'ltree', OID::Text.new
register_type 'cidr', OID::Cidr.new
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index a56ef91d07..f7b053aec6 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -215,6 +215,8 @@ module ActiveRecord
# Character types
when /^(?:character varying|bpchar)(?:\(\d+\))?$/
:string
+ when /^citext(?:\(\d+\))?$/
+ :citext
# Binary data types
when 'bytea'
:binary
@@ -393,6 +395,10 @@ module ActiveRecord
column name, type, options
end
+ def citext(name, options = {})
+ column(name, 'citext', options)
+ end
+
def column(name, type = nil, options = {})
super
column = self[name]
@@ -441,7 +447,8 @@ module ActiveRecord
macaddr: { name: "macaddr" },
uuid: { name: "uuid" },
json: { name: "json" },
- ltree: { name: "ltree" }
+ ltree: { name: "ltree" },
+ citext: { name: "citext" }
}
include Quoting
diff --git a/activerecord/test/cases/adapters/postgresql/citext_test.rb b/activerecord/test/cases/adapters/postgresql/citext_test.rb
new file mode 100644
index 0000000000..89ef46b539
--- /dev/null
+++ b/activerecord/test/cases/adapters/postgresql/citext_test.rb
@@ -0,0 +1,58 @@
+# encoding: utf-8
+
+require 'cases/helper'
+require 'active_record/base'
+require 'active_record/connection_adapters/postgresql_adapter'
+
+class PostgresqlCitextTest < ActiveRecord::TestCase
+ class Citext < ActiveRecord::Base
+ self.table_name = 'citexts'
+ end
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+
+ unless @connection.extension_enabled?('citext')
+ @connection.enable_extension 'citext'
+ @connection.commit_db_transaction
+ end
+
+ @connection.reconnect!
+
+ @connection.transaction do
+ @connection.create_table('citexts') do |t|
+ t.citext 'cival'
+ end
+ end
+ @column = Citext.columns_hash['cival']
+ end
+
+ def teardown
+ @connection.execute 'DROP TABLE IF EXISTS citexts;'
+ @connection.execute 'DROP EXTENSION IF EXISTS citext CASCADE;'
+ end
+
+ def test_citext_enabled
+ assert @connection.extension_enabled?('citext')
+ end
+
+ def test_column_type
+ assert_equal :citext, @column.type
+ end
+
+ def test_column_sql_type
+ assert_equal 'citext', @column.sql_type
+ end
+
+ def test_write
+ x = Citext.new(cival: 'Some CI Text')
+ assert x.save!
+ end
+
+ def test_select_case_insensitive
+ @connection.execute "insert into citexts (cival) values('Cased Text')"
+ x = Citext.where(cival: 'cased text').first
+ assert_equal('Cased Text', x.cival)
+ end
+
+end \ No newline at end of file
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 2748cbdbf4..575eb34a9c 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -319,6 +319,13 @@ class SchemaDumperTest < ActiveRecord::TestCase
end
end
+ def test_schema_dump_includes_citext_shorthand_definition
+ output = standard_dump
+ if %r{create_table "postgresql_citext"} =~ output
+ assert_match %r[t.citext "text_citext"], output
+ end
+ end
+
def test_schema_dump_includes_ltrees_shorthand_definition
output = standard_dump
if %r{create_table "postgresql_ltrees"} =~ output
diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb
index a86a188bcf..4fcbf4dbd2 100644
--- a/activerecord/test/schema/postgresql_specific_schema.rb
+++ b/activerecord/test/schema/postgresql_specific_schema.rb
@@ -1,7 +1,7 @@
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 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).each do |table_name|
+ postgresql_oids postgresql_xml_data_type defaults geometrics postgresql_timestamp_with_zones postgresql_partitioned_table postgresql_partitioned_table_parent postgresql_json_data_type postgresql_citext).each do |table_name|
execute "DROP TABLE IF EXISTS #{quote_table_name table_name}"
end
@@ -99,6 +99,15 @@ _SQL
_SQL
end
+ if 't' == select_value("select 'citext'=ANY(select typname from pg_type)")
+ execute <<_SQL
+ CREATE TABLE postgresql_citext (
+ id SERIAL PRIMARY KEY,
+ text_citext citext default ''::citext
+ );
+_SQL
+ end
+
if 't' == select_value("select 'json'=ANY(select typname from pg_type)")
execute <<_SQL
CREATE TABLE postgresql_json_data_type (