extendi-cassandra_object 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|
[](http://travis-ci.org/giovannelli/cassandra_object) [](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
|