mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-24 23:06:50 +00:00
Optimize merging associations
This commit is contained in:
parent
28aad30f4e
commit
dd32f91a25
@ -1,7 +1,32 @@
|
|||||||
require "active_support/core_ext/class/attribute"
|
require "active_support/core_ext/class/attribute"
|
||||||
require "active_support/core_ext/module/anonymous"
|
require "active_support/core_ext/module/anonymous"
|
||||||
|
require "set"
|
||||||
|
|
||||||
module ActiveModel
|
module ActiveModel
|
||||||
|
class OrderedSet
|
||||||
|
def initialize(array)
|
||||||
|
@array = array
|
||||||
|
@hash = {}
|
||||||
|
|
||||||
|
array.each do |item|
|
||||||
|
@hash[item] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def merge!(other)
|
||||||
|
other.each do |item|
|
||||||
|
next if @hash.key?(item)
|
||||||
|
|
||||||
|
@hash[item] = true
|
||||||
|
@array.push item
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_a
|
||||||
|
@array
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Active Model Array Serializer
|
# Active Model Array Serializer
|
||||||
#
|
#
|
||||||
# It serializes an array checking if each element that implements
|
# It serializes an array checking if each element that implements
|
||||||
@ -25,6 +50,7 @@ module ActiveModel
|
|||||||
|
|
||||||
def as_json(*args)
|
def as_json(*args)
|
||||||
@options[:hash] = hash = {}
|
@options[:hash] = hash = {}
|
||||||
|
@options[:unique_values] = {}
|
||||||
|
|
||||||
array = serializable_array.map(&:serializable_hash)
|
array = serializable_array.map(&:serializable_hash)
|
||||||
|
|
||||||
@ -352,6 +378,8 @@ module ActiveModel
|
|||||||
options ||= {}
|
options ||= {}
|
||||||
if root = options.fetch(:root, @options.fetch(:root, _root))
|
if root = options.fetch(:root, @options.fetch(:root, _root))
|
||||||
@options[:hash] = hash = {}
|
@options[:hash] = hash = {}
|
||||||
|
@options[:unique_values] = {}
|
||||||
|
|
||||||
hash.merge!(root => serializable_hash)
|
hash.merge!(root => serializable_hash)
|
||||||
hash
|
hash
|
||||||
else
|
else
|
||||||
@ -390,7 +418,24 @@ module ActiveModel
|
|||||||
end
|
end
|
||||||
|
|
||||||
def include!(name, options={})
|
def include!(name, options={})
|
||||||
hash = options[:hash] || @options[:hash]
|
# Make sure that if a special options[:hash] was passed in, we generate
|
||||||
|
# a new unique values hash and don't clobber the original. If the hash
|
||||||
|
# passed in is the same as the current options hash, use the current
|
||||||
|
# unique values.
|
||||||
|
#
|
||||||
|
# TODO: Should passing in a Hash even be public API here?
|
||||||
|
unique_values =
|
||||||
|
if hash = options[:hash]
|
||||||
|
if @options[:hash] == hash
|
||||||
|
@options[:unique_values] ||= {}
|
||||||
|
else
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
hash = @options[:hash]
|
||||||
|
@options[:unique_values] ||= {}
|
||||||
|
end
|
||||||
|
|
||||||
node = options[:node]
|
node = options[:node]
|
||||||
value = options[:value]
|
value = options[:value]
|
||||||
|
|
||||||
@ -409,18 +454,29 @@ module ActiveModel
|
|||||||
node[association.key] = association.serialize_ids
|
node[association.key] = association.serialize_ids
|
||||||
|
|
||||||
if association.embed_in_root?
|
if association.embed_in_root?
|
||||||
merge_association hash, association.plural_key, association.serialize_many
|
merge_association hash, association.plural_key, association.serialize_many, unique_values
|
||||||
end
|
end
|
||||||
elsif association.embed_objects?
|
elsif association.embed_objects?
|
||||||
node[association.key] = association.serialize
|
node[association.key] = association.serialize
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def merge_association(hash, key, value)
|
# In some cases, an Array of associations is built by merging the associated
|
||||||
if hash[key]
|
# content for all of the children. For instance, if a Post has_many comments,
|
||||||
hash[key] |= value
|
# which has_many tags, the top-level :tags key will contain the merged list
|
||||||
|
# of all tags for all comments of the post.
|
||||||
|
#
|
||||||
|
# In order to make this efficient, we store a :unique_values hash containing
|
||||||
|
# a unique list of all of the objects that are already in the Array. This
|
||||||
|
# avoids the need to scan through the Array looking for entries every time
|
||||||
|
# we want to merge a new list of values.
|
||||||
|
def merge_association(hash, key, value, unique_values)
|
||||||
|
if current_value = unique_values[key]
|
||||||
|
current_value.merge! value
|
||||||
|
hash[key] = current_value.to_a
|
||||||
elsif value
|
elsif value
|
||||||
hash[key] = value
|
hash[key] = value
|
||||||
|
unique_values[key] = OrderedSet.new(value)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user