datastax_rails 1.0.19.0 → 1.1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.rdoc +13 -2
- data/config/solrconfig.xml +3 -0
- data/lib/datastax_rails/associations/collection_association.rb +31 -0
- data/lib/datastax_rails/attribute_methods/definition.rb +2 -2
- data/lib/datastax_rails/base.rb +3 -7
- data/lib/datastax_rails/connection.rb +1 -0
- data/lib/datastax_rails/cql/alter_column_family.rb +9 -0
- data/lib/datastax_rails/cql/base.rb +2 -1
- data/lib/datastax_rails/cql/create_column_family.rb +3 -3
- data/lib/datastax_rails/cql/create_index.rb +25 -0
- data/lib/datastax_rails/cql/create_keyspace.rb +3 -3
- data/lib/datastax_rails/cql/delete.rb +3 -3
- data/lib/datastax_rails/cql/drop_index.rb +13 -0
- data/lib/datastax_rails/cql/insert.rb +2 -2
- data/lib/datastax_rails/cql/select.rb +2 -2
- data/lib/datastax_rails/cql/update.rb +20 -20
- data/lib/datastax_rails/cql.rb +2 -0
- data/lib/datastax_rails/persistence.rb +2 -10
- data/lib/datastax_rails/railtie.rb +7 -0
- data/lib/datastax_rails/relation/batches.rb +23 -10
- data/lib/datastax_rails/relation/facet_methods.rb +17 -0
- data/lib/datastax_rails/relation/finder_methods.rb +2 -2
- data/lib/datastax_rails/relation/search_methods.rb +1 -1
- data/lib/datastax_rails/relation.rb +14 -6
- data/lib/datastax_rails/tasks/column_family.rb +97 -18
- data/lib/datastax_rails/tasks/ds.rake +11 -0
- data/lib/datastax_rails/types/array_type.rb +1 -1
- data/lib/datastax_rails/types/boolean_type.rb +1 -1
- data/lib/datastax_rails/types/date_type.rb +1 -1
- data/lib/datastax_rails/types/float_type.rb +1 -1
- data/lib/datastax_rails/types/integer_type.rb +1 -1
- data/lib/datastax_rails/types/string_type.rb +2 -2
- data/lib/datastax_rails/types/text_type.rb +3 -4
- data/lib/datastax_rails/types/time_type.rb +1 -1
- data/lib/datastax_rails/validations/associated.rb +43 -0
- data/lib/datastax_rails/validations.rb +14 -2
- data/lib/datastax_rails/version.rb +1 -1
- data/lib/datastax_rails.rb +14 -14
- data/spec/datastax_rails/associations/has_many_association_spec.rb +1 -0
- data/spec/datastax_rails/base_spec.rb +6 -0
- data/spec/datastax_rails/cql/select_spec.rb +3 -3
- data/spec/datastax_rails/cql/update_spec.rb +2 -2
- data/spec/datastax_rails/persistence_spec.rb +16 -12
- data/spec/datastax_rails/relation/batches_spec.rb +20 -16
- data/spec/datastax_rails/relation/finder_methods_spec.rb +2 -2
- data/spec/dummy/log/test.log +3316 -0
- data/spec/spec.opts +0 -1
- data/spec/support/connection_double.rb +6 -0
- data/spec/support/default_consistency_shared_examples.rb +4 -2
- metadata +86 -107
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 315f2c0bed2d3ebd73b696212d09be65be6071f1
|
4
|
+
data.tar.gz: 3c7f2f05d532f73ec40128bf748f032cb7825ec4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 956823938bdc95ac435bd57a7ec19cd6d1f565790847d10117fb86f30a2db78cbbe3ca0466db66632c9cd6a826bc1564146b687ac15027e15e8de54639698754
|
7
|
+
data.tar.gz: 0c082e39d39012a3c79dbed78180433dee4cd9bd0138aa3c9116aa03a267a5dff3f009973a9f86fb323e3a9a40254efd4d1afa8762f39ec72e56ca3909aed5aa
|
data/README.rdoc
CHANGED
@@ -70,10 +70,21 @@ Once you've created some models, the following will upload the solr schemas and
|
|
70
70
|
It is safe to run ds:schema over and over. In fact, it is necessary to re-run it any time you change the
|
71
71
|
attributes on any model. DSR will only upload schema files if they have changed.
|
72
72
|
|
73
|
+
Create a sample Model. See Base documentation for more details:
|
74
|
+
|
75
|
+
class Person < DatastaxRails::Base
|
76
|
+
key :uuid
|
77
|
+
string :first_name
|
78
|
+
string :user_name
|
79
|
+
text :bio
|
80
|
+
date :birthdate
|
81
|
+
boolean :active
|
82
|
+
timestamps
|
83
|
+
end
|
84
|
+
|
73
85
|
=== Known issues
|
74
86
|
|
75
|
-
|
76
|
-
(if you were using one).
|
87
|
+
Trying to set a value to nil via the solr API results in the field value not changing at all. Updating it via CQL doesn't have this issue.
|
77
88
|
|
78
89
|
=== More information
|
79
90
|
|
data/config/solrconfig.xml
CHANGED
@@ -48,6 +48,9 @@
|
|
48
48
|
affect both how text is indexed and queried.
|
49
49
|
-->
|
50
50
|
<luceneMatchVersion>LUCENE_40</luceneMatchVersion>
|
51
|
+
|
52
|
+
<!-- Enable DSE Search new type mappings -->
|
53
|
+
<dseTypeMappingVersion>0</dseTypeMappingVersion>
|
51
54
|
|
52
55
|
<!-- lib directives can be used to instruct Solr to load an Jars
|
53
56
|
identified and use them to resolve any "plugins" specified in
|
@@ -154,6 +154,37 @@ module DatastaxRails
|
|
154
154
|
record
|
155
155
|
end
|
156
156
|
|
157
|
+
# Replace this collection with +other_array+
|
158
|
+
# This will perform a diff and delete/add only records that have changed.
|
159
|
+
def replace(other_array)
|
160
|
+
other_array.each { |val| raise_on_type_mismatch(val) }
|
161
|
+
original_target = load_target.dup
|
162
|
+
|
163
|
+
delete(target - other_array)
|
164
|
+
|
165
|
+
unless concat(other_array - target)
|
166
|
+
@target = original_target
|
167
|
+
raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
|
168
|
+
"new records could not be saved."
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Add +records+ to this association. Returns +self+ so method calls may be chained.
|
173
|
+
# Since << flattens its argument list and inserts each record, +push+ and +concat+ behave identically.
|
174
|
+
def concat(*records)
|
175
|
+
result = true
|
176
|
+
load_target if owner.new_record?
|
177
|
+
|
178
|
+
records.flatten.each do |record|
|
179
|
+
raise_on_type_mismatch(record)
|
180
|
+
add_to_target(record) do |r|
|
181
|
+
result &&= insert_record(record) unless owner.new_record?
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
result && records
|
186
|
+
end
|
187
|
+
|
157
188
|
private
|
158
189
|
|
159
190
|
# We have some records loaded from the database (persisted) and some that are
|
data/lib/datastax_rails/base.rb
CHANGED
@@ -324,7 +324,7 @@ module DatastaxRails #:nodoc:
|
|
324
324
|
self.default_consistency = :quorum
|
325
325
|
|
326
326
|
class_attribute :storage_method
|
327
|
-
self.storage_method = :
|
327
|
+
self.storage_method = :cql
|
328
328
|
|
329
329
|
class_attribute :models
|
330
330
|
self.models = []
|
@@ -479,7 +479,7 @@ module DatastaxRails #:nodoc:
|
|
479
479
|
delegate :count, :first, :first!, :last, :last!, :compute_stats, :to => :scoped
|
480
480
|
delegate :sum, :average, :minimum, :maximum, :stddev, :to => :scoped
|
481
481
|
delegate :cql, :with_cassandra, :with_solr, :commit_solr, :to => :scoped
|
482
|
-
delegate :find_each, :find_in_batches, :to => :scoped
|
482
|
+
delegate :find_each, :find_in_batches, :consistency, :to => :scoped
|
483
483
|
|
484
484
|
# Sets the column family name
|
485
485
|
#
|
@@ -493,7 +493,7 @@ module DatastaxRails #:nodoc:
|
|
493
493
|
#
|
494
494
|
# Returns [String] the name of the column family
|
495
495
|
def column_family
|
496
|
-
@column_family || name.pluralize
|
496
|
+
@column_family || name.underscore.pluralize
|
497
497
|
end
|
498
498
|
|
499
499
|
def payload_model?
|
@@ -508,10 +508,6 @@ module DatastaxRails #:nodoc:
|
|
508
508
|
klass
|
509
509
|
end
|
510
510
|
|
511
|
-
# def find(*keys)
|
512
|
-
# scoped.with_cassandra.find(keys)
|
513
|
-
# end
|
514
|
-
|
515
511
|
def find_by_id(id)
|
516
512
|
scoped.with_cassandra.find(id)
|
517
513
|
rescue RecordNotFound
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# require 'datastax_rails/rsolr_client_wrapper'
|
2
2
|
require 'rsolr/client_cert'
|
3
3
|
require 'rest_client'
|
4
|
+
require "cassandra-cql/1.2"
|
4
5
|
module DatastaxRails
|
5
6
|
# The connection module holds all the code for establishing and maintaining a connection to
|
6
7
|
# Datastax Exterprise. This includes both the Cassandra and Solr connections.
|
@@ -4,6 +4,7 @@ module DatastaxRails#:nodoc:
|
|
4
4
|
def initialize(cf_name)
|
5
5
|
@cf_name = cf_name
|
6
6
|
@action = nil
|
7
|
+
@consistency = 'QUORUM'
|
7
8
|
end
|
8
9
|
|
9
10
|
def add(column)
|
@@ -23,6 +24,12 @@ module DatastaxRails#:nodoc:
|
|
23
24
|
@action = 'ALTER'
|
24
25
|
self
|
25
26
|
end
|
27
|
+
|
28
|
+
def rename(col1,col2)
|
29
|
+
set_column([col1,col2])
|
30
|
+
@action = 'RENAME'
|
31
|
+
self
|
32
|
+
end
|
26
33
|
|
27
34
|
def set_column(column)
|
28
35
|
if(@action)
|
@@ -39,6 +46,8 @@ module DatastaxRails#:nodoc:
|
|
39
46
|
stmt << "ADD #{@column.keys.first} #{@column.values.first}"
|
40
47
|
elsif(@action == 'DROP')
|
41
48
|
stmt << "DROP #{@column}"
|
49
|
+
elsif(@action == 'RENAME')
|
50
|
+
stmt << "RENAME \"#{@column[0]}\" TO \"#{@column[1]}\""
|
42
51
|
end
|
43
52
|
|
44
53
|
stmt
|
@@ -4,6 +4,7 @@ module DatastaxRails
|
|
4
4
|
# Base initialize that sets the default consistency.
|
5
5
|
def initialize(klass, *args)
|
6
6
|
@consistency = klass.default_consistency.to_s.upcase
|
7
|
+
@keyspace = DatastaxRails::Base.config[:keyspace]
|
7
8
|
end
|
8
9
|
|
9
10
|
# Abstract. Should be overridden by subclasses
|
@@ -17,7 +18,7 @@ module DatastaxRails
|
|
17
18
|
def execute
|
18
19
|
cql = self.to_cql
|
19
20
|
puts cql if ENV['DEBUG_CQL'] == 'true'
|
20
|
-
DatastaxRails::Base.connection.execute_cql_query(cql)
|
21
|
+
DatastaxRails::Base.connection.execute_cql_query(cql, :consistency => CassandraCQL::Thrift::ConsistencyLevel.const_get(@consistency || 'QUORUM'))
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
@@ -6,7 +6,7 @@ module DatastaxRails#:nodoc:
|
|
6
6
|
@columns = {}
|
7
7
|
@storage_parameters = []
|
8
8
|
@key_type = 'uuid'
|
9
|
-
@key_columns = @key_name = "
|
9
|
+
@key_columns = @key_name = "key"
|
10
10
|
end
|
11
11
|
|
12
12
|
def key_type(key_type)
|
@@ -48,11 +48,11 @@ module DatastaxRails#:nodoc:
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def to_cql
|
51
|
-
stmt = "CREATE COLUMNFAMILY #{@cf_name} (
|
51
|
+
stmt = "CREATE COLUMNFAMILY #{@cf_name} (#{@key_name} #{@key_type}, "
|
52
52
|
@columns.each do |name,type|
|
53
53
|
stmt << "#{name} #{type}, "
|
54
54
|
end
|
55
|
-
stmt << "PRIMARY KEY (
|
55
|
+
stmt << "PRIMARY KEY (#{@key_columns}))"
|
56
56
|
unless @storage_parameters.empty?
|
57
57
|
stmt << " WITH "
|
58
58
|
stmt << @storage_parameters.join(" AND ")
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module DatastaxRails#:nodoc:
|
2
|
+
module Cql #:nodoc:
|
3
|
+
class CreateIndex < Base #:nodoc:
|
4
|
+
def initialize(index_name = nil)
|
5
|
+
@cf_name = nil
|
6
|
+
@column = nil
|
7
|
+
@index_name = index_name
|
8
|
+
end
|
9
|
+
|
10
|
+
def on(cf_name)
|
11
|
+
@cf_name = cf_name
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def column(column)
|
16
|
+
@column = column
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_cql
|
21
|
+
"CREATE INDEX #{@index_name} ON #{@cf_name} (#{@column})"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -17,12 +17,12 @@ module DatastaxRails#:nodoc:
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def to_cql
|
20
|
-
stmt = "CREATE KEYSPACE #{@ks_name} WITH
|
20
|
+
stmt = "CREATE KEYSPACE #{@ks_name} WITH REPLICATION = {'class' : '#{@strategy_class}'"
|
21
21
|
|
22
22
|
@strategy_options.each do |key, value|
|
23
|
-
stmt << "
|
23
|
+
stmt << ", '#{key.to_s}' : '#{value.to_s}'"
|
24
24
|
end
|
25
|
-
|
25
|
+
stmt << '}'
|
26
26
|
stmt
|
27
27
|
end
|
28
28
|
end
|
@@ -7,7 +7,7 @@ module DatastaxRails
|
|
7
7
|
@timestamp = nil
|
8
8
|
@columns = []
|
9
9
|
@conditions = {}
|
10
|
-
@key_name = "
|
10
|
+
@key_name = "key"
|
11
11
|
super
|
12
12
|
end
|
13
13
|
|
@@ -37,8 +37,8 @@ module DatastaxRails
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def to_cql
|
40
|
-
values = [@keys]
|
41
|
-
stmt = "DELETE #{@columns.join(',')} FROM #{@klass.column_family}
|
40
|
+
values = [@keys.collect{|k|k.to_s}]
|
41
|
+
stmt = "DELETE #{@columns.join(',')} FROM #{@klass.column_family} "
|
42
42
|
|
43
43
|
if(@timestamp)
|
44
44
|
stmt << "AND TIMESTAMP #{@timestamp} "
|
@@ -36,7 +36,7 @@ module DatastaxRails
|
|
36
36
|
keys << k.to_s
|
37
37
|
values << v
|
38
38
|
end
|
39
|
-
stmt = "INSERT INTO #{@klass.column_family} (#{keys.join(',')}) VALUES (#{('?'*keys.size).split(//).join(',')})
|
39
|
+
stmt = "INSERT INTO #{@klass.column_family} (#{keys.join(',')}) VALUES (#{('?'*keys.size).split(//).join(',')}) "
|
40
40
|
|
41
41
|
if(@ttl)
|
42
42
|
stmt << "AND TTL #{@ttl} "
|
@@ -46,7 +46,7 @@ module DatastaxRails
|
|
46
46
|
stmt << "AND TIMESTAMP #{@timestamp}"
|
47
47
|
end
|
48
48
|
|
49
|
-
CassandraCQL::Statement.sanitize(stmt, values)
|
49
|
+
CassandraCQL::Statement.sanitize(stmt, values).force_encoding('UTF-8')
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
@@ -39,10 +39,10 @@ module DatastaxRails#:nodoc:
|
|
39
39
|
def to_cql
|
40
40
|
conditions = []
|
41
41
|
values = []
|
42
|
-
stmt = "SELECT #{@select} FROM #{@klass.column_family}
|
42
|
+
stmt = "SELECT #{@select} FROM #{@klass.column_family} "
|
43
43
|
|
44
44
|
if @paginate
|
45
|
-
conditions << "token(
|
45
|
+
conditions << "token(key) > token('#{@paginate}')"
|
46
46
|
end
|
47
47
|
|
48
48
|
@conditions.each do |k,v|
|
@@ -37,29 +37,29 @@ module DatastaxRails
|
|
37
37
|
column_names = @columns.keys
|
38
38
|
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
stmt = "update #{@klass.column_family} "
|
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 "
|
45
52
|
|
46
|
-
|
47
|
-
stmt << "AND TIMESTAMP #{@timestamp}"
|
48
|
-
end
|
53
|
+
first_entry = column_names.first
|
49
54
|
|
50
|
-
|
51
|
-
|
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
|
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]])
|
59
58
|
end
|
60
|
-
|
61
|
-
|
62
|
-
stmt
|
59
|
+
end
|
60
|
+
|
61
|
+
stmt << CassandraCQL::Statement.sanitize(" WHERE key IN (?)", [@key])
|
62
|
+
stmt.force_encoding('UTF-8')
|
63
63
|
end
|
64
64
|
|
65
65
|
# def execute
|
data/lib/datastax_rails/cql.rb
CHANGED
@@ -13,9 +13,11 @@ module DatastaxRails
|
|
13
13
|
autoload :ColumnFamily
|
14
14
|
autoload :Consistency
|
15
15
|
autoload :CreateColumnFamily
|
16
|
+
autoload :CreateIndex
|
16
17
|
autoload :CreateKeyspace
|
17
18
|
autoload :Delete
|
18
19
|
autoload :DropColumnFamily
|
20
|
+
autoload :DropIndex
|
19
21
|
autoload :DropKeyspace
|
20
22
|
autoload :Insert
|
21
23
|
autoload :Select
|
@@ -112,7 +112,7 @@ module DatastaxRails
|
|
112
112
|
end
|
113
113
|
|
114
114
|
attribute_definitions.each do |k,definition|
|
115
|
-
casted[k.to_s] = definition.instantiate(object, attributes[k])
|
115
|
+
casted[k.to_s] = definition.instantiate(object, attributes[k]).to_s
|
116
116
|
end
|
117
117
|
casted
|
118
118
|
end
|
@@ -123,17 +123,8 @@ module DatastaxRails
|
|
123
123
|
end
|
124
124
|
|
125
125
|
def write_with_solr(key, attributes, options)
|
126
|
-
# We need to collect removed fields since we can't currently delete the column via
|
127
|
-
# the solr interface
|
128
|
-
removed_fields = []
|
129
|
-
attributes.each do |k,v|
|
130
|
-
removed_fields << k.to_s if v.blank?
|
131
|
-
end
|
132
126
|
xml_doc = RSolr::Xml::Generator.new.add(attributes.merge(:id => key))
|
133
127
|
self.solr_connection.update(:data => xml_doc, :params => {:replacefields => false, :cl => options[:consistency]})
|
134
|
-
unless removed_fields.empty?
|
135
|
-
cql.delete(key.to_s).columns(removed_fields).using(options[:consistency]).execute
|
136
|
-
end
|
137
128
|
end
|
138
129
|
end
|
139
130
|
|
@@ -205,6 +196,7 @@ module DatastaxRails
|
|
205
196
|
end
|
206
197
|
|
207
198
|
def write(options) #:nodoc:
|
199
|
+
options[:new_record] = new_record?
|
208
200
|
changed_attributes = changed.inject({}) { |h, n| h[n] = read_attribute(n); h }
|
209
201
|
return true if changed_attributes.empty?
|
210
202
|
self.class.write(key, changed_attributes, options)
|
@@ -1,8 +1,15 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'datastax_rails'
|
3
3
|
require 'rails'
|
4
|
+
require 'action_controller/railtie'
|
5
|
+
|
4
6
|
module DatastaxRails
|
5
7
|
class Railtie < Rails::Railtie
|
8
|
+
config.action_dispatch.rescue_responses.merge!(
|
9
|
+
'DatastaxRails::RecordNotFound' => :not_found,
|
10
|
+
'DatastaxRails::RecordInvalid' => :unprocessable_entity,
|
11
|
+
'DatastaxRails::RecordNotSaved' => :unprocessable_entity)
|
12
|
+
|
6
13
|
initializer 'datastax_rails.init' do
|
7
14
|
ActiveSupport.on_load(:datastax_rails) do
|
8
15
|
end
|
@@ -22,6 +22,16 @@ module DatastaxRails
|
|
22
22
|
records.each { |record| yield record }
|
23
23
|
end
|
24
24
|
end
|
25
|
+
|
26
|
+
def find_each_with_index(options = {})
|
27
|
+
idx = 0
|
28
|
+
find_in_batches(options) do |records|
|
29
|
+
records.each do |record|
|
30
|
+
yield record, idx
|
31
|
+
idx += 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
25
35
|
|
26
36
|
# Yields each batch of records that was found by the find +options+ as
|
27
37
|
# an array. The size of each batch is set by the <tt>:batch_size</tt>
|
@@ -50,14 +60,14 @@ module DatastaxRails
|
|
50
60
|
# @param options [Hash] finder options
|
51
61
|
# @yeild [records] a batch of DatastaxRails records
|
52
62
|
def find_in_batches(options = {})
|
53
|
-
relation = self
|
63
|
+
relation = self
|
54
64
|
|
55
|
-
unless @order_values.empty?
|
65
|
+
unless (@order_values.empty? || @order_values == [{:created_at => :asc}])
|
56
66
|
DatastaxRails::Base.logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size")
|
57
67
|
end
|
58
68
|
|
59
69
|
if (finder_options = options.except(:start, :batch_size)).present?
|
60
|
-
raise "You can't specify an order, it's forced to be #{
|
70
|
+
raise "You can't specify an order, it's forced to be #{relation.use_solr_value ? "created_at" : "key"}" if options[:order].present?
|
61
71
|
raise "You can't specify a limit, it's forced to be the batch_size" if options[:limit].present?
|
62
72
|
|
63
73
|
relation = apply_finder_options(finder_options)
|
@@ -66,20 +76,23 @@ module DatastaxRails
|
|
66
76
|
start = options.delete(:start)
|
67
77
|
batch_size = options.delete(:batch_size) || 1000
|
68
78
|
|
79
|
+
batch_order = relation.use_solr_value ? :created_at : :key
|
69
80
|
relation = relation.limit(batch_size)
|
70
|
-
|
71
|
-
|
81
|
+
relation = relation.order(batch_order) if relation.use_solr_value
|
82
|
+
records = start ? relation.where(batch_order).greater_than(start).to_a : relation.to_a
|
72
83
|
while records.size > 0
|
73
84
|
records_size = records.size
|
74
|
-
|
85
|
+
offset = relation.use_solr_value ? records.last.created_at.to_time : records.last.id
|
75
86
|
yield records
|
76
87
|
|
77
88
|
break if records_size < batch_size
|
78
|
-
|
79
|
-
|
80
|
-
|
89
|
+
if offset
|
90
|
+
if relation.use_solr_value
|
91
|
+
offset += 1
|
92
|
+
end
|
93
|
+
records = relation.where(batch_order).greater_than(offset).to_a
|
81
94
|
else
|
82
|
-
raise "
|
95
|
+
raise "Batch order not included in the custom select clause"
|
83
96
|
end
|
84
97
|
end
|
85
98
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module DatastaxRails
|
2
|
+
module FacetMethods
|
3
|
+
# Instructs SOLR to get facet counts on the passed in field.
|
4
|
+
#
|
5
|
+
# Model.facet(:category)
|
6
|
+
#
|
7
|
+
# This may be specified multiple times to get facet counts on multiple fields.
|
8
|
+
#
|
9
|
+
# @param field [String, Symbol] the field to get facet counts for
|
10
|
+
# @return [DatastaxRails::Relation] a new Relation object
|
11
|
+
def facet(field)
|
12
|
+
clone.tap do |r|
|
13
|
+
r.facet_field_values << field
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -137,11 +137,11 @@ module DatastaxRails
|
|
137
137
|
end
|
138
138
|
|
139
139
|
def find_one(id)
|
140
|
-
with_cassandra.where(:
|
140
|
+
with_cassandra.where(:key => id).first || raise(RecordNotFound, "Couldn't find #{@klass.name} with ID=#{id}")
|
141
141
|
end
|
142
142
|
|
143
143
|
def find_some(ids)
|
144
|
-
result = with_cassandra.where(:
|
144
|
+
result = with_cassandra.where(:key => ids).all
|
145
145
|
|
146
146
|
expected_size =
|
147
147
|
if @limit_value && ids.size > @limit_value
|
@@ -163,7 +163,7 @@ module DatastaxRails
|
|
163
163
|
return self if attribute.blank?
|
164
164
|
|
165
165
|
clone.tap do |r|
|
166
|
-
order_by = attribute.is_a?(Hash) ? attribute.dup : {attribute => :asc}
|
166
|
+
order_by = attribute.is_a?(Hash) ? attribute.dup : {attribute.to_sym => :asc}
|
167
167
|
|
168
168
|
r.order_values << order_by
|
169
169
|
end
|
@@ -240,7 +240,13 @@ module DatastaxRails
|
|
240
240
|
# works if you run against a secondary index. So this currently just
|
241
241
|
# delegates to the count_via_solr method.
|
242
242
|
def count_via_cql
|
243
|
-
|
243
|
+
select_columns = ['count(*)']
|
244
|
+
cql = @cql.select(select_columns)
|
245
|
+
cql.using(@consistency_value) if @consistency_value
|
246
|
+
@where_values.each do |wv|
|
247
|
+
cql.conditions(wv)
|
248
|
+
end
|
249
|
+
CassandraCQL::Result.new(cql.execute).fetch['count']
|
244
250
|
end
|
245
251
|
|
246
252
|
# Constructs a CQL query and runs it against Cassandra directly. For this to
|
@@ -248,7 +254,7 @@ module DatastaxRails
|
|
248
254
|
# For ad-hoc queries, you will have to use Solr.
|
249
255
|
def query_via_cql
|
250
256
|
select_columns = select_values.empty? ? (@klass.attribute_definitions.keys - @klass.lazy_attributes) : select_values.flatten
|
251
|
-
cql = @cql.select(select_columns)
|
257
|
+
cql = @cql.select(select_columns + ['key'])
|
252
258
|
cql.using(@consistency_value) if @consistency_value
|
253
259
|
@where_values.each do |wv|
|
254
260
|
cql.conditions(wv)
|
@@ -256,7 +262,7 @@ module DatastaxRails
|
|
256
262
|
@greater_than_values.each do |gtv|
|
257
263
|
gtv.each do |k,v|
|
258
264
|
# Special case if inequality is equal to the primary key (we're paginating)
|
259
|
-
if(k == :
|
265
|
+
if(k == :key)
|
260
266
|
cql.paginate(v)
|
261
267
|
end
|
262
268
|
end
|
@@ -266,7 +272,7 @@ module DatastaxRails
|
|
266
272
|
end
|
267
273
|
results = []
|
268
274
|
CassandraCQL::Result.new(cql.execute).fetch do |row|
|
269
|
-
results << @klass.instantiate(row
|
275
|
+
results << @klass.instantiate(row['key'], row.to_hash, select_columns)
|
270
276
|
end
|
271
277
|
results
|
272
278
|
end
|
@@ -362,7 +368,8 @@ module DatastaxRails
|
|
362
368
|
end
|
363
369
|
|
364
370
|
select_columns = select_values.empty? ? (@klass.attribute_definitions.keys - @klass.lazy_attributes) : select_values.flatten
|
365
|
-
|
371
|
+
select_columns << "id"
|
372
|
+
params[:fl] = select_columns.collect(&:to_s).join(",")
|
366
373
|
unless(@stats_values.empty?)
|
367
374
|
params[:stats] = 'true'
|
368
375
|
@stats_values.flatten.each do |sv|
|
@@ -398,6 +405,7 @@ module DatastaxRails
|
|
398
405
|
if solr_response["stats"]
|
399
406
|
@stats = solr_response["stats"]["stats_fields"].with_indifferent_access
|
400
407
|
end
|
408
|
+
pp params if ENV['DEBUG_SOLR'] == 'true'
|
401
409
|
results
|
402
410
|
end
|
403
411
|
|
@@ -487,7 +495,7 @@ module DatastaxRails
|
|
487
495
|
def method_missing(method, *args, &block) #:nodoc:
|
488
496
|
if Array.method_defined?(method)
|
489
497
|
to_a.send(method, *args, &block)
|
490
|
-
elsif @klass.respond_to?(method)
|
498
|
+
elsif @klass.respond_to?(method, true)
|
491
499
|
scoping { @klass.send(method, *args, &block) }
|
492
500
|
else
|
493
501
|
super
|