datastax_rails 2.0.18 → 2.1.23

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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/config/solrconfig.xml.erb +7 -7
  3. data/lib/datastax_rails/associations/collection_association.rb +4 -4
  4. data/lib/datastax_rails/associations/has_many_association.rb +1 -1
  5. data/lib/datastax_rails/attribute_methods/dirty.rb +6 -0
  6. data/lib/datastax_rails/attribute_methods/primary_key.rb +9 -1
  7. data/lib/datastax_rails/attribute_methods/read.rb +2 -2
  8. data/lib/datastax_rails/attribute_methods/typecasting.rb +4 -7
  9. data/lib/datastax_rails/attribute_methods.rb +25 -0
  10. data/lib/datastax_rails/autosave_association.rb +3 -3
  11. data/lib/datastax_rails/base.rb +33 -11
  12. data/lib/datastax_rails/column.rb +25 -15
  13. data/lib/datastax_rails/connection.rb +1 -1
  14. data/lib/datastax_rails/cql/base.rb +31 -19
  15. data/lib/datastax_rails/cql/select.rb +2 -2
  16. data/lib/datastax_rails/dynamic_model.rb +1 -1
  17. data/lib/datastax_rails/errors.rb +3 -0
  18. data/lib/datastax_rails/instrumentation/controller_runtime.rb +52 -0
  19. data/lib/datastax_rails/instrumentation/log_subscriber.rb +92 -0
  20. data/lib/datastax_rails/instrumentation.rb +4 -0
  21. data/lib/datastax_rails/persistence.rb +49 -17
  22. data/lib/datastax_rails/railtie.rb +7 -0
  23. data/lib/datastax_rails/reflection.rb +16 -12
  24. data/lib/datastax_rails/relation/batches.rb +1 -1
  25. data/lib/datastax_rails/relation/finder_methods.rb +5 -5
  26. data/lib/datastax_rails/relation/modification_methods.rb +11 -26
  27. data/lib/datastax_rails/relation/search_methods.rb +10 -11
  28. data/lib/datastax_rails/relation.rb +81 -50
  29. data/lib/datastax_rails/scoping.rb +1 -1
  30. data/lib/datastax_rails/serialization.rb +10 -6
  31. data/lib/datastax_rails/serializers/xml_serializer.rb +3 -1
  32. data/lib/datastax_rails/tasks/ds.rake +25 -26
  33. data/lib/datastax_rails/timestamps.rb +1 -1
  34. data/lib/datastax_rails/types/dynamic_set.rb +4 -0
  35. data/lib/datastax_rails/version.rb +1 -1
  36. data/lib/datastax_rails/wide_storage_model.rb +3 -1
  37. data/lib/datastax_rails.rb +1 -0
  38. data/spec/datastax_rails/attribute_methods/read_spec.rb +33 -0
  39. data/spec/datastax_rails/attribute_methods/typecasting_spec.rb +25 -0
  40. data/spec/datastax_rails/base_spec.rb +1 -1
  41. data/spec/datastax_rails/callbacks_spec.rb +6 -0
  42. data/spec/datastax_rails/column_spec.rb +20 -0
  43. data/spec/datastax_rails/cql/base_spec.rb +1 -1
  44. data/spec/datastax_rails/cql/select_spec.rb +7 -1
  45. data/spec/datastax_rails/persistence_spec.rb +22 -3
  46. data/spec/datastax_rails/relation/finder_methods_spec.rb +13 -0
  47. data/spec/datastax_rails/relation/search_methods_spec.rb +37 -12
  48. data/spec/datastax_rails/serialization_spec.rb +17 -0
  49. data/spec/dummy/log/development.log +0 -24195
  50. data/spec/dummy/log/test.log +20 -15610
  51. data/spec/factories/hobbies.rb +1 -0
  52. data/spec/factories/jobs.rb +7 -0
  53. data/spec/factories/people.rb +1 -0
  54. data/spec/factories/person_roles.rb +7 -0
  55. data/spec/factories/roles.rb +6 -0
  56. data/spec/factories/uuid_keys.rb +6 -0
  57. data/spec/feature/associations_spec.rb +26 -0
  58. data/spec/support/models.rb +82 -0
  59. metadata +19 -4
  60. data/spec/dummy/log/production.log +0 -2
@@ -0,0 +1,52 @@
1
+ require 'active_support/core_ext/module/attr_internal'
2
+
3
+ module DatastaxRails
4
+ module Instrumentation
5
+ # Hooks into ActionController to display Solr and CQL runtime
6
+ #
7
+ # @see https://github.com/rails/rails/blob/master/activerecord/lib/active_record/railties/controller_runtime.rb
8
+ #
9
+ module ControllerRuntime
10
+ extend ActiveSupport::Concern
11
+
12
+ protected
13
+
14
+ attr_internal :solr_runtime
15
+ attr_internal :cql_runtime
16
+
17
+ def process_action(action, *args)
18
+ DatastaxRails::Instrumentation::LogSubscriber.reset_solr_runtime
19
+ DatastaxRails::Instrumentation::LogSubscriber.reset_cql_runtime
20
+ super
21
+ end
22
+
23
+ def cleanup_view_runtime
24
+ solr_rt_before_render = DatastaxRails::Instrumentation::LogSubscriber.reset_solr_runtime
25
+ cql_rt_before_render = DatastaxRails::Instrumentation::LogSubscriber.reset_cql_runtime
26
+ self.solr_runtime = (solr_runtime || 0) + solr_rt_before_render
27
+ self.cql_runtime = (cql_runtime || 0) + cql_rt_before_render
28
+ runtime = super
29
+ solr_rt_after_render = DatastaxRails::Instrumentation::LogSubscriber.reset_solr_runtime
30
+ cql_rt_after_render = DatastaxRails::Instrumentation::LogSubscriber.reset_cql_runtime
31
+ self.solr_runtime += solr_rt_after_render
32
+ self.cql_runtime += cql_rt_after_render
33
+ runtime - solr_rt_after_render - cql_rt_after_render
34
+ end
35
+
36
+ def append_info_to_payload(payload)
37
+ super
38
+ payload[:solr_runtime] = (solr_runtime || 0) + DatastaxRails::Instrumentation::LogSubscriber.reset_solr_runtime
39
+ payload[:cql_runtime] = (cql_runtime || 0) + DatastaxRails::Instrumentation::LogSubscriber.reset_cql_runtime
40
+ end
41
+
42
+ module ClassMethods
43
+ def log_process_action(payload)
44
+ messages, solr_runtime, cql_runtime = super, payload[:solr_runtime], payload[:cql_runtime]
45
+ messages << ('Solr: %.1fms' % solr_runtime.to_f) if solr_runtime
46
+ messages << ('CQL: %.1fms' % cql_runtime.to_f) if cql_runtime
47
+ messages
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,92 @@
1
+ module DatastaxRails
2
+ module Instrumentation
3
+ # A log subscriber to attach to Datastax related events
4
+ #
5
+ # @see https://github.com/rails/rails/blob/master/activerecord/lib/active_record/log_subscriber.rb
6
+ #
7
+ class LogSubscriber < ActiveSupport::LogSubscriber
8
+ def initialize(*args)
9
+ super
10
+ @odd = false
11
+ end
12
+
13
+ def self.solr_runtime=(value)
14
+ Thread.current['datastax_solr_runtime'] = value
15
+ end
16
+
17
+ def self.solr_runtime
18
+ Thread.current['datastax_solr_runtime'] ||= 0
19
+ end
20
+
21
+ def self.cql_runtime=(value)
22
+ Thread.current['datastax_cql_runtime'] = value
23
+ end
24
+
25
+ def self.cql_runtime
26
+ Thread.current['datastax_cql_runtime'] ||= 0
27
+ end
28
+
29
+ def self.reset_solr_runtime
30
+ rt, self.solr_runtime = solr_runtime, 0
31
+ rt
32
+ end
33
+
34
+ def self.reset_cql_runtime
35
+ rt, self.cql_runtime = cql_runtime, 0
36
+ rt
37
+ end
38
+
39
+ # Intercept `solr.datastax_rails` events, and display them in the Rails log
40
+ def solr(event)
41
+ self.class.solr_runtime += event.duration
42
+ return unless logger.debug? && DatastaxRails::Base.log_solr_queries
43
+
44
+ payload = event.payload
45
+
46
+ name = "#{payload[:klass]} #{payload[:name]} (#{event.duration.round(1)}ms)"
47
+ search = payload[:search].inspect.gsub(/:(\w+)=>/, '\1: ')
48
+
49
+ if odd?
50
+ name = color(name, CYAN, true)
51
+ search = color(search, nil, true)
52
+ else
53
+ name = color(name, MAGENTA, true)
54
+ end
55
+
56
+ debug " #{name} #{search}"
57
+ end
58
+
59
+ # Intercept `cql.datastax_rails` events, and display them in the Rails log
60
+ def cql(event)
61
+ self.class.cql_runtime += event.duration
62
+ return unless logger.debug? && DatastaxRails::Base.log_cql_queries
63
+
64
+ payload = event.payload
65
+
66
+ name = "#{payload[:klass]} #{payload[:name]} (#{event.duration.round(1)}ms)"
67
+ cql = payload[:cql]
68
+ binds = nil
69
+ results = payload[:result_count]
70
+
71
+ unless (payload[:binds] || []).empty?
72
+ binds = ' ' + payload[:binds].inspect
73
+ end
74
+
75
+ if odd?
76
+ name = color(name, CYAN, true)
77
+ cql = color(cql, nil, true)
78
+ else
79
+ name = color(name, MAGENTA, true)
80
+ end
81
+
82
+ debug " #{name} #{cql}#{binds} - #{results} results"
83
+ end
84
+
85
+ def odd?
86
+ @odd = !@odd
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ DatastaxRails::Instrumentation::LogSubscriber.attach_to :datastax_rails
@@ -0,0 +1,4 @@
1
+ module DatastaxRails
2
+ module Instrumentation
3
+ end
4
+ end
@@ -29,7 +29,7 @@ module DatastaxRails
29
29
  # keys = keys.flat_map { |k| attribute_definitions[primary_key].type_cast(k) }
30
30
  keys.each do |key|
31
31
  typecast_key = {}
32
- key.each { |k, v| typecast_key[k] = attribute_definitions[k].type_cast(v) }
32
+ key.each { |k, v| typecast_key[k] = attribute_definitions[k].type_cast_for_cql3(v) }
33
33
 
34
34
  ActiveSupport::Notifications.instrument('remove.datastax_rails', column_family: column_family, key: key) do
35
35
  c = cql.delete(typecast_key)
@@ -60,11 +60,12 @@ module DatastaxRails
60
60
  end
61
61
  end
62
62
 
63
- # Write a record to cassandra. Can be either an insert or an update (they are exactly the same to cassandra)
63
+ # Write a full record to cassandra.
64
64
  #
65
65
  # @param [DatastaxRails::Base] record the record that we are writing
66
66
  # @param [Hash] options a hash containing various options
67
67
  # @option options [Symbol] :consistency the consistency to set for the Cassandra operation (e.g., ALL)
68
+ # @option options [Symbol] :new_record whether or not this is a new record (i.e., INSERT vs UPDATE)
68
69
  def write(record, options = {})
69
70
  level = (options[:consistency] || default_consistency).to_s.upcase
70
71
  if valid_consistency?(level)
@@ -77,9 +78,37 @@ module DatastaxRails
77
78
  key: key.to_s,
78
79
  attributes: record.attributes) do
79
80
  if (storage_method == :solr)
80
- write_with_solr(record, options)
81
+ write_with_solr(record.id_for_update, encode_attributes(record, false), options)
81
82
  else
