datastax_rails 1.0.14.10 → 1.0.15
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/lib/datastax_rails/grouped_collection.rb +9 -0
- data/lib/datastax_rails/relation/search_methods.rb +20 -5
- data/lib/datastax_rails/relation.rb +42 -15
- data/lib/datastax_rails/tasks/column_family.rb +1 -0
- data/lib/datastax_rails/version.rb +1 -1
- data/lib/datastax_rails.rb +1 -0
- data/spec/datastax_rails/cql/update_spec.rb +1 -1
- data/spec/datastax_rails/relation_spec.rb +28 -0
- data/spec/dummy/log/test.log +1943 -0
- metadata +5 -5
@@ -96,15 +96,30 @@ module DatastaxRails
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
-
# Group results by
|
100
|
-
# for each group.
|
99
|
+
# Group results by a given attribute only returning the top results
|
100
|
+
# for each group. In Lucene, this is often referred to as Field Collapsing.
|
101
|
+
#
|
102
|
+
# This modifies the behavior of pagination. When using a group, +per_page+ will
|
103
|
+
# specify the number of results returned *for each group*. In addition, +page+
|
104
|
+
# will move all groups forward by one page possibly resulting in some groups
|
105
|
+
# getting dropped off if they have fewer matching entires than others.
|
106
|
+
#
|
107
|
+
# When grouping is being used, the sort values will be used to sort results within
|
108
|
+
# a given group. Any sorting of the groups themselves will need to be handled
|
109
|
+
# after-the-fact as the groups are returned as hash of Collection objects.
|
110
|
+
#
|
111
|
+
# Because SOLR is doing the grouping work, we can only group on single-valued
|
112
|
+
# fields (i.e., not +text+ or +array+ attributes). In the future, SOLR may
|
113
|
+
# support grouping on multi-valued fields.
|
114
|
+
#
|
115
|
+
# NOTE: Group names will be lower-cased
|
101
116
|
#
|
102
117
|
# Model.group(:program_id)
|
103
|
-
def group(
|
104
|
-
return self if
|
118
|
+
def group(attribute)
|
119
|
+
return self if attribute.blank?
|
105
120
|
|
106
121
|
clone.tap do |r|
|
107
|
-
r.
|
122
|
+
r.group_value = attribute
|
108
123
|
end
|
109
124
|
end
|
110
125
|
|
@@ -2,8 +2,8 @@ require 'rsolr'
|
|
2
2
|
|
3
3
|
module DatastaxRails
|
4
4
|
class Relation
|
5
|
-
MULTI_VALUE_METHODS = [:
|
6
|
-
SINGLE_VALUE_METHODS = [:page, :per_page, :reverse_order, :query_parser, :consistency, :ttl, :use_solr, :escape]
|
5
|
+
MULTI_VALUE_METHODS = [:order, :where, :where_not, :fulltext, :greater_than, :less_than, :select]
|
6
|
+
SINGLE_VALUE_METHODS = [:page, :per_page, :reverse_order, :query_parser, :consistency, :ttl, :use_solr, :escape, :group]
|
7
7
|
|
8
8
|
SOLR_CHAR_RX = /([\+\!\(\)\[\]\^\"\~\:\'\=]+)/
|
9
9
|
|
@@ -74,6 +74,9 @@ module DatastaxRails
|
|
74
74
|
# If the relation has not been populated yet, a limit of 1 will be
|
75
75
|
# placed on the query before it is executed.
|
76
76
|
#
|
77
|
+
# For a grouped query, this still returns the total number of
|
78
|
+
# matching documents
|
79
|
+
#
|
77
80
|
# Compare with #size.
|
78
81
|
#
|
79
82
|
# XXX: Count via CQL is useless unless criteria has been applied.
|
@@ -164,9 +167,12 @@ module DatastaxRails
|
|
164
167
|
# the number of results in the current page. DatastaxRails models
|
165
168
|
# can have a +default_page_size+ set which will cause them to be
|
166
169
|
# paginated all the time.
|
170
|
+
#
|
171
|
+
# For a grouped query, this returns the size of the largest group.
|
172
|
+
#
|
167
173
|
# Compare with #count
|
168
174
|
def size
|
169
|
-
return @results.size if loaded?
|
175
|
+
return @results.size if loaded? && !@group_value
|
170
176
|
total_entries = count
|
171
177
|
(per_page_value && total_entries > per_page_value) ? per_page_value : total_entries
|
172
178
|
end
|
@@ -184,7 +190,7 @@ module DatastaxRails
|
|
184
190
|
return @results if loaded?
|
185
191
|
if use_solr_value
|
186
192
|
@results = query_via_solr
|
187
|
-
@count = @results.total_entries
|
193
|
+
@count = @group_value ? @results.total_for_all : @results.total_entries
|
188
194
|
else
|
189
195
|
@results = query_via_cql
|
190
196
|
end
|
@@ -245,7 +251,8 @@ module DatastaxRails
|
|
245
251
|
# Runs the query with a limit of 1 just to grab the total results attribute off
|
246
252
|
# the result set.
|
247
253
|
def count_via_solr
|
248
|
-
limit(1).select(:id).to_a
|
254
|
+
results = limit(1).select(:id).to_a
|
255
|
+
@group_value ? results.total_for_all : results.total_entries
|
249
256
|
end
|
250
257
|
|
251
258
|
# Escapes values that might otherwise mess up the URL or confuse SOLR.
|
@@ -325,24 +332,44 @@ module DatastaxRails
|
|
325
332
|
|
326
333
|
select_columns = select_values.empty? ? (@klass.attribute_definitions.keys - @klass.lazy_attributes) : select_values.flatten
|
327
334
|
|
328
|
-
|
329
|
-
|
335
|
+
if(@group_value)
|
336
|
+
results = DatastaxRails::GroupedCollection.new
|
337
|
+
params[:group] = 'true'
|
338
|
+
params['group.field'] = @group_value
|
339
|
+
params['group.limit'] = @per_page_value
|
340
|
+
params['group.offset'] = (@page_value - 1) * @per_page_value
|
341
|
+
params['group.ngroups'] = 'true'
|
342
|
+
response = rsolr.post('select', :params => params)["grouped"][@group_value.to_s]
|
343
|
+
results.total_groups = response['ngroups'].to_i
|
344
|
+
results.total_for_all = response['matches'].to_i
|
345
|
+
results.total_entries = 0
|
346
|
+
response['groups'].each do |group|
|
347
|
+
results[group['groupValue']] = parse_docs(group['doclist'], select_columns)
|
348
|
+
results.total_entries = results[group['groupValue']].total_entries if results[group['groupValue']].total_entries > results.total_entries
|
349
|
+
end
|
350
|
+
else
|
351
|
+
response = rsolr.paginate(@page_value, @per_page_value, 'select', :params => params)["response"]
|
352
|
+
results = parse_docs(response, select_columns)
|
353
|
+
end
|
354
|
+
results
|
355
|
+
end
|
356
|
+
|
357
|
+
|
358
|
+
def parse_docs(response, select_columns)
|
330
359
|
results = DatastaxRails::Collection.new
|
331
360
|
results.total_entries = response['numFound'].to_i
|
332
|
-
|
333
|
-
|
334
|
-
|
361
|
+
response['docs'].each do |doc|
|
362
|
+
id = doc['id']
|
363
|
+
if(@consistency_value)
|
335
364
|
obj = @klass.with_cassandra.consistency(@consistency_value).find_by_id(id)
|
336
365
|
results << obj if obj
|
337
|
-
|
338
|
-
|
339
|
-
response['docs'].each do |doc|
|
340
|
-
key = doc.delete('id')
|
341
|
-
results << @klass.instantiate(key,doc, select_columns)
|
366
|
+
else
|
367
|
+
results << @klass.instantiate(id, doc, select_columns)
|
342
368
|
end
|
343
369
|
end
|
344
370
|
results
|
345
371
|
end
|
372
|
+
protected(:parse_docs)
|
346
373
|
|
347
374
|
def inspect(just_me = false)
|
348
375
|
just_me ? super() : to_a.inspect
|
@@ -109,6 +109,7 @@ module DatastaxRails
|
|
109
109
|
solr_url = "#{DatastaxRails::Base.solr_base_url}/resource/#{DatastaxRails::Base.config[:keyspace]}.#{model.column_family}"
|
110
110
|
uri = URI.parse(solr_url)
|
111
111
|
Net::HTTP.start(uri.host, uri.port) do |http|
|
112
|
+
http.read_timeout(300)
|
112
113
|
if force || solrconfig_digest != sm_digests['solrconfig']
|
113
114
|
puts "Posting Solr Config file to '#{solr_url}/solrconfig.xml'"
|
114
115
|
http.post(uri.path+"/solrconfig.xml", solrconfig)
|
data/lib/datastax_rails.rb
CHANGED
@@ -8,7 +8,7 @@ describe DatastaxRails::Cql::Update do
|
|
8
8
|
it "should generate valid CQL" do
|
9
9
|
cql = DatastaxRails::Cql::Update.new(@model_class, "12345")
|
10
10
|
cql.using(DatastaxRails::Cql::Consistency::QUORUM).columns(:name => 'John', :age => '23')
|
11
|
-
cql.to_cql.should
|
11
|
+
cql.to_cql.should match(/update users using consistency QUORUM SET (name = 'John', age = '23'|age = '23', name = 'John') WHERE KEY IN \('12345'\)/)
|
12
12
|
end
|
13
13
|
|
14
14
|
it_has_behavior "default_consistency"
|
@@ -127,4 +127,32 @@ describe DatastaxRails::Relation do
|
|
127
127
|
relation.total_pages.should == 4
|
128
128
|
end
|
129
129
|
end
|
130
|
+
|
131
|
+
describe "grouped queries" do
|
132
|
+
before(:each) do
|
133
|
+
Person.create(:name => 'John', :nickname => 'J')
|
134
|
+
Person.create(:name => 'Jason', :nickname => 'J')
|
135
|
+
Person.create(:name => 'James', :nickname => 'J')
|
136
|
+
Person.create(:name => 'Kathrine', :nickname => 'Kat')
|
137
|
+
Person.create(:name => 'Kathy', :nickname => 'Kat')
|
138
|
+
Person.create(:name => 'Steven', :nickname => 'Steve')
|
139
|
+
Person.commit_solr
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should return matching documents grouped by an attribute" do
|
143
|
+
results = Person.group(:nickname).all
|
144
|
+
results['j'].should have(3).items
|
145
|
+
results['kat'].should have(2).items
|
146
|
+
results['steve'].should have(1).item
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should return total_entires as the highest value of any group" do
|
150
|
+
results = Person.group(:nickname).all
|
151
|
+
results.total_entries.should eq(3)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should still return a total count when using the count method" do
|
155
|
+
results = Person.group(:nickname).count.should eq(6)
|
156
|
+
end
|
157
|
+
end
|
130
158
|
end
|