rocket_tag 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.5.1
@@ -5,5 +5,11 @@ module RocketTag
5
5
 
6
6
  validates_presence_of :name
7
7
  validates_uniqueness_of :name
8
+
9
+ def self.by_taggable_type(type)
10
+ joins{taggings}.where{taggings.taggable_type == type.to_s}
11
+ end
12
+
13
+
8
14
  end
9
15
  end
@@ -1,4 +1,40 @@
1
1
  require 'squeel'
2
+ module Squeel
3
+ module Adapters
4
+ module ActiveRecord
5
+ module RelationExtensions
6
+
7
+ # The purpose of this call is to close a query and make
8
+ # it behave as a simple table or view. If a query has
9
+ # aggregate functions applied then downstream active
10
+ # relation chaining causes unpredictable behaviour.
11
+ #
12
+ # This call isolates the group by behaviours.
13
+ def isolate_group_by_as(type)
14
+ type.from("(#{to_sql}) #{type.table_name}")
15
+ end
16
+
17
+ def select_all
18
+ select('*')
19
+ end
20
+
21
+ # We really only want to group on id for practical
22
+ # purposes but POSTGRES requires that a group by outputs
23
+ # all the column names not under an aggregate function.
24
+ #
25
+ # This little helper generates such a group by
26
+ def group_by_all_columns
27
+ cn = self.column_names
28
+ group { cn.map { |col| __send__(col) } }
29
+ end
30
+
31
+ def exists
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
2
38
 
3
39
  module RocketTag
4
40
  module Taggable
@@ -81,6 +117,7 @@ module RocketTag
81
117
  @contexts[context.to_sym] || []
82
118
  end
83
119
 
120
+
84
121
  def tagged_similar options = {}
85
122
  context = options.delete :on
86
123
  if context
@@ -111,14 +148,13 @@ module RocketTag
111
148
  s | t
112
149
  end
113
150
 
114
- inner = self.class.select{count(~id).as(tags_count)}.
115
- select("#{self.class.table_name}.*").
116
- joins{tags}.where{condition}.
117
- group(self.class.column_names.map{|col| "#{self.class.table_name}.#{col}"}).
118
- where{~id != my{id}}.
119
- order("tags_count DESC")
151
+ r = self.class.
152
+ joins{tags}.
153
+ where{condition}.
154
+ where{~id != my{id}}
155
+
156
+ self.class.count_tags(r)
120
157
 
121
- r = self.class.from("(#{inner.to_sql}) #{self.class.table_name}")
122
158
  end
123
159
  end
124
160
 
@@ -128,9 +164,44 @@ module RocketTag
128
164
  @rocket_tag ||= RocketTag::Taggable::Manager.new(self)
129
165
  end
130
166
 
131
- def _with_tag_context context
167
+ # Provides the tag counting functionality by adding an
168
+ # aggregate count on id. Assumes valid a join has been
169
+ # made.
170
+ def count_tags(rel)
171
+ rel.select_all.
172
+ select{count(~id).as(tags_count)}.
173
+ group_by_all_columns.
174
+ order("tags_count DESC").
175
+ isolate_group_by_as(self)
176
+ end
177
+
178
+ # Filters tags according to
179
+ # context. context param can
180
+ # be either a single context
181
+ # id or an array of context ids
182
+ def with_tag_context context
132
183
  if context
133
- where{taggings.context == context.to_s}
184
+ if context
185
+ if context.class == Array
186
+ contexts = context
187
+ else
188
+ contexts = [context]
189
+ end
190
+ else
191
+ contexts = []
192
+ end
193
+
194
+ conditions = contexts.map do |context|
195
+ squeel do
196
+ (taggings.context == context.to_s)
197
+ end
198
+ end
199
+
200
+ condition = conditions.inject do |s, t|
201
+ s | t
202
+ end
203
+
204
+ where{condition}
134
205
  else
135
206
  where{ }
136
207
  end
@@ -151,25 +222,17 @@ module RocketTag
151
222
  # Generates a query that provides the matches
152
223
  # along with an extra column :tags_count.
153
224
  def tagged_with tags_list, options = {}
154
- on = options.delete :on
155
225
 
156
- inner = select{count(~id).as(tags_count)}.
157
- select("#{self.table_name}.*").
158
- joins{tags}.
226
+ r = joins{tags}.
159
227
  where{tags.name.in(tags_list)}.
160
- _with_tag_context(on).
161
- group(self.column_names.map{|col| "#{self.table_name}.#{col}"})
228
+ with_tag_context(options.delete :on)
162
229
 
163
- # Wrap the inner query with an outer query to shield
164
- # the group and aggregate clauses from downstream
165
- # queries
166
- r = from("(#{inner.to_sql}) #{table_name}")
230
+
231
+ r = count_tags(r)
167
232
 
