-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
354 additions
and
149 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
require_relative 'tagged_with_query/query_base' | ||
require_relative 'tagged_with_query/exclude_tags_query' | ||
require_relative 'tagged_with_query/any_tags_query' | ||
require_relative 'tagged_with_query/all_tags_query' | ||
|
||
module ActsAsTaggableOn::Taggable::TaggedWithQuery | ||
def self.build(taggable_model, tag_model, tagging_model, tag_list, options) | ||
if options[:exclude].present? | ||
ExcludeTagsQuery.new(taggable_model, tag_model, tagging_model, tag_list, options).build | ||
elsif options[:any].present? | ||
AnyTagsQuery.new(taggable_model, tag_model, tagging_model, tag_list, options).build | ||
else | ||
AllTagsQuery.new(taggable_model, tag_model, tagging_model, tag_list, options).build | ||
end | ||
end | ||
end |
113 changes: 113 additions & 0 deletions
113
lib/acts_as_taggable_on/taggable/tagged_with_query/all_tags_query.rb
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
module ActsAsTaggableOn::Taggable::TaggedWithQuery | ||
class AllTagsQuery < QueryBase | ||
def build | ||
taggable_model.joins(each_tag_in_list) | ||
.group(by_taggable) | ||
.having(tags_that_matches_count) | ||
.order(order_conditions) | ||
.readonly(false) | ||
end | ||
|
||
private | ||
|
||
def each_tag_in_list | ||
arel_join = taggable_arel_table | ||
|
||
tag_list.each do |tag| | ||
tagging_alias = tagging_arel_table.alias(tagging_alias(tag)) | ||
arel_join = arel_join | ||
.join(tagging_alias) | ||
.on(on_conditions(tag, tagging_alias)) | ||
end | ||
|
||
if options[:match_all].present? | ||
arel_join = arel_join | ||
.join(tagging_arel_table, Arel::Nodes::OuterJoin) | ||
.on( | ||
match_all_on_conditions | ||
) | ||
end | ||
|
||
return arel_join.join_sources | ||
end | ||
|
||
def on_conditions(tag, tagging_alias) | ||
on_condition = tagging_alias[:taggable_id].eq(taggable_arel_table[taggable_model.primary_key]) | ||
.and(tagging_alias[:taggable_type].eq(taggable_model.base_class.name)) | ||
.and( | ||
tagging_alias[:tag_id].in( | ||
tag_arel_table.project(tag_arel_table[:id]).where(tag_match_type(tag)) | ||
) | ||
) | ||
|
||
if options[:start_at].present? | ||
on_condition = on_condition.and(tagging_alias[:created_at].gteq(options[:start_at])) | ||
end | ||
|
||
if options[:end_at].present? | ||
on_condition = on_condition.and(tagging_alias[:created_at].lteq(options[:end_at])) | ||
end | ||
|
||
if options[:on].present? | ||
on_condition = on_condition.and(tagging_alias[:context].lteq(options[:on])) | ||
end | ||
|
||
if (owner = options[:owned_by]).present? | ||
owner_table = owner.class.base_class.arel_table | ||
|
||
on_condition = on_condition.and(tagging_alias[:tagger_id].eq(owner.id)) | ||
.and(tagging_alias[:tagger_type].eq(owner.class.base_class.to_s)) | ||
end | ||
|
||
on_condition | ||
end | ||
|
||
def match_all_on_conditions | ||
on_condition = tagging_arel_table[:taggable_id].eq(taggable_arel_table[taggable_model.primary_key]) | ||
.and(tagging_arel_table[:taggable_type].eq(taggable_model.base_class.name)) | ||
|
||
if options[:start_at].present? | ||
on_condition = on_condition.and(tagging_arel_table[:created_at].gteq(options[:start_at])) | ||
end | ||
|
||
if options[:end_at].present? | ||
on_condition = on_condition.and(tagging_arel_table[:created_at].lteq(options[:end_at])) | ||
end | ||
|
||
if options[:on].present? | ||
on_condition = on_condition.and(tagging_arel_table[:context].lteq(options[:on])) | ||
end | ||
|
||
on_condition | ||
end | ||
|
||
def by_taggable | ||
return [] unless options[:match_all].present? | ||
|
||
taggable_arel_table[taggable_model.primary_key] | ||
end | ||
|
||
def tags_that_matches_count | ||
return [] unless options[:match_all].present? | ||
|
||
taggable_model.find_by_sql(tag_arel_table.project(Arel.star.count).where(tags_match_type).to_sql) | ||
|
||
tagging_arel_table[:taggable_id].count.eq( | ||
tag_arel_table.project(Arel.star.count).where(tags_match_type) | ||
) | ||
end | ||
|
||
def order_conditions | ||
order_by = [] | ||
order_by << tagging_arel_table.project(tagging_arel_table[Arel.star].count.as('taggings_count')).order('taggings_count DESC').to_sql if options[:order_by_matching_tag_count].present? && options[:match_all].blank? | ||
|
||
order_by << options[:order] if options[:order].present? | ||
order_by.join(', ') | ||
end | ||
|
||
def tagging_alias(tag) | ||
alias_base_name = taggable_model.base_class.name.downcase | ||
adjust_taggings_alias("#{alias_base_name[0..11]}_taggings_#{ActsAsTaggableOn::Utils.sha_prefix(tag)}") | ||
end | ||
end | ||
end |
75 changes: 75 additions & 0 deletions
75
lib/acts_as_taggable_on/taggable/tagged_with_query/any_tags_query.rb
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
module ActsAsTaggableOn::Taggable::TaggedWithQuery | ||
class AnyTagsQuery < QueryBase | ||
def build | ||
taggable_model.select(all_fields) | ||
.where(model_has_at_least_one_tag) | ||
.order(order_conditions) | ||
.readonly(false) | ||
end | ||
|
||
private | ||
|
||
def all_fields | ||
taggable_arel_table[Arel.star] | ||
end | ||
|
||
def model_has_at_least_one_tag | ||
tagging_alias = tagging_arel_table.alias(alias_name(tag_list)) | ||
|
||
|
||
tagging_arel_table.project(Arel.star).where(at_least_one_tag).exists | ||
end | ||
|
||
def at_least_one_tag | ||
exists_contition = tagging_arel_table[:taggable_id].eq(taggable_arel_table[taggable_model.primary_key]) | ||
.and(tagging_arel_table[:taggable_type].eq(taggable_model.base_class.name)) | ||
.and( | ||
tagging_arel_table[:tag_id].in( | ||
tag_arel_table.project(tag_arel_table[:id]).where(tags_match_type) | ||
) | ||
) | ||
|
||
if options[:start_at].present? | ||
exists_contition = exists_contition.and(tagging_arel_table[:created_at].gteq(options[:start_at])) | ||
end | ||
|
||
if options[:end_at].present? | ||
exists_contition = exists_contition.and(tagging_arel_table[:created_at].lteq(options[:end_at])) | ||
end | ||
|
||
if options[:on].present? | ||
exists_contition = exists_contition.and(tagging_arel_table[:context].lteq(options[:on])) | ||
end | ||
|
||
if (owner = options[:owned_by]).present? | ||
owner_table = owner.class.base_class.arel_table | ||
|
||
exists_contition = exists_contition.and(tagging_arel_table[:tagger_id].eq(owner.id)) | ||
.and(tagging_arel_table[:tagger_type].eq(owner.class.base_class.to_s)) | ||
end | ||
|
||
exists_contition | ||
end | ||
|
||
def order_conditions | ||
order_by = [] | ||
if options[:order_by_matching_tag_count].present? | ||
order_by << "(SELECT count(*) FROM #{tagging_model.table_name} WHERE #{at_least_one_tag.to_sql}) desc" | ||
end | ||
|
||
order_by << options[:order] if options[:order].present? | ||
order_by.join(', ') | ||
end | ||
|
||
def alias_name(tag_list) | ||
alias_base_name = taggable_model.base_class.name.downcase | ||
taggings_context = options[:on] ? "_#{options[:on]}" : '' | ||
|
||
taggings_alias = adjust_taggings_alias( | ||
"#{alias_base_name[0..4]}#{taggings_context[0..6]}_taggings_#{ActsAsTaggableOn::Utils.sha_prefix(tag_list.join('_'))}" | ||
) | ||
|
||
taggings_alias | ||
end | ||
end | ||
end |
Oops, something went wrong.