82
- write_with_cql(record, options)
83
+ write_with_cql(record.id_for_update, encode_attributes(record, true), options)
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ # Write one or more attributes directly to cassandra. Bypasses all normal validation and callbacks.
90
+ # Record must be already persisted.
91
+ #
92
+ # @param [DatastaxRails::Base] record the record that we are writing
93
+ # @param [Hash] options a hash containing various options
94
+ # @option options [Symbol] :consistency the consistency to set for the Cassandra operation (e.g., ALL)
95
+ # @raise [NotPersistedError] if the record isn't persisted
96
+ def write_attribute(record, attributes, options = {})
97
+ fail NotPersistedError if record.new_record?
98
+ level = (options[:consistency] || default_consistency).to_s.upcase
99
+ if valid_consistency?(level)
100
+ options[:consistency] = level
101
+ else
102
+ fail ArgumentError, "'#{level}' is not a valid Cassandra consistency level"
103
+ end
104
+ record.id.tap do |key|
105
+ ActiveSupport::Notifications.instrument('update.datastax_rails', column_family: column_family,
106
+ key: key.to_s,
107
+ attributes: record.attributes) do
108
+ if (storage_method == :solr)
109
+ write_with_solr(record.id_for_update, encode_attributes(record, false, attributes), options)
110
+ else
111
+ write_with_cql(record.id_for_update, encode_attributes(record, true, attributes), options)
83
112
  end
84
113
  end
85
114
  end
@@ -102,13 +131,17 @@ module DatastaxRails
102
131
  # @param [DatastaxRails::Base] record the record whose attributes we're encoding
103
132
  # @param [Boolean] cql True if we're formatting for CQL, otherwise False
104
133
  # @return [Hash] a new hash with attributes encoded for storage
105
- def encode_attributes(record, cql)
134
+ def encode_attributes(record, cql, attributes = {})
106
135
  encoded = {}
107
136
  Types::DirtyCollection.ignore_modifications do
108
- record.changed.each do |column_name|
109
- value = record.read_attribute(column_name)
110
- encoded[column_name.to_s] = cql ? attribute_definitions[column_name].type_cast_for_cql3(value) :
111
- attribute_definitions[column_name].type_cast_for_solr(value)
137
+ if attributes.empty?
138
+ record.send(cql ? 'changed' : 'column_names').each do |column_name|
139
+ attributes[column_name] = record.read_attribute(column_name)
140
+ end
141
+ end
142
+ attributes.each do |k, v|
143
+ encoded[k.to_s] = cql ? attribute_definitions[k].type_cast_for_cql3(v) :
144
+ attribute_definitions[k].type_cast_for_solr(v)
112
145
  end
113
146
  end
114
147
  encoded
@@ -116,19 +149,17 @@ module DatastaxRails
116
149
 
117
150
  private
118
151
 
119
- def write_with_cql(record, options)
120
- encoded = encode_attributes(record, true)
152
+ def write_with_cql(id, encoded, options)
121
153
  if options[:new_record]
122
154
  cql.insert.columns(encoded).using(options[:consistency]).execute
123
155
  else
124
- cql.update(record.id_for_update).columns(encoded).using(options[:consistency]).execute
156
+ cql.update(id).columns(encoded).using(options[:consistency]).execute
125
157
  end
126
158
  end
127
159
 
128
- def write_with_solr(record, options)
129
- encoded = encode_attributes(record, false)
130
- xml_doc = RSolr::Xml::Generator.new.add(encoded.merge(primary_key => record.id.to_s))
131
- solr_connection.update(data: xml_doc, params: { replacefields: false, cl: options[:consistency] })
160
+ def write_with_solr(id, encoded, options)
161
+ xml_doc = RSolr::Xml::Generator.new.add(encoded)
162
+ solr_connection.update(data: xml_doc, params: { cl: options[:consistency] })
132
163
  end
133
164
  end
134
165
 
@@ -151,6 +182,7 @@ module DatastaxRails
151
182
  @destroyed = true
152
183
  freeze
153
184
  end
185
+ alias_method :destroy_without_callbacks, :destroy
154
186
 
