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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7f33ea4a5998a0a9037609d93c924510d3274631
4
- data.tar.gz: 34a9ee8f8b1069418b21752e1435f6ed16d461c1
3
+ metadata.gz: efe17be3c5e2444bff2078ff198a4103e590a436
4
+ data.tar.gz: 5bfd5a2ec7ab2393478ca07102627d62707422b2
5
5
  SHA512:
6
- metadata.gz: 8a4a65a5eadb7f814e16f7c35a84cac6359526e2e1fdce9114a787af32dd96d9340905ffe3240b1241c6c706f9accbc5a95036928d2d2851cd8e5839d3127dd4
7
- data.tar.gz: 668273dbc3a7113e62b874866aa3a27d72b90f8fb6003dd062c873a3ccea5cc7b477faebc2e1831f53043bdfe224ae3b5d5b751697ee191f849f5c4f3521972e
6
+ metadata.gz: 19d0cd635b148b38e5c9a85faab5595d65b45c94ec32387e3f7b2188e6e3cc3b5924e8bc63ad3d957ad25ab1ac5ca57cfe1d7fd02bed8429070e9c24cfa48cd0
7
+ data.tar.gz: 3b63a775a8af44163f983b5d933407aa977c5e33ea92f165723909fe806c07499600fca99eee34a98c8e4e175c5d88c40a686c400f2c5a1cb8a24fd3becfb0a3
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'extendi-cassandra_object'
5
- s.version = '1.0.5'
5
+ s.version = '1.0.6'
6
6
  s.description = 'Cassandra ActiveModel'
7
7
  s.summary = 'Cassandra ActiveModel'
8
8
  s.authors = ['Duccio Giovannelli', 'gotime']
@@ -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 { |id|
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.map { |a| type_hints << CassandraObject::Types::TypeHelper.guess_type(a) } if !arguments.nil?
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 { |q|
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 { |id| "'#{id}'" }.join(',')})"
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 << "ALLOW FILTERING" if @scope.klass.allow_filtering
33
+ str << 'ALLOW FILTERING' if @scope.klass.allow_filtering
34
34
  return [] << str.delete_if(&:blank?) * ' '
35
35
  end
36
- @scope.id_values.map { |id|
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 << "ALLOW FILTERING" if @scope.klass.allow_filtering
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).map do |item|
146
- item.rows.map { |x| ids << x[primary_key_column] }
147
- new_next_cursor = item.paging_state if !item.last_page?
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 { |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)
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.map { |x| elems << x }
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
- to_a.send(method_name, *args, &block)
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 = pre[: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
- self.id_values = pre[:ids]
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
- resp.each do |cql_row|
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
- # limit
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.to_a
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).to_a.first
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).to_a
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).to_a
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
- to_a.select(&block)
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 to_a
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
@@ -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'").to_a
129
+ res1 = Issue.cql_response.where("column1 < 'poi'").execute
108
130
  # bi parameter
109
- res = Issue.cql_response.where('column1 < ?', 'poi').to_a
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.5
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-05-15 00:00:00.000000000 Z
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: