Skip to content

Commit

Permalink
Make querying associations more explicit
Browse files Browse the repository at this point in the history
Closes #171
  • Loading branch information
paulcsmith committed Jul 31, 2019
1 parent a93bf4c commit a8112f3
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 16 deletions.
29 changes: 23 additions & 6 deletions spec/query_associations_spec.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
require "./spec_helper"

# Ensure it works with inherited query classes
class CommentQuery < Comment::BaseQuery
def body_eq(value)
body.eq(value)
end
end

describe "Query associations" do
it "can query associations" do
post_with_matching_comment = PostBox.create
Expand All @@ -16,10 +23,12 @@ describe "Query associations" do
.post_id(post_without_matching_comment.id)
.create

posts = Post::BaseQuery.new.join_comments.where_comments(&.body.eq("matching"))
posts = Post::BaseQuery.new
.where_comments(CommentQuery.new.body_eq("matching"))
posts.results.should eq([post_with_matching_comment])

posts = Post::BaseQuery.new.join_comments.where_comments(&.body("matching"))
posts = Post::BaseQuery.new
.where_comments(Comment::BaseQuery.new.body("matching"))
posts.results.should eq([post_with_matching_comment])
end

Expand All @@ -38,7 +47,9 @@ describe "Query associations" do
.post_id(post_without_matching_comment.id)
.create

posts = Post::BaseQuery.new.inner_join_comments.where_comments(&.body.eq("matching"))
posts = Post::BaseQuery.new
.inner_join_comments
.where_comments(Comment::BaseQuery.new.body.eq("matching"), auto_inner_join: false)
posts.to_sql[0].should contain "INNER JOIN"
posts.results.should eq([post_with_matching_comment])
end
Expand All @@ -58,7 +69,9 @@ describe "Query associations" do
.post_id(post_without_matching_comment.id)
.create

posts = Post::BaseQuery.new.left_join_comments.where_comments(&.body.eq("matching"))
posts = Post::BaseQuery.new
.left_join_comments
.where_comments(Comment::BaseQuery.new.body.eq("matching"), auto_inner_join: false)
posts.to_sql[0].should contain "LEFT JOIN"
posts.results.should eq([post_with_matching_comment])
end
Expand All @@ -78,7 +91,9 @@ describe "Query associations" do
.post_id(post_without_matching_comment.id)
.create

posts = Post::BaseQuery.new.right_join_comments.where_comments(&.body.eq("matching"))
posts = Post::BaseQuery.new
.right_join_comments
.where_comments(Comment::BaseQuery.new.body.eq("matching"), auto_inner_join: false)
posts.to_sql[0].should contain "RIGHT JOIN"
posts.results.should eq([post_with_matching_comment])
end
Expand All @@ -98,7 +113,9 @@ describe "Query associations" do
.post_id(post_without_matching_comment.id)
.create

posts = Post::BaseQuery.new.full_join_comments.where_comments(&.body.eq("matching"))
posts = Post::BaseQuery.new
.full_join_comments
.where_comments(Comment::BaseQuery.new.body.eq("matching"), auto_inner_join: false)
posts.to_sql[0].should contain "FULL JOIN"
posts.results.should eq([post_with_matching_comment])
end
Expand Down
4 changes: 2 additions & 2 deletions src/avram/associations/has_many.cr
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ module Avram::Associations::HasMany
all_{{ assoc_name }} = preload_query
.dup
.join_{{ through.id }}
.where_{{ through.id }} do |through_query|
.__yield_where_{{ through.id }} do |through_query|
through_query.{{ foreign_key.id }}.in(ids)
end
.preload_{{ through.id }}
Expand Down Expand Up @@ -90,7 +90,7 @@ module Avram::Associations::HasMany
{{ model }}::BaseQuery
.new
.join_{{ through.id }}
.where_{{ through.id }} do |through_query|
.__yield_where_{{ through.id }} do |through_query|
through_query.{{ foreign_key.id }}(id)
end
.preload_{{ through.id }}
Expand Down
26 changes: 18 additions & 8 deletions src/avram/base_query_template.cr
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class Avram::BaseQueryTemplate
)
{% elsif assoc[:through] %}
{{ join_type.downcase.id }}_join_{{ assoc[:through].id }}
where_{{ assoc[:through].id }} do |join_query|
__yield_where_{{ assoc[:through].id }} do |join_query|
join_query.{{ join_type.downcase.id }}_join_{{ assoc[:table_name] }}
end
{% else %}
Expand All @@ -85,20 +85,30 @@ class Avram::BaseQueryTemplate
{% end %}


def where_{{ assoc[:table_name] }}
{{ assoc[:type] }}::BaseQuery.new_with_existing_query(query).tap do |assoc_query|
yield assoc_query
end
def where_{{ assoc[:table_name] }}(assoc_query : ::{{ assoc[:type] }}::BaseQuery, auto_inner_join : Bool = true)
join_{{ assoc[:table_name] }} if auto_inner_join
query.merge(assoc_query.query)
self
end

# :nodoc:
# Used internally for has_many throuogh queries
def __yield_where_{{ assoc[:table_name] }}
assoc_query = yield {{ assoc[:type] }}::BaseQuery.new
query.merge(assoc_query.query)
self
end

def {{ assoc[:table_name] }}
\{% raise <<-ERROR
The methods for querying associations are now prefixed with 'where_'
The methods for querying associations have changed
* They are now prefixed with 'where_'.
* The query is no longer yielded. You must pass it explicitly.
Try this...
Example:
▸ Use 'where_{{ assoc[:table_name] }}'
where_{{ assoc[:table_name] }}({{ assoc[:type] }}Query.new.some_condition)
ERROR
%}
yield # This is not used. Just there so it works with blocks.
Expand Down

0 comments on commit a8112f3

Please sign in to comment.