From 3b516b5beb79f7e8c1fdd123e7d5a03c00349cdf Mon Sep 17 00:00:00 2001 From: "Dickson S. Guedes" Date: Wed, 5 Sep 2012 14:01:21 -0300 Subject: ActiveRecord support to PostgreSQL 9.2 JSON type This implements the support to encode/decode JSON data to/from database and creating columns of type JSON using a native type [1] supported by PostgreSQL from version 9.2. [1] http://www.postgresql.org/docs/9.2/static/datatype-json.html --- .../lib/active_record/connection_adapters/column.rb | 1 + .../active_record/connection_adapters/postgresql/cast.rb | 16 ++++++++++++++++ .../active_record/connection_adapters/postgresql/oid.rb | 9 +++++++++ .../connection_adapters/postgresql/quoting.rb | 8 ++++++-- .../connection_adapters/postgresql_adapter.rb | 13 ++++++++++++- 5 files changed, 44 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters') diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index d0237848c7..0390168461 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -124,6 +124,7 @@ module ActiveRecord when :boolean then "#{klass}.value_to_boolean(#{var_name})" when :hstore then "#{klass}.string_to_hstore(#{var_name})" when :inet, :cidr then "#{klass}.string_to_cidr(#{var_name})" + when :json then "#{klass}.string_to_json(#{var_name})" else var_name end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb index 20e482dcc2..b59195f98a 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb @@ -37,6 +37,22 @@ module ActiveRecord end end + def json_to_string(object) + if Hash === object + ActiveSupport::JSON.encode(object) + else + object + end + end + + def string_to_json(string) + if String === string + ActiveSupport::JSON.decode(string) + else + string + end + end + def string_to_cidr(string) if string.nil? nil diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb index 6657491c06..b8e7687b21 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb @@ -145,6 +145,14 @@ module ActiveRecord end end + class Json < Type + def type_cast(value) + return if value.nil? + + ConnectionAdapters::PostgreSQLColumn.string_to_json value + end + end + class TypeMap def initialize @mapping = {} @@ -244,6 +252,7 @@ module ActiveRecord register_type 'polygon', OID::Identity.new register_type 'circle', OID::Identity.new register_type 'hstore', OID::Hstore.new + register_type 'json', OID::Json.new register_type 'cidr', OID::Cidr.new alias_type 'inet', 'cidr' diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb index 1ae7443cde..152258a2f4 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -22,6 +22,7 @@ module ActiveRecord when Hash case column.sql_type when 'hstore' then super(PostgreSQLColumn.hstore_to_string(value), column) + when 'json' then super(PostgreSQLColumn.json_to_string(value), column) else super end when IPAddr @@ -66,8 +67,11 @@ module ActiveRecord return super unless 'bytea' == column.sql_type { :value => value, :format => 1 } when Hash - return super unless 'hstore' == column.sql_type - PostgreSQLColumn.hstore_to_string(value) + case column.sql_type + when 'hstore' then PostgreSQLColumn.hstore_to_string(value) + when 'json' then PostgreSQLColumn.json_to_string(value) + else super + end when IPAddr return super unless ['inet','cidr'].includes? column.sql_type PostgreSQLColumn.cidr_to_string(value) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 956e83bfd8..c508afb33e 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -106,6 +106,9 @@ module ActiveRecord # Hstore when /\A'(.*)'::hstore\z/ $1 + # JSON + when /\A'(.*)'::json\z/ + $1 # Object identifier types when /\A-?\d+\z/ $1 @@ -201,6 +204,9 @@ module ActiveRecord # UUID type when 'uuid' :uuid + # JSON type + when 'json' + :json # Small and big integer types when /^(?:small|big)int$/ :integer @@ -267,6 +273,10 @@ module ActiveRecord def uuid(name, options = {}) column(name, 'uuid', options) end + + def json(name, options = {}) + column(name, 'json', options) + end end ADAPTER_NAME = 'PostgreSQL' @@ -290,7 +300,8 @@ module ActiveRecord inet: { name: "inet" }, cidr: { name: "cidr" }, macaddr: { name: "macaddr" }, - uuid: { name: "uuid" } + uuid: { name: "uuid" }, + json: { name: "json" } } include Quoting -- cgit v1.2.3