155
187
  # TODO: Make this work
156
188
  # def touch(name = nil)
@@ -190,7 +222,7 @@ module DatastaxRails
190
222
  end
191
223
 
192
224
  # Updates the attributes of the model from the passed-in hash and saves the
193
- # record If the object is invalid, the saving will fail and false will be returned.
225
+ # record. If the object is invalid, the saving will fail and false will be returned.
194
226
  def update_attributes(attributes, _options = {})
195
227
  assign_attributes(attributes)
196
228
  save
@@ -27,6 +27,13 @@ module DatastaxRails
27
27
  end
28
28
  end
29
29
  end
30
+
31
+ # Instrumentation
32
+ require 'datastax_rails/instrumentation/log_subscriber'
33
+ require 'datastax_rails/instrumentation/controller_runtime'
34
+ ActiveSupport.on_load(:action_controller) do
35
+ include DatastaxRails::Instrumentation::ControllerRuntime
36
+ end
30
37
  end
31
38
 
32
39
  rake_tasks do
@@ -185,18 +185,22 @@ module DatastaxRails
185
185
  @type ||= options[:as] && "#{options[:as]}_type"
186
186
  end
187
187
 
188
+ def primary_key_column
189
+ @primary_key_column ||= klass.columns.find { |c| c.name == klass.primary_key }
190
+ end
191
+
188
192
  def association_foreign_key
189
193
  @association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
190
194
  end
191
195
 
192
196
  # klass option is necessary to support loading polymorphic associations
193
- # def association_primary_key(klass = nil)
194
- # options[:primary_key] || primary_key(klass || self.klass)
195
- # end
196
- #
197
- # def datastax_rails_primary_key
198
- # @datastax_rails_primary_key ||= options[:primary_key] || primary_key(solandra_object)
199
- # end
197
+ def association_primary_key(klass = nil)
198
+ options[:primary_key] || primary_key(klass || self.klass)
199
+ end
200
+
201
+ def datastax_rails_primary_key
202
+ @datastax_rails_primary_key ||= options[:primary_key] || primary_key(datastax_rails)
203
+ end
200
204
 
201
205
  def check_validity!
202
206
  check_validity_of_inverse!
@@ -303,9 +307,9 @@ module DatastaxRails
303
307
  end
304
308
  end
305
309
 
306
- # def primary_key(klass)
307
- # klass.key || raise(UnknownPrimaryKey.new(klass))
308
- # end
310
+ def primary_key(klass)
311
+ klass.primary_key || raise(UnknownPrimaryKey.new(klass))
312
+ end
309
313
  end
310
314
 
311
315
  # Holds all the meta-data about a :through association as it was specified
@@ -385,7 +389,7 @@ module DatastaxRails
385
389
  # of relevant reflections, plus any :source_type or polymorphic :as constraints.
386
390
  def conditions
387
391
  @conditions ||= begin
388
- conditions = source_reflection.conditions.map { |c| c.dup }
392
+ conditions = source_reflection.conditions.map(&:dup)
389
393
 
390
394
  # Add to it the conditions from this reflection if necessary.
391
395
  conditions.first << options[:conditions] if options[:conditions]
@@ -434,7 +438,7 @@ module DatastaxRails
434
438
  #
435
439
  def source_reflection_names
436
440
  @source_reflection_names ||=
437
- (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).map { |n| n.to_sym }
441
+ (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).map(&:to_sym)
438
442
  end
439
443
 
440
444
  def source_options
@@ -85,7 +85,7 @@ module DatastaxRails
85
85
  records = start ? relation.where(@klass.primary_key).greater_than(start).to_a : relation.to_a
86
86
  while records.size > 0
87
87
  records_size = records.size
88
- offset = records.last.id
88
+ offset = records.last.__id
89
89
  yield records
90
90
 
91
91
  break if records_size < batch_size
@@ -81,14 +81,14 @@ module DatastaxRails
81
81
  # Post.find_by "published_at < ?", 2.weeks.ago
