diff options
Diffstat (limited to 'activejob/lib/active_job/serializers')
11 files changed, 355 insertions, 0 deletions
diff --git a/activejob/lib/active_job/serializers/array_serializer.rb b/activejob/lib/active_job/serializers/array_serializer.rb new file mode 100644 index 0000000000..f0254f4488 --- /dev/null +++ b/activejob/lib/active_job/serializers/array_serializer.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module ActiveJob + module Serializers + # Provides methods to serialize and deserialize `Array` + class ArraySerializer < BaseSerializer + class << self + alias_method :deserialize?, :serialize? + + def serialize(array) + array.map { |arg| ::ActiveJob::Serializers.serialize(arg) } + end + + def deserialize(array) + array.map { |arg| ::ActiveJob::Serializers.deserialize(arg) } + end + + private + + def klass + ::Array + end + end + end + end +end diff --git a/activejob/lib/active_job/serializers/base_serializer.rb b/activejob/lib/active_job/serializers/base_serializer.rb new file mode 100644 index 0000000000..98f7852fd6 --- /dev/null +++ b/activejob/lib/active_job/serializers/base_serializer.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module ActiveJob + module Serializers + class BaseSerializer + class << self + def serialize?(argument) + argument.is_a?(klass) + end + end + end + end +end diff --git a/activejob/lib/active_job/serializers/class_serializer.rb b/activejob/lib/active_job/serializers/class_serializer.rb new file mode 100644 index 0000000000..d36e8c0ebc --- /dev/null +++ b/activejob/lib/active_job/serializers/class_serializer.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module ActiveJob + module Serializers + # Provides methods to serialize and deserialize `Class` (`ActiveRecord::Base`, `MySpecialService`, ...) + class ClassSerializer < ObjectSerializer + class << self + def serialize(argument_klass) + { key => "::#{argument_klass.name}" } + end + + def key + "_aj_class" + end + + private + + def klass + ::Class + end + end + end + end +end diff --git a/activejob/lib/active_job/serializers/duration_serializer.rb b/activejob/lib/active_job/serializers/duration_serializer.rb new file mode 100644 index 0000000000..72b7b9528a --- /dev/null +++ b/activejob/lib/active_job/serializers/duration_serializer.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module ActiveJob + module Serializers + # Provides methods to serialize and deserialize `ActiveSupport::Duration` (`1.day`, `2.weeks`, ...) + class DurationSerializer < ObjectSerializer + class << self + def serialize(duration) + { + key => duration.value, + parts_key => ::ActiveJob::Serializers.serialize(duration.parts) + } + end + + def deserialize(hash) + value = hash[key] + parts = ::ActiveJob::Serializers.deserialize(hash[parts_key]) + + klass.new(value, parts) + end + + def key + "_aj_activesupport_duration" + end + + private + + def klass + ::ActiveSupport::Duration + end + + def keys + super.push parts_key + end + + def parts_key + "parts" + end + end + end + end +end diff --git a/activejob/lib/active_job/serializers/global_id_serializer.rb b/activejob/lib/active_job/serializers/global_id_serializer.rb new file mode 100644 index 0000000000..1961e43fca --- /dev/null +++ b/activejob/lib/active_job/serializers/global_id_serializer.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module ActiveJob + module Serializers + # Provides methods to serialize and deserialize objects which mixes `GlobalID::Identification`, + # including `ActiveRecord::Base` models + class GlobalIDSerializer < ObjectSerializer + class << self + def serialize(object) + { key => object.to_global_id.to_s } + rescue URI::GID::MissingModelIdError + raise SerializationError, "Unable to serialize #{object.class} " \ + "without an id. (Maybe you forgot to call save?)" + end + + def deserialize(hash) + GlobalID::Locator.locate(hash[key]) + end + + def key + "_aj_globalid" + end + + private + + def klass + ::GlobalID::Identification + end + end + end + end +end diff --git a/activejob/lib/active_job/serializers/hash_serializer.rb b/activejob/lib/active_job/serializers/hash_serializer.rb new file mode 100644 index 0000000000..eee081de7c --- /dev/null +++ b/activejob/lib/active_job/serializers/hash_serializer.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +module ActiveJob + module Serializers + # Provides methods to serialize and deserialize `Hash` (`{key: field, ...}`) + # Only `String` or `Symbol` can be used as a key. Values will be serialized by known serializers + class HashSerializer < BaseSerializer + class << self + def serialize(hash) + symbol_keys = hash.each_key.grep(Symbol).map(&:to_s) + result = serialize_hash(hash) + result[key] = symbol_keys + result + end + + def deserialize?(argument) + argument.is_a?(Hash) && argument[key] + end + + def deserialize(hash) + result = hash.transform_values { |v| ::ActiveJob::Serializers::deserialize(v) } + symbol_keys = result.delete(key) + transform_symbol_keys(result, symbol_keys) + end + + def key + "_aj_symbol_keys" + end + + private + + def serialize_hash(hash) + hash.each_with_object({}) do |(key, value), result| + result[serialize_hash_key(key)] = ::ActiveJob::Serializers.serialize(value) + end + end + + def serialize_hash_key(key) + raise SerializationError.new("Only string and symbol hash keys may be serialized as job arguments, but #{key.inspect} is a #{key.class}") unless [String, Symbol].include?(key.class) + + raise SerializationError.new("Can't serialize a Hash with reserved key #{key.inspect}") if ActiveJob::Base.reserved_serializers_keys.include?(key.to_s) + + key.to_s + end + + def transform_symbol_keys(hash, symbol_keys) + hash.transform_keys do |key| + if symbol_keys.include?(key) + key.to_sym + else + key + end + end + end + + def klass + ::Hash + end + end + end + end +end diff --git a/activejob/lib/active_job/serializers/hash_with_indifferent_access_serializer.rb b/activejob/lib/active_job/serializers/hash_with_indifferent_access_serializer.rb new file mode 100644 index 0000000000..50e80757cd --- /dev/null +++ b/activejob/lib/active_job/serializers/hash_with_indifferent_access_serializer.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module ActiveJob + module Serializers + # Provides methods to serialize and deserialize `ActiveSupport::HashWithIndifferentAccess` + # Values will be serialized by known serializers + class HashWithIndifferentAccessSerializer < HashSerializer + class << self + def serialize(hash) + result = serialize_hash(hash) + result[key] = ::ActiveJob::Serializers.serialize(true) + result + end + + def deserialize?(argument) + argument.is_a?(Hash) && argument[key] + end + + def deserialize(hash) + result = hash.transform_values { |v| ::ActiveJob::Serializers.deserialize(v) } + result.delete(key) + result.with_indifferent_access + end + + def key + "_aj_hash_with_indifferent_access" + end + + private + + def klass + ::ActiveSupport::HashWithIndifferentAccess + end + end + end + end +end diff --git a/activejob/lib/active_job/serializers/object_serializer.rb b/activejob/lib/active_job/serializers/object_serializer.rb new file mode 100644 index 0000000000..075360b26e --- /dev/null +++ b/activejob/lib/active_job/serializers/object_serializer.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module ActiveJob + module Serializers + class ObjectSerializer < BaseSerializer + class << self + def serialize(object) + { key => object.class.name } + end + + def deserialize?(argument) + argument.respond_to?(:keys) && argument.keys == keys + end + + def deserialize(hash) + hash[key].constantize + end + + private + + def keys + [key] + end + end + end + end +end diff --git a/activejob/lib/active_job/serializers/standard_type_serializer.rb b/activejob/lib/active_job/serializers/standard_type_serializer.rb new file mode 100644 index 0000000000..8969b31d6b --- /dev/null +++ b/activejob/lib/active_job/serializers/standard_type_serializer.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module ActiveJob + module Serializers + # Provides methods to serialize and deserialize standard types + # (`NilClass`, `String`, `Integer`, `Fixnum`, `Bignum`, `Float`, `BigDecimal`, `TrueClass`, `FalseClass`) + class StandardTypeSerializer < BaseSerializer + class << self + def serialize?(argument) + ::ActiveJob::Arguments::TYPE_WHITELIST.include? argument.class + end + + def serialize(argument) + argument + end + + alias_method :deserialize?, :serialize? + + def deserialize(argument) + object = GlobalID::Locator.locate(argument) if argument.is_a? String + object || argument + end + end + end + end +end diff --git a/activejob/lib/active_job/serializers/struct_serializer.rb b/activejob/lib/active_job/serializers/struct_serializer.rb new file mode 100644 index 0000000000..f6791611ed --- /dev/null +++ b/activejob/lib/active_job/serializers/struct_serializer.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module ActiveJob + module Serializers + # Provides methods to serialize and deserialize struct instances + # (`Struct.new('Rectangle', :width, :height).new(12, 20)`) + class StructSerializer < ObjectSerializer + class << self + def serialize(object) + super.merge values_key => ::ActiveJob::Serializers.serialize(object.values) + end + + def deserialize(hash) + values = ::ActiveJob::Serializers.deserialize(hash[values_key]) + super.new(*values) + end + + def key + "_aj_struct" + end + + private + + def klass + ::Struct + end + + def keys + super.push values_key + end + + def values_key + "values" + end + end + end + end +end diff --git a/activejob/lib/active_job/serializers/symbol_serializer.rb b/activejob/lib/active_job/serializers/symbol_serializer.rb new file mode 100644 index 0000000000..f128ae8284 --- /dev/null +++ b/activejob/lib/active_job/serializers/symbol_serializer.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module ActiveJob + module Serializers + # Provides methods to serialize and deserialize `Symbol` (`:foo`, `:bar`, ...) + class SymbolSerializer < ObjectSerializer + class << self + def serialize(symbol) + { key => symbol.to_s } + end + + def deserialize(hash) + hash[key].to_sym + end + + def key + "_aj_symbol" + end + + private + + def klass + ::Symbol + end + end + end + end +end |