[JSON-API] Add support for "include" query #95
Conversation
145bad4
to
82d18a7
Compare
|
||
# ... | ||
|
||
yask.call(user, env: @rack_env) |
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.
typo? Should that fancy gem (ataru) have picked this up?
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.
Thanks, forgot about Ataru, fixed :)
I'm aware I'm being a bit cheeky here, but what do you think of this version 😉 require "rack/utils"
module Yaks
module Behaviour
module OptionalIncludes
RACK_KEY = "yaks.optional_includes".freeze
def associations
super.select(&method(:include_association?))
end
private
def include_association?(association)
includes = env.fetch(RACK_KEY) do
query_string = env.fetch("QUERY_STRING", "")
query = Rack::Utils.parse_query(query_string)
env[RACK_KEY] = query.fetch("include", "").split(",").map { |r| r.split(".") }
end
includes.any? do |relationship|
relationship[mapper_stack.size] == association.name.to_s
end
end
end
end
end |
|
||
def has_many(name, options = {}) # rubocop:disable Style/PredicateName | ||
super name, options.merge(if: ->{include_association?(name)}) | ||
end |
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.
So what do we think about merging only if the key doesn't already exist in the options. That way we could always or never include a particular sub-resource simply by putting something in the config for :if
Can you see any issues with that approach?
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.
With the new implementation proposed by @plexus it's no longer valid to implement it this way. However, I think my original implementation had the downside of overriding the :if
, and I think the user would want to keep OptionalInclude's :if
and still add their own.
Now we just need to think how to specify these options. @plexus, any ideas?
Nice. thanks @janko-m! |
Yeah as @groyoh said, I always make that typo myself. |
@plexus For me it seems dangerous to cache it in Rack env, I think it could cause threading issues. But it would be useful to somehow cache the parsing of |
@plexus But I really like the rest of the changes, I will implement those. |
Each request gets a new Rack env, so even if you run multi-threaded, each request will be handled by a single thread |
You're right. Since I agree with everything you've written, I simply copy-pasted your implementation :) |
end | ||
|
||
# ... | ||
|
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.
To fix ataru, try adding this in ataru_setup.rb
at top level:
User = Struct.new
this in the Setup
module:
def user
User.new
end
and this in the README here:
yaks = Yaks.new
and run ataru locally with ataru check
.
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.
Thanks, I didn't know how to run Ataru. Instead of adding anything to ataru_setup.rb
, I reused the existing objects.
Btw, how do you run RuboCop locally? I tried bundle exec rake rubocop
from both yaks/
and top-level directory, and it says that the task is missing.
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.
bundle exec rake rubocop
from the top level should work. Does it show up when you do bundle exec rake -T
?
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.
Actaully, I meant to say that from the top-level it works, but it throws a lot of offenses unrelated to my files, so it doesn't seem like the same Rake task that is run on Travis.
😄 |
For mutant, have your tried |
Thanks, that did work. I only had to change it to
Because I'm not requiring that behaviour by default. I will go on fixing those. |
With the new version users will still be able to provide their own The main other case I can see is where an association is not optional, i.e. will always be included regardless of the |
@janko-m I think there is a |
@groyoh I left it out on purpose, because I'm requiring |
I was also thinking not to load any of |
Ok, it makes sense! 😉 I think it should be written explicitly in the README that we should require it (and not only put it in the code block). Shouldn't we also add |
@groyoh Good call, I will edit the README. Well, I'm not sure about Mutant, if we add another behaviour then we'll need to change again. Is there a better way? |
@janko-m actually I do not really have a better solution. It does not look like a huge trade off for me. We won't have too many behaviour files hopefully 😄 requires = %w(
-ryaks
-ryaks/behaviour/optional_include
)
args = %w[-Ilib --use rspec --score 100] + requires + opts + [pattern] |
I have an existenial problem here. Mutant is replacing the So I'm in a situation where I can introduce a meaningless test just to make Mutant pass. What should I do? |
@janko-m Why do you say that the test is meaningless? If it's there, it should be tested IMO. |
ffd4fc4
to
b8a0052
Compare
|
||
def associations | ||
super.select do |association| | ||
association.if != Undefined || include_association?(association) |
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.
Wouldn't that also include it even if we have if: ->{ false }
for example?
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 would at this stage, map_associations
handles evaluating the if and taking the association out
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.
@groyoh Yes, but this is exactly what I want. I want that if someone specifies :if
, that include_association?
checking is ignored. Because I want it to mean that their overriding this behaviour for that association. If someone specifies :if -> { false }
, that should mean that they never want this association included (in which case of course they wouldn't even put it there).
@janko-m The behaviour you described makes sense to me. I would expect that if I supply my own callback for |
@danelowe Yes, |
I think this is ready for merge, is there something more I need to do? 😃 |
include Yaks::Behaviour::OptionalIncludes | ||
|
||
has_one :author | ||
has_many :comments, if: ->{true} |
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.
You're lucky the docs don't get Rubocopped. Oh hey there's an idea :D
A few minor nitpicks. You want to fix them? I don't consider them blocking |
[JSON-API] Add support for "include" query
Managed to correct the readme comment :) |
You're welcome! Thank you guys for such a detailed code review, it's really great that we merged our opinions together, I think this really helps keep quality of changes at a high level. |
I very much agree |
Good job! Keep up the good work 👍 |
I would like to get some code review on this, especially if I wrote the tests good. I didn't manage to figure out how to run Muntant for this, I ran
PATTERN="Yaks::Behaviour::OptionalIncludes*" bundle exec rake mutant
, but the output looked like nothing has been run.Fixes #83