1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

JSON is still an adapter specific type.

Several changes were made in #21110 which I am strongly opposed to.
(this is what I get for going on vacation. :trollface:) No type should
be introduced into the generic `ActiveRecord::Type` namespace, and
*certainly* should not be registered into the registry unconstrained
unless it is supported by *all* adapters (which basically means that it
was specified in the ANSI SQL standard).

I do not think `# :nodoc:` ing the type is sufficient, as it still makes
the code of Rails itself very unclear as to what the role of that class
is. While I would argue that this shouldn't even be a super class, and
that MySql and PG's JSON types are only superficially duplicated (they
might look the same but will change for different reasons in the
future).

However, I don't feel strongly enough about it as a point of contention
(and the biggest cost of harming the blameability has already occured),
so I simply moved the superclass into a namespace where its role is
absolutely clear.

After this change, `attribute :foo, :json` will once again work with
MySQL and PG, but not with Sqlite3 or any third party adapters.

Unresolved questions
--------------------

The types that and adapter publishes (at least those are unique to that
adapter, and not adding additional behavior like `MysqlString` should
probably be part of the adapter's public API. Should we standardize the
namespace for these, and document them?
This commit is contained in:
Sean Griffin 2015-08-21 17:45:46 -06:00
parent 90bcb6dea7
commit ffc4710c2b
8 changed files with 50 additions and 36 deletions

View file

@ -1050,7 +1050,7 @@ module ActiveRecord
end end
end end
class MysqlJson < Type::Json # :nodoc: class MysqlJson < Type::Internal::AbstractJson # :nodoc:
def changed_in_place?(raw_old_value, new_value) def changed_in_place?(raw_old_value, new_value)
# Normalization is required because MySQL JSON data format includes # Normalization is required because MySQL JSON data format includes
# the space between the elements. # the space between the elements.

View file

@ -8,6 +8,7 @@ require 'active_record/connection_adapters/postgresql/oid/decimal'
require 'active_record/connection_adapters/postgresql/oid/enum' require 'active_record/connection_adapters/postgresql/oid/enum'
require 'active_record/connection_adapters/postgresql/oid/hstore' require 'active_record/connection_adapters/postgresql/oid/hstore'
require 'active_record/connection_adapters/postgresql/oid/inet' require 'active_record/connection_adapters/postgresql/oid/inet'
require 'active_record/connection_adapters/postgresql/oid/json'
require 'active_record/connection_adapters/postgresql/oid/jsonb' require 'active_record/connection_adapters/postgresql/oid/jsonb'
require 'active_record/connection_adapters/postgresql/oid/money' require 'active_record/connection_adapters/postgresql/oid/money'
require 'active_record/connection_adapters/postgresql/oid/point' require 'active_record/connection_adapters/postgresql/oid/point'

View file

@ -0,0 +1,10 @@
module ActiveRecord
module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
class Json < Type::Internal::AbstractJson
end
end
end
end
end

View file

@ -2,7 +2,7 @@ module ActiveRecord
module ConnectionAdapters module ConnectionAdapters
module PostgreSQL module PostgreSQL
module OID # :nodoc: module OID # :nodoc:
class Jsonb < Type::Json # :nodoc: class Jsonb < Json # :nodoc:
def type def type
:jsonb :jsonb
end end

View file

@ -482,7 +482,7 @@ module ActiveRecord
m.register_type 'bytea', OID::Bytea.new m.register_type 'bytea', OID::Bytea.new
m.register_type 'point', OID::Point.new m.register_type 'point', OID::Point.new
m.register_type 'hstore', OID::Hstore.new m.register_type 'hstore', OID::Hstore.new
m.register_type 'json', Type::Json.new m.register_type 'json', OID::Json.new
m.register_type 'jsonb', OID::Jsonb.new m.register_type 'jsonb', OID::Jsonb.new
m.register_type 'cidr', OID::Cidr.new m.register_type 'cidr', OID::Cidr.new
m.register_type 'inet', OID::Inet.new m.register_type 'inet', OID::Inet.new
@ -838,6 +838,7 @@ module ActiveRecord
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql) ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql) ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql) ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
ActiveRecord::Type.register(:json, OID::Json, adapter: :postgresql)
ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql) ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql) ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql) ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)

View file

@ -10,7 +10,6 @@ require 'active_record/type/decimal'
require 'active_record/type/decimal_without_scale' require 'active_record/type/decimal_without_scale'
require 'active_record/type/float' require 'active_record/type/float'
require 'active_record/type/integer' require 'active_record/type/integer'
require 'active_record/type/json'
require 'active_record/type/serialized' require 'active_record/type/serialized'
require 'active_record/type/string' require 'active_record/type/string'
require 'active_record/type/text' require 'active_record/type/text'
@ -21,6 +20,8 @@ require 'active_record/type/adapter_specific_registry'
require 'active_record/type/type_map' require 'active_record/type/type_map'
require 'active_record/type/hash_lookup_type_map' require 'active_record/type/hash_lookup_type_map'
require 'active_record/type/internal/abstract_json'
module ActiveRecord module ActiveRecord
module Type module Type
@registry = AdapterSpecificRegistry.new @registry = AdapterSpecificRegistry.new
@ -60,7 +61,6 @@ module ActiveRecord
register(:decimal, Type::Decimal, override: false) register(:decimal, Type::Decimal, override: false)
register(:float, Type::Float, override: false) register(:float, Type::Float, override: false)
register(:integer, Type::Integer, override: false) register(:integer, Type::Integer, override: false)
register(:json, Type::Json, override: false)
register(:string, Type::String, override: false) register(:string, Type::String, override: false)
register(:text, Type::Text, override: false) register(:text, Type::Text, override: false)
register(:time, Type::Time, override: false) register(:time, Type::Time, override: false)

View file

@ -0,0 +1,33 @@
module ActiveRecord
module Type
module Internal # :nodoc:
class AbstractJson < Type::Value # :nodoc:
include Type::Helpers::Mutable
def type
:json
end
def deserialize(value)
if value.is_a?(::String)
::ActiveSupport::JSON.decode(value) rescue nil
else
value
end
end
def serialize(value)
if value.is_a?(::Array) || value.is_a?(::Hash)
::ActiveSupport::JSON.encode(value)
else
value
end
end
def accessor
ActiveRecord::Store::StringKeyedHashAccessor
end
end
end
end
end

View file

@ -1,31 +0,0 @@
module ActiveRecord
module Type
class Json < Type::Value # :nodoc:
include Type::Helpers::Mutable
def type
:json
end
def deserialize(value)
if value.is_a?(::String)
::ActiveSupport::JSON.decode(value) rescue nil
else
value
end
end
def serialize(value)
if value.is_a?(::Array) || value.is_a?(::Hash)
::ActiveSupport::JSON.encode(value)
else
value
end
end
def accessor
ActiveRecord::Store::StringKeyedHashAccessor
end
end
end
end