extendi-cassandra_object 1.0.5 → 1.0.6
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/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:
|