82
82
  def find_by(*args)
83
83
  where_values << escape_attributes(args.first)
84
- first
84
+ dont_escape.first
85
85
  end
86
86
 
87
87
  # Like <tt>find_by</tt>, except that if no record is found, raises
88
88
  # an <tt>DatastaxRails::RecordNotFound</tt> error.
89
89
  def find_by!(*args)
90
90
  where_values << escape_attributes(args.first)
91
- first!
91
+ dont_escape.first!
92
92
  end
93
93
 
94
94
  # A convenience wrapper for <tt>find(:first, *args)</tt>. You can pass in all the
@@ -155,7 +155,7 @@ module DatastaxRails
155
155
  escaped = {}
156
156
  conditions.each do |k, v|
157
157
  if v.is_a?(String)
158
- escaped[k] = v.gsub(/(\W)/, '\\\\\1')
158
+ escaped[k] = v.gsub(/([^\w\- ])/, '\\\\\1')
159
159
  else
160
160
  escaped[k] = v
161
161
  end
@@ -183,7 +183,7 @@ module DatastaxRails
183
183
  end
184
184
 
185
185
  def find_one(id)
186
- key = @klass.attribute_definitions[@klass.primary_key].type_cast(id)
186
+ key = @klass.attribute_definitions[@klass.primary_key].type_cast_for_cql3(id)
187
187
  key || fail(RecordNotFound, "Couldn't find #{@klass.name} with an invalid ID=#{id}")
188
188
 
189
189
  with_cassandra.where(@klass.primary_key => key).first ||
@@ -192,7 +192,7 @@ module DatastaxRails
192
192
 
193
193
  def find_some(ids)
194
194
  keys = ids.map do |id|
195
- @klass.attribute_definitions[@klass.primary_key].type_cast(id) ||
195
+ @klass.attribute_definitions[@klass.primary_key].type_cast_for_cql3(id) ||
196
196
  fail(RecordNotFound, "Couldn't find #{@klass.name} with an invalid ID=#{id}")
197
197
  end
198
198
  result = with_cassandra.where(@klass.primary_key => keys).all
@@ -1,6 +1,6 @@
1
1
  module DatastaxRails
2
2
  module ModificationMethods
3
- # Destroys the records matching +conditions+ by instantiating each
3
+ # Destroys the records matching this relation by instantiating each
4
4
  # record and calling its +destroy+ method. Each object's callbacks are
5
5
  # executed (including <tt>:dependent</tt> association options and
6
6
  # +before_destroy+/+after_destroy+ Observer methods). Returns the
@@ -10,35 +10,20 @@ module DatastaxRails
10
10
  #
11
11
  # Note: Instantiation, callback execution, and deletion of each
12
12
  # record can be time consuming when you're removing many records at
13
- # once. However, it is necessary to perform it this way to ensure
14
- # that the SOLR index stays in sync with the Cassandra data store.
13
+ # once. However, it is necessary to perform it this way since we have
14
+ # to get the results from SOLR (most likely) in order to know what to delete.
15
15
  #
16
- # +delete_all+ is aliased to this because you can't delete without running
17
- # the requisite callbacks. (at least not yet)
18
- #
19
- # ==== Parameters
20
- #
21
- # * +conditions+ - A string, array, or hash that specifies which records
22
- # to destroy. If omitted, all records matching the current relation are
23
- # destroyed. See the Conditions section in the introduction to
24
- # DatastaxRails::Base for more information.
25
- #
26
- # ==== Examples
27
- #
28
- # Person.destroy_all(:status => "inactive")
16
+ # Person.destroy_all
29
17
  # Person.where(:age => 0..18).destroy_all
30
18
  # Person.where_not(:status => "active").destroy_all
31
- def destroy_all(conditions = nil)
32
- if conditions
33
- ret = where(conditions).destroy_all
34
- else
35
- ret = to_a.each { |object| object.destroy }
36
- end
37
- reset
38
- ret
19
+ def destroy_all
20
+ to_a.each(&:destroy).tap { |_| reset }
21
+ end
22
+
23
+ # Like +destroy_all+ but will not run callbacks. It will still have to instantiate the objects.
24
+ def delete_all
25
+ select(klass.primary_key).to_a.each(&:destroy_without_callbacks).tap { |_| reset }
39
26
  end
