Created
November 10, 2023 06:18
-
-
Save zhandao/cefc5484cf38a78f0111c25b8a75cfe5 to your computer and use it in GitHub Desktop.
[Ruby on Rails] having or missing associations with filter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module HavingAssoc | |
extend ActiveSupport::Concern | |
class_methods do | |
# @example | |
# Child.missing_assoc(:lessons) | |
# Child.missing_assoc(:lessons).size # => children's count | |
# Child.missing_assoc(:lessons, filter: Lesson.finished) # => [children] | |
def missing_assoc(assoc_name, filter: nil) | |
if filter.nil? | |
where.missing(assoc_name) | |
else | |
having_assoc(assoc_name, count: "= 0", filter:) | |
end | |
end | |
# @example | |
# Child.having_assoc(:lessons, count: "> 10") # => [children] | |
# Child.having_assoc(:lessons, count: "> 10").size # => { id: count } | |
# Child.having_assoc(:lessons, count: "> 10", | |
# filter: Lesson.where("date > ?", 1.year.ago)) # => [children] | |
# Child.having_assoc(:lessons, count: "> 10", filter: ..).size # => { id: 0 } | |
# | |
# @param [Symbol] count_as must be `:count_all` if want to use `.size` | |
def having_assoc(assoc_name, count:, filter: nil, count_as: :count_all) | |
assoc_table_name = reflect_on_all_associations.find { _1.name == assoc_name.to_sym }.table_name | |
if filter.nil? | |
left_outer_joins(assoc_name) | |
.select("#{table_name}.*, COUNT(*) FILTER (WHERE #{assoc_table_name}.id IS NOT NULL) AS #{count_as}") | |
.having("count(#{assoc_table_name}) #{count}") | |
else | |
filter_sql = filter.to_sql.split(" WHERE ").last | |
left_outer_joins(assoc_name) | |
.select("#{table_name}.*, COUNT(*) FILTER (WHERE #{filter_sql}) AS #{count_as}") | |
.having("count(#{assoc_table_name}) FILTER (WHERE #{filter_sql}) #{count}") | |
end.group(:id) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment