-
Notifications
You must be signed in to change notification settings - Fork 897
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
Extract ActsAsArModel to QueryRelation gem #11120
Conversation
👍 on the query_relation gem update for this, just verified with updated PR (with local mixin) ManageIQ/manageiq-api-client#24 |
👍 lgtm |
its green! |
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.
This is getting there.
I agree that getting away from find
looks like a good idea.
I just don't want to introduce a gem that has a magical callback method in our code.
# This method is called by QueryRelation upon executing the query. | ||
# Since it will receive non-legacy search options, we need to convert | ||
# them to handle the legacy find. | ||
def self.search(mode, options = {}) |
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.
The original code just called standard active record api find
.
If we want to deviate from that, would it make sense to just call QueryRelation
with a block?
QueryRelation.new(self, *args) do |mode, options|
find(mode, to_legacy_options(options))
end
not sure if QueryRelation
would needself
other than looking up klass
. Maybe passing that in would be better
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 I see you proposing is essentially creating an anonymous proc for the callback instead of a method / telling QueryRelation to use that method.
The only thing I don't like about the anonymous proc is that it's not testable in isolation.
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.
# old
class MyModel
def self.search(*_)
end
def self.all
QueryRelation.new(self)
end
end
model = MyModel.all.where(...).order(...)
expect(model).to receive(:search).with(...)
# new
class MyModel
def self.search(*_)
end
def self.all
QueryRelation.new(self) { |mode, options| search(mode, options) }
end
end
model = MyModel.all.where(...).order(...)
expect(model).to receive(:search).with(...)
# MIQ is unchanged:
expect(model).to receive(:find).with(...)
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.
the anonymous proc is private. and does not need to be tested. Maybe for this I propose an integration test. But I feel this is ok since the "integration" test is only testing the public interfaces of a single class.
QueryRelation
tests ensure that calling these methods populate the hash.
MyModel
test can ignore QueryRelation
and just focuses that if you call it, it will call find correctly.
describe QueryRelation do
describe "#all" do
it "yields" do
model = double("Model", :klass => "Model")
expect(model).to receive("rslt=").with(:select => %w(abc)).and_return([1])
expect(QueryRelation.new(model).select("abc").to_a).to eq([1])
end
end
end
Yea, I think changing the self
going in would be better. Possibly passing in :klass
. It would simplify the proc and the double.
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.
The original code just called standard active record api find.
Was thinking about this more and although the original code did this it was against the "old" find interface, which, moving forward, I don't want QueryRelation to abide by. The "current" find interface for ActiveRecord only accepts ids. As such, QueryRelation expects a different method, intentionally not find
so the caller (or perhaps the QueryRelation::Queryable mixin) can implement an id-based find. The method name I chose was search
after some negotiation with @abellotti, with the purpose being to take the options from QueryRelation and use them to do the search against the source.
In this case of ActsAsArModel, it takes the options, converts them to legacy options and calls the legacy find. Ideally, I'd like to kill the legacy find method of ActsAsArModel, and then kill the to_legacy_options method as well, moving towards the "current" ActiveRecord like interface.
Note that the method search
is just the default, the caller can override that to whatever they want.
QueryRelation.new(self, :query_method => :my_magic_method)
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 think what I don't like about QueryRelation.new(self) { |mode, options| search(mode, options) }
is that the block is a pointless forwarding method. Declaring that search is the default method, and providing an override (see the query_method comment above) felt more Rubyish.
I see your point about it being semi-magical that QueryRelation is going to, by default, call search
on self
, and it appears you want to make that more explicit. I was sort of taking the documentation-driven approach that you see with things like Mixins. For example, it is documented for Enumerable
that if you implement the .each
method, then everything will just work. Similarly, I was thinking that for QueryRelation
if you implement the .search
method, then everything will just work.
Note that if the caller wants explicit, they can also do QueryRelation.new(self, :query_method => :search)
. Does that work for you?
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 tend to agree with @Fryguy here. Nice thing about current approach is less setup for caller for default/documented implementation (e.g. requiring self.search), other can be registered via :query_method. Also, as noted earlier, with the find() implemented in the caller, it can be fine-tuned/performant as needed which I've done in the API Client making the queries to the Server more efficient and levering bulk queries 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.
good news: you won me over on using search
bad news: now I'm not sure if I want to link klass
and search
together.
oh, and did I say how much I liked how you pulled out to_legacy_options
? very cool stuff
end | ||
private_class_method :search | ||
|
||
def self.to_legacy_options(options) |
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 like moving this here. thanks
I'm ok with this. The gist of my thought was: ManageIQ/query_relation#5 |
@kbrock Sounds good. I'm thinking lets get this in as is to unblock manageiq_api_client. Then I'll release a new query_relation gem and then have a follow up PR to switch from git to a real gem. Don't quite want to release query_relation yet as we might have to add a couple of things for manageiq_api_client. Additionally, we can debate the proc interface vs klass vs method in ManageIQ/query_relation#5 |
cc79e81
to
381ca40
Compare
Rebased |
<pr_mergeability_checker />This pull request is not mergeable. Please rebase and repush. |
HAHA! I beat you @miq-bot ! |
Checked commit Fryguy@381ca40 with ruby 2.2.5, rubocop 0.37.2, and haml-lint 0.16.1 |
@Fryguy not sure about replication travis failure. |
Extract ActsAsArModel to QueryRelation gem (cherry picked from commit a88ea04)
Euwe Backport details: $ git log
commit a6b797815996974b94c7eddfb0a5b226a77f7e75
Author: Keenan Brock <keenan@thebrocks.net>
Date: Thu Sep 29 19:01:39 2016 -0400
Merge pull request #11120 from Fryguy/extract_acts_as_ar_relation
Extract ActsAsArModel to QueryRelation gem
(cherry picked from commit a88ea045413938cbe0970eaa0a52476f7803df90) |
Marking this PR as WIP until I release a "real" gem. For now, I wanted to get the repo out there and start iterating on it with some of the needs from @abellotti . Having this WIP PR in place allows us to verify that ManageIQ still works after any changes there.EDIT: Will make the gem release in a separate PR.@kbrock @abellotti Please review.