11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
# File 'lib/no_fly_list/taggable_record/query/mysql_strategy.rb', line 11
def define_query_methods(setup)
context = setup.context
taggable_klass = setup.taggable_klass
tagging_klass = setup.tagging_class_name.constantize
tagging_table = tagging_klass.arel_table tag_klass = setup.tag_class_name.constantize
tag_table = tag_klass.arel_table
singular_name = context.to_s.singularize
taggable_klass.class_eval do
scope "with_any_#{context}", lambda { |*tags|
tags = tags.flatten.compact.uniq
return none if tags.empty?
query = Arel::SelectManager.new(self)
.from(table_name)
.project(arel_table[primary_key])
.distinct
.join(tagging_table).on(tagging_table[:taggable_id].eq(arel_table[primary_key]))
.join(tag_table).on(tag_table[:id].eq(tagging_table[:tag_id]))
.where(tagging_table[:context].eq(singular_name))
.where(tag_table[:name].in(tags))
where(arel_table[primary_key].in(query))
}
scope "with_all_#{context}", lambda { |*tags|
tags = tags.flatten.compact.uniq
return none if tags.empty?
count_function = Arel::Nodes::NamedFunction.new(
"COUNT",
[ Arel::Nodes::NamedFunction.new("DISTINCT", [ tag_table[:name] ]) ]
)
query = Arel::SelectManager.new(self)
.from(table_name)
.project(arel_table[primary_key])
.join(tagging_table).on(tagging_table[:taggable_id].eq(arel_table[primary_key]))
.join(tag_table).on(tag_table[:id].eq(tagging_table[:tag_id]))
.where(tagging_table[:context].eq(singular_name))
.where(tag_table[:name].in(tags))
.group(arel_table[primary_key])
.having(count_function.eq(tags.size))
where(arel_table[primary_key].in(query))
}
scope "without_any_#{context}", lambda { |*tags|
tags = tags.flatten.compact.uniq
return all if tags.empty?
subquery = joins(tagging_table)
.where(tagging_table[:context].eq(singular_name))
.where(tagging_table.name => { context: singular_name })
.where(tag_table.name => { name: tags })
.select(primary_key)
where("#{table_name}.#{primary_key} NOT IN (?)", subquery)
}
scope "without_#{context}", lambda {
subquery = if setup.polymorphic
setup.tagging_class_name.constantize
.where(context: singular_name)
.where(taggable_type: name)
.select(:taggable_id)
else
setup.tagging_class_name.constantize
.where(context: singular_name)
.select(:taggable_id)
end
where("#{table_name}.#{primary_key} NOT IN (?)", subquery)
}
scope "with_exact_#{context}", lambda { |*tags|
tags = tags.flatten.compact.uniq
if tags.empty?
send("without_#{context}")
else
Arel::Nodes::NamedFunction.new(
"COUNT",
[ Arel::Nodes::NamedFunction.new("DISTINCT", [ tag_table[:id] ]) ]
)
all_tags_query = select(arel_table[primary_key])
.joins("INNER JOIN #{tagging_table.name} ON #{tagging_table.name}.taggable_id = #{table_name}.#{primary_key}")
.joins("INNER JOIN #{tag_table.name} ON #{tag_table.name}.id = #{tagging_table.name}.tag_id")
.where("#{tagging_table.name}.context = ?", context.to_s.singularize)
.where("#{tag_table.name}.name IN (?)", tags)
.group(arel_table[primary_key])
.having("COUNT(DISTINCT #{tag_table.name}.id) = ?", tags.size)
other_tags_query = select(arel_table[primary_key])
.joins("INNER JOIN #{tagging_table.name} ON #{tagging_table.name}.taggable_id = #{table_name}.#{primary_key}")
.joins("INNER JOIN #{tag_table.name} ON #{tag_table.name}.id = #{tagging_table.name}.tag_id")
.where("#{tagging_table.name}.context = ?", context.to_s.singularize)
.where("#{tag_table.name}.name NOT IN (?)", tags)
where("#{table_name}.#{primary_key} IN (?)", all_tags_query)
.where("#{table_name}.#{primary_key} NOT IN (?)", other_tags_query)
end
}
end
end
|