extendi-cassandra_object 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/extendi-cassandra_object.gemspec +1 -1
- data/lib/cassandra_object/adapters/cassandra_adapter.rb +6 -6
- data/lib/cassandra_object/adapters/cassandra_schemaless_adapter.rb +27 -11
- data/lib/cassandra_object/scope.rb +13 -11
- data/lib/cassandra_object/scope/finder_methods.rb +11 -4
- data/lib/cassandra_object/scope/query_methods.rb +6 -2
- data/test/unit/core_test.rb +10 -0
- data/test/unit/scope/finder_methods_test.rb +24 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: efe17be3c5e2444bff2078ff198a4103e590a436
|
4
|
+
data.tar.gz: 5bfd5a2ec7ab2393478ca07102627d62707422b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19d0cd635b148b38e5c9a85faab5595d65b45c94ec32387e3f7b2188e6e3cc3b5924e8bc63ad3d957ad25ab1ac5ca57cfe1d7fd02bed8429070e9c24cfa48cd0
|
7
|
+
data.tar.gz: 3b63a775a8af44163f983b5d933407aa977c5e33ea92f165723909fe806c07499600fca99eee34a98c8e4e175c5d88c40a686c400f2c5a1cb8a24fd3becfb0a3
|
@@ -30,14 +30,14 @@ module CassandraObject
|
|
30
30
|
str << "ALLOW FILTERING" if @scope.klass.allow_filtering
|
31
31
|
return [] << str.delete_if(&:blank?) * ' '
|
32
32
|
end
|
33
|
-
@scope.id_values.map
|
33
|
+
@scope.id_values.map do |id|
|
34
34
|
str = [
|
35
35
|
"SELECT #{select_string} FROM #{@scope.klass.column_family}",
|
36
36
|
where_string_async(id)
|
37
37
|
]
|
38
38
|
str << "ALLOW FILTERING" if @scope.klass.allow_filtering
|
39
39
|
str.delete_if(&:blank?) * ' '
|
40
|
-
|
40
|
+
end
|
41
41
|
end
|
42
42
|
|
43
43
|
def where_string_async(id)
|
@@ -110,17 +110,17 @@ module CassandraObject
|
|
110
110
|
def execute(statement, arguments = [])
|
111
111
|
ActiveSupport::Notifications.instrument('cql.cassandra_object', cql: statement) do
|
112
112
|
type_hints = []
|
113
|
-
arguments.
|
113
|
+
arguments.each { |a| type_hints << CassandraObject::Types::TypeHelper.guess_type(a) } unless arguments.nil?
|
114
114
|
connection.execute statement, arguments: arguments, type_hints: type_hints, consistency: consistency, page_size: config[:page_size]
|
115
115
|
end
|
116
116
|
end
|
117
117
|
|
118
118
|
def execute_async(queries, arguments = [])
|
119
|
-
futures = queries.map
|
119
|
+
futures = queries.map do |q|
|
120
120
|
ActiveSupport::Notifications.instrument('cql.cassandra_object', cql: q) do
|
121
121
|
connection.execute_async q, arguments: arguments, consistency: consistency, page_size: config[:page_size]
|
122
122
|
end
|
123
|
-
|
123
|
+
end
|
124
124
|
futures.map do |future|
|
125
125
|
rows = future.get
|
126
126
|
rows
|
@@ -169,7 +169,7 @@ module CassandraObject
|
|
169
169
|
|
170
170
|
def delete(table, key, ids)
|
171
171
|
ids = [ids] if !ids.is_a?(Array)
|
172
|
-
statement = "DELETE FROM #{table} WHERE #{key} IN (#{ids.map
|
172
|
+
statement = "DELETE FROM #{table} WHERE #{key} IN (#{ids.map{|id| "'#{id}'"}.join(',')})"
|
173
173
|
execute(statement, nil)
|
174
174
|
end
|
175
175
|
|
@@ -30,17 +30,17 @@ module CassandraObject
|
|
30
30
|
"SELECT #{select_string} FROM #{@scope.klass.column_family}",
|
31
31
|
where_string_async(nil)
|
32
32
|
]
|
33
|
-
str <<
|
33
|
+
str << 'ALLOW FILTERING' if @scope.klass.allow_filtering
|
34
34
|
return [] << str.delete_if(&:blank?) * ' '
|
35
35
|
end
|
36
|
-
@scope.id_values.map
|
36
|
+
@scope.id_values.map do |id|
|
37
37
|
str = [
|
38
38
|
"SELECT #{select_string} FROM #{@scope.klass.column_family}",
|
39
39
|
where_string_async(id)
|
40
40
|
]
|
41
|
-
str <<
|
41
|
+
str << 'ALLOW FILTERING' if @scope.klass.allow_filtering
|
42
42
|
str.delete_if(&:blank?) * ' '
|
43
|
-
|
43
|
+
end
|
44
44
|
end
|
45
45
|
|
46
46
|
def where_string_async(id)
|
@@ -142,9 +142,9 @@ module CassandraObject
|
|
142
142
|
query << " LIMIT #{scope.limit_value}" if scope.limit_value == 1
|
143
143
|
ids = []
|
144
144
|
new_next_cursor = nil
|
145
|
-
execute_async([query], nil, per_page, next_cursor).
|
146
|
-
item.rows.
|
147
|
-
new_next_cursor = item.paging_state
|
145
|
+
execute_async([query], nil, per_page, next_cursor).each do |item|
|
146
|
+
item.rows.each { |x| ids << x[primary_key_column] }
|
147
|
+
new_next_cursor = item.paging_state unless item.last_page?
|
148
148
|
end
|
149
149
|
return {ids: ids, new_next_cursor: new_next_cursor}
|
150
150
|
end
|
@@ -154,19 +154,35 @@ module CassandraObject
|
|
154
154
|
queries.compact! if queries.present?
|
155
155
|
raise CassandraObject::RecordNotFound if !queries.present?
|
156
156
|
|
157
|
-
arguments = scope.select_values.select
|
158
|
-
arguments += scope.where_values.select.each_with_index
|
157
|
+
arguments = scope.select_values.select{ |sv| sv != :column1 }.map(&:to_s)
|
158
|
+
arguments += scope.where_values.select.each_with_index{ |_, i| i.odd? }.reject{ |c| c.empty? }.map(&:to_s)
|
159
159
|
records = execute_async(queries, arguments).map do |item|
|
160
160
|
# pagination
|
161
161
|
elems = []
|
162
162
|
loop do
|
163
|
-
item.rows.
|
163
|
+
item.rows.each{ |x| elems << x }
|
164
164
|
break if item.last_page?
|
165
165
|
item = item.next_page
|
166
166
|
end
|
167
167
|
elems
|
168
168
|
end
|
169
|
-
records.flatten!
|
169
|
+
{results: records.flatten!}
|
170
|
+
end
|
171
|
+
|
172
|
+
def select_paginated(scope)
|
173
|
+
queries = QueryBuilder.new(self, scope).to_query_async
|
174
|
+
queries.compact! if queries.present?
|
175
|
+
raise CassandraObject::RecordNotFound if !queries.present?
|
176
|
+
|
177
|
+
arguments = scope.select_values.select{ |sv| sv != :column1 }.map(&:to_s)
|
178
|
+
arguments += scope.where_values.select.each_with_index{ |_, i| i.odd? }.reject{ |c| c.empty? }.map(&:to_s)
|
179
|
+
new_next_cursor = nil
|
180
|
+
records = []
|
181
|
+
execute_async(queries, arguments, scope.limit_value, scope.next_cursor).each do |item|
|
182
|
+
new_next_cursor = item.paging_state unless item.last_page?
|
183
|
+
item.rows.each{ |x| records << x }
|
184
|
+
end
|
185
|
+
return {results: records, new_next_cursor: new_next_cursor}
|
170
186
|
end
|
171
187
|
|
172
188
|
def insert(table, id, attributes, ttl = nil)
|
@@ -34,13 +34,13 @@ module CassandraObject
|
|
34
34
|
if klass.respond_to?(method_name)
|
35
35
|
scoping { klass.send(method_name, *args, &block) }
|
36
36
|
elsif Array.method_defined?(method_name)
|
37
|
-
|
37
|
+
execute.send(method_name, *args, &block)
|
38
38
|
else
|
39
39
|
super
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
def select_records
|
43
|
+
def select_records(auto_paginate = true)
|
44
44
|
results = []
|
45
45
|
records = {}
|
46
46
|
new_next_cursor = nil
|
@@ -50,24 +50,25 @@ module CassandraObject
|
|
50
50
|
records[key] = attributes
|
51
51
|
end
|
52
52
|
else
|
53
|
-
if @is_all
|
53
|
+
if @is_all && @id_values.empty?
|
54
54
|
pre = klass.adapter.pre_select(self, @limit_value, @next_cursor)
|
55
|
-
new_next_cursor
|
55
|
+
new_next_cursor ||= pre[:new_next_cursor]
|
56
56
|
return {results: [], next_cursor: new_next_cursor} if pre[:ids].empty? # fix last query all if ids is empty
|
57
|
-
|
57
|
+
@id_values = pre[:ids]
|
58
58
|
end
|
59
59
|
|
60
|
-
resp = klass.adapter.select(self)
|
60
|
+
resp = auto_paginate ? klass.adapter.select(self) : klass.adapter.select_paginated(self)
|
61
61
|
primary_key_column = klass.adapter.primary_key_column
|
62
|
-
|
62
|
+
new_next_cursor ||= resp[:new_next_cursor]
|
63
|
+
resp[:results].each do |cql_row|
|
63
64
|
key = cql_row[primary_key_column]
|
64
65
|
records[key] ||= {}
|
65
66
|
records[key][cql_row.values[1]] = cql_row.values[2]
|
66
67
|
end
|
67
|
-
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
records = records.first(@limit_value) if @limit_value.present?
|
71
|
+
|
71
72
|
records.each do |key, attributes|
|
72
73
|
if self.raw_response || self.schema_type == :dynamic_attributes
|
73
74
|
results << {key => attributes.values.compact.empty? ? attributes.keys : attributes}
|
@@ -75,11 +76,12 @@ module CassandraObject
|
|
75
76
|
results << klass.instantiate(key, attributes)
|
76
77
|
end
|
77
78
|
end
|
78
|
-
results = results.reduce({}, :merge) if self.schema_type == :dynamic_attributes
|
79
|
+
results = results.reduce({}, :merge!) if self.schema_type == :dynamic_attributes
|
79
80
|
if @is_all
|
80
81
|
return {results: results, next_cursor: new_next_cursor}
|
82
|
+
else
|
83
|
+
return results
|
81
84
|
end
|
82
|
-
return results
|
83
85
|
end
|
84
86
|
|
85
87
|
end
|
@@ -15,16 +15,23 @@ module CassandraObject
|
|
15
15
|
nil
|
16
16
|
end
|
17
17
|
|
18
|
+
def find_in_batches(id, next_cursor = nil)
|
19
|
+
obj = self.clone
|
20
|
+
obj.is_all = true
|
21
|
+
obj.next_cursor = next_cursor
|
22
|
+
obj.where_ids(id).execute_paged
|
23
|
+
end
|
24
|
+
|
18
25
|
def find_all_in_batches(next_cursor = nil)
|
19
26
|
obj = self.clone
|
20
27
|
obj.is_all = true
|
21
28
|
obj.next_cursor = next_cursor
|
22
|
-
obj.
|
29
|
+
obj.execute
|
23
30
|
end
|
24
31
|
|
25
32
|
def first
|
26
33
|
return limit(1).find_all_in_batches[:results].first if self.schema_type == :dynamic_attributes || self.schema_type == :schemaless
|
27
|
-
limit(1).
|
34
|
+
limit(1).execute.first
|
28
35
|
end
|
29
36
|
|
30
37
|
private
|
@@ -33,7 +40,7 @@ module CassandraObject
|
|
33
40
|
if id.blank?
|
34
41
|
raise CassandraObject::RecordNotFound, "Couldn't find #{self.name} with key #{id.inspect}"
|
35
42
|
elsif self.schema_type == :dynamic_attributes
|
36
|
-
record = where_ids(id).
|
43
|
+
record = where_ids(id).execute
|
37
44
|
raise CassandraObject::RecordNotFound if record.empty?
|
38
45
|
record
|
39
46
|
elsif record = where_ids(id)[0]
|
@@ -47,7 +54,7 @@ module CassandraObject
|
|
47
54
|
ids = ids.flatten
|
48
55
|
return [] if ids.empty?
|
49
56
|
ids = ids.compact.map(&:to_s).uniq
|
50
|
-
where_ids(ids).
|
57
|
+
where_ids(ids).execute
|
51
58
|
end
|
52
59
|
end
|
53
60
|
end
|
@@ -21,7 +21,7 @@ module CassandraObject
|
|
21
21
|
|
22
22
|
def select(*values, &block)
|
23
23
|
if block_given?
|
24
|
-
|
24
|
+
execute.select(&block)
|
25
25
|
else
|
26
26
|
clone.select!(*values)
|
27
27
|
end
|
@@ -60,10 +60,14 @@ module CassandraObject
|
|
60
60
|
clone.limit! value
|
61
61
|
end
|
62
62
|
|
63
|
-
def
|
63
|
+
def execute
|
64
64
|
select_records
|
65
65
|
end
|
66
66
|
|
67
|
+
def execute_paged
|
68
|
+
select_records(false)
|
69
|
+
end
|
70
|
+
|
67
71
|
end
|
68
72
|
end
|
69
73
|
end
|
data/test/unit/core_test.rb
CHANGED
@@ -52,4 +52,14 @@ class CassandraObject::CoreTest < CassandraObject::TestCase
|
|
52
52
|
issue = Issue.create
|
53
53
|
assert issue.inspect =~ /^#<Issue id: \"\w+\", created_at: \".+\", updated_at: \".+\", description: \".+\">$/
|
54
54
|
end
|
55
|
+
|
56
|
+
test 'inspect schema' do
|
57
|
+
issue = IssueSchema.create(title: 'tit', description: 'desc')
|
58
|
+
assert issue.inspect =~ /^#<IssueSchema id: \"\w+\", title: \".+\", description: \".+\", created_at: \".+\", updated_at: \".+\">$/
|
59
|
+
end
|
60
|
+
|
61
|
+
test 'inspect dynamic' do
|
62
|
+
issue = IssueDynamic.create(key: '1', title: 'tit', dynamic_field1: 'one', dynamic_field2: 'two')
|
63
|
+
assert issue.inspect =~ /^{:key=>\".+\", :title=>\".+\", :dynamic_field1=>\".+\", :dynamic_field2=>\".+\"}$/
|
64
|
+
end
|
55
65
|
end
|
@@ -39,10 +39,32 @@ class CassandraObject::FinderMethodsTest < CassandraObject::TestCase
|
|
39
39
|
second_issue = IssueDynamic.create(key: '2', title: 'tit', dynamic_field1: 'one', dynamic_field2: 'two')
|
40
40
|
res = IssueDynamic.find_all_in_batches
|
41
41
|
reobjected = res[:results].map { |key, val| {key: key }.merge(val) }
|
42
|
+
IssueDynamic.delete(['1', '2'])
|
42
43
|
|
43
44
|
assert_equal [first_issue, second_issue].size, reobjected.size
|
44
45
|
end
|
45
46
|
|
47
|
+
test 'find by key in batches dynamic paged' do
|
48
|
+
100.times.each do |i|
|
49
|
+
IssueDynamic.create(key: '1', title: 'tit', "dynamic_field_#{i}" => ['a'])
|
50
|
+
IssueDynamic.create(key: '2', title: 'tit', "dynamic_field_#{i}" => ['a'])
|
51
|
+
end
|
52
|
+
|
53
|
+
resp = IssueDynamic.limit(10).find_in_batches('1')
|
54
|
+
columns = resp[:results]['1']
|
55
|
+
assert_equal 10, columns.size
|
56
|
+
assert_equal 'dynamic_field_0', columns.keys.first
|
57
|
+
|
58
|
+
cursor = resp[:next_cursor]
|
59
|
+
resp = IssueDynamic.limit(10).find_in_batches('1', cursor)
|
60
|
+
columns = resp[:results]['1']
|
61
|
+
assert_equal 10, columns.size
|
62
|
+
assert_equal 'dynamic_field_18', columns.keys.first
|
63
|
+
|
64
|
+
IssueDynamic.delete(['1', '2'])
|
65
|
+
end
|
66
|
+
|
67
|
+
|
46
68
|
test 'find all in batches dynamic paged' do
|
47
69
|
|
48
70
|
issues = []
|
@@ -104,9 +126,9 @@ class CassandraObject::FinderMethodsTest < CassandraObject::TestCase
|
|
104
126
|
test 'where' do
|
105
127
|
# todo make better tests
|
106
128
|
# mono parameter
|
107
|
-
res1 = Issue.cql_response.where("column1 < 'poi'").
|
129
|
+
res1 = Issue.cql_response.where("column1 < 'poi'").execute
|
108
130
|
# bi parameter
|
109
|
-
res = Issue.cql_response.where('column1 < ?', 'poi').
|
131
|
+
res = Issue.cql_response.where('column1 < ?', 'poi').execute
|
110
132
|
end
|
111
133
|
|
112
134
|
# test 'limit in first' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: extendi-cassandra_object
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Duccio Giovannelli
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-
|
12
|
+
date: 2017-06-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -200,3 +200,4 @@ signing_key:
|
|
200
200
|
specification_version: 4
|
201
201
|
summary: Cassandra ActiveModel
|
202
202
|
test_files: []
|
203
|
+
has_rdoc:
|