40
- # TODO: Find a way to delete from both without instantiating
41
- alias_method :delete_all, :destroy_all
42
27
 
43
28
  # Destroy an object (or multiple objects) that has the given id, the object is instantiated first,
44
29
  # therefore all callbacks and filters are fired off before the object is deleted. This method is
@@ -397,8 +397,6 @@ module DatastaxRails
397
397
  r.where_values << { k => value }
398
398
  end
399
399
  attributes.delete(k)
400
- else
401
- attributes[k] = solr_format(k, v)
402
400
  end
403
401
  end
404
402
  r.where_values << attributes unless attributes.empty?
@@ -441,8 +439,6 @@ module DatastaxRails
441
439
  r.where_not_values << { k => value }
442
440
  end
443
441
  attributes.delete(k)
444
- else
445
- attributes[k] = solr_format(k, v)
446
442
  end
447
443
  end
448
444
  r.where_not_values << attributes unless attributes.empty?
@@ -545,7 +541,8 @@ module DatastaxRails
545
541
  when value.is_a?(Time) || value.is_a?(DateTime) || value.is_a?(Date)
546
542
  column.type_cast_for_solr(value)
547
543
  when value.is_a?(Array) || value.is_a?(Set)
548
- column.type_cast_for_solr(value).map { |v| v.to_s.gsub(/ /, '\\ ') }.join(' OR ')
544
+ value = value.to_a.compact if column.primary
545
+ value.map { |v| column.type_cast_for_solr(v, column.options[:holds]).to_s.gsub(/ /, '\\ ') }.join(' OR ')
549
546
  when value.is_a?(Fixnum)
550
547
  value < 0 ? "\\#{value}" : value
551
548
  when value.is_a?(Range)
@@ -554,6 +551,8 @@ module DatastaxRails
554
551
  solr_escape(downcase_query(value.gsub(/ /, '\\ ')))
555
552
  when value.is_a?(FalseClass), value.is_a?(TrueClass)
556
553
  value.to_s
554
+ # when value.is_a?(::Cql::Uuid)
555
+ # value.to_s
557
556
  else
558
557
  value
559
558
  end
@@ -570,9 +569,9 @@ module DatastaxRails
570
569
  def equal_to(value) #:nodoc:
571
570
  @relation.clone.tap do |r|
572
571
  if @invert
573
- r.where_not_values << { @attribute => r.solr_format(@attribute, value) }
572
+ r.where_not_values << { @attribute => value }
574
573
  else
575
- r.where_values << { @attribute => r.solr_format(@attribute, value) }
574
+ r.where_values << { @attribute => value }
576
575
  end
577
576
  end
578
577
  end
@@ -580,9 +579,9 @@ module DatastaxRails
580
579
  def greater_than(value) #:nodoc:
581
580
  @relation.clone.tap do |r|
582
581
  if @invert
583
- r.less_than_values << { @attribute => r.solr_format(@attribute, value) }
582
+ r.less_than_values << { @attribute => value }
584
583
  else
585
- r.greater_than_values << { @attribute => r.solr_format(@attribute, value) }
584
+ r.greater_than_values << { @attribute => value }
586
585
  end
587
586
  end
588
587
  end
@@ -590,9 +589,9 @@ module DatastaxRails
590
589
  def less_than(value) #:nodoc:
591
590
  @relation.clone.tap do |r|
592
591
  if @invert
593
- r.greater_than_values << { @attribute => r.solr_format(@attribute, value) }
592
+ r.greater_than_values << { @attribute => value }
594
593
  else
595
- r.less_than_values << { @attribute => r.solr_format(@attribute, value) }
594
+ r.less_than_values << { @attribute => value }
596
595
  end
597
596
  end
598
597
  end