datastax_rails 1.2.3 → 2.0.3
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.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.rdoc +20 -8
- data/config/schema.xml.erb +22 -19
- data/config/solrconfig.xml.erb +1 -1
- data/lib/cql-rb_extensions.rb +27 -0
- data/lib/datastax_rails.rb +13 -17
- data/lib/datastax_rails/associations/association.rb +1 -4
- data/lib/datastax_rails/associations/collection_proxy.rb +0 -13
- data/lib/datastax_rails/attribute_assignment.rb +28 -91
- data/lib/datastax_rails/attribute_methods.rb +109 -44
- data/lib/datastax_rails/attribute_methods/before_type_cast.rb +71 -0
- data/lib/datastax_rails/attribute_methods/dirty.rb +52 -11
- data/lib/datastax_rails/attribute_methods/primary_key.rb +87 -0
- data/lib/datastax_rails/attribute_methods/read.rb +120 -0
- data/lib/datastax_rails/attribute_methods/typecasting.rb +52 -21
- data/lib/datastax_rails/attribute_methods/write.rb +59 -0
- data/lib/datastax_rails/base.rb +227 -236
- data/lib/datastax_rails/cassandra_only_model.rb +25 -19
- data/lib/datastax_rails/column.rb +384 -0
- data/lib/datastax_rails/connection.rb +12 -13
- data/lib/datastax_rails/cql/alter_column_family.rb +0 -1
- data/lib/datastax_rails/cql/base.rb +15 -3
- data/lib/datastax_rails/cql/column_family.rb +2 -2
- data/lib/datastax_rails/cql/create_column_family.rb +7 -18
- data/lib/datastax_rails/cql/delete.rb +4 -9
- data/lib/datastax_rails/cql/insert.rb +2 -8
- data/lib/datastax_rails/cql/select.rb +4 -4
- data/lib/datastax_rails/cql/update.rb +8 -17
- data/lib/datastax_rails/dynamic_model.rb +98 -0
- data/lib/datastax_rails/payload_model.rb +19 -31
- data/lib/datastax_rails/persistence.rb +39 -54
- data/lib/datastax_rails/railtie.rb +1 -0
- data/lib/datastax_rails/reflection.rb +1 -1
- data/lib/datastax_rails/relation.rb +20 -20
- data/lib/datastax_rails/relation/batches.rb +18 -16
- data/lib/datastax_rails/relation/facet_methods.rb +1 -1
- data/lib/datastax_rails/relation/finder_methods.rb +6 -10
- data/lib/datastax_rails/relation/search_methods.rb +62 -48
- data/lib/datastax_rails/rsolr_client_wrapper.rb +1 -1
- data/lib/datastax_rails/schema/cassandra.rb +34 -62
- data/lib/datastax_rails/schema/migrator.rb +9 -24
- data/lib/datastax_rails/schema/solr.rb +13 -30
- data/lib/datastax_rails/schema_cache.rb +67 -0
- data/lib/datastax_rails/timestamps.rb +84 -11
- data/lib/datastax_rails/types/dirty_collection.rb +88 -0
- data/lib/datastax_rails/types/dynamic_list.rb +14 -0
- data/lib/datastax_rails/types/dynamic_map.rb +32 -0
- data/lib/datastax_rails/types/dynamic_set.rb +10 -0
- data/lib/datastax_rails/util/solr_repair.rb +4 -5
- data/lib/datastax_rails/validations.rb +6 -12
- data/lib/datastax_rails/validations/uniqueness.rb +0 -4
- data/lib/datastax_rails/version.rb +1 -1
- data/lib/datastax_rails/wide_storage_model.rb +13 -29
- data/lib/schema_migration.rb +4 -0
- data/spec/datastax_rails/associations_spec.rb +0 -1
- data/spec/datastax_rails/attribute_methods_spec.rb +9 -6
- data/spec/datastax_rails/base_spec.rb +26 -0
- data/spec/datastax_rails/column_spec.rb +238 -0
- data/spec/datastax_rails/cql/select_spec.rb +1 -1
- data/spec/datastax_rails/cql/update_spec.rb +2 -2
- data/spec/datastax_rails/persistence_spec.rb +29 -15
- data/spec/datastax_rails/relation/batches_spec.rb +5 -5
- data/spec/datastax_rails/relation/finder_methods_spec.rb +0 -20
- data/spec/datastax_rails/relation/search_methods_spec.rb +8 -0
- data/spec/datastax_rails/relation_spec.rb +7 -0
- data/spec/datastax_rails/schema/migrator_spec.rb +5 -10
- data/spec/datastax_rails/schema/solr_spec.rb +1 -1
- data/spec/datastax_rails/types/dynamic_list_spec.rb +20 -0
- data/spec/datastax_rails/types/dynamic_map_spec.rb +22 -0
- data/spec/datastax_rails/types/dynamic_set_spec.rb +16 -0
- data/spec/dummy/config/application.rb +2 -1
- data/spec/dummy/config/datastax.yml +6 -3
- data/spec/dummy/config/environments/development.rb +4 -5
- data/spec/dummy/config/environments/test.rb +0 -5
- data/spec/dummy/log/development.log +18 -0
- data/spec/dummy/log/test.log +36 -0
- data/spec/feature/dynamic_fields_spec.rb +9 -0
- data/spec/feature/overloaded_tables_spec.rb +24 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/default_consistency_shared_examples.rb +2 -2
- data/spec/support/models.rb +28 -14
- metadata +212 -188
- data/lib/datastax_rails/identity.rb +0 -64
- data/lib/datastax_rails/identity/abstract_key_factory.rb +0 -29
- data/lib/datastax_rails/identity/custom_key_factory.rb +0 -37
- data/lib/datastax_rails/identity/hashed_natural_key_factory.rb +0 -10
- data/lib/datastax_rails/identity/natural_key_factory.rb +0 -39
- data/lib/datastax_rails/identity/uuid_key_factory.rb +0 -27
- data/lib/datastax_rails/type.rb +0 -16
- data/lib/datastax_rails/types.rb +0 -9
- data/lib/datastax_rails/types/array_type.rb +0 -86
- data/lib/datastax_rails/types/base_type.rb +0 -42
- data/lib/datastax_rails/types/binary_type.rb +0 -19
- data/lib/datastax_rails/types/boolean_type.rb +0 -22
- data/lib/datastax_rails/types/date_type.rb +0 -23
- data/lib/datastax_rails/types/float_type.rb +0 -18
- data/lib/datastax_rails/types/integer_type.rb +0 -18
- data/lib/datastax_rails/types/string_type.rb +0 -16
- data/lib/datastax_rails/types/text_type.rb +0 -15
- data/lib/datastax_rails/types/time_type.rb +0 -23
- data/spec/datastax_rails/types/float_type_spec.rb +0 -31
- data/spec/datastax_rails/types/integer_type_spec.rb +0 -31
- data/spec/datastax_rails/types/time_type_spec.rb +0 -28
@@ -20,7 +20,8 @@ module DatastaxRails
|
|
20
20
|
if keys.last.is_a?(Hash)
|
21
21
|
options = keys.pop
|
22
22
|
end
|
23
|
-
|
23
|
+
keys = keys.flatten.collect {|k| self.attribute_definitions[self.primary_key].type_cast(k)}
|
24
|
+
ActiveSupport::Notifications.instrument("remove.datastax_rails", :column_family => column_family, :key => keys) do
|
24
25
|
c = cql.delete(keys)
|
25
26
|
if(options[:consistency])
|
26
27
|
level = options[:consistency].to_s.upcase
|
@@ -50,24 +51,22 @@ module DatastaxRails
|
|
50
51
|
|
51
52
|
# Write a record to cassandra. Can be either an insert or an update (they are exactly the same to cassandra)
|
52
53
|
#
|
53
|
-
# @param [
|
54
|
-
# @param [Hash] attributes a hash containing the columns to set on the record
|
54
|
+
# @param [DatastaxRails::Base] record the record that we are writing
|
55
55
|
# @param [Hash] options a hash containing various options
|
56
56
|
# @option options [Symbol] :consistency the consistency to set for the Cassandra operation (e.g., ALL)
|
57
|
-
def write(
|
58
|
-
attributes = encode_attributes(attributes)
|
57
|
+
def write(record, options = {})
|
59
58
|
level = (options[:consistency] || self.default_consistency).to_s.upcase
|
60
59
|
if(valid_consistency?(level))
|
61
60
|
options[:consistency] = level
|
62
61
|
else
|
63
62
|
raise ArgumentError, "'#{level}' is not a valid Cassandra consistency level"
|
64
63
|
end
|
65
|
-
|
66
|
-
ActiveSupport::Notifications.instrument("insert.datastax_rails", :column_family => column_family, :key => key, :attributes => attributes) do
|
64
|
+
record.id.tap do |key|
|
65
|
+
ActiveSupport::Notifications.instrument("insert.datastax_rails", :column_family => column_family, :key => key.to_s, :attributes => record.attributes) do
|
67
66
|
if(self.storage_method == :solr)
|
68
|
-
write_with_solr(
|
67
|
+
write_with_solr(record, options)
|
69
68
|
else
|
70
|
-
write_with_cql(
|
69
|
+
write_with_cql(record, options)
|
71
70
|
end
|
72
71
|
end
|
73
72
|
end
|
@@ -81,49 +80,40 @@ module DatastaxRails
|
|
81
80
|
# to build this object. Used so that we can avoid lazy-loading attributes that don't exist.
|
82
81
|
# @return [DatastaxRails::Base] a model with the given attributes
|
83
82
|
def instantiate(key, attributes, selected_attributes = [])
|
84
|
-
allocate.
|
85
|
-
object.instance_variable_set("@loaded_attributes", {}.with_indifferent_access)
|
86
|
-
object.instance_variable_set("@key", parse_key(key)) if key
|
87
|
-
object.instance_variable_set("@new_record", false)
|
88
|
-
object.instance_variable_set("@destroyed", false)
|
89
|
-
object.instance_variable_set("@attributes", typecast_attributes(object, attributes, selected_attributes).with_indifferent_access)
|
90
|
-
end
|
83
|
+
allocate.init_with('attributes' => attributes)
|
91
84
|
end
|
92
|
-
|
85
|
+
|
93
86
|
# Encodes the attributes in preparation for storing in cassandra. Calls the coders on the various type classes
|
94
87
|
# to do the heavy lifting.
|
95
88
|
#
|
96
|
-
# @param [
|
89
|
+
# @param [DatastaxRails::Base] record the record whose attributes we're encoding
|
90
|
+
# @param [Boolean] cql True if we're formatting for CQL, otherwise False
|
97
91
|
# @return [Hash] a new hash with attributes encoded for storage
|
98
|
-
def encode_attributes(
|
92
|
+
def encode_attributes(record, cql)
|
99
93
|
encoded = {}
|
100
|
-
|
101
|
-
|
94
|
+
Types::DirtyCollection.ignore_modifications do
|
95
|
+
record.changed.each do |column_name|
|
96
|
+
value = record.read_attribute(column_name)
|
97
|
+
encoded[column_name.to_s] = cql ? attribute_definitions[column_name].type_cast_for_cql3(value) :
|
98
|
+
attribute_definitions[column_name].type_cast_for_solr(value)
|
99
|
+
end
|
102
100
|
end
|
103
101
|
encoded
|
104
102
|
end
|
105
|
-
|
106
|
-
def typecast_attributes(object, attributes, selected_attributes = [])
|
107
|
-
attributes = attributes.symbolize_keys
|
108
|
-
casted = {}
|
109
|
-
|
110
|
-
selected_attributes.each do |att|
|
111
|
-
object.loaded_attributes[att] = true
|
112
|
-
end
|
113
|
-
|
114
|
-
attribute_definitions.each do |k,definition|
|
115
|
-
casted[k.to_s] = definition.instantiate(object, attributes[k.to_sym])#.to_s
|
116
|
-
end
|
117
|
-
casted
|
118
|
-
end
|
119
103
|
|
120
104
|
private
|
121
|
-
def write_with_cql(
|
122
|
-
|
105
|
+
def write_with_cql(record, options)
|
106
|
+
encoded = encode_attributes(record, true)
|
107
|
+
if options[:new_record]
|
108
|
+
cql.insert.columns(encoded).using(options[:consistency]).execute
|
109
|
+
else
|
110
|
+
cql.update(record.id).columns(encoded).using(options[:consistency]).execute
|
111
|
+
end
|
123
112
|
end
|
124
113
|
|
125
|
-
def write_with_solr(
|
126
|
-
|
114
|
+
def write_with_solr(record, options)
|
115
|
+
encoded = encode_attributes(record, false)
|
116
|
+
xml_doc = RSolr::Xml::Generator.new.add(encoded.merge(self.primary_key => record.id.to_s))
|
127
117
|
self.solr_connection.update(:data => xml_doc, :params => {:replacefields => false, :cl => options[:consistency]})
|
128
118
|
end
|
129
119
|
end
|
@@ -153,7 +143,7 @@ module DatastaxRails
|
|
153
143
|
end
|
154
144
|
|
155
145
|
def destroy(options = {})
|
156
|
-
self.class.remove(
|
146
|
+
self.class.remove(id, options)
|
157
147
|
@destroyed = true
|
158
148
|
freeze
|
159
149
|
end
|
@@ -173,20 +163,15 @@ module DatastaxRails
|
|
173
163
|
|
174
164
|
# Updates the attributes of the model from the passed-in hash and saves the
|
175
165
|
# record If the object is invalid, the saving will fail and false will be returned.
|
176
|
-
#
|
177
|
-
# When updating model attributes, mass-assignment security protection is respected.
|
178
|
-
# If no +:as+ option is supplied then the +:default+ role will be used.
|
179
|
-
# If you want to bypass the protection given by +attr_protected+ and
|
180
|
-
# +attr_accessible+ then you can do so using the +:without_protection+ option.
|
181
166
|
def update_attributes(attributes, options = {})
|
182
|
-
self.assign_attributes(attributes
|
167
|
+
self.assign_attributes(attributes)
|
183
168
|
save
|
184
169
|
end
|
185
170
|
|
186
171
|
# Updates its receiver just like +update_attributes+ but calls <tt>save!</tt> instead
|
187
172
|
# of +save+, so an exception is raised if the record is invalid.
|
188
173
|
def update_attributes!(attributes, options = {})
|
189
|
-
self.assign_attributes(attributes
|
174
|
+
self.assign_attributes(attributes)
|
190
175
|
save!
|
191
176
|
end
|
192
177
|
|
@@ -223,26 +208,26 @@ module DatastaxRails
|
|
223
208
|
|
224
209
|
private
|
225
210
|
def _create_or_update(options)
|
226
|
-
result = new_record? ?
|
211
|
+
result = new_record? ? _create_record(options) : _update_record(options)
|
227
212
|
result != false
|
228
213
|
end
|
229
214
|
|
230
|
-
def
|
231
|
-
|
215
|
+
def _create_record(options)
|
216
|
+
# TODO: handle the non-UUID case
|
217
|
+
self.id ||= ::Cql::TimeUuid::Generator.new.next
|
232
218
|
_write(options)
|
233
219
|
@new_record = false
|
234
|
-
|
220
|
+
self.id
|
235
221
|
end
|
236
222
|
|
237
|
-
def
|
223
|
+
def _update_record(options)
|
238
224
|
_write(options)
|
239
225
|
end
|
240
226
|
|
241
227
|
def _write(options) #:nodoc:
|
242
228
|
options[:new_record] = new_record?
|
243
|
-
changed_attributes = changed.inject({}) { |h, n| h[n] = read_attribute(n); h }
|
244
229
|
return true if changed_attributes.empty?
|
245
|
-
self.class.write(
|
230
|
+
self.class.write(self, options)
|
246
231
|
end
|
247
232
|
end
|
248
233
|
end
|
@@ -314,7 +314,7 @@ module DatastaxRails
|
|
314
314
|
# Gets the source of the through reflection. It checks both a singularized
|
315
315
|
# and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>.
|
316
316
|
#
|
317
|
-
# class Post <
|
317
|
+
# class Post < DatastaxRails::Base
|
318
318
|
# has_many :taggings
|
319
319
|
# has_many :tags, :through => :taggings
|
320
320
|
# end
|
@@ -250,8 +250,6 @@ module DatastaxRails
|
|
250
250
|
when true
|
251
251
|
return :solr
|
252
252
|
else
|
253
|
-
# If we've already decided to use cassandra, just go with it.
|
254
|
-
return :cassandra unless use_solr_value
|
255
253
|
[order_values, where_not_values, fulltext_values, greater_than_values, less_than_values, field_facet_values,
|
256
254
|
range_facet_values, group_value].each do |solr_only_stuff|
|
257
255
|
return :solr unless solr_only_stuff.blank?
|
@@ -260,8 +258,7 @@ module DatastaxRails
|
|
260
258
|
return :solr unless page_value == 1
|
261
259
|
@where_values.each do |wv|
|
262
260
|
wv.each do |k,v|
|
263
|
-
|
264
|
-
if(klass.attribute_definitions[k].indexed == :solr || !klass.attribute_definitions[k].indexed)
|
261
|
+
unless klass.column_for_attribute(k).options[:cql_index]
|
265
262
|
return :solr
|
266
263
|
end
|
267
264
|
end
|
@@ -292,7 +289,7 @@ module DatastaxRails
|
|
292
289
|
cql.conditions(wv)
|
293
290
|
end
|
294
291
|
cql.allow_filtering if @allow_filtering_value
|
295
|
-
|
292
|
+
cql.execute.first['count']
|
296
293
|
end
|
297
294
|
|
298
295
|
# Constructs a CQL query and runs it against Cassandra directly. For this to
|
@@ -300,15 +297,15 @@ module DatastaxRails
|
|
300
297
|
# For ad-hoc queries, you will have to use Solr.
|
301
298
|
def query_via_cql
|
302
299
|
select_columns = select_values.empty? ? (@klass.attribute_definitions.keys - @klass.lazy_attributes) : select_values.flatten
|
303
|
-
cql = @cql.select((select_columns + @klass.
|
300
|
+
cql = @cql.select((select_columns + [@klass.primary_key]).uniq)
|
304
301
|
cql.using(@consistency_value) if @consistency_value
|
305
302
|
@where_values.each do |wv|
|
306
|
-
cql.conditions(Hash[wv.map {|k,v| [(k.
|
303
|
+
cql.conditions(Hash[wv.map {|k,v| [(k.to_s == 'id' ? @klass.primary_key : k), v]}])
|
307
304
|
end
|
308
305
|
@greater_than_values.each do |gtv|
|
309
306
|
gtv.each do |k,v|
|
310
307
|
# Special case if inequality is equal to the primary key (we're paginating)
|
311
|
-
if(k ==
|
308
|
+
if(k.to_s == @klass.primary_key)
|
312
309
|
cql.paginate(v)
|
313
310
|
end
|
314
311
|
end
|
@@ -319,10 +316,10 @@ module DatastaxRails
|
|
319
316
|
cql.allow_filtering if @allow_filtering_value
|
320
317
|
results = []
|
321
318
|
begin
|
322
|
-
|
323
|
-
results << @klass.instantiate(row[
|
319
|
+
cql.execute.each do |row|
|
320
|
+
results << @klass.instantiate(row[@klass.primary_key], row, select_columns)
|
324
321
|
end
|
325
|
-
rescue
|
322
|
+
rescue ::Cql::CqlError => e # TODO: Break out the various exception types
|
326
323
|
# If we get an exception about an empty key, ignore it. We'll return an empty set.
|
327
324
|
if e.message =~ /Key may not be empty/
|
328
325
|
# No-Op
|
@@ -377,7 +374,7 @@ module DatastaxRails
|
|
377
374
|
|
378
375
|
def full_solr_range(attr)
|
379
376
|
if(self.klass.attribute_definitions[attr])
|
380
|
-
self.klass.attribute_definitions[attr].
|
377
|
+
self.klass.attribute_definitions[attr].full_solr_range
|
381
378
|
else
|
382
379
|
'[\"\" TO *]'
|
383
380
|
end
|
@@ -495,8 +492,9 @@ module DatastaxRails
|
|
495
492
|
end
|
496
493
|
|
497
494
|
select_columns = select_values.empty? ? (@klass.attribute_definitions.keys - @klass.lazy_attributes) : select_values.flatten
|
498
|
-
select_columns <<
|
499
|
-
|
495
|
+
select_columns << @klass.primary_key
|
496
|
+
select_columns.collect! {|c| @klass.column_for_attribute(c).try(:type) == :map ? "#{c.to_s}*" : c.to_s}
|
497
|
+
params[:fl] = select_columns.uniq.join(",")
|
500
498
|
unless(@stats_values.empty?)
|
501
499
|
params[:stats] = 'true'
|
502
500
|
@stats_values.flatten.each do |sv|
|
@@ -556,12 +554,11 @@ module DatastaxRails
|
|
556
554
|
results.current_page = @page_value || 1
|
557
555
|
results.total_entries = response['numFound'].to_i
|
558
556
|
response['docs'].each do |doc|
|
559
|
-
id = doc[
|
557
|
+
id = @klass.attribute_definitions[@klass.primary_key].type_cast(doc[@klass.primary_key])
|
560
558
|
if(@consistency_value)
|
561
559
|
obj = @klass.with_cassandra.consistency(@consistency_value).find_by_id(id)
|
562
560
|
results << obj if obj
|
563
561
|
else
|
564
|
-
#byebug
|
565
562
|
results << @klass.instantiate(id, doc, select_columns)
|
566
563
|
end
|
567
564
|
end
|
@@ -607,20 +604,23 @@ module DatastaxRails
|
|
607
604
|
rsolr.commit :commit_attributes => {}
|
608
605
|
end
|
609
606
|
|
607
|
+
SOLR_DATE_REGEX = /(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z)/i
|
610
608
|
# Everything that gets indexed into solr is downcased as part of the analysis phase.
|
611
609
|
# Normally, this is done to the query as well, but if your query includes wildcards
|
612
610
|
# then analysis isn't performed. This means that the query does not get downcased.
|
613
611
|
# We therefore need to perform the downcasing ourselves. This does it while still
|
614
|
-
# leaving boolean operations (AND, OR, NOT) upcased.
|
612
|
+
# leaving boolean operations (AND, OR, NOT, TO) and dates upcased.
|
615
613
|
def downcase_query(value)
|
616
614
|
if(value.is_a?(String))
|
617
615
|
value.split(/\bAND\b/).collect do |a|
|
618
616
|
a.split(/\bOR\b/).collect do |o|
|
619
|
-
o.split(/\bNOT\b/).collect do |n|
|
620
|
-
n.
|
617
|
+
o.split(/\bNOT\b/).collect do |n|
|
618
|
+
n.split(/\bTO\b/).collect do |t|
|
619
|
+
t.downcase
|
620
|
+
end.join("TO")
|
621
621
|
end.join("NOT")
|
622
622
|
end.join("OR")
|
623
|
-
end.join("AND")
|
623
|
+
end.join("AND").gsub(SOLR_DATE_REGEX) { $1.upcase }
|
624
624
|
else
|
625
625
|
value
|
626
626
|
end
|
@@ -6,7 +6,7 @@ module DatastaxRails
|
|
6
6
|
#
|
7
7
|
# Example:
|
8
8
|
#
|
9
|
-
# Person.where(
|
9
|
+
# Person.where(in_college: true).find_each do |person|
|
10
10
|
# person.party_all_night!
|
11
11
|
# end
|
12
12
|
#
|
@@ -15,6 +15,9 @@ module DatastaxRails
|
|
15
15
|
# you just need to loop over less than 1000 records, it's probably
|
16
16
|
# better just to use the regular find methods.
|
17
17
|
#
|
18
|
+
# You can also pass the +:start+ option to specify an offset to
|
19
|
+
# control the starting point.
|
20
|
+
#
|
18
21
|
# @param options [Hash] finder options
|
19
22
|
# @yield [record] a single DatastaxRails record
|
20
23
|
def find_each(options = {})
|
@@ -23,6 +26,7 @@ module DatastaxRails
|
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
29
|
+
# Same as {find_each} but yields the index as a second parameter.
|
26
30
|
def find_each_with_index(options = {})
|
27
31
|
idx = 0
|
28
32
|
find_in_batches(options) do |records|
|
@@ -44,30 +48,29 @@ module DatastaxRails
|
|
44
48
|
# worker 2 handle from 10,000 and beyond (by setting the <tt>:start</tt>
|
45
49
|
# option on that worker).
|
46
50
|
#
|
47
|
-
# It's not possible to set the order.
|
48
|
-
# Cassandra's key placement strategy.
|
49
|
-
#
|
50
|
-
#
|
51
|
-
# You can't set the limit, however. That's used to control the batch sizes.
|
51
|
+
# It's not possible to set the order. For Cassandra based batching, the
|
52
|
+
# order is set according to Cassandra's key placement strategy. For Solr
|
53
|
+
# based batching, the order is ascending order of the primary key.
|
54
|
+
# You can't set the limit either. That's used to control the batch sizes.
|
52
55
|
#
|
53
56
|
# Example:
|
54
57
|
#
|
55
|
-
# Person.where(
|
58
|
+
# Person.where(in_college: true).find_in_batches do |group|
|
56
59
|
# sleep(50) # Make sure it doesn't get too crowded in there!
|
57
60
|
# group.each { |person| person.party_all_night! }
|
58
61
|
# end
|
59
62
|
#
|
60
63
|
# @param options [Hash] finder options
|
61
|
-
# @
|
64
|
+
# @yield [records] a batch of DatastaxRails records
|
62
65
|
def find_in_batches(options = {})
|
63
66
|
relation = self
|
64
67
|
|
65
|
-
unless (@order_values.empty?
|
68
|
+
unless (@order_values.empty?)
|
66
69
|
DatastaxRails::Base.logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size")
|
67
70
|
end
|
68
71
|
|
69
72
|
if (finder_options = options.except(:start, :batch_size)).present?
|
70
|
-
raise "You can't specify an order, it's forced to be #{
|
73
|
+
raise "You can't specify an order, it's forced to be #{@klass.primary_key}" if options[:order].present?
|
71
74
|
raise "You can't specify a limit, it's forced to be the batch_size" if options[:limit].present?
|
72
75
|
|
73
76
|
relation = apply_finder_options(finder_options)
|
@@ -76,21 +79,20 @@ module DatastaxRails
|
|
76
79
|
start = options.delete(:start)
|
77
80
|
batch_size = options.delete(:batch_size) || 1000
|
78
81
|
|
79
|
-
batch_order = (relation.use_solr_value ? :created_at : :key)
|
80
82
|
relation = relation.limit(batch_size)
|
81
|
-
relation = relation.order(
|
82
|
-
records = start ? relation.where(
|
83
|
+
relation = relation.order(@klass.primary_key) if relation.use_solr_value
|
84
|
+
records = start ? relation.where(@klass.primary_key).greater_than(start).to_a : relation.to_a
|
83
85
|
while records.size > 0
|
84
86
|
records_size = records.size
|
85
|
-
offset =
|
87
|
+
offset = records.last.id
|
86
88
|
yield records
|
87
89
|
|
88
90
|
break if records_size < batch_size
|
89
91
|
if offset
|
90
92
|
if relation.use_solr_value
|
91
|
-
offset
|
93
|
+
offset = ::Cql::Uuid.new(offset.value+1)
|
92
94
|
end
|
93
|
-
records = relation.where(
|
95
|
+
records = relation.where(@klass.primary_key).greater_than(offset).to_a
|
94
96
|
else
|
95
97
|
raise "Batch order not included in the custom select clause"
|
96
98
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module DatastaxRails
|
2
2
|
module FacetMethods
|
3
3
|
# Instructs SOLR to get facet counts on the passed in field. Results are available in the facets accessor.
|
4
|
-
# Facets include Field and Range (Date is not supported as it is depricated in Solr).
|
4
|
+
# Facets include Field and Range (Date is not supported as it is depricated in Solr - use a range instead).
|
5
5
|
#
|
6
6
|
# results = Article.field_facet(:author)
|
7
7
|
# results.facets => {"author"=>["vonnegut", 2. "asimov", 3]}
|
@@ -140,15 +140,8 @@ module DatastaxRails
|
|
140
140
|
def find_by_attributes(match, attributes, *args) #:nodoc:
|
141
141
|
|
142
142
|
conditions = Hash[attributes.map {|a| [a, args[attributes.index(a)]]}]
|
143
|
-
|
144
|
-
self.where_values << escape_attributes(conditions)
|
145
|
-
result = self.send(match.finder)
|
146
|
-
elsif Rails.version =~ /^4.*/
|
147
|
-
result = self.send(match.finder, conditions)
|
148
|
-
end
|
143
|
+
result = self.send(match.finder, conditions)
|
149
144
|
|
150
|
-
#result = where(conditions).send(match.finder)
|
151
|
-
|
152
145
|
if match.blank? && result.blank?
|
153
146
|
raise RecordNotFound, "Couldn't find #{klass.name} with #{conditions.to_a.collect {|p| p.join('=')}.join(', ')}"
|
154
147
|
else
|
@@ -191,11 +184,14 @@ module DatastaxRails
|
|
191
184
|
end
|
192
185
|
|
193
186
|
def find_one(id)
|
194
|
-
|
187
|
+
key = @klass.attribute_definitions[@klass.primary_key].type_cast(id) || raise(RecordNotFound, "Couldn't find #{@klass.name} with an invalid ID=#{id}")
|
188
|
+
|
189
|
+
with_cassandra.where(@klass.primary_key => key).first || raise(RecordNotFound, "Couldn't find #{@klass.name} with ID=#{id}")
|
195
190
|
end
|
196
191
|
|
197
192
|
def find_some(ids)
|
198
|
-
|
193
|
+
keys = ids.collect {|id| @klass.attribute_definitions[@klass.primary_key].type_cast(id) || "Couldn't find #{@klass.name} with an invalid ID=#{id}"}
|
194
|
+
result = with_cassandra.where(@klass.primary_key => keys).all
|
199
195
|
|
200
196
|
expected_size =
|
201
197
|
if @limit_value && ids.size > @limit_value
|