cequel 1.7.0 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +64 -75
- data/README.md +32 -4
- data/Rakefile +8 -7
- data/lib/cequel/metal/data_set.rb +29 -4
- data/lib/cequel/metal/keyspace.rb +18 -14
- data/lib/cequel/metal/request_logger.rb +7 -0
- data/lib/cequel/record/data_set_builder.rb +15 -1
- data/lib/cequel/record/properties.rb +2 -0
- data/lib/cequel/record/record_set.rb +28 -2
- data/lib/cequel/schema/table_reader.rb +1 -1
- data/lib/cequel/version.rb +1 -1
- data/spec/examples/metal/data_set_spec.rb +24 -0
- data/spec/examples/record/dirty_spec.rb +0 -8
- data/spec/examples/record/persistence_spec.rb +2 -2
- data/spec/examples/record/properties_spec.rb +5 -0
- data/spec/examples/record/record_set_spec.rb +35 -0
- data/spec/examples/record/schema_spec.rb +42 -0
- data/spec/examples/schema/table_reader_spec.rb +16 -15
- data/spec/examples/schema/table_synchronizer_spec.rb +14 -13
- data/spec/examples/schema/table_updater_spec.rb +23 -20
- data/spec/examples/schema/table_writer_spec.rb +13 -12
- data/spec/examples/spec_support/preparation_spec.rb +8 -0
- data/spec/support/helpers.rb +8 -0
- metadata +3 -6
- data/DRIVER_TODO +0 -5
- data/cequel.gemspec +0 -42
- data/tags +0 -836
@@ -187,23 +187,13 @@ module Cequel
|
|
187
187
|
execute_with_consistency(statement, bind_vars, default_consistency)
|
188
188
|
end
|
189
189
|
|
190
|
-
|
191
|
-
|
192
|
-
#
|
193
|
-
# @param statement [String] CQL string
|
194
|
-
# @param bind_vars [Array] array of values for bind variables
|
195
|
-
# @param consistency [Symbol] consistency at which to execute query
|
196
|
-
# @return [Enumerable] the results of the query
|
197
|
-
#
|
198
|
-
# @since 1.1.0
|
199
|
-
#
|
200
|
-
def execute_with_consistency(statement, bind_vars, consistency)
|
201
|
-
retries = max_retries
|
190
|
+
def execute_with_options(statement, bind_vars, options={})
|
191
|
+
options[:consistency] ||= default_consistency
|
202
192
|
|
193
|
+
retries = max_retries
|
203
194
|
log('CQL', statement, *bind_vars) do
|
204
195
|
begin
|
205
|
-
client.execute(sanitize(statement, bind_vars),
|
206
|
-
consistency: consistency || default_consistency)
|
196
|
+
client.execute(sanitize(statement, bind_vars), options)
|
207
197
|
rescue Cassandra::Errors::NoHostsAvailable,
|
208
198
|
Ione::Io::ConnectionError => e
|
209
199
|
clear_active_connections!
|
@@ -213,6 +203,20 @@ module Cequel
|
|
213
203
|
retry
|
214
204
|
end
|
215
205
|
end
|
206
|
+
|
207
|
+
end
|
208
|
+
#
|
209
|
+
# Execute a CQL query in this keyspace with the given consistency
|
210
|
+
#
|
211
|
+
# @param statement [String] CQL string
|
212
|
+
# @param bind_vars [Array] array of values for bind variables
|
213
|
+
# @param consistency [Symbol] consistency at which to execute query
|
214
|
+
# @return [Enumerable] the results of the query
|
215
|
+
#
|
216
|
+
# @since 1.1.0
|
217
|
+
#
|
218
|
+
def execute_with_consistency(statement, bind_vars, consistency)
|
219
|
+
execute_with_options(statement, bind_vars, {consistency: consistency || default_consistency})
|
216
220
|
end
|
217
221
|
|
218
222
|
#
|
@@ -51,9 +51,16 @@ module Cequel
|
|
51
51
|
private
|
52
52
|
|
53
53
|
def format_for_log(label, timing, statement, bind_vars)
|
54
|
+
bind_vars = bind_vars.map{|it| String === it ? limit_length(it) : it }
|
54
55
|
format('%s (%s) %s', label, timing, sanitize(statement, bind_vars))
|
55
56
|
end
|
56
57
|
|
58
|
+
def limit_length(str)
|
59
|
+
return str if str.length < 100
|
60
|
+
|
61
|
+
str[0..25] + "..." + str[-25..-1]
|
62
|
+
end
|
63
|
+
|
57
64
|
def_delegator 'Cequel::Metal::Keyspace', :sanitize
|
58
65
|
private :sanitize
|
59
66
|
end
|
@@ -40,6 +40,8 @@ module Cequel
|
|
40
40
|
add_bounds
|
41
41
|
add_order
|
42
42
|
set_consistency
|
43
|
+
set_page_size
|
44
|
+
set_paging_state
|
43
45
|
data_set
|
44
46
|
end
|
45
47
|
|
@@ -51,7 +53,7 @@ module Cequel
|
|
51
53
|
:scoped_key_names, :scoped_key_values,
|
52
54
|
:scoped_indexed_column, :lower_bound,
|
53
55
|
:upper_bound, :reversed?, :order_by_column,
|
54
|
-
:query_consistency, :ascends_by?
|
56
|
+
:query_consistency, :query_page_size, :query_paging_state, :ascends_by?
|
55
57
|
|
56
58
|
private
|
57
59
|
|
@@ -97,6 +99,18 @@ module Cequel
|
|
97
99
|
end
|
98
100
|
end
|
99
101
|
|
102
|
+
def set_page_size
|
103
|
+
if query_page_size
|
104
|
+
self.data_set = data_set.page_size(query_page_size)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def set_paging_state
|
109
|
+
if query_paging_state
|
110
|
+
self.data_set = data_set.paging_state(query_paging_state)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
100
114
|
def sort_direction
|
101
115
|
ascends_by?(order_by_column) ? :asc : :desc
|
102
116
|
end
|
@@ -464,6 +464,30 @@ module Cequel
|
|
464
464
|
scoped(query_consistency: consistency)
|
465
465
|
end
|
466
466
|
|
467
|
+
#
|
468
|
+
# Set the page_size at which to read records into the record set.
|
469
|
+
#
|
470
|
+
# @param page_size [Integer] page_size for reads
|
471
|
+
# @return [RecordSet] record set tuned to given page_size
|
472
|
+
#
|
473
|
+
def page_size(page_size)
|
474
|
+
scoped(query_page_size: page_size)
|
475
|
+
end
|
476
|
+
|
477
|
+
#
|
478
|
+
# Set the paging_state at which to read records into the record set.
|
479
|
+
#
|
480
|
+
# @param paging_state [String] paging_state for reads
|
481
|
+
# @return [RecordSet] record set tuned to given paging_state
|
482
|
+
#
|
483
|
+
def paging_state(paging_state)
|
484
|
+
scoped(query_paging_state: paging_state)
|
485
|
+
end
|
486
|
+
|
487
|
+
def next_paging_state
|
488
|
+
data_set.next_paging_state
|
489
|
+
end
|
490
|
+
|
467
491
|
#
|
468
492
|
# @overload first
|
469
493
|
# @return [Record] the first record in this record set
|
@@ -667,9 +691,11 @@ module Cequel
|
|
667
691
|
attr_reader :attributes
|
668
692
|
hattr_reader :attributes, :select_columns, :scoped_key_values,
|
669
693
|
:row_limit, :lower_bound, :upper_bound,
|
670
|
-
:scoped_indexed_column, :query_consistency
|
694
|
+
:scoped_indexed_column, :query_consistency,
|
695
|
+
:query_page_size, :query_paging_state
|
671
696
|
protected :select_columns, :scoped_key_values, :row_limit, :lower_bound,
|
672
|
-
:upper_bound, :scoped_indexed_column, :query_consistency
|
697
|
+
:upper_bound, :scoped_indexed_column, :query_consistency,
|
698
|
+
:query_page_size, :query_paging_state
|
673
699
|
hattr_inquirer :attributes, :reversed
|
674
700
|
protected :reversed?
|
675
701
|
|
@@ -75,7 +75,7 @@ module Cequel
|
|
75
75
|
def read_partition_keys
|
76
76
|
validators = table_data['key_validator']
|
77
77
|
types = parse_composite_types(validators) || [validators]
|
78
|
-
columns = partition_columns.
|
78
|
+
columns = partition_columns.sort_by { |c| c['component_index'] }
|
79
79
|
.map { |c| c['column_name'] }
|
80
80
|
|
81
81
|
columns.zip(types) do |name, type|
|
data/lib/cequel/version.rb
CHANGED
@@ -654,6 +654,30 @@ describe Cequel::Metal::DataSet do
|
|
654
654
|
end
|
655
655
|
end
|
656
656
|
|
657
|
+
describe '#page_size' do
|
658
|
+
let(:data_set) { cequel[:posts].page_size(1) }
|
659
|
+
|
660
|
+
it 'should issue SELECT with scoped page size' do
|
661
|
+
expect_query_with_options(/SELECT/, :page_size => 1) { data_set.to_a }
|
662
|
+
end
|
663
|
+
|
664
|
+
it 'should issue COUNT with scoped page size' do
|
665
|
+
expect_query_with_options(/SELECT.*COUNT/, :page_size => 1) { data_set.count }
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
describe '#paging_state' do
|
670
|
+
let(:data_set) { cequel[:posts].paging_state(nil) }
|
671
|
+
|
672
|
+
it 'should issue SELECT with scoped paging state' do
|
673
|
+
expect_query_with_options(/SELECT/, :paging_state => nil) { data_set.to_a }
|
674
|
+
end
|
675
|
+
|
676
|
+
it 'should issue COUNT with scoped paging state' do
|
677
|
+
expect_query_with_options(/SELECT.*COUNT/, :paging_state => nil) { data_set.count }
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
657
681
|
describe 'result enumeration' do
|
658
682
|
let(:row) { row_keys.merge(:title => 'Big Data') }
|
659
683
|
|
@@ -128,8 +128,8 @@ describe Cequel::Record::Persistence do
|
|
128
128
|
it 'should save with specified TTL' do
|
129
129
|
blog.name = 'Cequel 1.4'
|
130
130
|
blog.save(ttl: 10)
|
131
|
-
expect(cequel[Blog.table_name].select_ttl(:name).first.ttl(:name))
|
132
|
-
to
|
131
|
+
expect(cequel[Blog.table_name].select_ttl(:name).first.ttl(:name))
|
132
|
+
.to be_between(9,10).inclusive
|
133
133
|
end
|
134
134
|
|
135
135
|
it 'should save with specified timestamp' do
|
@@ -53,6 +53,11 @@ describe Cequel::Record::Properties do
|
|
53
53
|
title).to eq('Big Data')
|
54
54
|
end
|
55
55
|
|
56
|
+
it 'should mark the attribute as dirty when setting attributes' do
|
57
|
+
expect(Post.new { |post| post.title = 'Big Data' }.changed).to eq(['title'])
|
58
|
+
expect(Post.new { |post| post.title = 'Big Data' }.changes).to eq({'title' => [nil,'Big Data']})
|
59
|
+
end
|
60
|
+
|
56
61
|
it 'should get attributes with indifferent access' do
|
57
62
|
post = Post.new.tap { |post| post.attributes = {:downcased_title => 'big data' }}
|
58
63
|
expect(post.attributes[:title]).to eq 'Big Data'
|
@@ -811,6 +811,41 @@ describe Cequel::Record::RecordSet do
|
|
811
811
|
end
|
812
812
|
end
|
813
813
|
|
814
|
+
describe '#page_size' do
|
815
|
+
it 'should return the number of records specified by page_size' do
|
816
|
+
expect(Post.page_size(2).to_a.length).to be(2)
|
817
|
+
end
|
818
|
+
end
|
819
|
+
|
820
|
+
describe '#next_paging_state' do
|
821
|
+
it 'should return the paging state of the result' do
|
822
|
+
expect(Post.page_size(1).next_paging_state).not_to eq(nil)
|
823
|
+
end
|
824
|
+
end
|
825
|
+
|
826
|
+
describe '#paging_state' do
|
827
|
+
let(:page_one) { Post.page_size(1) }
|
828
|
+
let(:page_two) { Post.page_size(1).paging_state(page_one.next_paging_state) }
|
829
|
+
let(:page_size) { 3 }
|
830
|
+
|
831
|
+
it 'should page through all records' do
|
832
|
+
all_pages = []
|
833
|
+
next_paging_state = nil
|
834
|
+
|
835
|
+
loop do
|
836
|
+
a_page = Post.page_size(page_size).paging_state(next_paging_state)
|
837
|
+
next_paging_state = a_page.next_paging_state
|
838
|
+
|
839
|
+
# There may be less than page size records on final page
|
840
|
+
expect(a_page.to_a.length).to be <= page_size
|
841
|
+
all_pages.concat(a_page.to_a)
|
842
|
+
break if next_paging_state.nil?
|
843
|
+
end
|
844
|
+
|
845
|
+
expect(all_pages).to eq(posts.to_a)
|
846
|
+
end
|
847
|
+
end
|
848
|
+
|
814
849
|
describe '#count' do
|
815
850
|
let(:records) { blogs }
|
816
851
|
|
@@ -73,6 +73,48 @@ describe Cequel::Record::Schema do
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
+
context 'CQL3 table with non-dictionary-ordered partition columns' do
|
77
|
+
let(:table_name) { 'accesses_' + SecureRandom.hex(4) }
|
78
|
+
|
79
|
+
let(:model) do
|
80
|
+
model_table_name = table_name
|
81
|
+
Class.new do
|
82
|
+
include Cequel::Record
|
83
|
+
self.table_name = model_table_name
|
84
|
+
|
85
|
+
key :serial, :text, partition: true
|
86
|
+
key :username, :text, partition: true
|
87
|
+
key :date, :text, partition: true
|
88
|
+
key :access_time, :timeuuid
|
89
|
+
column :url, :text
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
let(:model_modified) do
|
94
|
+
model_table_name = table_name
|
95
|
+
Class.new do
|
96
|
+
include Cequel::Record
|
97
|
+
self.table_name = model_table_name
|
98
|
+
|
99
|
+
key :serial, :text, partition: true
|
100
|
+
key :username, :text, partition: true
|
101
|
+
key :date, :text, partition: true
|
102
|
+
key :access_time, :timeuuid
|
103
|
+
column :url, :text
|
104
|
+
column :user_agent, :text
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
before { model.synchronize_schema }
|
109
|
+
after { cequel.schema.drop_table(table_name) }
|
110
|
+
|
111
|
+
it 'should be able to synchronize schema again' do
|
112
|
+
expect {
|
113
|
+
model_modified.synchronize_schema
|
114
|
+
}.not_to raise_error
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
76
118
|
context 'wide-row legacy table' do
|
77
119
|
let(:table_name) { 'legacy_posts_' + SecureRandom.hex(4) }
|
78
120
|
|
@@ -2,16 +2,17 @@
|
|
2
2
|
require File.expand_path('../../spec_helper', __FILE__)
|
3
3
|
|
4
4
|
describe Cequel::Schema::TableReader do
|
5
|
+
let(:table_name) { :"posts_#{SecureRandom.hex(4)}" }
|
5
6
|
|
6
7
|
after do
|
7
|
-
cequel.schema.drop_table(
|
8
|
+
cequel.schema.drop_table(table_name)
|
8
9
|
end
|
9
10
|
|
10
|
-
let(:table) { cequel.schema.read_table(
|
11
|
+
let(:table) { cequel.schema.read_table(table_name) }
|
11
12
|
|
12
13
|
describe 'reading simple key' do
|
13
14
|
before do
|
14
|
-
cequel.execute("CREATE TABLE
|
15
|
+
cequel.execute("CREATE TABLE #{table_name} (permalink text PRIMARY KEY)")
|
15
16
|
end
|
16
17
|
|
17
18
|
it 'should read name correctly' do
|
@@ -30,7 +31,7 @@ describe Cequel::Schema::TableReader do
|
|
30
31
|
describe 'reading single non-partition key' do
|
31
32
|
before do
|
32
33
|
cequel.execute <<-CQL
|
33
|
-
CREATE TABLE
|
34
|
+
CREATE TABLE #{table_name} (
|
34
35
|
blog_subdomain text,
|
35
36
|
permalink ascii,
|
36
37
|
PRIMARY KEY (blog_subdomain, permalink)
|
@@ -63,7 +64,7 @@ describe Cequel::Schema::TableReader do
|
|
63
64
|
describe 'reading reverse-ordered non-partition key' do
|
64
65
|
before do
|
65
66
|
cequel.execute <<-CQL
|
66
|
-
CREATE TABLE
|
67
|
+
CREATE TABLE #{table_name} (
|
67
68
|
blog_subdomain text,
|
68
69
|
permalink ascii,
|
69
70
|
PRIMARY KEY (blog_subdomain, permalink)
|
@@ -89,7 +90,7 @@ describe Cequel::Schema::TableReader do
|
|
89
90
|
describe 'reading compound non-partition key' do
|
90
91
|
before do
|
91
92
|
cequel.execute <<-CQL
|
92
|
-
CREATE TABLE
|
93
|
+
CREATE TABLE #{table_name} (
|
93
94
|
blog_subdomain text,
|
94
95
|
permalink ascii,
|
95
96
|
author_id uuid,
|
@@ -116,7 +117,7 @@ describe Cequel::Schema::TableReader do
|
|
116
117
|
describe 'reading compound partition key' do
|
117
118
|
before do
|
118
119
|
cequel.execute <<-CQL
|
119
|
-
CREATE TABLE
|
120
|
+
CREATE TABLE #{table_name} (
|
120
121
|
blog_subdomain text,
|
121
122
|
permalink ascii,
|
122
123
|
PRIMARY KEY ((blog_subdomain, permalink))
|
@@ -142,7 +143,7 @@ describe Cequel::Schema::TableReader do
|
|
142
143
|
describe 'reading compound partition and non-partition keys' do
|
143
144
|
before do
|
144
145
|
cequel.execute <<-CQL
|
145
|
-
CREATE TABLE
|
146
|
+
CREATE TABLE #{table_name} (
|
146
147
|
blog_subdomain text,
|
147
148
|
permalink ascii,
|
148
149
|
author_id uuid,
|
@@ -183,7 +184,7 @@ describe Cequel::Schema::TableReader do
|
|
183
184
|
|
184
185
|
before do
|
185
186
|
cequel.execute <<-CQL
|
186
|
-
CREATE TABLE
|
187
|
+
CREATE TABLE #{table_name} (
|
187
188
|
blog_subdomain text,
|
188
189
|
permalink ascii,
|
189
190
|
title text,
|
@@ -194,7 +195,7 @@ describe Cequel::Schema::TableReader do
|
|
194
195
|
PRIMARY KEY (blog_subdomain, permalink)
|
195
196
|
)
|
196
197
|
CQL
|
197
|
-
cequel.execute(
|
198
|
+
cequel.execute("CREATE INDEX posts_author_id_idx ON #{table_name} (author_id)")
|
198
199
|
end
|
199
200
|
|
200
201
|
it 'should read types of scalar data columns' do
|
@@ -255,7 +256,7 @@ describe Cequel::Schema::TableReader do
|
|
255
256
|
|
256
257
|
before do
|
257
258
|
cequel.execute <<-CQL
|
258
|
-
CREATE TABLE
|
259
|
+
CREATE TABLE #{table_name} (permalink text PRIMARY KEY)
|
259
260
|
WITH bloom_filter_fp_chance = 0.02
|
260
261
|
AND comment = 'Posts table'
|
261
262
|
AND compaction = {
|
@@ -315,7 +316,7 @@ describe Cequel::Schema::TableReader do
|
|
315
316
|
describe 'skinny-row compact storage' do
|
316
317
|
before do
|
317
318
|
cequel.execute <<-CQL
|
318
|
-
CREATE TABLE
|
319
|
+
CREATE TABLE #{table_name} (permalink text PRIMARY KEY, title text, body text)
|
319
320
|
WITH COMPACT STORAGE
|
320
321
|
CQL
|
321
322
|
end
|
@@ -333,7 +334,7 @@ describe Cequel::Schema::TableReader do
|
|
333
334
|
describe 'wide-row compact storage' do
|
334
335
|
before do
|
335
336
|
cequel.execute <<-CQL
|
336
|
-
CREATE TABLE
|
337
|
+
CREATE TABLE #{table_name} (
|
337
338
|
blog_subdomain text,
|
338
339
|
id uuid,
|
339
340
|
data text,
|
@@ -356,7 +357,7 @@ describe Cequel::Schema::TableReader do
|
|
356
357
|
describe 'skinny-row legacy table', thrift: true do
|
357
358
|
before do
|
358
359
|
legacy_connection.execute <<-CQL
|
359
|
-
CREATE TABLE
|
360
|
+
CREATE TABLE #{table_name} (permalink text PRIMARY KEY, title text, body text)
|
360
361
|
CQL
|
361
362
|
end
|
362
363
|
subject { table }
|
@@ -375,7 +376,7 @@ describe Cequel::Schema::TableReader do
|
|
375
376
|
describe 'wide-row legacy table', thrift: true do
|
376
377
|
before do
|
377
378
|
legacy_connection.execute(<<-CQL2)
|
378
|
-
CREATE COLUMNFAMILY
|
379
|
+
CREATE COLUMNFAMILY #{table_name} (blog_subdomain text PRIMARY KEY)
|
379
380
|
WITH comparator=uuid AND default_validation=text
|
380
381
|
CQL2
|
381
382
|
end
|