datastax_rails 1.0.15 → 1.0.16.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/datastax_rails/collection.rb +4 -0
- data/lib/datastax_rails/connection.rb +43 -7
- data/lib/datastax_rails/cql/base.rb +0 -1
- data/lib/datastax_rails/cql/update.rb +28 -26
- data/lib/datastax_rails/grouped_collection.rb +8 -0
- data/lib/datastax_rails/persistence.rb +4 -0
- data/lib/datastax_rails/railtie.rb +2 -1
- data/lib/datastax_rails/relation/search_methods.rb +120 -32
- data/lib/datastax_rails/relation/spawn_methods.rb +31 -6
- data/lib/datastax_rails/relation.rb +30 -9
- data/lib/datastax_rails/rsolr_client_wrapper.rb +1 -1
- data/lib/datastax_rails/tasks/column_family.rb +38 -11
- data/lib/datastax_rails/tasks/keyspace.rb +1 -1
- data/lib/datastax_rails/types/binary_type.rb +2 -0
- data/lib/datastax_rails/types/date_type.rb +1 -0
- data/lib/datastax_rails/types/string_type.rb +1 -2
- data/lib/datastax_rails/types/time_type.rb +1 -0
- data/lib/datastax_rails/version.rb +1 -1
- data/lib/datastax_rails.rb +1 -1
- data/spec/datastax_rails/relation/search_methods_spec.rb +44 -1
- data/spec/datastax_rails/validations/uniqueness_spec.rb +2 -2
- data/spec/dummy/config/datastax.yml +29 -22
- data/spec/dummy/config/datastax_rails.crt +18 -0
- data/spec/dummy/config/datastax_rails.key +15 -0
- data/spec/dummy/log/development.log +3 -0
- data/spec/dummy/log/test.log +2637 -0
- metadata +17 -24
@@ -1,5 +1,9 @@
|
|
1
1
|
module DatastaxRails
|
2
2
|
class Collection < Array
|
3
|
+
# @!attribute [r] total_entries
|
4
|
+
# @return [Fixnum] the total number of entries that match the search
|
5
|
+
# @!attribute [r] last_column_name
|
6
|
+
# @return [Fixnum] the last column that was returned in the search in case you limited the number of columns (not supported)
|
3
7
|
attr_accessor :last_column_name, :total_entries
|
4
8
|
|
5
9
|
def inspect
|
@@ -1,4 +1,6 @@
|
|
1
1
|
# require 'datastax_rails/rsolr_client_wrapper'
|
2
|
+
require 'rsolr/client_cert'
|
3
|
+
require 'rest_client'
|
2
4
|
module DatastaxRails
|
3
5
|
# The connection module holds all the code for establishing and maintaining a connection to
|
4
6
|
# Datastax Exterprise. This includes both the Cassandra and Solr connections.
|
@@ -13,7 +15,8 @@ module DatastaxRails
|
|
13
15
|
module ClassMethods
|
14
16
|
DEFAULT_OPTIONS = {
|
15
17
|
:servers => "127.0.0.1:9160",
|
16
|
-
:thrift => {}
|
18
|
+
:thrift => {},
|
19
|
+
:cql_version => '3.0.0'
|
17
20
|
}
|
18
21
|
|
19
22
|
# Returns the current server that we are talking to. This is useful when you are talking to a
|
@@ -48,6 +51,11 @@ module DatastaxRails
|
|
48
51
|
# solr:
|
49
52
|
# port: 8983
|
50
53
|
# path: /solr
|
54
|
+
# ssl:
|
55
|
+
# use_ssl: true
|
56
|
+
# cert: config/datastax_rails.crt
|
57
|
+
# key: config/datastax_rails.key
|
58
|
+
# keypass: changeme
|
51
59
|
#
|
52
60
|
# The +servers+ entry should be a list of all of the servers in your local datacenter. These
|
53
61
|
# are the servers that DSR will attempt to connect to and will round-robin through.
|
@@ -85,26 +93,54 @@ module DatastaxRails
|
|
85
93
|
DatastaxRails::Base.config = spec.with_indifferent_access
|
86
94
|
spec.reverse_merge!(DEFAULT_OPTIONS)
|
87
95
|
connection_options = spec[:connection_options] || {}
|
88
|
-
self.connection = CassandraCQL::Database.new(spec[:servers], {:keyspace => spec[:keyspace]}, connection_options.symbolize_keys)
|
96
|
+
self.connection = CassandraCQL::Database.new(spec[:servers], {:keyspace => spec[:keyspace], :cql_version => spec[:cql_version]}, connection_options.symbolize_keys)
|
89
97
|
end
|
90
98
|
|
91
99
|
# Returns the base portion of the URL for connecting to SOLR based on the current Cassandra server.
|
92
100
|
#
|
93
101
|
# @return [String] in the form of 'http://localhost:8983/solr'
|
94
102
|
def solr_base_url
|
95
|
-
DatastaxRails::Base.establish_connection unless self.connection
|
103
|
+
DatastaxRails::Base.establish_connection unless self.connection
|
96
104
|
port = DatastaxRails::Base.config[:solr][:port]
|
97
105
|
path = DatastaxRails::Base.config[:solr][:path]
|
98
|
-
|
106
|
+
protocol = DatastaxRails::Base.config[:solr].has_key?(:ssl) && DatastaxRails::Base.config[:solr][:ssl][:use_ssl] ? 'https' : 'http'
|
107
|
+
"#{protocol}://#{self.current_server}:#{port}#{path}"
|
108
|
+
end
|
109
|
+
|
110
|
+
# Wraps and caches a solr connection object
|
111
|
+
#
|
112
|
+
# @params [Boolean] reconnect force a new connection
|
113
|
+
# @return [DatastaxRails::RSolrClientWrapper] a wrapped RSolr connection
|
114
|
+
def solr_connection(reconnect = false)
|
115
|
+
if(!@rsolr || reconnect)
|
116
|
+
@rsolr = DatastaxRails::RSolrClientWrapper.new(establish_solr_connection)
|
117
|
+
end
|
118
|
+
@rsolr
|
99
119
|
end
|
100
120
|
|
101
121
|
# Similar to +establish_connection+, this method creates a connection object for Solr. Since HTTP is stateless, this doesn't
|
102
122
|
# actually launch the connection, but it gets everything set up so that RSolr can do its work. It's important to note that
|
103
123
|
# unlike the cassandra connection which is global to all of DSR, each model will have its own solr_connection.
|
104
124
|
#
|
105
|
-
# @return [
|
106
|
-
def
|
107
|
-
|
125
|
+
# @return [RSolr::Client] RSolr client object
|
126
|
+
def establish_solr_connection
|
127
|
+
opts = {:url => "#{solr_base_url}/#{DatastaxRails::Base.connection.keyspace}.#{self.column_family}"}
|
128
|
+
if DatastaxRails::Base.config[:solr].has_key?(:ssl) &&
|
129
|
+
DatastaxRails::Base.config[:solr][:ssl].has_key?(:cert) &&
|
130
|
+
DatastaxRails::Base.config[:solr][:ssl][:use_ssl]
|
131
|
+
cert = Pathname.new(DatastaxRails::Base.config[:solr][:ssl][:cert])
|
132
|
+
key = Pathname.new(DatastaxRails::Base.config[:solr][:ssl][:key])
|
133
|
+
pass = DatastaxRails::Base.config[:solr][:ssl][:keypass]
|
134
|
+
cert = Rails.root.join(cert) unless cert.absolute?
|
135
|
+
key = Rails.root.join(key) unless key.absolute?
|
136
|
+
opts[:ssl_cert_file] = cert.to_s
|
137
|
+
opts[:ssl_key_file] = key.to_s
|
138
|
+
opts[:ssl_key_pass] = pass if pass
|
139
|
+
|
140
|
+
RSolr::ClientCert.connect opts
|
141
|
+
else
|
142
|
+
RSolr.connect opts
|
143
|
+
end
|
108
144
|
end
|
109
145
|
end
|
110
146
|
end
|
@@ -34,38 +34,40 @@ module DatastaxRails
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def to_cql
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
if(@ttl)
|
43
|
-
stmt << "AND TTL #{@ttl} "
|
44
|
-
end
|
45
|
-
|
46
|
-
if(@timestamp)
|
47
|
-
stmt << "AND TIMESTAMP #{@timestamp}"
|
48
|
-
end
|
49
|
-
|
50
|
-
unless columns.empty?
|
51
|
-
stmt << "SET "
|
37
|
+
column_names = @columns.keys
|
38
|
+
cql = ""
|
39
|
+
Tempfile.open('cql', Rails.root.join("tmp")) do |stmt|
|
40
|
+
stmt << "update #{@klass.column_family} using consistency #{@consistency} "
|
52
41
|
|
53
|
-
|
42
|
+
if(@ttl)
|
43
|
+
stmt << "AND TTL #{@ttl} "
|
44
|
+
end
|
54
45
|
|
55
|
-
|
56
|
-
|
46
|
+
if(@timestamp)
|
47
|
+
stmt << "AND TIMESTAMP #{@timestamp}"
|
48
|
+
end
|
57
49
|
|
58
|
-
columns.
|
59
|
-
stmt << "
|
60
|
-
|
50
|
+
unless @columns.empty?
|
51
|
+
stmt << "SET "
|
52
|
+
|
53
|
+
first_entry = column_names.first
|
54
|
+
|
55
|
+
stmt << CassandraCQL::Statement.sanitize("#{first_entry.to_s} = ?", [@columns[first_entry]])
|
56
|
+
column_names[1..-1].each do |col|
|
57
|
+
stmt << CassandraCQL::Statement.sanitize(", #{col.to_s} = ?", [@columns[col]])
|
58
|
+
end
|
61
59
|
end
|
60
|
+
|
61
|
+
stmt << CassandraCQL::Statement.sanitize(" WHERE KEY IN (?)", [@key])
|
62
|
+
stmt.rewind
|
63
|
+
cql = stmt.read
|
62
64
|
end
|
63
|
-
|
64
|
-
stmt << " WHERE KEY IN (?)"
|
65
|
-
values << @key
|
66
|
-
|
67
|
-
CassandraCQL::Statement.sanitize(stmt, values)
|
65
|
+
cql
|
68
66
|
end
|
67
|
+
|
68
|
+
# def execute
|
69
|
+
# puts to_cql.truncate(50)
|
70
|
+
# end
|
69
71
|
end
|
70
72
|
end
|
71
73
|
end
|
@@ -1,5 +1,13 @@
|
|
1
1
|
module DatastaxRails
|
2
|
+
# GroupedCollection extends Hash to add some additional metadata. The hash keys will be the values
|
3
|
+
# for the thing that was grouped on. The hash entries point to instances of DatastaxRails::Collection.
|
2
4
|
class GroupedCollection < Hash
|
5
|
+
# @!attribute [r] total_entries
|
6
|
+
# @return [Fixnum] the total number of entries *in the largest group*. This is to allow will_paginate to work properly.
|
7
|
+
# @!attribute [r] total_groups
|
8
|
+
# @return [Fixnum] the total number of groups if the groups were paginated (not supported yet)
|
9
|
+
# @!attribute [r] total_for_all
|
10
|
+
# @return [Fixnum] the total number of entries across all groups that match this search
|
3
11
|
attr_accessor :total_entries, :total_groups, :total_for_all
|
4
12
|
|
5
13
|
def inspect
|
@@ -15,6 +15,9 @@ module DatastaxRails
|
|
15
15
|
# been updated yet with the results. In practice, this should not happen for
|
16
16
|
# records that were created over your connection, but it is possible for other
|
17
17
|
# connections to create records that you can't see yet.
|
18
|
+
#
|
19
|
+
# @param level [Symbol, String] the level to set the consistency at
|
20
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
18
21
|
def consistency(level)
|
19
22
|
level = level.to_s.upcase
|
20
23
|
unless self.valid_consistency?(level)
|
@@ -34,6 +37,8 @@ module DatastaxRails
|
|
34
37
|
#
|
35
38
|
# Note that fulltext searches are NEVER escaped. Use Relation.solr_escape if you
|
36
39
|
# want that done.
|
40
|
+
#
|
41
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
37
42
|
def dont_escape
|
38
43
|
clone.tap do |r|
|
39
44
|
r.escape_value = false
|
@@ -44,6 +49,9 @@ module DatastaxRails
|
|
44
49
|
# a module or a block provided
|
45
50
|
#
|
46
51
|
# The object returned is a relation which can be further extended
|
52
|
+
#
|
53
|
+
# @param modules [Proc] one or more proc objects
|
54
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
47
55
|
def extending(*modules)
|
48
56
|
modules << Module.new(&Proc.new) if block_given?
|
49
57
|
|
@@ -69,6 +77,9 @@ module DatastaxRails
|
|
69
77
|
# 30
|
70
78
|
# end
|
71
79
|
# end
|
80
|
+
#
|
81
|
+
# @param value [String, Fixnum] the number of records to include on a page
|
82
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
72
83
|
def limit(value)
|
73
84
|
clone.tap do |r|
|
74
85
|
r.per_page_value = value.to_i
|
@@ -79,6 +90,9 @@ module DatastaxRails
|
|
79
90
|
# Sets the page number to retrieve
|
80
91
|
#
|
81
92
|
# Model.page(2)
|
93
|
+
#
|
94
|
+
# @param value [String, Fixnum] the page number to retrieve
|
95
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
82
96
|
def page(value)
|
83
97
|
clone.tap do |r|
|
84
98
|
r.page_value = value.to_i
|
@@ -88,6 +102,10 @@ module DatastaxRails
|
|
88
102
|
# WillPaginate compatible method for paginating
|
89
103
|
#
|
90
104
|
# Model.paginate(:page => 2, :per_page => 10)
|
105
|
+
# @param options [Hash] the options to pass to paginate
|
106
|
+
# @option options [String, Fixnum] :page the page number to retrieve
|
107
|
+
# @option options [String, Fixnum] :per_page the number of records to include on a page
|
108
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
91
109
|
def paginate(options = {})
|
92
110
|
options = options.reverse_merge({:page => 1, :per_page => 30})
|
93
111
|
clone.tap do |r|
|
@@ -102,7 +120,7 @@ module DatastaxRails
|
|
102
120
|
# This modifies the behavior of pagination. When using a group, +per_page+ will
|
103
121
|
# specify the number of results returned *for each group*. In addition, +page+
|
104
122
|
# will move all groups forward by one page possibly resulting in some groups
|
105
|
-
#
|
123
|
+
# showing up empty if they have fewer matching entires than others.
|
106
124
|
#
|
107
125
|
# When grouping is being used, the sort values will be used to sort results within
|
108
126
|
# a given group. Any sorting of the groups themselves will need to be handled
|
@@ -115,6 +133,11 @@ module DatastaxRails
|
|
115
133
|
# NOTE: Group names will be lower-cased
|
116
134
|
#
|
117
135
|
# Model.group(:program_id)
|
136
|
+
#
|
137
|
+
# The object the hash entries point to will be a DatastaxRails::Collection
|
138
|
+
#
|
139
|
+
# @param attribute [Symbol, String] the attribute to group by
|
140
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
118
141
|
def group(attribute)
|
119
142
|
return self if attribute.blank?
|
120
143
|
|
@@ -133,6 +156,9 @@ module DatastaxRails
|
|
133
156
|
#
|
134
157
|
# Model.order(:name)
|
135
158
|
# Model.order(:name => :desc)
|
159
|
+
#
|
160
|
+
# @param attribute [Symbol, String, Hash] the attribute to sort by and optionally the direction to sort in
|
161
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
136
162
|
def order(attribute)
|
137
163
|
return self if attribute.blank?
|
138
164
|
|
@@ -184,15 +210,15 @@ module DatastaxRails
|
|
184
210
|
end
|
185
211
|
end
|
186
212
|
|
187
|
-
# Reverses the order of the results
|
213
|
+
# Reverses the order of the results. The following are equivalent:
|
188
214
|
#
|
189
215
|
# Model.order(:name).reverse_order
|
190
|
-
#
|
191
|
-
# Model.order(:name => :desc)
|
216
|
+
# Model.order(:name => :desc)
|
192
217
|
#
|
193
218
|
# Model.order(:name).reverse_order.reverse_order
|
194
|
-
# is equivalent to
|
195
219
|
# Model.order(:name => :asc)
|
220
|
+
#
|
221
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
196
222
|
def reverse_order
|
197
223
|
clone.tap do |r|
|
198
224
|
r.reverse_order_value == !r.reverse_order_value
|
@@ -206,11 +232,14 @@ module DatastaxRails
|
|
206
232
|
# *This only applies to fulltext queries*
|
207
233
|
#
|
208
234
|
# Model.query_parser('disMax').fulltext("john smith")
|
209
|
-
|
210
|
-
|
235
|
+
#
|
236
|
+
# @param parser [String] the parser to use for the fulltext query
|
237
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
238
|
+
def query_parser(parser)
|
239
|
+
return self if parser.blank?
|
211
240
|
|
212
241
|
clone.tap do |r|
|
213
|
-
r.query_parser_value =
|
242
|
+
r.query_parser_value = parser
|
214
243
|
end
|
215
244
|
end
|
216
245
|
|
@@ -221,6 +250,8 @@ module DatastaxRails
|
|
221
250
|
# it becomes available in SOLR is not guaranteed to be insignificant. It's
|
222
251
|
# very possible to insert a new record and not find it when immediately doing
|
223
252
|
# a SOLR search for it.
|
253
|
+
#
|
254
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
224
255
|
def with_solr
|
225
256
|
clone.tap do |r|
|
226
257
|
r.use_solr_value = true
|
@@ -232,7 +263,9 @@ module DatastaxRails
|
|
232
263
|
# cassandra.
|
233
264
|
#
|
234
265
|
# NOTE that this method assumes that you have all the proper secondary indexes
|
235
|
-
# in place before you attempt to use it. If not, you will get an error.
|
266
|
+
# in place before you attempt to use it. If not, you will get an error.
|
267
|
+
#
|
268
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
236
269
|
def with_cassandra
|
237
270
|
clone.tap do |r|
|
238
271
|
r.use_solr_value = false
|
@@ -255,21 +288,43 @@ module DatastaxRails
|
|
255
288
|
# Model.where(:created_at).greater_than(1.day.ago)
|
256
289
|
# Model.where(:age).less_than(65)
|
257
290
|
#
|
291
|
+
# There is an alternate form of specifying greater than/less than queries
|
292
|
+
# that can be done with a single call. This is useful for remote APIs and
|
293
|
+
# such.
|
294
|
+
#
|
295
|
+
# Model.where(:created_at => {:greater_than => 1.day.ago})
|
296
|
+
# Model.where(:age => {:less_than => 65})
|
297
|
+
#
|
258
298
|
# NOTE: Due to the way SOLR handles range queries, all greater/less than
|
259
|
-
#
|
260
|
-
#
|
299
|
+
# queries are actually greater/less than or equal to queries.
|
300
|
+
# There is no way to perform a strictly greater/less than query.
|
301
|
+
#
|
302
|
+
# @param attribute [Symbol, String, Hash] a hash of conditions or a single attribute that will be followed by
|
303
|
+
# greater_than or less_than
|
304
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
261
305
|
def where(attribute)
|
262
306
|
return self if attribute.blank?
|
263
|
-
|
264
307
|
if attribute.is_a?(Symbol)
|
265
308
|
WhereProxy.new(self, attribute)
|
266
309
|
else
|
267
|
-
attributes = attribute.dup
|
268
|
-
attributes.each do |k,v|
|
269
|
-
attributes[k] = solr_format(v)
|
270
|
-
end
|
271
310
|
clone.tap do |r|
|
272
|
-
|
311
|
+
attributes = attribute.dup
|
312
|
+
attributes.each do |k,v|
|
313
|
+
if(v.is_a?(Hash))
|
314
|
+
comp, value = v.first
|
315
|
+
if(comp.to_s == 'greater_than')
|
316
|
+
r.greater_than_values << {k => value}
|
317
|
+
elsif(comp.to_s == 'less_than')
|
318
|
+
r.less_than_values << {k => value}
|
319
|
+
else
|
320
|
+
r.where_values << {k => value}
|
321
|
+
end
|
322
|
+
attributes.delete(k)
|
323
|
+
else
|
324
|
+
attributes[k] = solr_format(v)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
r.where_values << attributes unless attributes.empty?
|
273
328
|
end
|
274
329
|
end
|
275
330
|
end
|
@@ -285,22 +340,37 @@ module DatastaxRails
|
|
285
340
|
# Model.where_not(:group_id => ['1234', '5678'])
|
286
341
|
#
|
287
342
|
# The above would find all models where group id is neither 1234 or 5678.
|
343
|
+
#
|
344
|
+
# @param attribute [Symbol, String, Hash] a hash of conditions or a single attribute that will be followed by
|
345
|
+
# greater_than or less_than
|
346
|
+
# @return [DatastaxRails::Relation, DatastaxRails::SearchMethods::WhereProxy] a new Relation object
|
347
|
+
# or a proxy object if just an attribute was passed
|
288
348
|
def where_not(attribute)
|
289
349
|
return self if attribute.blank?
|
290
350
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
351
|
+
if attribute.is_a?(Symbol)
|
352
|
+
WhereProxy.new(self, attribute, true)
|
353
|
+
else
|
354
|
+
clone.tap do |r|
|
355
|
+
attributes = attribute.dup
|
356
|
+
attributes.each do |k,v|
|
357
|
+
if(v.is_a?(Hash))
|
358
|
+
comp, value = v.first
|
359
|
+
if(comp.to_s == 'greater_than')
|
360
|
+
r.less_than_values << {k => value}
|
361
|
+
elsif(comp.to_s == 'less_than')
|
362
|
+
r.greater_than_values << {k => value}
|
363
|
+
else
|
364
|
+
r.where_not_values << {k => value}
|
365
|
+
end
|
366
|
+
attributes.delete(k)
|
367
|
+
else
|
368
|
+
attributes[k] = solr_format(v)
|
369
|
+
end
|
296
370
|
end
|
297
|
-
|
298
|
-
attributes << {k => solr_format(v)}
|
371
|
+
r.where_not_values << attributes unless attributes.empty?
|
299
372
|
end
|
300
373
|
end
|
301
|
-
clone.tap do |r|
|
302
|
-
r.where_not_values += attributes
|
303
|
-
end
|
304
374
|
end
|
305
375
|
|
306
376
|
# Specifies a full text search string to be processed by SOLR
|
@@ -314,6 +384,12 @@ module DatastaxRails
|
|
314
384
|
#
|
315
385
|
# Model.fulltext("john smith", :fields => [:title])
|
316
386
|
# Model.fulltext("john smith", :hightlight => [:body])
|
387
|
+
#
|
388
|
+
# @param query [String] a fulltext query to pass to solr
|
389
|
+
# @param opts [Hash] an optional options hash to modify the fulltext query
|
390
|
+
# @option opts [Array] :fields list of fields to search instead of the default of all text fields (not-implemented)
|
391
|
+
# @option opts [Array] :highlight list of fields to retrieve highlights for (not-implemented)
|
392
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
317
393
|
def fulltext(query, opts = {})
|
318
394
|
return self if query.blank?
|
319
395
|
|
@@ -367,25 +443,37 @@ module DatastaxRails
|
|
367
443
|
end
|
368
444
|
|
369
445
|
class WhereProxy #:nodoc:
|
370
|
-
def initialize(relation, attribute) #:nodoc:
|
371
|
-
@relation, @attribute = relation, attribute
|
446
|
+
def initialize(relation, attribute, invert = false) #:nodoc:
|
447
|
+
@relation, @attribute, @invert = relation, attribute, invert
|
372
448
|
end
|
373
449
|
|
374
450
|
def equal_to(value) #:nodoc:
|
375
451
|
@relation.clone.tap do |r|
|
376
|
-
|
452
|
+
if @invert
|
453
|
+
r.where_not_values << {@attribute => r.solr_format(value)}
|
454
|
+
else
|
455
|
+
r.where_values << {@attribute => r.solr_format(value)}
|
456
|
+
end
|
377
457
|
end
|
378
458
|
end
|
379
459
|
|
380
460
|
def greater_than(value) #:nodoc:
|
381
461
|
@relation.clone.tap do |r|
|
382
|
-
|
462
|
+
if @invert
|
463
|
+
r.less_than_values << {@attribute => r.solr_format(value)}
|
464
|
+
else
|
465
|
+
r.greater_than_values << {@attribute => r.solr_format(value)}
|
466
|
+
end
|
383
467
|
end
|
384
468
|
end
|
385
469
|
|
386
470
|
def less_than(value) #:nodoc:
|
387
471
|
@relation.clone.tap do |r|
|
388
|
-
|
472
|
+
if @invert
|
473
|
+
r.greater_than_values << {@attribute => r.solr_format(value)}
|
474
|
+
else
|
475
|
+
r.less_than_values << {@attribute => r.solr_format(value)}
|
476
|
+
end
|
389
477
|
end
|
390
478
|
end
|
391
479
|
end
|
@@ -86,20 +86,45 @@ module DatastaxRails
|
|
86
86
|
result
|
87
87
|
end
|
88
88
|
|
89
|
-
VALID_FIND_OPTIONS = [:conditions, :limit, :select, :offset, :order, :group, :page, :per_page]
|
90
|
-
|
91
|
-
|
89
|
+
VALID_FIND_OPTIONS = [:conditions, :limit, :select, :offset, :order, :group, :page, :per_page, :fulltext, :consistency, :with_solr, :with_cassandra, :where, :where_not]
|
90
|
+
# Applies the passed in finder options and returns a new Relation.
|
91
|
+
# Takes any of the options below and calls them on the relation as if they
|
92
|
+
# were methods (+conditions+ is passed to +where+).
|
93
|
+
#
|
94
|
+
# @param [Hash] options the options hash
|
95
|
+
# @option options [Hash] :conditions
|
96
|
+
# @option options [Symbol, String] :consistency
|
97
|
+
# @option options [String] :fulltext
|
98
|
+
# @option options [Symbol, String] :group
|
99
|
+
# @option options [Integer, String] :limit
|
100
|
+
# @option options [Integer, String] :offset
|
101
|
+
# @option options [String, Hash] :order
|
102
|
+
# @option options [Integer, String] :page
|
103
|
+
# @option options [Integer, String] :per_page
|
104
|
+
# @option options [Array] :select
|
105
|
+
# @option options [Hash] :where
|
106
|
+
# @option options [Hash] :where_not
|
107
|
+
# @option options [Boolean] :with_cassandra
|
108
|
+
# @option options [Boolean] :with_solr
|
109
|
+
# @return [DatastaxRails::Relation] relation with all options applied
|
110
|
+
# @raise [ArgumentError] if an invalid option is passed in
|
111
|
+
def apply_finder_options(options)
|
112
|
+
relation = self
|
92
113
|
return relation unless options
|
93
114
|
|
94
115
|
options.assert_valid_keys(VALID_FIND_OPTIONS)
|
95
116
|
finders = options.dup
|
96
117
|
finders.delete_if { |key, value| value.nil? }
|
97
118
|
|
98
|
-
(
|
99
|
-
|
119
|
+
((VALID_FIND_OPTIONS - [:conditions]) & finders.keys).each do |finder|
|
120
|
+
if(finder.to_s =~ /(with_solr|with_cassandra)/)
|
121
|
+
relation = relation.send(finder)
|
122
|
+
else
|
123
|
+
relation = relation.send(finder, finders[finder])
|
124
|
+
end
|
100
125
|
end
|
101
126
|
|
102
|
-
relation = relation.where(finders[:conditions]) if
|
127
|
+
relation = relation.where(finders[:conditions]) if finders.has_key?(:conditions)
|
103
128
|
relation
|
104
129
|
end
|
105
130
|
end
|
@@ -24,7 +24,13 @@ module DatastaxRails
|
|
24
24
|
alias :loaded? :loaded
|
25
25
|
alias :default_scoped? :default_scoped
|
26
26
|
|
27
|
-
|
27
|
+
# Initializes the Relation. Defaults page value to 1, per_page to the class
|
28
|
+
# default, and solr use to true. Everything else gets defaulted to nil or
|
29
|
+
# empty.
|
30
|
+
#
|
31
|
+
# @param [Class] klass the child of DatastaxRails::Base that this relation searches
|
32
|
+
# @param [String, Symbol] column_family the name of the column family this relation searches
|
33
|
+
def initialize(klass, column_family)
|
28
34
|
@klass, @column_family = klass, column_family
|
29
35
|
@loaded = false
|
30
36
|
@results = []
|
@@ -146,12 +152,14 @@ module DatastaxRails
|
|
146
152
|
@results = []
|
147
153
|
end
|
148
154
|
|
149
|
-
|
155
|
+
# Copies will have changes made to the criteria and so need to be reset.
|
156
|
+
def initialize_copy(other)
|
150
157
|
reset
|
151
158
|
@search = nil
|
152
159
|
end
|
153
160
|
|
154
|
-
|
161
|
+
# Performs a deep copy using Marshal when cloning.
|
162
|
+
def clone
|
155
163
|
dup.tap do |r|
|
156
164
|
MULTI_VALUE_METHODS.each do |m|
|
157
165
|
r.send("#{m}_values=", Marshal.load(Marshal.dump(self.send("#{m}_values"))))
|
@@ -210,7 +218,8 @@ module DatastaxRails
|
|
210
218
|
scoping { @klass.create!(*args, &block) }
|
211
219
|
end
|
212
220
|
|
213
|
-
|
221
|
+
# Override respond_to? so that it matches method_missing
|
222
|
+
def respond_to?(method, include_private = false)
|
214
223
|
Array.method_defined?(method) ||
|
215
224
|
@klass.respond_to?(method, include_private) ||
|
216
225
|
super
|
@@ -339,7 +348,7 @@ module DatastaxRails
|
|
339
348
|
params['group.limit'] = @per_page_value
|
340
349
|
params['group.offset'] = (@page_value - 1) * @per_page_value
|
341
350
|
params['group.ngroups'] = 'true'
|
342
|
-
response = rsolr.post('select', :
|
351
|
+
response = rsolr.post('select', :data => params)["grouped"][@group_value.to_s]
|
343
352
|
results.total_groups = response['ngroups'].to_i
|
344
353
|
results.total_for_all = response['matches'].to_i
|
345
354
|
results.total_entries = 0
|
@@ -348,13 +357,18 @@ module DatastaxRails
|
|
348
357
|
results.total_entries = results[group['groupValue']].total_entries if results[group['groupValue']].total_entries > results.total_entries
|
349
358
|
end
|
350
359
|
else
|
351
|
-
response = rsolr.paginate(@page_value, @per_page_value, 'select', :params =>
|
360
|
+
response = rsolr.paginate(@page_value, @per_page_value, 'select', :data => params, :method => :post)["response"]
|
352
361
|
results = parse_docs(response, select_columns)
|
353
362
|
end
|
354
363
|
results
|
355
364
|
end
|
356
365
|
|
357
|
-
|
366
|
+
# Parse out a set of documents and return the results
|
367
|
+
#
|
368
|
+
# @param response [Hash] the response hash from SOLR with a set of documents
|
369
|
+
# @param select_columns [Array] the columns that we actually selected from SOLR
|
370
|
+
#
|
371
|
+
# @return [DatastaxRails::Collection] the resulting collection
|
358
372
|
def parse_docs(response, select_columns)
|
359
373
|
results = DatastaxRails::Collection.new
|
360
374
|
results.total_entries = response['numFound'].to_i
|
@@ -371,6 +385,10 @@ module DatastaxRails
|
|
371
385
|
end
|
372
386
|
protected(:parse_docs)
|
373
387
|
|
388
|
+
# Inspects the results of the search instead of the Relation itself.
|
389
|
+
# Passing true causes the Relation to be inspected.
|
390
|
+
#
|
391
|
+
# @param [Boolean] just_me if true, inspect the Relation, otherwise the results
|
374
392
|
def inspect(just_me = false)
|
375
393
|
just_me ? super() : to_a.inspect
|
376
394
|
end
|
@@ -389,11 +407,14 @@ module DatastaxRails
|
|
389
407
|
@klass.send(:with_scope, self, :overwrite) { yield }
|
390
408
|
end
|
391
409
|
|
392
|
-
|
410
|
+
# Merges all of the where values together into a single hash
|
411
|
+
def where_values_hash
|
393
412
|
where_values.inject({}) { |values,v| values.merge(v) }
|
394
413
|
end
|
395
414
|
|
396
|
-
|
415
|
+
# Creates a scope that includes all of the where values plus anything
|
416
|
+
# that is in +create_with_value+.
|
417
|
+
def scope_for_create
|
397
418
|
@scope_for_create ||= where_values_hash.merge(create_with_value)
|
398
419
|
end
|
399
420
|
|
@@ -10,7 +10,7 @@ module DatastaxRails
|
|
10
10
|
def method_missing(sym, *args, &block)
|
11
11
|
if @rsolr.uri.host != DatastaxRails::Base.current_server
|
12
12
|
@rsolr.uri.host = DatastaxRails::Base.current_server
|
13
|
-
@rsolr =
|
13
|
+
@rsolr = DatastaxRails::Base.establish_solr_connection
|
14
14
|
end
|
15
15
|
@rsolr.__send__(sym, *args, &block)
|
16
16
|
rescue Errno::ECONNREFUSED
|