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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
# File 'lib/no_fly_list/taggable_record/query/sqlite_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?
tagged_ids = distinct
.joins("INNER JOIN #{tagging_table} ON #{tagging_table}.taggable_id = #{table_name}.id")
.joins("INNER JOIN #{context} ON #{context}.id = #{tagging_table}.tag_id")
.where("#{context}.name IN (?)", tags)
.pluck("#{table_name}.id")
where("#{table_name}.id NOT IN (?)", tagged_ids.present? ? tagged_ids : [ -1 ])
}
scope "without_#{context}", lambda {
subquery = if setup.polymorphic
setup.tagging_class_name.constantize
.where(context: singular_name, taggable_type: name)
.select(:taggable_id)
else
setup.tagging_class_name.constantize
.where(context: singular_name)
.select(:taggable_id)
end
where("id 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 = ?", singular_name)
.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 = ?", singular_name)
.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
}
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
|