aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilippe Creux <pcreux@gmail.com>2014-07-24 10:39:39 -0700
committerPhilippe Creux <pcreux@gmail.com>2014-07-24 10:39:39 -0700
commit99b82fdf03fcf6d6ca8e2d810ba35011723a5267 (patch)
treec232bfff40548797590277a1bb2935343b162324
parent3f4e97f807eb475ac8c311e5baf138249a8a1ab2 (diff)
downloadrails-99b82fdf03fcf6d6ca8e2d810ba35011723a5267.tar.gz
rails-99b82fdf03fcf6d6ca8e2d810ba35011723a5267.tar.bz2
rails-99b82fdf03fcf6d6ca8e2d810ba35011723a5267.zip
Add support for Postgresql JSONB
[Philippe Creux, Chris Teague]
-rw-r--r--activerecord/CHANGELOG.md10
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb23
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb1
-rw-r--r--activerecord/test/cases/adapters/postgresql/json_test.rb34
6 files changed, 64 insertions, 9 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 089f93db45..d56db89056 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,13 @@
+* Add support for Postgresql JSONB
+
+ Example:
+
+ create_table :posts do |t|
+ t.jsonb :meta_data
+ end
+
+ *Philippe Creux*, *Chris Teague*
+
* `db:purge` with MySQL respects `Rails.env`.
*Yves Senn*
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
index d05ce61330..d28a2b4fa0 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
@@ -14,6 +14,7 @@ require 'active_record/connection_adapters/postgresql/oid/hstore'
require 'active_record/connection_adapters/postgresql/oid/inet'
require 'active_record/connection_adapters/postgresql/oid/integer'
require 'active_record/connection_adapters/postgresql/oid/json'
+require 'active_record/connection_adapters/postgresql/oid/jsonb'
require 'active_record/connection_adapters/postgresql/oid/money'
require 'active_record/connection_adapters/postgresql/oid/point'
require 'active_record/connection_adapters/postgresql/oid/range'
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb
new file mode 100644
index 0000000000..34ed32ad35
--- /dev/null
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb
@@ -0,0 +1,23 @@
+module ActiveRecord
+ module ConnectionAdapters
+ module PostgreSQL
+ module OID # :nodoc:
+ class Jsonb < Json # :nodoc:
+ def type
+ :jsonb
+ end
+
+ def changed_in_place?(raw_old_value, new_value)
+ # Postgres does not preserve insignificant whitespaces when
+ # roundtripping jsonb columns. This causes some false positives for
+ # the comparison here. Therefore, we need to parse and re-dump the
+ # raw value here to ensure the insignificant whitespaces are
+ # consitent with our encoder's output.
+ raw_old_value = type_cast_for_database(type_cast_from_database(raw_old_value))
+ super(raw_old_value, new_value)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb
index 0867e5ef54..83554bbf74 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb
@@ -64,6 +64,10 @@ module ActiveRecord
column(name, :json, options)
end
+ def jsonb(name, options = {})
+ column(name, :jsonb, options)
+ end
+
def citext(name, options = {})
column(name, :citext, options)
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index f660fc41cf..eede374678 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -451,6 +451,7 @@ module ActiveRecord
m.register_type 'point', OID::Point.new
m.register_type 'hstore', OID::Hstore.new
m.register_type 'json', OID::Json.new
+ m.register_type 'jsonb', OID::Jsonb.new
m.register_type 'cidr', OID::Cidr.new
m.register_type 'inet', OID::Inet.new
m.register_type 'uuid', OID::Uuid.new
diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb
index cb3c02fa3a..86ba849445 100644
--- a/activerecord/test/cases/adapters/postgresql/json_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/json_test.rb
@@ -4,7 +4,7 @@ require "cases/helper"
require 'active_record/base'
require 'active_record/connection_adapters/postgresql_adapter'
-class PostgresqlJSONTest < ActiveRecord::TestCase
+module PostgresqlJSONSharedTestCases
class JsonDataType < ActiveRecord::Base
self.table_name = 'json_data_type'
@@ -16,8 +16,8 @@ class PostgresqlJSONTest < ActiveRecord::TestCase
begin
@connection.transaction do
@connection.create_table('json_data_type') do |t|
- t.json 'payload', :default => {}
- t.json 'settings'
+ t.public_send column_type, 'payload', default: {} # t.json 'payload', default: {}
+ t.public_send column_type, 'settings' # t.json 'settings'
end
end
rescue ActiveRecord::StatementInvalid
@@ -26,21 +26,21 @@ class PostgresqlJSONTest < ActiveRecord::TestCase
@column = JsonDataType.columns_hash['payload']
end
- teardown do
+ def teardown
@connection.execute 'drop table if exists json_data_type'
end
def test_column
column = JsonDataType.columns_hash["payload"]
- assert_equal :json, column.type
- assert_equal "json", column.sql_type
+ assert_equal column_type, column.type
+ assert_equal column_type.to_s, column.sql_type
assert_not column.number?
assert_not column.binary?
assert_not column.array
end
def test_default
- @connection.add_column 'json_data_type', 'permissions', :json, default: '{"users": "read", "posts": ["read", "write"]}'
+ @connection.add_column 'json_data_type', 'permissions', column_type, default: '{"users": "read", "posts": ["read", "write"]}'
JsonDataType.reset_column_information
assert_equal({"users"=>"read", "posts"=>["read", "write"]}, JsonDataType.column_defaults['permissions'])
@@ -52,11 +52,11 @@ class PostgresqlJSONTest < ActiveRecord::TestCase
def test_change_table_supports_json
@connection.transaction do
@connection.change_table('json_data_type') do |t|
- t.json 'users', default: '{}'
+ t.public_send column_type, 'users', default: '{}' # t.json 'users', default: '{}'
end
JsonDataType.reset_column_information
column = JsonDataType.columns_hash['users']
- assert_equal :json, column.type
+ assert_equal column_type, column.type
raise ActiveRecord::Rollback # reset the schema change
end
@@ -175,3 +175,19 @@ class PostgresqlJSONTest < ActiveRecord::TestCase
assert_not json.changed?
end
end
+
+class PostgresqlJSONTest < ActiveRecord::TestCase
+ include PostgresqlJSONSharedTestCases
+
+ def column_type
+ :json
+ end
+end
+
+class PostgresqlJSONBTest < ActiveRecord::TestCase
+ include PostgresqlJSONSharedTestCases
+
+ def column_type
+ :jsonb
+ end
+end