extendi-cassandra_object 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +5 -1
- data/README.md +6 -5
- data/extendi-cassandra_object.gemspec +1 -1
- data/lib/cassandra_object/adapters/cassandra_adapter.rb +31 -29
- data/lib/cassandra_object/adapters/cassandra_schemaless_adapter.rb +32 -33
- data/lib/cassandra_object/scope/finder_methods.rb +33 -31
- data/lib/cassandra_object/scoping.rb +2 -0
- data/test/support/cassandra.rb +0 -3
- data/test/unit/connections/connections_test.rb +0 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5523ad43210b62402fbfb637042415f14a7fe174fa3f3646556b1b1e3701df9
|
4
|
+
data.tar.gz: a9ed0b2512e264395a1340c2fbccbaf9259d893105c738c9724d2ee0eba2a944
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f038a28315870cef3b0bc1366e3baa46d4098b7a7c3a4733ec02a2a71281861f87a111e9dfbf1d5c9a0c167b8e1e72198662dded4c7a7b90acbd154b5131e305
|
7
|
+
data.tar.gz: 58ab0a6d6347d97533334ee017ef8d7f9aaf9890e770d1b2abf3629f7e1b80f0a372241985c7c38e47dc4cebd8a2efa100a5c98384ff6ca17dea6927f976ea76
|
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Cassandra Object
|
2
2
|
[![Build Status](https://secure.travis-ci.org/giovannelli/cassandra_object.png)](http://travis-ci.org/giovannelli/cassandra_object) [![Code Climate](https://codeclimate.com/github/giovannelli/cassandra_object/badges/gpa.svg)](https://codeclimate.com/github/giovannelli/cassandra_object)
|
3
3
|
|
4
|
-
Cassandra Object uses ActiveModel to mimic much of the behavior in ActiveRecord.
|
4
|
+
Cassandra Object uses ActiveModel to mimic much of the behavior in ActiveRecord.
|
5
5
|
Use cql3 provided by ruby-driver gem and uses the old thrift structure with the possible option at [this link](https://docs.datastax.com/en/cql/3.1/cql/cql_reference/create_table_r.html?hl=create%2Ctable):
|
6
6
|
|
7
7
|
```shell
|
@@ -118,16 +118,16 @@ You can define a custom configuration for the cassandra connection, allowing you
|
|
118
118
|
```ruby
|
119
119
|
class Widget < CassandraObject::BaseSchema
|
120
120
|
string :name
|
121
|
-
|
121
|
+
|
122
122
|
def self.custom_config
|
123
|
-
#return custom cassandra configuration
|
123
|
+
#return custom cassandra configuration
|
124
124
|
{ }
|
125
125
|
end
|
126
126
|
end
|
127
127
|
```
|
128
|
-
|
128
|
+
|
129
129
|
## Using with Cassandra
|
130
|
-
|
130
|
+
|
131
131
|
Add a config/cassandra.yml:
|
132
132
|
|
133
133
|
```yaml
|
@@ -138,6 +138,7 @@ development:
|
|
138
138
|
connect_timeout: 0.1,
|
139
139
|
request_timeout: 0.1,
|
140
140
|
consistency: :any/:one/:two/:three/:quorum/:all/:local_quorum/:each_quorum/:serial/:local_serial/:local_one,
|
141
|
+
write_consistency: :any/:one/:two/:three/:quorum/:all/:local_quorum/:each_quorum/:serial/:local_serial/:local_one,
|
141
142
|
protocol_version: 3,
|
142
143
|
page_size: 10000,
|
143
144
|
trace: true/false
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
gem 'cassandra-driver'
|
2
4
|
require 'cassandra'
|
3
5
|
require 'logger'
|
@@ -6,7 +8,6 @@ module CassandraObject
|
|
6
8
|
module Adapters
|
7
9
|
class CassandraAdapter < AbstractAdapter
|
8
10
|
class QueryBuilder
|
9
|
-
|
10
11
|
def initialize(adapter, scope)
|
11
12
|
@adapter = adapter
|
12
13
|
@scope = scope
|
@@ -27,7 +28,7 @@ module CassandraObject
|
|
27
28
|
"SELECT #{select_string} FROM #{@scope.klass.column_family}",
|
28
29
|
where_string_async(nil)
|
29
30
|
]
|
30
|
-
str <<
|
31
|
+
str << 'ALLOW FILTERING' if @scope.klass.allow_filtering
|
31
32
|
return [] << str.delete_if(&:blank?) * ' '
|
32
33
|
end
|
33
34
|
|
@@ -43,10 +44,10 @@ module CassandraObject
|
|
43
44
|
wheres = @scope.where_values.dup.select.each_with_index { |_, i| i.even? }
|
44
45
|
if ids.present?
|
45
46
|
wheres << if ids.size > 1
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
"#{@scope._key} IN (#{ids.map { |id| "'#{id}'" }.join(',')})"
|
48
|
+
else
|
49
|
+
"#{@scope._key} = '#{ids.first}'"
|
50
|
+
end
|
50
51
|
end
|
51
52
|
"WHERE #{wheres * ' AND '}" if wheres.any?
|
52
53
|
end
|
@@ -62,6 +63,7 @@ module CassandraObject
|
|
62
63
|
:connections_per_local_node,
|
63
64
|
:connections_per_remote_node,
|
64
65
|
:consistency,
|
66
|
+
:write_consistency,
|
65
67
|
:credentials,
|
66
68
|
:futures_factory,
|
67
69
|
:hosts,
|
@@ -94,7 +96,7 @@ module CassandraObject
|
|
94
96
|
params = cluster_options[policy_key]
|
95
97
|
if params
|
96
98
|
if params.is_a?(Hash)
|
97
|
-
cluster_options[policy_key] = (class_template % [params[:policy].classify]).constantize.new(*params[:params]||[])
|
99
|
+
cluster_options[policy_key] = (class_template % [params[:policy].classify]).constantize.new(*params[:params] || [])
|
98
100
|
else
|
99
101
|
cluster_options[policy_key] = (class_template % [params.classify]).constantize.new
|
100
102
|
end
|
@@ -106,7 +108,8 @@ module CassandraObject
|
|
106
108
|
heartbeat_interval: cluster_options.keys.include?(:heartbeat_interval) ? cluster_options[:heartbeat_interval] : 30,
|
107
109
|
idle_timeout: cluster_options[:idle_timeout] || 60,
|
108
110
|
max_schema_agreement_wait: 1,
|
109
|
-
consistency: cluster_options[:consistency] || :
|
111
|
+
consistency: cluster_options[:consistency] || :local_one,
|
112
|
+
write_consistency: cluster_options[:write_consistency] || cluster_options[:consistency] || :local_one,
|
110
113
|
protocol_version: cluster_options[:protocol_version] || 3,
|
111
114
|
page_size: cluster_options[:page_size] || 10000
|
112
115
|
})
|
@@ -121,6 +124,8 @@ module CassandraObject
|
|
121
124
|
end
|
122
125
|
|
123
126
|
def execute(statement, arguments = [])
|
127
|
+
consistency = config[:write_consistency] || config[:consistency]
|
128
|
+
# puts "cassandra adapter: #{consistency}"
|
124
129
|
ActiveSupport::Notifications.instrument('cql.cassandra_object', cql: statement) do
|
125
130
|
type_hints = []
|
126
131
|
arguments.each { |a| type_hints << CassandraObject::Types::TypeHelper.guess_type(a) } unless arguments.nil?
|
@@ -129,6 +134,8 @@ module CassandraObject
|
|
129
134
|
end
|
130
135
|
|
131
136
|
def execute_async(queries, arguments = [])
|
137
|
+
consistency = config[:consistency]
|
138
|
+
# puts "execute_async adapter: #{consistency}"
|
132
139
|
retries = 0
|
133
140
|
futures = queries.map do |q|
|
134
141
|
ActiveSupport::Notifications.instrument('cql.cassandra_object', cql: q) do
|
@@ -151,8 +158,8 @@ module CassandraObject
|
|
151
158
|
def select(scope)
|
152
159
|
queries = QueryBuilder.new(self, scope).to_query_async
|
153
160
|
# todo paginate
|
154
|
-
arguments = scope.where_values.select.each_with_index{ |_, i| i.odd? }.reject{ |c| c.blank? }
|
155
|
-
cql_rows = execute_async(queries, arguments).map{|item| item.rows.map{|x| x}}.flatten!
|
161
|
+
arguments = scope.where_values.select.each_with_index { |_, i| i.odd? }.reject { |c| c.blank? }
|
162
|
+
cql_rows = execute_async(queries, arguments).map { |item| item.rows.map { |x| x } }.flatten!
|
156
163
|
cql_rows.each do |cql_row|
|
157
164
|
attributes = cql_row.to_hash
|
158
165
|
key = attributes.delete(scope._key)
|
@@ -170,31 +177,31 @@ module CassandraObject
|
|
170
177
|
|
171
178
|
def write(table, id, attributes, ttl = nil)
|
172
179
|
statement = "INSERT INTO #{table} (#{(attributes.keys).join(',')}) VALUES (#{(['?'] * attributes.size).join(',')})"
|
173
|
-
statement += " USING TTL #{ttl
|
180
|
+
statement += " USING TTL #{ttl}" if ttl.present?
|
174
181
|
arguments = attributes.values
|
175
182
|
execute(statement, arguments)
|
176
183
|
end
|
177
184
|
|
178
185
|
def write_update(table, id, attributes)
|
179
|
-
queries =[]
|
186
|
+
queries = []
|
180
187
|
# id here is the name of the key of the model
|
181
188
|
id_value = attributes[id]
|
182
189
|
if (not_nil_attributes = attributes.reject { |key, value| value.nil? }).any?
|
183
190
|
statement = "INSERT INTO #{table} (#{(not_nil_attributes.keys).join(',')}) VALUES (#{(['?'] * not_nil_attributes.size).join(',')})"
|
184
|
-
queries << {query: statement, arguments: not_nil_attributes.values}
|
191
|
+
queries << { query: statement, arguments: not_nil_attributes.values }
|
185
192
|
end
|
186
193
|
if (nil_attributes = attributes.select { |key, value| value.nil? }).any?
|
187
|
-
queries << {query: "DELETE #{nil_attributes.keys.join(',')} FROM #{table} WHERE #{id} = ?", arguments: [id_value.to_s]}
|
194
|
+
queries << { query: "DELETE #{nil_attributes.keys.join(',')} FROM #{table} WHERE #{id} = ?", arguments: [id_value.to_s] }
|
188
195
|
end
|
189
196
|
execute_batchable(queries)
|
190
197
|
end
|
191
198
|
|
192
199
|
def delete(scope, ids, attributes = {})
|
193
200
|
ids = [ids] if !ids.is_a?(Array)
|
194
|
-
statement = "DELETE FROM #{scope.column_family} WHERE #{scope._key} IN (#{ids.map{|id| '?'}.join(',')})"
|
201
|
+
statement = "DELETE FROM #{scope.column_family} WHERE #{scope._key} IN (#{ids.map { |id| '?' }.join(',')})"
|
195
202
|
arguments = ids
|
196
203
|
unless attributes.blank?
|
197
|
-
statement += " AND #{attributes.keys.map{ |k| "#{k} = ?" }.join(' AND ')}"
|
204
|
+
statement += " AND #{attributes.keys.map { |k| "#{k} = ?" }.join(' AND ')}"
|
198
205
|
arguments += attributes.values
|
199
206
|
end
|
200
207
|
execute(statement, arguments)
|
@@ -202,20 +209,23 @@ module CassandraObject
|
|
202
209
|
|
203
210
|
def delete_single(obj)
|
204
211
|
keys = obj.class._keys
|
205
|
-
wheres = keys.map{ |k| "#{k} = ?" }.join(' AND ')
|
206
|
-
arguments = keys.map{ |k| obj.attributes[k] }
|
212
|
+
wheres = keys.map { |k| "#{k} = ?" }.join(' AND ')
|
213
|
+
arguments = keys.map { |k| obj.attributes[k] }
|
207
214
|
statement = "DELETE FROM #{obj.class.column_family} WHERE #{wheres}"
|
208
215
|
execute(statement, arguments)
|
209
216
|
end
|
210
217
|
|
211
218
|
def execute_batch(statements)
|
212
|
-
raise '
|
219
|
+
raise 'Statements is empty!' if statements.empty?
|
220
|
+
consistency = config[:write_consistency] || config[:consistency]
|
221
|
+
# puts "cassandra adapter execute batch #{consistency}"
|
222
|
+
|
213
223
|
batch = connection.batch do |b|
|
214
224
|
statements.each do |statement|
|
215
225
|
b.add(statement[:query], arguments: statement[:arguments])
|
216
226
|
end
|
217
227
|
end
|
218
|
-
connection.execute(batch, page_size: config[:page_size])
|
228
|
+
connection.execute(batch, consistency: consistency, page_size: config[:page_size])
|
219
229
|
end
|
220
230
|
|
221
231
|
# SCHEMA
|
@@ -244,7 +254,7 @@ module CassandraObject
|
|
244
254
|
def schema_execute(cql, keyspace)
|
245
255
|
schema_db = Cassandra.cluster cassandra_cluster_options
|
246
256
|
connection = schema_db.connect keyspace
|
247
|
-
connection.execute cql, consistency: consistency
|
257
|
+
connection.execute cql, consistency: config[:write_consistency] || config[:consistency]
|
248
258
|
end
|
249
259
|
|
250
260
|
def cassandra_version
|
@@ -253,14 +263,6 @@ module CassandraObject
|
|
253
263
|
|
254
264
|
# /SCHEMA
|
255
265
|
|
256
|
-
def consistency
|
257
|
-
defined?(@consistency) ? @consistency : nil
|
258
|
-
end
|
259
|
-
|
260
|
-
def consistency=(val)
|
261
|
-
@consistency = val
|
262
|
-
end
|
263
|
-
|
264
266
|
def statement_create_with_options(stmt, options = '')
|
265
267
|
if !options.nil?
|
266
268
|
statement_with_options stmt, options
|
@@ -45,10 +45,10 @@ module CassandraObject
|
|
45
45
|
|
46
46
|
if ids.present?
|
47
47
|
conditions << if ids.size > 1
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
"#{@adapter.primary_key_column} IN (#{ids.map { |id| "'#{id}'" }.join(',')})"
|
49
|
+
else
|
50
|
+
"#{@adapter.primary_key_column} = '#{ids.first}'"
|
51
|
+
end
|
52
52
|
end
|
53
53
|
|
54
54
|
select_values = @scope.select_values.select { |sv| sv != :column1 }
|
@@ -75,6 +75,7 @@ module CassandraObject
|
|
75
75
|
:connections_per_local_node,
|
76
76
|
:connections_per_remote_node,
|
77
77
|
:consistency,
|
78
|
+
:write_consistency,
|
78
79
|
:credentials,
|
79
80
|
:futures_factory,
|
80
81
|
:hosts,
|
@@ -107,7 +108,7 @@ module CassandraObject
|
|
107
108
|
params = cluster_options[policy_key]
|
108
109
|
if params
|
109
110
|
if params.is_a?(Hash)
|
110
|
-
cluster_options[policy_key] = (class_template % [params[:policy].classify]).constantize.new(*params[:params]||[])
|
111
|
+
cluster_options[policy_key] = (class_template % [params[:policy].classify]).constantize.new(*params[:params] || [])
|
111
112
|
else
|
112
113
|
cluster_options[policy_key] = (class_template % [params.classify]).constantize.new
|
113
114
|
end
|
@@ -119,7 +120,8 @@ module CassandraObject
|
|
119
120
|
heartbeat_interval: cluster_options.keys.include?(:heartbeat_interval) ? cluster_options[:heartbeat_interval] : 30,
|
120
121
|
idle_timeout: cluster_options[:idle_timeout] || 60,
|
121
122
|
max_schema_agreement_wait: 1,
|
122
|
-
consistency: cluster_options[:consistency] || :
|
123
|
+
consistency: cluster_options[:consistency] || :local_one,
|
124
|
+
write_consistency: cluster_options[:write_consistency] || cluster_options[:consistency] || :local_one,
|
123
125
|
protocol_version: cluster_options[:protocol_version] || 3,
|
124
126
|
page_size: cluster_options[:page_size] || 10000
|
125
127
|
})
|
@@ -134,12 +136,17 @@ module CassandraObject
|
|
134
136
|
end
|
135
137
|
|
136
138
|
def execute(statement, arguments = [])
|
139
|
+
consistency = config[:write_consistency] || config[:consistency]
|
140
|
+
# puts "schemaless adapter: #{consistency}"
|
137
141
|
ActiveSupport::Notifications.instrument('cql.cassandra_object', cql: statement) do
|
138
142
|
connection.execute statement, arguments: arguments, consistency: consistency, page_size: config[:page_size]
|
139
143
|
end
|
140
144
|
end
|
141
145
|
|
142
146
|
def execute_async(queries, arguments = [], per_page = nil, next_cursor = nil)
|
147
|
+
consistency = config[:consistency]
|
148
|
+
# puts "schemaless adapter async: #{consistency}"
|
149
|
+
|
143
150
|
retries = 0
|
144
151
|
per_page ||= config[:page_size]
|
145
152
|
futures = queries.map { |q|
|
@@ -169,7 +176,7 @@ module CassandraObject
|
|
169
176
|
item.rows.each { |x| ids << x[primary_key_column] }
|
170
177
|
new_next_cursor = item.paging_state unless item.last_page?
|
171
178
|
end
|
172
|
-
|
179
|
+
{ ids: ids, new_next_cursor: new_next_cursor }
|
173
180
|
end
|
174
181
|
|
175
182
|
def select(scope)
|
@@ -177,19 +184,19 @@ module CassandraObject
|
|
177
184
|
queries.compact! if queries.present?
|
178
185
|
raise CassandraObject::RecordNotFound if !queries.present?
|
179
186
|
|
180
|
-
arguments = scope.select_values.select{ |sv| sv != :column1 }.map(&:to_s)
|
181
|
-
arguments += scope.where_values.select.each_with_index{ |_, i| i.odd? }.reject{ |c| c.empty? }.map(&:to_s)
|
187
|
+
arguments = scope.select_values.select { |sv| sv != :column1 }.map(&:to_s)
|
188
|
+
arguments += scope.where_values.select.each_with_index { |_, i| i.odd? }.reject { |c| c.empty? }.map(&:to_s)
|
182
189
|
records = execute_async(queries, arguments).map do |item|
|
183
190
|
# pagination
|
184
191
|
elems = []
|
185
192
|
loop do
|
186
|
-
item.rows.each{ |x| elems << x }
|
193
|
+
item.rows.each { |x| elems << x }
|
187
194
|
break if item.last_page?
|
188
195
|
item = item.next_page
|
189
196
|
end
|
190
197
|
elems
|
191
198
|
end
|
192
|
-
{results: records.flatten!}
|
199
|
+
{ results: records.flatten! }
|
193
200
|
end
|
194
201
|
|
195
202
|
def select_paginated(scope)
|
@@ -197,15 +204,15 @@ module CassandraObject
|
|
197
204
|
queries.compact! if queries.present?
|
198
205
|
raise CassandraObject::RecordNotFound if !queries.present?
|
199
206
|
|
200
|
-
arguments = scope.select_values.select{ |sv| sv != :column1 }.map(&:to_s)
|
201
|
-
arguments += scope.where_values.select.each_with_index{ |_, i| i.odd? }.reject{ |c| c.empty? }.map(&:to_s)
|
207
|
+
arguments = scope.select_values.select { |sv| sv != :column1 }.map(&:to_s)
|
208
|
+
arguments += scope.where_values.select.each_with_index { |_, i| i.odd? }.reject { |c| c.empty? }.map(&:to_s)
|
202
209
|
new_next_cursor = nil
|
203
210
|
records = []
|
204
211
|
execute_async(queries, arguments, scope.limit_value, scope.next_cursor).each do |item|
|
205
212
|
new_next_cursor = item.paging_state unless item.last_page?
|
206
|
-
item.rows.each{ |x| records << x }
|
213
|
+
item.rows.each { |x| records << x }
|
207
214
|
end
|
208
|
-
{results: records, new_next_cursor: new_next_cursor}
|
215
|
+
{ results: records, new_next_cursor: new_next_cursor }
|
209
216
|
end
|
210
217
|
|
211
218
|
def insert(table, id, attributes, ttl = nil)
|
@@ -218,16 +225,15 @@ module CassandraObject
|
|
218
225
|
|
219
226
|
def write(table, id, attributes, ttl)
|
220
227
|
queries = []
|
221
|
-
# puts attributes
|
222
228
|
attributes.each do |column, value|
|
223
229
|
if !value.nil?
|
224
230
|
query = "INSERT INTO #{table} (#{primary_key_column},column1,value) VALUES (?,?,?)"
|
225
|
-
query += " USING TTL #{ttl
|
231
|
+
query += " USING TTL #{ttl}" if !ttl.nil?
|
226
232
|
args = [id.to_s, column.to_s, value.to_s]
|
227
233
|
|
228
|
-
queries << {query: query, arguments: args}
|
234
|
+
queries << { query: query, arguments: args }
|
229
235
|
else
|
230
|
-
queries << {query: "DELETE FROM #{table} WHERE #{primary_key_column} = ? AND column1= ?", arguments: [id.to_s, column.to_s]}
|
236
|
+
queries << { query: "DELETE FROM #{table} WHERE #{primary_key_column} = ? AND column1= ?", arguments: [id.to_s, column.to_s] }
|
231
237
|
end
|
232
238
|
end
|
233
239
|
execute_batchable(queries)
|
@@ -237,18 +243,20 @@ module CassandraObject
|
|
237
243
|
ids = [ids] if !ids.is_a?(Array)
|
238
244
|
arguments = nil
|
239
245
|
arguments = ids if ids.size == 1
|
240
|
-
statement = "DELETE FROM #{table} WHERE #{create_ids_where_clause(ids)}"
|
246
|
+
statement = "DELETE FROM #{table} WHERE #{create_ids_where_clause(ids)}" # .gsub('?', ids.map { |id| "'#{id}'" }.join(','))
|
241
247
|
execute(statement, arguments)
|
242
248
|
end
|
243
249
|
|
244
250
|
def execute_batch(statements)
|
245
|
-
|
251
|
+
consistency = config[:write_consistency] || config[:consistency]
|
252
|
+
# puts "schemaless execute batch #{consistency}"
|
253
|
+
raise 'Statements is empty!' if statements.empty?
|
246
254
|
batch = connection.batch do |b|
|
247
255
|
statements.each do |statement|
|
248
256
|
b.add(statement[:query], arguments: statement[:arguments])
|
249
257
|
end
|
250
258
|
end
|
251
|
-
connection.execute(batch, page_size: config[:page_size])
|
259
|
+
connection.execute(batch, consistency: consistency, page_size: config[:page_size])
|
252
260
|
end
|
253
261
|
|
254
262
|
# SCHEMA
|
@@ -275,7 +283,7 @@ module CassandraObject
|
|
275
283
|
def schema_execute(cql, keyspace)
|
276
284
|
schema_db = Cassandra.cluster cassandra_cluster_options
|
277
285
|
connection = schema_db.connect keyspace
|
278
|
-
connection.execute cql, consistency: consistency
|
286
|
+
connection.execute cql, consistency: config[:write_consistency] || config[:consistency]
|
279
287
|
end
|
280
288
|
|
281
289
|
def cassandra_version
|
@@ -284,14 +292,6 @@ module CassandraObject
|
|
284
292
|
|
285
293
|
# /SCHEMA
|
286
294
|
|
287
|
-
def consistency
|
288
|
-
defined?(@consistency) ? @consistency : nil
|
289
|
-
end
|
290
|
-
|
291
|
-
def consistency=(val)
|
292
|
-
@consistency = val
|
293
|
-
end
|
294
|
-
|
295
295
|
def statement_create_with_options(stmt, options)
|
296
296
|
if !options.nil?
|
297
297
|
statement_with_options stmt, options
|
@@ -338,9 +338,8 @@ module CassandraObject
|
|
338
338
|
return ids if ids.empty?
|
339
339
|
ids = ids.first if ids.is_a?(Array) && ids.one?
|
340
340
|
sql = ids.is_a?(Array) ? "#{primary_key_column} IN (#{ids.map { |id| "'#{id}'" }.join(',')})" : "#{primary_key_column} = ?"
|
341
|
-
|
341
|
+
sql
|
342
342
|
end
|
343
|
-
|
344
343
|
end
|
345
344
|
end
|
346
345
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CassandraObject
|
2
4
|
class Scope
|
3
5
|
module FinderMethods
|
@@ -16,60 +18,60 @@ module CassandraObject
|
|
16
18
|
end
|
17
19
|
|
18
20
|
def find_in_batches(id, next_cursor = nil)
|
19
|
-
obj =
|
21
|
+
obj = clone
|
20
22
|
obj.is_all = true
|
21
23
|
obj.next_cursor = next_cursor
|
22
24
|
obj.where_ids(id).execute_paged
|
23
25
|
end
|
24
26
|
|
25
27
|
def find_all_in_batches(next_cursor = nil)
|
26
|
-
obj =
|
28
|
+
obj = clone
|
27
29
|
obj.is_all = true
|
28
30
|
obj.next_cursor = next_cursor
|
29
31
|
obj.execute
|
30
32
|
end
|
31
33
|
|
32
34
|
def first
|
33
|
-
return limit(1).find_all_in_batches[:results].first if
|
35
|
+
return limit(1).find_all_in_batches[:results].first if schema_type == :dynamic_attributes || schema_type == :schemaless
|
34
36
|
limit(1).execute.first
|
35
37
|
end
|
36
38
|
|
37
39
|
private
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
41
|
+
def find_one(id)
|
42
|
+
if id.blank?
|
43
|
+
not_found(id)
|
44
|
+
elsif schema_type == :dynamic_attributes
|
45
|
+
record = where_ids(id).execute
|
46
|
+
not_found(id) if record.empty?
|
47
|
+
record
|
48
|
+
elsif record = where_ids(id)[0]
|
49
|
+
record
|
50
|
+
else
|
51
|
+
not_found(id)
|
52
|
+
end
|
50
53
|
end
|
51
|
-
end
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
-
|
55
|
+
def find_some(pids)
|
56
|
+
ids = pids.flatten.compact.uniq.map(&:to_s)
|
57
|
+
return [] if ids.empty?
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
+
qr = where_ids(ids).execute
|
60
|
+
is_dymnamic = qr.is_a?(Hash)
|
59
61
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
62
|
+
results = qr.sort_by do |r|
|
63
|
+
id = r.keys.first if r.is_a?(Hash)
|
64
|
+
id = r[0] if r.is_a?(Array)
|
65
|
+
id = r.id if id.nil?
|
66
|
+
ids.index(id)
|
67
|
+
end
|
66
68
|
|
67
|
-
|
68
|
-
|
69
|
+
is_dymnamic ? Hash[results] : results
|
70
|
+
end
|
69
71
|
|
70
|
-
|
71
|
-
|
72
|
-
|
72
|
+
def not_found(id)
|
73
|
+
raise CassandraObject::RecordNotFound, "Couldn't find #{name} with key #{id.inspect}"
|
74
|
+
end
|
73
75
|
end
|
74
76
|
end
|
75
77
|
end
|
data/test/support/cassandra.rb
CHANGED
@@ -38,9 +38,6 @@ CassandraObject::Schemaless.create_column_family 'IssueDynamics'
|
|
38
38
|
CassandraObject::Schemaless.create_column_family 'IssuesCustomConfig'
|
39
39
|
CassandraObject::Schema.create_column_family 'IssueSchemaFathers', { attributes: 'id text, title text, field float, created_at timestamp, updated_at timestamp, PRIMARY KEY (id)', options: {} }
|
40
40
|
CassandraObject::Schema.create_column_family 'IssueSchemaChildren', { attributes: 'id text, title text, description text, field float, created_at timestamp, updated_at timestamp, issue_schema_father_id text, PRIMARY KEY (id)', options: {} }
|
41
|
-
CassandraObject::BaseSchemaless.adapter.consistency = :quorum
|
42
|
-
CassandraObject::BaseSchemalessDynamic.adapter.consistency = :quorum
|
43
|
-
CassandraObject::BaseSchema.adapter.consistency = :quorum
|
44
41
|
|
45
42
|
CassandraObject::Base.class_eval do
|
46
43
|
class_attribute :created_records
|