lib/jsonapi/resource_set.rb in jsonapi-resources-0.10.7 vs lib/jsonapi/resource_set.rb in jsonapi-resources-0.11.0.beta2
- old
+ new
@@ -1,31 +1,45 @@
+# frozen_string_literal: true
+
module JSONAPI
# Contains a hash of resource types which contain a hash of resources, relationships and primary status keyed by
# resource id.
class ResourceSet
attr_reader :resource_klasses, :populated
- def initialize(resource_id_tree = nil)
+ def initialize(source, include_related = nil, options = nil)
@populated = false
- @resource_klasses = resource_id_tree.nil? ? {} : flatten_resource_id_tree(resource_id_tree)
+ tree = if source.is_a?(JSONAPI::ResourceTree)
+ source
+ elsif source.class.include?(JSONAPI::ResourceCommon)
+ JSONAPI::PrimaryResourceTree.new(resource: source, include_related: include_related, options: options)
+ elsif source.is_a?(Array)
+ JSONAPI::PrimaryResourceTree.new(resources: source, include_related: include_related, options: options)
+ end
+
+ if tree
+ @resource_klasses = flatten_resource_tree(tree)
+ end
end
- def populate!(serializer, context, find_options)
+ def populate!(serializer, context, options)
+ return if @populated
+
# For each resource klass we want to generate the caching key
# Hash for collecting types and ids
# @type [Hash<Class<Resource>, Id[]]]
missed_resource_ids = {}
# Array for collecting CachedResponseFragment::Lookups
# @type [Lookup[]]
lookups = []
-
# Step One collect all of the lookups for the cache, or keys that don't require cache access
@resource_klasses.each_key do |resource_klass|
+ missed_resource_ids[resource_klass] ||= []
serializer_config_key = serializer.config_key(resource_klass).gsub("/", "_")
context_json = resource_klass.attribute_caching_context(context).to_json
context_b64 = JSONAPI.configuration.resource_cache_digest_function.call(context_json)
context_key = "ATTR-CTX-#{context_b64.gsub("/", "_")}"
@@ -45,11 +59,17 @@
context_key,
cache_ids
)
)
else
- missed_resource_ids[resource_klass] = @resource_klasses[resource_klass].keys
+ @resource_klasses[resource_klass].keys.each do |k|
+ if @resource_klasses[resource_klass][k][:resource].nil?
+ missed_resource_ids[resource_klass] << k
+ else
+ register_resource(resource_klass, @resource_klasses[resource_klass][k][:resource])
+ end
+ end
end
end
if lookups.any?
raise "You've declared some Resources as caching without providing a caching store" if JSONAPI.configuration.resource_cache.nil?
@@ -58,11 +78,10 @@
found_resources = CachedResponseFragment.lookup(lookups, context)
else
found_resources = {}
end
-
# Step Three collect the results and collect hit/miss stats
stats = {}
found_resources.each do |resource_klass, resources|
resources.each do |id, cached_resource|
stats[resource_klass] ||= {}
@@ -70,11 +89,10 @@
if cached_resource.nil?
stats[resource_klass][:misses] ||= 0
stats[resource_klass][:misses] += 1
# Collect misses
- missed_resource_ids[resource_klass] ||= []
missed_resource_ids[resource_klass].push(id)
else
stats[resource_klass][:hits] ||= 0
stats[resource_klass][:hits] += 1
@@ -87,18 +105,19 @@
writes = []
# Step Four find any of the missing resources and join them into the result
missed_resource_ids.each_pair do |resource_klass, ids|
- find_opts = {context: context, fields: find_options[:fields]}
+ next if ids.empty?
+
+ find_opts = {context: context, fields: options[:fields]}
found_resources = resource_klass.find_to_populate_by_keys(ids, find_opts)
found_resources.each do |resource|
relationship_data = @resource_klasses[resource_klass][resource.id][:relationships]
if resource_klass.caching?
-
serializer_config_key = serializer.config_key(resource_klass).gsub("/", "_")
context_json = resource_klass.attribute_caching_context(context).to_json
context_b64 = JSONAPI.configuration.resource_cache_digest_function.call(context_json)
context_key = "ATTR-CTX-#{context_b64.gsub("/", "_")}"
@@ -146,29 +165,30 @@
stat[:misses] || 0
)
end
end
- def flatten_resource_id_tree(resource_id_tree, flattened_tree = {})
- resource_id_tree.fragments.each_pair do |resource_rid, fragment|
+ def flatten_resource_tree(resource_tree, flattened_tree = {})
+ resource_tree.fragments.each_pair do |resource_rid, fragment|
resource_klass = resource_rid.resource_klass
id = resource_rid.id
flattened_tree[resource_klass] ||= {}
flattened_tree[resource_klass][id] ||= {primary: fragment.primary, relationships: {}}
- flattened_tree[resource_klass][id][:cache_id] ||= fragment.cache
+ flattened_tree[resource_klass][id][:cache_id] ||= fragment.cache if fragment.cache
+ flattened_tree[resource_klass][id][:resource] ||= fragment.resource if fragment.resource
fragment.related.try(:each_pair) do |relationship_name, related_rids|
- flattened_tree[resource_klass][id][:relationships][relationship_name] ||= Set.new
+ flattened_tree[resource_klass][id][:relationships][relationship_name] ||= SortedSet.new
flattened_tree[resource_klass][id][:relationships][relationship_name].merge(related_rids)
end
end
- related_resource_id_trees = resource_id_tree.related_resource_id_trees
- related_resource_id_trees.try(:each_value) do |related_resource_id_tree|
- flatten_resource_id_tree(related_resource_id_tree, flattened_tree)
+ related_resource_trees = resource_tree.related_resource_trees
+ related_resource_trees.try(:each_value) do |related_resource_tree|
+ flatten_resource_tree(related_resource_tree, flattened_tree)
end
flattened_tree
end
end