Permalink
Browse files

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?
  • Loading branch information...
sgrif committed Aug 21, 2015
1 parent 90bcb6d commit ffc4710c2bff273b82ddb76675701f986d82ef4f
@@ -1050,7 +1050,7 @@ def text_to_sql(limit) # :nodoc:
end
end
class MysqlJson < Type::Json # :nodoc:
class MysqlJson < Type::Internal::AbstractJson # :nodoc:
def changed_in_place?(raw_old_value, new_value)
# Normalization is required because MySQL JSON data format includes
# the space between the elements.
@@ -8,6 +8,7 @@
require 'active_record/connection_adapters/postgresql/oid/enum'
require 'active_record/connection_adapters/postgresql/oid/hstore'
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/money'
require 'active_record/connection_adapters/postgresql/oid/point'
@@ -0,0 +1,10 @@
module ActiveRecord
module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
class Json < Type::Internal::AbstractJson
end
end
end
end
end
@@ -2,7 +2,7 @@ module ActiveRecord
module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
class Jsonb < Type::Json # :nodoc:
class Jsonb < Json # :nodoc:
def type
:jsonb
end
@@ -482,7 +482,7 @@ def initialize_type_map(m) # :nodoc:
m.register_type 'bytea', OID::Bytea.new
m.register_type 'point', OID::Point.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 'cidr', OID::Cidr.new
m.register_type 'inet', OID::Inet.new
@@ -838,6 +838,7 @@ def construct_coder(row, coder_class)
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
ActiveRecord::Type.register(:hstore, OID::Hstore, 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(:money, OID::Money, adapter: :postgresql)
ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)
@@ -10,7 +10,6 @@
require 'active_record/type/decimal_without_scale'
require 'active_record/type/float'
require 'active_record/type/integer'
require 'active_record/type/json'
require 'active_record/type/serialized'
require 'active_record/type/string'
require 'active_record/type/text'
@@ -21,6 +20,8 @@
require 'active_record/type/type_map'
require 'active_record/type/hash_lookup_type_map'
require 'active_record/type/internal/abstract_json'
module ActiveRecord
module Type
@registry = AdapterSpecificRegistry.new
@@ -60,7 +61,6 @@ def current_adapter_name
register(:decimal, Type::Decimal, override: false)
register(:float, Type::Float, override: false)
register(:integer, Type::Integer, override: false)
register(:json, Type::Json, override: false)
register(:string, Type::String, override: false)
register(:text, Type::Text, override: false)
register(:time, Type::Time, override: false)
@@ -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

This file was deleted.

Oops, something went wrong.

1 comment on commit ffc4710

@metaskills

This comment has been minimized.

Show comment
Hide comment
@metaskills

metaskills Sep 7, 2015

Contributor

⭐️

Contributor

metaskills commented on ffc4710 Sep 7, 2015

⭐️

Please sign in to comment.