-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lazy dig #44
Lazy dig #44
Conversation
@Bajena Is that good enough in general? ) Checking CC issues in meanwhile ) |
60143d6
to
42f30bd
Compare
@Bajena fixed CC, ready for review ) please release it with as a new version if possible, that is the last piece of puzzle for me ) |
What's the most typical use case for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fine overall. I posted some minor comments.
# Recursively loads the tree of lazy relationships | ||
# The nesting is limited to 3 levels. | ||
# | ||
# @param object [Object] Lazy relationships will be loaded for this record. | ||
# @param level [Integer] Current nesting level | ||
def load_all_lazy_relationships(object, level = NESTING_START_LEVEL) | ||
def init_all_lazy_relationships(object, level = NESTING_START_LEVEL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea with renaming this. I'd even consider renaming it to sth like collect_all_lazy_relationships
or touch_all_lazy_relationships
, but this is good enough as well 👍
|
||
module AmsLazyRelationships::Core | ||
module LazyDigMethod | ||
def lazy_dig(*relation_names) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be good to add some documentation to this method - what args it accepts, what it returns and an example of use
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added! )
next_objects = lazy_dig_next_objects!(relation_name, serializer, object) | ||
next unless next_objects | ||
|
||
relationships[:multiple] ||= next_objects.respond_to?(:to_ary) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using ||=
on boolean values is a bit risky, because it'll get overwritten even if the value was set previously but is false
or nil
.
Do we even need this :multiple
key anyways?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, we always initialize this flag by false at the beginning
def lazy_dig(*relation_names)
relationships = {
multiple: false,
# ...
}
The idea is to maintain the singular/plural nature of lazy_dig
returned value based on singular/plural nature of the chain
of requested relation names. I.e.
lazy_dig(:company, :logo) # returns single AR record or nil
lazy_dig(:companies, :logo) # returns the array of AR records
lazy_dig(:company, :logos) # returns the array of AR records
In general, lazy_dig
will return single AR object (or nil) if every
relationship in a chain was a kind of singular association, and will return an array otherwise. So highlighted expression is hunting for any single plural relationship
relationships[:multiple] ||= next_objects.respond_to?(:to_ary)
. Then we decide what kind of return value will be as follows
relationships[:multiple] ? objects : objects.first
end | ||
|
||
def lazy_dig_next_objects!(relation_name, serializer, object) | ||
serializer&.send( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd even consider raising an ArgumentError
exception here if there's no such (lazy) relationship in the serializer. It'd prevent nil
s, because of typos. On the other hand standard dig
doesn't care neither 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly I don't have a strong opinion on this, even don't know is that good or bad for me personally )
I just wanted to simulate the Hash#dig
behavior which silently ignores any kind of misses )
My vote is to leave that as it is ) If we need more strict method (I'm not sure that we are though) - let it have a bang
name like lazy_dig!
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd even consider raising an ArgumentError exception here if there's no such (lazy) relationship in the serializer.
Hm, thinking about raising the ArgumentError widely
module AmsLazyRelationships::Core
module Evaluation
def load_lazy_relationship(relation_name, object)
lrm = lazy_relationships[relation_name]
# Raise ArgumentError ?.
return unless lrm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Bajena Yeah, did that, added tests, please take a look )
The quote right from my project, very similar to example posted to README.md: class OrganizationSerializer
lazy_belongs_to :logo
end
class UserSerializer
lazy_belongs_to :organization
attribute(:organization_logo_url) { lazy_dig(:organization, :logo)&.url }
end I.e. our motivation is the same as described in
, but we are going several steps deeper through nested relationships. |
6b61a25
to
b712485
Compare
b712485
to
2381a13
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work, nothing more to add🎉 Thanks for your hard work!
* Use uuids as primary keys within test suite * Add `lazy_dig` as serializer instance method
Released v0.2.0 |
@Bajena thank you a lot! ) |
It introduces
lazy_dig
serializer instance method, in order to dig through nested associations keeping laziness and N+1-free evaluation.Also we turn all primary keys into UUIDs within a test suite, that is much stronger. Indeed, with auto-increment keys when we assert the things like
it's possible to face with false-positive result when not
BlogPosts
but, say,Comments
was JSONed, just because