-
Notifications
You must be signed in to change notification settings - Fork 64
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
New method to add parenthesis to queries #652
Conversation
…blish precedence. Fixes #488
# Clears the last conjunction | ||
# e.g. users.age = $1 AND -> users.age = $1 | ||
def clear_conjunction | ||
@wheres.last.conjunction = Avram::Where::Conjunction::None unless @wheres.empty? |
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 was needed because the last where might "("
and it was generating WHERE ( AND users.age...
@@ -322,6 +328,9 @@ class Avram::QueryBuilder | |||
[clause, sql_clause.conjunction.to_s] | |||
end | |||
|
|||
# Remove blank conjunctions | |||
statements.reject!(&.blank?) |
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.
By adding in the Avram::Where::Conjunction::None
, the statements
might look like ["(", "", "users.age = $1", "AND", ")", "AND"]
@stephendolan you mentioned needing to use this, can you see if this would work for your usecase? |
Heck yeah! I'll pop in and try it this weekend, @jwoertink ! Thanks for putting this together. |
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 I'm happy with this 👍 Just the one issue
…d cause blank WHERE statements to be added.
Before I approve, @jwoertink what happens in this scenario: UserQuery.new.name("Susan").where do |q|
if false
q.name("john")
else
q
end
end.age(25).to_sql I'm wondering how the clear last conjunction works if the where doesn't add any conditions. |
lol 😂 another good catch... Maybe I need to rethink how this is done... You'll end up with this:
|
Should it raise an exception if you use this |
If that is valid SQL, I'm ok with it for now. I have a rough idea of how we might refactor the where storage in the future. |
It is not valid SQL...
|
Though, it probably is an edge case... I guess we could open up a separate issue and come back to refactor later? |
I'd prefer not to push a feature with a know bug. Could you check if the last item in the array is an open parens and remove it if so? |
it "doesn't add parenthesis when query to wrap is provided" do | ||
query = UserQuery.new.name("Susan").where do |q| | ||
some_condition = false | ||
if some_condition |
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.
Because ameba throws an error if you use a bool literal as a condition
Yeah, I was able to just check the last added Where, and see it was the PrecedenceStart. Then I can just remove it, and skip the rest. |
|
||
# Removes the last `Avram::Where` to be added | ||
def remove_last_where | ||
@wheres.pop |
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.
Should this return self
? 🤔
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.
@matthewmcgarvey what are your thoughts on this? I assume no one will call this but us... but should this return self
? or do you think it even matters?
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 was looking at query builder yesterday and couldn't see any pattern to when we clone queryable vs query builder. I wouldn't worry about it
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.
Cool. Thanks for the reviews!
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.
Lots of tiny issues, but you got it there, nice job! 🎉
Finally got around to playing with this in my production app, and it worked beautifully. This is really handy to throw into a scope so that no matter where you use it, you can guarantee that your results are grouped. Here's an example where I want to search videos by a search term across lots of attributes: class VideoQuery < Video::BaseQuery
def matching_search_term(search_term : String)
where do |query|
query.title.ilike(search_term)
.or(&.description.ilike(search_term))
.or(&.left_join_topics.where_topics(TopicQuery.new.label.ilike(search_term)))
end
end
end |
This is pretty dope!! Can you also pass a query object to where, or does it need to be a block? e.g. can you do |
You can do |
Fixes #488
When it comes to more complex queries, you may need to specify precedence for your conditions. This is done by wrapping your condition in parenthesis.
This PR adds a new
where
overload for your query objects that takes a block, and will wrap whatever query is defined inside the block.This opens Avram up to a lot more complex (but type-safe) queries.