168
233
  if options.delete :all
169
234
  r = r.where{tags_count==tags_list.length}
170
- end
171
-
172
- if min = options.delete(:min)
235
+ elsif min = options.delete(:min)
173
236
  r = r.where{tags_count>=min}
174
237
  end
175
238
 
@@ -178,7 +241,7 @@ module RocketTag
178
241
  id.in(r.select{"id"})
179
242
  end
180
243
  else
181
- r.select("*")
244
+ r
182
245
  end
183
246
 
184
247
  end
@@ -186,45 +249,20 @@ module RocketTag
186
249
  # Generates a query that returns list of popular tags
187
250
  # for given model with an extra column :tags_count.
188
251
  def popular_tags options={}
189
- context = options.delete :on
190
- if context
191
- if context.class == Array
192
- contexts = context
193
- else
194
- contexts = [context]
195
- end
196
- else
197
- contexts = []
198
- end
199
252
 
200
- conditions = contexts.map do |context|
201
- squeel do
202
- (taggings.context == context.to_s)
203
- end
204
- end
253
+ r =
254
+ RocketTag::Tag.
255
+ joins{taggings}.
256
+ with_tag_context(options.delete :on).
257
+ by_taggable_type(self)
205
258
 
206
- condition = conditions.inject do |s, t|
207
- s | t
208
- end
209
- inner = RocketTag::Tag.select{count(~id).as(tags_count)}.
210
- select("#{RocketTag::Tag.table_name}.*").
211
- joins{taggings.outer}.where{condition}.
212
- where{ taggings.taggable_type == my{self.to_s} }.
213
- group{~id} #.
214
- #order("tags_count DESC")
215
- r = from("(#{inner.to_sql}) #{table_name}")
259
+ r = count_tags(r)
216
260
 
217
261
  if min = options.delete(:min)
218
262
  r = r.where{tags_count>=min}
219
263
  end
220
264
 
221
- if options.delete :sifter
222
- squeel do
223
- id.in(r.select{"id"})
224
- end
225
- else
226
- r.select("*")
227
- end
265
+ r
228
266
  end
229
267
 
230
268
  def setup_for_rocket_tag
@@ -261,7 +299,10 @@ module RocketTag
261
299
  tags_to_assign = exisiting_tags + created_tags
262
300
 
263
301
  tags_to_assign.each do |tag|
264
- tagging = Tagging.new :tag => tag, :taggable => self, :context => context, :tagger => nil
302
+ tagging = Tagging.new :tag => tag,
303
+ :taggable => self,
304
+ :context => context,
305
+ :tagger => nil
265
306
  self.taggings << tagging
266
307
  end
267
308
  end
data/rocket_tag.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "rocket_tag"
8
- s.version = "0.5.0"
8
+ s.version = "0.5.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Brad Phelan"]
12
- s.date = "2012-06-26"
12
+ s.date = "2012-06-29"
13
13
  s.description = ""
14
14
  s.email = "bradphelan@xtargets.com"
15
15
  s.extra_rdoc_files = [
@@ -306,18 +306,16 @@ describe TaggableModel do
306
306
  end
307
307
  end
308
308
 
309
- describe "#tagged_with_sifter" do
310
- it "should be the work horse of #tagged_with but returns a sifter that can be composed into other queries" do
309
+ describe "Using in subqueries" do
310
+ it "should be possible to select the 'id' of the relation to use in a subquery" do
311
+
311
312
  TaggableModel.where do
312
- TaggableModel.tagged_with_sifter(["a", "b"]) & TaggableModel.tagged_with_sifter(["c"])
313
+ id.in(TaggableModel.tagged_with(["a", "b"]).select{id}) &
314
+ id.in(TaggableModel.tagged_with(["c"]).select{id})
313
315
  end.count.should == 2
314
316
 
315
- x = TaggableModel.where do
316
- TaggableModel.tagged_with_sifter(["a", "b"]) & TaggableModel.tagged_with_sifter(["c"])
317
- end.to_sql
318
-
319
317
  TaggableModel.where do
320
- TaggableModel.tagged_with_sifter(["a", "b"])
318
+ id.in(TaggableModel.tagged_with(["a", "b"]).select{id})
321
319
  end.count.should == 4
322
320
  end
323
321
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rocket_tag
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.5.0
5
+ version: 0.5.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Brad Phelan
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-06-26 00:00:00 Z
13
+ date: 2012-06-29 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -144,7 +144,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
144
144
  requirements:
145
145
  - - ">="
146
146
  - !ruby/object:Gem::Version
147
- hash: -285597818413014276
147
+ hash: 88231840862745454
148
148
  segments:
149
149
  - 0
150
150
  version: "0"