Skip to content

Commit

Permalink
Prefetch relationships according to JSONAPI include
Browse files Browse the repository at this point in the history
  • Loading branch information
willcosgrove committed Feb 13, 2019
1 parent 5e4ef33 commit 286964c
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 14 deletions.
1 change: 1 addition & 0 deletions ams_lazy_relationships.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Gem::Specification.new do |spec|

spec.add_dependency "active_model_serializers"
spec.add_dependency "batch-loader", "~> 1.2"
spec.add_dependency "jsonapi-renderer"

spec.add_development_dependency "activerecord"
# A Ruby library for testing against different versions of dependencies
Expand Down
8 changes: 5 additions & 3 deletions lib/ams_lazy_relationships/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ module Initializer
def initialize(object, options = {})
super

# binding.pry
# self.class.include_directive_from_options(@instance_options)
self.class.send(:load_all_lazy_relationships, self, options.fetch(:level, 0))
prefetch = options.fetch(:prefetch) {
self.class.include_directive_from_options(@instance_options)
}

self.class.send(:load_all_lazy_relationships, self, prefetch)
end
end
end
24 changes: 13 additions & 11 deletions lib/ams_lazy_relationships/core/evaluation.rb
Original file line number Diff line number Diff line change
@@ -1,41 +1,43 @@
# frozen_string_literal: true

require "jsonapi/include_directive"

module AmsLazyRelationships::Core
# Module responsible for lazy loading the relationships during the runtime
module Evaluation
private

LAZY_NESTING_LEVELS = 3
NESTING_START_LEVEL = 1
DEFAULT_PREFETCH = JSONAPI::IncludeDirective.new("")

# Recursively loads the tree of lazy relationships
#
# @param instance [Object] Lazy relationships will be loaded for this serializer.
def load_all_lazy_relationships(instance, level = NESTING_START_LEVEL)
def load_all_lazy_relationships(instance, prefetch)
return unless instance.object
return if level >= LAZY_NESTING_LEVELS

return unless lazy_relationships

lazy_relationships.each_value do |lrm|
load_lazy_relationship(lrm, instance, level)
lazy_relationships.each do |key, lrm|
next unless prefetch.key? key

next_prefetch = prefetch[key]
load_lazy_relationship(lrm, instance, next_prefetch)
end
end

# @param lrm [LazyRelationshipMeta] relationship data
# @param instance [Object] Serializer instance to load the relationship for
def load_lazy_relationship(lrm, instance, level = NESTING_START_LEVEL)

def load_lazy_relationship(lrm, instance, prefetch = DEFAULT_PREFETCH)
lrm.loader.load(instance, lrm.load_for) do |batch_records|
deep_load_for_yielded_records(
batch_records,
lrm,
level
prefetch
)
end
end

def deep_load_for_yielded_records(batch_records, lrm, level)
def deep_load_for_yielded_records(batch_records, lrm, prefetch)
# There'll be no more nesting if there's no
# reflection for this relationship. We can skip deeper lazy loading.
return unless lrm.reflection
Expand All @@ -44,7 +46,7 @@ def deep_load_for_yielded_records(batch_records, lrm, level)
serializer_class =
lrm.serializer_class || ActiveModel::Serializer.serializer_for(r)

serializer_class.new(r, level: level + 1)
serializer_class.new(r, prefetch: prefetch)
end
end
end
Expand Down

0 comments on commit 286964c

Please sign in to comment.