cequel 2.0.2 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e428934f7aef3a261e5ee1c06b940ea008fd17de
4
- data.tar.gz: 49a65b153251cb761a8421c56268d5b9c83d6966
3
+ metadata.gz: 2ff9eed6cd9463e5896643152fd7314b4df3324e
4
+ data.tar.gz: 6e62173d98fa94f77d6022ca22501ae778e40139
5
5
  SHA512:
6
- metadata.gz: 623e015fa5d288ca1302eafaec1ada9aa0224b23a28c854e6e69e3dd7dfaa6d5e32a768291ecb9d23d2b3eb4f80a272fe57ef045cb4651f5a69217a264cafb3e
7
- data.tar.gz: 5ddbd20b44c69675be0025cea406961dad9a336b91853ae68b30914138e4b78c23baff03be79278a387b24d0a827e676485db78c045d5d5e9ffc40adcf902ed3
6
+ metadata.gz: 4ad422adb85827d83efa126565c8d43f4c1b34626a154e2f627fcdb7d04e0567d6635941cc88bfa622a3f79aeec875fd30da653ecbe9c71f0f9a45a1bc738c1b
7
+ data.tar.gz: 1d157437a9c7d435412a22206d8e2103b2b214c494acdd2719a3aae8d7ef5969dd674036b271f823bd026aa50b664afd99413afc5b4edb0bfd61cb2f249f773c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 2.0.3
2
+
3
+ * Add synchronization around use of @cluster and other variables Fix ([PR 333](https://github.com/cequel/cequel/pull/333))
4
+ * expose if the dataset is on the last page ([PR 335](https://github.com/cequel/cequel/pull/335))
5
+ * Delegate error handling to a policy object, allow for arbitrary options to be passed to cassandra driver gem ([PR 336](https://github.com/cequel/cequel/pull/336))
6
+ * Fixes README.md ([PR 340](https://github.com/cequel/cequel/pull/340))
7
+ * skip synchronizing materialized view ([PR 346](https://github.com/cequel/cequel/pull/346))
8
+ * Fixed link to cassandra documentation ([PR 347](https://github.com/cequel/cequel/pull/347))
9
+
10
+
1
11
  ## 2.0.2
2
12
 
3
13
  * Fix intermittent failures around preparing statements ([PR 330](https://github.com/cequel/cequel/pull/330))
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cequel (2.0.2)
4
+ cequel (2.0.3)
5
5
  activemodel (>= 4.0)
6
6
  cassandra-driver (~> 3.0)
7
7
 
data/README.md CHANGED
@@ -231,7 +231,7 @@ multiple queries in your logs if you're iterating over a huge result set.
231
231
  CQL has [special handling for the `timeuuid`
232
232
  type](https://docs.datastax.com/en/cql/3.3/cql/cql_reference/uuid_type_r.html),
233
233
  which allows you to return a rows whose UUID keys correspond to a range of
234
- timestamps.
234
+ timestamps.
235
235
 
236
236
  Cequel automatically constructs timeuuid range queries if you pass a `Time`
237
237
  value for a range over a `timeuuid` column. So, if you want to get the posts
@@ -393,7 +393,7 @@ Both read and write consistency default to `QUORUM`.
393
393
  ### Compression ###
394
394
 
395
395
  Cassandra supports [frame compression](http://datastax.github.io/ruby-driver/features/#compression),
396
- which can give you a performance boost if your requests or responses are big. To enable it you can
396
+ which can give you a performance boost if your requests or responses are big. To enable it you can
397
397
  specify `client_compression` to use in cequel.yaml.
398
398
 
399
399
  ```yaml
@@ -539,14 +539,6 @@ essentially the same thing: both simply persist the given column data at the
539
539
  given key(s). So, you may think you are creating a new record, but in fact
540
540
  you're overwriting data at an existing record:
541
541
 
542
- #### Counting ####
543
-
544
- Counting is not the same as in a RDB, as it can have a much longer runtime and
545
- can put unexpected load on your cluster. As a result Cequel does not support
546
- this feature. It is still possible to execute raw cql to get the counts, should
547
- you require this functionality.
548
- `MyModel.connection.execute('select count(*) from table_name;').first['count']`
549
-
550
542
  ``` ruby
551
543
  # I'm just creating a blog here.
552
544
  blog1 = Blog.create!(
@@ -566,6 +558,14 @@ above code will just overwrite the `name` in that row. Note that the
566
558
  `description` will not be touched by the second statement; upserts only work on
567
559
  the columns that are given.
568
560
 
561
+ #### Counting ####
562
+
563
+ Counting is not the same as in a RDB, as it can have a much longer runtime and
564
+ can put unexpected load on your cluster. As a result Cequel does not support
565
+ this feature. It is still possible to execute raw cql to get the counts, should
566
+ you require this functionality.
567
+ `MyModel.connection.execute('select count(*) from table_name;').first['count']`
568
+
569
569
  ## Compatibility ##
570
570
 
571
571
  ### Rails ###
data/lib/cequel.rb CHANGED
@@ -8,6 +8,7 @@ require 'cassandra'
8
8
 
9
9
  require 'cequel/errors'
10
10
  require 'cequel/util'
11
+ require 'cequel/metal/policy/cassandra_error'
11
12
  require 'cequel/metal'
12
13
  require 'cequel/schema'
13
14
  require 'cequel/type'
@@ -579,10 +579,26 @@ module Cequel
579
579
  end
580
580
  end
581
581
 
582
+ #
583
+ # Exposes current paging state for stateless pagination
584
+ #
585
+ # @return [String] or nil
586
+ #
587
+ # @see http://docs.datastax.com/en/developer/ruby-driver/3.0/api/cassandra/result/#paging_state-instance_method
588
+ #
582
589
  def next_paging_state
583
590
  results.paging_state
584
591
  end
585
592
 
593
+ #
594
+ # @return [Boolean] Returns whether no more pages are available
595
+ #
596
+ # @see http://docs.datastax.com/en/developer/ruby-driver/3.0/api/cassandra/result/#last_page?-instance_method
597
+ #
598
+ def last_page?
599
+ results.last_page?
600
+ end
601
+
586
602
  # rubocop:enable LineLength
587
603
 
588
604
  #
@@ -21,10 +21,6 @@ module Cequel
21
21
  attr_reader :hosts
22
22
  # @return Integer port to connect to Cassandra nodes on
23
23
  attr_reader :port
24
- # @return Integer maximum number of retries to reconnect to Cassandra
25
- attr_reader :max_retries
26
- # @return Float delay between retries to reconnect to Cassandra
27
- attr_reader :retry_delay
28
24
  # @return [Symbol] the default consistency for queries in this keyspace
29
25
  # @since 1.1.0
30
26
  attr_writer :default_consistency
@@ -34,6 +30,10 @@ module Cequel
34
30
  attr_reader :ssl_config
35
31
  # @return [Symbol] The client compression option
36
32
  attr_reader :client_compression
33
+ # @return [Hash] A hash of additional options passed to Cassandra, if any
34
+ attr_reader :cassandra_options
35
+ # @return [Object] The error policy object in use by this keyspace
36
+ attr_reader :error_policy
37
37
 
38
38
  #
39
39
  # @!method write(statement, *bind_vars)
@@ -52,7 +52,7 @@ module Cequel
52
52
  # consistency. Will be included the current batch operation if one is
53
53
  # present.
54
54
  #
55
- # @param (see #execute_with_consistency)
55
+ # @param (see #execute_with_options)
56
56
  # @return [void]
57
57
  #
58
58
  def_delegator :write_target, :execute_with_options,
@@ -94,8 +94,8 @@ module Cequel
94
94
  # @see Cequel.connect
95
95
  #
96
96
  def initialize(configuration={})
97
- configure(configuration)
98
97
  @lock = Monitor.new
98
+ configure(configuration)
99
99
  end
100
100
 
101
101
  #
@@ -122,8 +122,12 @@ module Cequel
122
122
  # certificate
123
123
  # @option configuration [String] :private_key path to ssl client private
124
124
  # key
125
- # @option configuartion [String] :passphrase the passphrase for client
125
+ # @option configuration [String] :passphrase the passphrase for client
126
126
  # private key
127
+ # @option configuration [String] :cassandra_error_policy A mixin for
128
+ # handling errors from Cassandra
129
+ # @option configuration [Hash] :cassandra_options A hash of arbitrary
130
+ # options to pass to Cassandra
127
131
  # @return [void]
128
132
  #
129
133
  def configure(configuration = {})
@@ -132,11 +136,11 @@ module Cequel
132
136
  "with Cassandra. The :thrift option is deprecated and ignored."
133
137
  end
134
138
  @configuration = configuration
135
-
139
+
140
+ @error_policy = extract_cassandra_error_policy(configuration)
141
+ @cassandra_options = extract_cassandra_options(configuration)
136
142
  @hosts, @port = extract_hosts_and_port(configuration)
137
143
  @credentials = extract_credentials(configuration)
138
- @max_retries = extract_max_retries(configuration)
139
- @retry_delay = extract_retry_delay(configuration)
140
144
  @ssl_config = extract_ssl_config(configuration)
141
145
 
142
146
  @name = configuration[:keyspace]
@@ -184,7 +188,7 @@ module Cequel
184
188
  # @param bind_vars [Object] values for bind variables
185
189
  # @return [Enumerable] the results of the query
186
190
  #
187
- # @see #execute_with_consistency
191
+ # @see #execute_with_options
188
192
  #
189
193
  def execute(statement, *bind_vars)
190
194
  execute_with_options(Statement.new(statement, bind_vars), { consistency: default_consistency })
@@ -211,7 +215,7 @@ module Cequel
211
215
  end
212
216
 
213
217
  log('CQL', statement) do
214
- client_retry do
218
+ error_policy.execute_stmt(self) do
215
219
  client.execute(cql, options)
216
220
  end
217
221
  end
@@ -230,7 +234,7 @@ module Cequel
230
234
  else
231
235
  statement
232
236
  end
233
- client_retry do
237
+ error_policy.execute_stmt(self) do
234
238
  client.prepare(cql)
235
239
  end
236
240
  end
@@ -241,15 +245,17 @@ module Cequel
241
245
  # @return [void]
242
246
  #
243
247
  def clear_active_connections!
244
- if defined? @client
245
- remove_instance_variable(:@client)
246
- end
247
- if defined? @client_without_keyspace
248
- remove_instance_variable(:@client_without_keyspace)
249
- end
250
- if defined? @cluster
251
- @cluster.close
252
- remove_instance_variable(:@cluster)
248
+ synchronize do
249
+ if defined? @client
250
+ remove_instance_variable(:@client)
251
+ end
252
+ if defined? @client_without_keyspace
253
+ remove_instance_variable(:@client_without_keyspace)
254
+ end
255
+ if defined? @cluster
256
+ @cluster.close
257
+ remove_instance_variable(:@cluster)
258
+ end
253
259
  end
254
260
  end
255
261
 
@@ -308,21 +314,6 @@ module Cequel
308
314
  def_delegator :lock, :synchronize
309
315
  private :lock
310
316
 
311
- def client_retry
312
- retries = max_retries
313
- begin
314
- yield
315
- rescue Cassandra::Errors::NoHostsAvailable,
316
- Cassandra::Errors::ExecutionError,
317
- Cassandra::Errors::TimeoutError
318
- clear_active_connections!
319
- raise if retries == 0
320
- retries -= 1
321
- sleep(retry_delay)
322
- retry
323
- end
324
- end
325
-
326
317
  def client_without_keyspace
327
318
  synchronize do
328
319
  @client_without_keyspace ||= cluster.connect
@@ -334,6 +325,7 @@ module Cequel
334
325
  options.merge!(credentials) if credentials
335
326
  options.merge!(ssl_config) if ssl_config
336
327
  options.merge!(compression: client_compression) if client_compression
328
+ options.merge!(cassandra_options) if cassandra_options
337
329
  end
338
330
  end
339
331
 
@@ -373,14 +365,6 @@ module Cequel
373
365
  configuration.slice(:username, :password).presence
374
366
  end
375
367
 
376
- def extract_max_retries(configuration)
377
- configuration.fetch(:max_retries, 3)
378
- end
379
-
380
- def extract_retry_delay(configuration)
381
- configuration.fetch(:retry_delay, 0.5)
382
- end
383
-
384
368
  def extract_ssl_config(configuration)
385
369
  ssl_config = {}
386
370
  ssl_config[:ssl] = configuration.fetch(:ssl, nil)
@@ -391,7 +375,24 @@ module Cequel
391
375
  ssl_config.each { |key, value| ssl_config.delete(key) unless value }
392
376
  ssl_config
393
377
  end
394
-
378
+
379
+ def extract_cassandra_error_policy(configuration)
380
+ value = configuration.fetch(:cassandra_error_policy, ::Cequel::Metal::Policy::CassandraError::ClearAndRetryPolicy)
381
+ # Accept a class name as a string, create an instance of it
382
+ if value.is_a?(String)
383
+ value.constantize.new(configuration)
384
+ # Accept a class, instantiate it
385
+ elsif value.is_a?(Class)
386
+ value.new(configuration)
387
+ # Accept a value, assume it is a ready to use policy object
388
+ else
389
+ value
390
+ end
391
+ end
392
+
393
+ def extract_cassandra_options(configuration)
394
+ configuration[:cassandra_options]
395
+ end
395
396
  end
396
397
  end
397
398
  end
@@ -0,0 +1,75 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Cequel
3
+ module Metal
4
+ module Policy
5
+ module CassandraError
6
+ class ErrorPolicyBase
7
+ # This class is used by the Keyspace object to dictate
8
+ # how a failure from Cassandra is handled.
9
+ # The only method defined is
10
+ # execute_stmt(keyspace)
11
+ # The first argument is an instance of the Keyspace class
12
+ # This method may raise an error to abort the operation,
13
+ #
14
+ # The specific instance is chosen by passing configuration options
15
+ # See Keyspace#configure
16
+
17
+ # On instantiation, the configuraiton hash passed to Cequel is
18
+ # available here
19
+ def initialize(options = {})
20
+ end
21
+
22
+ def execute_stmt(keyspace)
23
+ raise NotImplementedError, "#execute_stmt must be implemented in #{self.class.name}"
24
+ end
25
+ end
26
+
27
+ class ClearAndRetryPolicy < ErrorPolicyBase
28
+ # @return Integer maximum number of retries to reconnect to Cassandra
29
+ attr_reader :max_retries
30
+ # @return Float delay between retries to reconnect to Cassandra
31
+ attr_reader :retry_delay
32
+ # @return Boolean if this policy clears connections before retry
33
+ attr_reader :clear_before_retry
34
+ def initialize(options = {})
35
+ @max_retries = options.fetch(:max_retries, 3)
36
+ @retry_delay = options.fetch(:retry_delay, 0.5)
37
+ @clear_before_retry = !!options.fetch(:clear_before_retry, true)
38
+
39
+ if @retry_delay <= 0.0
40
+ raise ArgumentError, "The value for retry must be a positive number, not '#{@retry_delay}'"
41
+ end
42
+ end
43
+
44
+ def execute_stmt(keyspace)
45
+ retries_remaining = max_retries
46
+ begin
47
+ yield
48
+ rescue Cassandra::Errors::NoHostsAvailable,
49
+ Cassandra::Errors::ExecutionError,
50
+ Cassandra::Errors::TimeoutError => exc
51
+ raise error if retries_remaining == 0
52
+ sleep(retry_delay)
53
+ keyspace.clear_active_connections! if clear_before_retry
54
+ retries_remaining -= 1
55
+ retry
56
+ end
57
+ end
58
+ end
59
+
60
+ module RetryPolicy
61
+ def self.new(options = {})
62
+ options[:clear_before_retry] = false
63
+ ClearAndRetryPolicy.new(options)
64
+ end
65
+ end
66
+
67
+ class RaisePolicy < ErrorPolicyBase
68
+ def execute_stmt(keyspace)
69
+ yield
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -173,7 +173,7 @@ module Cequel
173
173
  # @param options [Options] options for save
174
174
  # @option options [Boolean] :validate (true) whether to run validations
175
175
  # before saving
176
- # @option options [Symbol] :consistency (:quorum) what consistency with
176
+ # @option options [Symbol] :consistency what consistency with
177
177
  # which to persist the changes
178
178
  # @option options [Integer] :ttl time-to-live of the updated rows in
179
179
  # seconds
@@ -211,7 +211,7 @@ module Cequel
211
211
  # Remove this record from the database
212
212
  #
213
213
  # @param options [Options] options for deletion
214
- # @option options [Symbol] :consistency (:quorum) what consistency with
214
+ # @option options [Symbol] :consistency what consistency with
215
215
  # which to persist the deletion
216
216
  # @option options [Time] :timestamp the writetime to use for the deletion
217
217
  #
@@ -488,6 +488,10 @@ module Cequel
488
488
  data_set.next_paging_state
489
489
  end
490
490
 
491
+ def last_page?
492
+ data_set.last_page?
493
+ end
494
+
491
495
  #
492
496
  # @overload first
493
497
  # @return [Record] the first record in this record set
@@ -80,8 +80,21 @@ module Cequel
80
80
  # @return [void]
81
81
  #
82
82
  def synchronize_schema
83
+ reader = get_table_reader
84
+ return if reader.materialized_view?
83
85
  Cequel::Schema::TableSynchronizer
84
- .apply(connection, read_schema, table_schema)
86
+ .apply(connection, reader.read, table_schema)
87
+ end
88
+
89
+ #
90
+ # Return a {TableReader} instance
91
+ #
92
+ # @return [Schema::TableReader] object
93
+ #
94
+ def get_table_reader
95
+ fail MissingTableNameError unless table_name
96
+
97
+ connection.schema.get_table_reader(table_name)
85
98
  end
86
99
 
87
100
  #
@@ -92,9 +105,7 @@ module Cequel
92
105
  # table in the database
93
106
  #
94
107
  def read_schema
95
- fail MissingTableNameError unless table_name
96
-
97
- connection.schema.read_table(table_name)
108
+ table_reader.read
98
109
  end
99
110
 
100
111
  #
@@ -118,6 +118,14 @@ module Cequel
118
118
  TableReader.read(keyspace, name)
119
119
  end
120
120
 
121
+ #
122
+ # @param name [Symbol] name of the table to read
123
+ # @return [TableReader] object
124
+ #
125
+ def get_table_reader(name)
126
+ TableReader.get(keyspace, name)
127
+ end
128
+
121
129
  #
122
130
  # Create a table in the keyspace
123
131
  #
@@ -190,6 +198,16 @@ module Cequel
190
198
  keyspace.execute("DROP TABLE #{name}")
191
199
  end
192
200
 
201
+ #
202
+ # Drop this materialized view from the keyspace
203
+ #
204
+ # @param name [Symbol] name of the materialized view to drop
205
+ # @return [void]
206
+ #
207
+ def drop_materialized_view(name)
208
+ keyspace.execute("DROP MATERIALIZED VIEW #{name}")
209
+ end
210
+
193
211
  #
194
212
  # Create or update a table to match a given schema structure. The desired
195
213
  # schema structure is defined by the directives given in the block; this
@@ -29,6 +29,16 @@ module Cequel
29
29
  new(keyspace, table_name).read
30
30
  end
31
31
 
32
+ #
33
+ # Return a {TableReader} instance
34
+ #
35
+ # @param (see #initialize)
36
+ # @return [TableReader] object
37
+ #
38
+ def self.get(keyspace, table_name)
39
+ new(keyspace, table_name)
40
+ end
41
+
32
42
  #
33
43
  # @param keyspace [Metal::Keyspace] keyspace to read the table from
34
44
  # @param table_name [Symbol] name of the table to read
@@ -59,6 +69,18 @@ module Cequel
59
69
  end
60
70
  end
61
71
 
72
+ #
73
+ # Check if it is materialized view
74
+ #
75
+ # @return [boolean] true if it is materialized view
76
+ #
77
+ # @api private
78
+ #
79
+ def materialized_view?
80
+ cluster.keyspace(keyspace.name)
81
+ .has_materialized_view?(table_name.to_s)
82
+ end
83
+
62
84
  protected
63
85
 
64
86
  attr_reader :keyspace, :table_name, :table
@@ -150,18 +172,20 @@ module Cequel
150
172
  end
151
173
 
152
174
  def table_data
153
- @table_data ||=
154
- begin
155
- cluster = keyspace.cluster
156
- cluster.refresh_schema
175
+ @table_data ||= cluster.keyspace(keyspace.name)
176
+ .table(table_name.to_s)
177
+ end
157
178
 
158
- fail(NoSuchKeyspaceError, "No such keyspace #{keyspace.name}") if
159
- !cluster.has_keyspace?(keyspace.name)
179
+ def cluster
180
+ @cluster ||= begin
181
+ cluster = keyspace.cluster
182
+ cluster.refresh_schema
160
183
 
161
- cluster
162
- .keyspace(keyspace.name)
163
- .table(table_name.to_s)
164
- end
184
+ fail(NoSuchKeyspaceError, "No such keyspace #{keyspace.name}") if
185
+ !cluster.has_keyspace?(keyspace.name)
186
+
187
+ cluster
188
+ end
165
189
  end
166
190
  end
167
191
  end
data/lib/cequel/type.rb CHANGED
@@ -195,7 +195,7 @@ module Cequel
195
195
  #
196
196
  # `ascii` columns store 7-bit ASCII character data
197
197
  #
198
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
198
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
199
199
  # CQL3 data type documentation
200
200
  #
201
201
  class Ascii < String
@@ -215,7 +215,7 @@ module Cequel
215
215
  # `blob` columns store arbitrary bytes of data, represented as 8-bit ASCII
216
216
  # strings of hex digits
217
217
  #
218
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
218
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
219
219
  # CQL3 data type documentation
220
220
  #
221
221
  class Blob < String
@@ -239,7 +239,7 @@ module Cequel
239
239
  #
240
240
  # `boolean` types store boolean values
241
241
  #
242
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
242
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
243
243
  # CQL3 data type documentation
244
244
  #
245
245
  class Boolean < Base
@@ -256,7 +256,7 @@ module Cequel
256
256
  # counter columns cannot be updated without Cassandra internally reading
257
257
  # the existing state of the column
258
258
  #
259
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
259
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
260
260
  # CQL3 data type documentation
261
261
  #
262
262
  class Counter < Base
@@ -277,7 +277,7 @@ module Cequel
277
277
  #
278
278
  # `decimal` columns store decimal numeric values
279
279
  #
280
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
280
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
281
281
  # CQL3 data type documentation
282
282
  #
283
283
  class Decimal < Base
@@ -290,7 +290,7 @@ module Cequel
290
290
  #
291
291
  # `double` columns store 64-bit floating-point numeric values
292
292
  #
293
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
293
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
294
294
  # CQL3 data type documentation
295
295
  #
296
296
  class Double < Base
@@ -303,7 +303,7 @@ module Cequel
303
303
  #
304
304
  # `inet` columns store IP addresses
305
305
  #
306
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
306
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
307
307
  # CQL3 data type documentation
308
308
  #
309
309
  class Inet < Base
@@ -316,7 +316,7 @@ module Cequel
316
316
  #
317
317
  # `int` columns store 32-bit integer values
318
318
  #
319
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
319
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
320
320
  # CQL3 data type documentation
321
321
  #
322
322
  class Int < Base
@@ -333,7 +333,7 @@ module Cequel
333
333
  #
334
334
  # `float` columns store 32-bit floating-point numeric values
335
335
  #
336
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
336
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
337
337
  # CQL3 data type documentation
338
338
  #
339
339
  class Float < Double; end
@@ -342,7 +342,7 @@ module Cequel
342
342
  #
343
343
  # `bigint` columns store 64-bit integer values
344
344
  #
345
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
345
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
346
346
  # CQL3 data type documentation
347
347
  #
348
348
  class Bigint < Int
@@ -357,7 +357,7 @@ module Cequel
357
357
  # `varchar` columns; the names can be used interchangeably. Text columns do
358
358
  # not have a length limit
359
359
  #
360
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
360
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
361
361
  # CQL3 data type documentation
362
362
  #
363
363
  class Text < String
@@ -406,7 +406,7 @@ module Cequel
406
406
  # created using the {Cequel.uuid} method, and a value can be checked to see
407
407
  # if it is a UUID recognized by Cequel using the {Cequel.uuid?} method.
408
408
  #
409
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
409
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
410
410
  # CQL3 data type documentation
411
411
  #
412
412
  class Uuid < Base
@@ -435,7 +435,7 @@ module Cequel
435
435
  # functionality presumes the use of type 1 UUIDs, which encode the
436
436
  # timestamp of their creation.
437
437
  #
438
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
438
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
439
439
  # CQL3 data type documentation
440
440
  #
441
441
  class Timeuuid < Uuid
@@ -452,7 +452,7 @@ module Cequel
452
452
  #
453
453
  # `varint` columns store arbitrary-length integer data
454
454
  #
455
- # @see http://cassandra.apache.org/doc/cql3/CQL.html#types
455
+ # @see https://cassandra.apache.org/doc/latest/cql/types.html
456
456
  # CQL3 data type documentation
457
457
  #
458
458
  class Varint < Int
@@ -1,5 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module Cequel
3
3
  # The current version of the library
4
- VERSION = '2.0.2'
4
+ VERSION = '2.0.3'
5
5
  end
@@ -115,6 +115,100 @@ describe Cequel::Metal::Keyspace do
115
115
  expect(connect.client_compression).to eq client_compression
116
116
  end
117
117
  end
118
+
119
+ describe '#cassandra_options' do
120
+ let(:cassandra_options) { {foo: :bar} }
121
+ let(:connect) do
122
+ Cequel.connect host: Cequel::SpecSupport::Helpers.host,
123
+ port: Cequel::SpecSupport::Helpers.port,
124
+ cassandra_options: cassandra_options
125
+ end
126
+ it 'passes the cassandra options as part of the client options' do
127
+ expect(connect.send(:client_options)).to have_key(:foo)
128
+ end
129
+ end
130
+
131
+ describe 'cassandra error handling' do
132
+ let(:connect_options) do
133
+ {
134
+ host: Cequel::SpecSupport::Helpers.host,
135
+ port: Cequel::SpecSupport::Helpers.port
136
+ }
137
+ end
138
+
139
+ let(:default_connect) do
140
+ Cequel.connect(connect_options)
141
+ end
142
+
143
+ class SpecCassandraErrorHandler
144
+ def initialize(options = {})
145
+ end
146
+
147
+ def execute_stmt(keyspace)
148
+ yield
149
+ end
150
+ end
151
+
152
+ it 'uses the error handler passed in as a string' do
153
+ obj = Cequel.connect connect_options.merge(
154
+ cassandra_error_policy: 'SpecCassandraErrorHandler')
155
+
156
+ expect(obj.error_policy.class).to equal(SpecCassandraErrorHandler)
157
+ end
158
+
159
+ it 'uses the error handler passed in as a module' do
160
+ obj = Cequel.connect connect_options.merge(
161
+ cassandra_error_policy: SpecCassandraErrorHandler)
162
+
163
+ expect(obj.error_policy.class).to equal(SpecCassandraErrorHandler)
164
+ end
165
+
166
+ it 'uses the instance of an error handler passed in' do
167
+ policy = SpecCassandraErrorHandler.new
168
+
169
+ obj = Cequel.connect connect_options.merge(
170
+ cassandra_error_policy: policy)
171
+
172
+ expect(obj.error_policy).to equal(policy)
173
+ end
174
+
175
+ it 'responds to error policy' do
176
+ # Always defined, even if config does not specify it
177
+ expect(default_connect).to respond_to(:error_policy)
178
+ end
179
+
180
+ it 'calls execute_stmt on the error policy' do
181
+ policy = ::Cequel::Metal::Policy::CassandraError::RetryPolicy.new
182
+
183
+ obj = Cequel.connect connect_options.merge(
184
+ cassandra_error_policy: policy)
185
+ expect(policy).to receive(:execute_stmt).at_least(:once)
186
+ obj.execute_with_options(Cequel::Metal::Statement.new('select * from system.peers;'))
187
+ end
188
+
189
+ it 'rejects a negative value for retry delay' do
190
+ expect { Cequel.connect connect_options.merge(
191
+ retry_delay: -1.0)
192
+ }.to raise_error(ArgumentError)
193
+ end
194
+
195
+ it 'accepts a configured value for retry delay' do
196
+ obj = Cequel.connect connect_options.merge(
197
+ retry_delay: 1337.0)
198
+
199
+ # do not compare floats exactly, it is error prone
200
+ # the value is passed to the error policy
201
+ expect(obj.error_policy.retry_delay).to be_within(0.1).of(1337.0)
202
+ end
203
+
204
+ it 'can clear active connections' do
205
+ expect {
206
+ default_connect.clear_active_connections!
207
+ }.to change {
208
+ default_connect.client
209
+ }
210
+ end
211
+ end
118
212
 
119
213
  describe "#execute" do
120
214
  let(:statement) { "SELECT id FROM posts" }
@@ -396,4 +396,40 @@ describe Cequel::Schema::TableReader do
396
396
  [Cequel::Schema::DataColumn.new(:value, :text)]
397
397
  ) }
398
398
  end
399
+
400
+ describe 'materialized view exists', thrift: true do
401
+ let!(:name) { table_name }
402
+ let(:view_name) { "#{name}_view" }
403
+ before do
404
+ cequel.execute <<-CQL
405
+ CREATE TABLE #{table_name} (
406
+ blog_subdomain text,
407
+ permalink ascii,
408
+ PRIMARY KEY (blog_subdomain, permalink)
409
+ )
410
+ CQL
411
+ cequel.execute <<-CQL
412
+ CREATE MATERIALIZED VIEW #{view_name} AS
413
+ SELECT blog_subdomain, permalink
414
+ FROM #{name}
415
+ WHERE blog_subdomain IS NOT NULL AND permalink IS NOT NULL
416
+ PRIMARY KEY ( blog_subdomain, permalink )
417
+ CQL
418
+ end
419
+ after do
420
+ cequel.schema.drop_materialized_view(view_name)
421
+ end
422
+
423
+ context 'when materialized_view' do
424
+ let(:reader) { cequel.schema.get_table_reader(view_name) }
425
+ subject { reader }
426
+ its(:materialized_view?) { should eq true }
427
+ end
428
+
429
+ context 'when table' do
430
+ let(:reader) { cequel.schema.get_table_reader(name) }
431
+ subject { reader }
432
+ its(:materialized_view?) { should eq false }
433
+ end
434
+ end
399
435
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mat Brown
@@ -29,7 +29,7 @@ authors:
29
29
  autorequire:
30
30
  bindir: bin
31
31
  cert_chain: []
32
- date: 2016-10-17 00:00:00.000000000 Z
32
+ date: 2017-01-06 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: activemodel
@@ -219,6 +219,7 @@ files:
219
219
  - lib/cequel/metal/keyspace.rb
220
220
  - lib/cequel/metal/logging.rb
221
221
  - lib/cequel/metal/new_relic_instrumentation.rb
222
+ - lib/cequel/metal/policy/cassandra_error.rb
222
223
  - lib/cequel/metal/request_logger.rb
223
224
  - lib/cequel/metal/row.rb
224
225
  - lib/cequel/metal/row_specification.rb