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