cassandra-driver 3.0.3-java → 3.1.0-java

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +46 -31
  3. data/lib/cassandra.rb +35 -44
  4. data/lib/cassandra/cluster.rb +40 -11
  5. data/lib/cassandra/cluster/client.rb +193 -159
  6. data/lib/cassandra/cluster/connector.rb +12 -10
  7. data/lib/cassandra/cluster/control_connection.rb +38 -10
  8. data/lib/cassandra/cluster/options.rb +8 -4
  9. data/lib/cassandra/cluster/registry.rb +1 -2
  10. data/lib/cassandra/cluster/schema/fetchers.rb +122 -26
  11. data/lib/cassandra/column_container.rb +9 -4
  12. data/lib/cassandra/custom_data.rb +24 -22
  13. data/lib/cassandra/driver.rb +30 -13
  14. data/lib/cassandra/errors.rb +12 -2
  15. data/lib/cassandra/execution/options.rb +52 -16
  16. data/lib/cassandra/execution/profile.rb +150 -0
  17. data/lib/cassandra/execution/profile_manager.rb +71 -0
  18. data/lib/cassandra/execution/trace.rb +5 -4
  19. data/lib/cassandra/executors.rb +1 -1
  20. data/lib/cassandra/index.rb +1 -1
  21. data/lib/cassandra/keyspace.rb +36 -1
  22. data/lib/cassandra/protocol.rb +5 -0
  23. data/lib/cassandra/protocol/coder.rb +2 -1
  24. data/lib/cassandra/protocol/cql_byte_buffer.rb +21 -0
  25. data/lib/cassandra/protocol/responses/read_failure_error_response.rb +10 -4
  26. data/lib/cassandra/protocol/responses/write_failure_error_response.rb +14 -8
  27. data/lib/cassandra/protocol/v3.rb +2 -1
  28. data/lib/cassandra/protocol/v4.rb +58 -20
  29. data/lib/cassandra/result.rb +1 -1
  30. data/lib/cassandra/session.rb +43 -16
  31. data/lib/cassandra/statements/bound.rb +5 -1
  32. data/lib/cassandra/statements/prepared.rb +8 -3
  33. data/lib/cassandra/table.rb +72 -0
  34. data/lib/cassandra/trigger.rb +67 -0
  35. data/lib/cassandra/types.rb +12 -24
  36. data/lib/cassandra/udt.rb +3 -6
  37. data/lib/cassandra/uuid/generator.rb +6 -3
  38. data/lib/cassandra/version.rb +1 -1
  39. data/lib/cassandra_murmur3.jar +0 -0
  40. metadata +5 -2
@@ -32,7 +32,7 @@ module Cassandra
32
32
  @consistency,
33
33
  @retries,
34
34
  @trace_id ?
35
- Execution::Trace.new(@trace_id, @client) :
35
+ Execution::Trace.new(@trace_id, @client, @options.load_balancing_policy) :
36
36
  nil)
37
37
  end
38
38
 
@@ -29,10 +29,11 @@ module Cassandra
29
29
  def_delegators :@client, :keyspace
30
30
 
31
31
  # @private
32
- def initialize(client, default_options, futures_factory)
32
+ def initialize(client, default_options, futures_factory, profile_manager)
33
33
  @client = client
34
34
  @options = default_options
35
35
  @futures = futures_factory
36
+ @profile_manager = profile_manager
36
37
  end
37
38
 
38
39
  # Executes a given statement and returns a future result
@@ -66,6 +67,8 @@ module Cassandra
66
67
  # statement can be retried safely on timeout.
67
68
  # @option options [Hash<[String, Symbol], String>] :payload (nil) custom
68
69
  # outgoing payload to be sent with the request.
70
+ # @option options [String, Symbol] :execution_profile (nil) name of {Cassandra::Execution::Profile}
71
+ # from which to obtain certain query options. Defaults to the cluster's default execution profile.
69
72
  #
70
73
  # @see Cassandra.cluster Options that can be specified on the cluster-level
71
74
  # and their default values.
@@ -78,14 +81,9 @@ module Cassandra
78
81
  #
79
82
  # @return [Cassandra::Future<Cassandra::Result>]
80
83
  #
81
- # @see Cassandra::Session#execute A list of errors this future can be
82
- # resolved with
84
+ # @see Cassandra::Session#execute A list of errors this future can be resolved with
83
85
  def execute_async(statement, options = nil)
84
- options = if options
85
- @options.override(options)
86
- else
87
- @options
88
- end
86
+ options = merge_execution_options(options)
89
87
 
90
88
  case statement
91
89
  when ::String
@@ -110,7 +108,7 @@ module Cassandra
110
108
  # Cassandra::Statements::Bound, Cassandra::Statements::Prepared]
111
109
  # statement to execute
112
110
  #
113
- # @param options [Hash] (nil) a customizable set of options
111
+ # @param options [Hash] (nil) a customizable set of options. See {#execute_async} for details.
114
112
  #
115
113
  # @see Cassandra::Session#execute_async
116
114
  # @see Cassandra::Future#get
@@ -138,15 +136,13 @@ module Cassandra
138
136
  # @option options [Boolean] :idempotent (false) specify whether the
139
137
  # statement being prepared can be retried safely on timeout during
140
138
  # execution.
139
+ # @option options [String, Symbol] :execution_profile (nil) name of {Cassandra::Execution::Profile}
140
+ # from which to obtain certain query options. Defaults to the cluster's default execution profile.
141
141
  #
142
142
  # @return [Cassandra::Future<Cassandra::Statements::Prepared>] future
143
143
  # prepared statement
144
144
  def prepare_async(statement, options = nil)
145
- options = if options.is_a?(::Hash)
146
- @options.override(options)
147
- else
148
- @options
149
- end
145
+ options = merge_execution_options(options)
150
146
 
151
147
  case statement
152
148
  when ::String
@@ -161,14 +157,20 @@ module Cassandra
161
157
  end
162
158
 
163
159
  # A blocking wrapper around {Cassandra::Session#prepare_async}
160
+ #
161
+ # @param statement [String, Cassandra::Statements::Simple] a statement to
162
+ # prepare
163
+ #
164
+ # @param options [Hash] (nil) a customizable set of options. See {#prepare_async} for details.
165
+ #
164
166
  # @see Cassandra::Session#prepare_async
165
167
  # @see Cassandra::Future#get
166
168
  #
167
169
  # @return [Cassandra::Statements::Prepared] prepared statement
168
170
  # @raise [Cassandra::Errors::NoHostsAvailable] if none of the hosts can be reached
169
171
  # @raise [Cassandra::Errors::ExecutionError] if Cassandra returns an error response
170
- def prepare(*args)
171
- prepare_async(*args).get
172
+ def prepare(statement, options = nil)
173
+ prepare_async(statement, options).get
172
174
  end
173
175
 
174
176
  # Returns a logged {Statements::Batch} instance and optionally yields it to
@@ -235,5 +237,30 @@ module Cassandra
235
237
  "@keyspace=#{keyspace.inspect}, " \
236
238
  "@options=#{@options.inspect}>"
237
239
  end
240
+
241
+ private
242
+
243
+ # @private
244
+ def merge_execution_options(options)
245
+ if options
246
+ Util.assert_instance_of(::Hash, options, "options must be a Hash, #{options.inspect} given")
247
+ # Yell if the caller gave us a bad profile name.
248
+ execution_profile = nil
249
+ if options.key?(:execution_profile)
250
+ execution_profile = @profile_manager.profiles[options[:execution_profile]]
251
+ raise ::ArgumentError.new("Unknown execution profile #{options[:execution_profile]}") unless execution_profile
252
+ end
253
+
254
+ # This looks a little hokey, so let's explain: Execution::Options.override takes a
255
+ # varargs-style array of things to merge into the base options object (to produce
256
+ # a new Options object, not mutate the base). If an execution profile was specified,
257
+ # we want its attributes to override the base options. In addition, if individual options
258
+ # were specified, we want *those* to take precedence over the execution profile attributes.
259
+ # So we override in this order.
260
+ @options.override(execution_profile, options)
261
+ else
262
+ @options
263
+ end
264
+ end
238
265
  end
239
266
  end
@@ -28,15 +28,19 @@ module Cassandra
28
28
  attr_reader :params
29
29
  # @private
30
30
  attr_reader :params_types, :result_metadata, :keyspace, :partition_key
31
+ # @private prepared-statement id
32
+ attr_reader :id
31
33
 
32
34
  # @private
33
- def initialize(cql,
35
+ def initialize(id,
36
+ cql,
34
37
  params_types,
35
38
  result_metadata,
36
39
  params,
37
40
  keyspace = nil,
38
41
  partition_key = nil,
39
42
  idempotent = false)
43
+ @id = id
40
44
  @cql = cql
41
45
  @params_types = params_types
42
46
  @result_metadata = result_metadata
@@ -27,9 +27,12 @@ module Cassandra
27
27
  attr_reader :cql
28
28
  # @private
29
29
  attr_reader :result_metadata
30
+ # @private prepared-statement id
31
+ attr_reader :id
30
32
 
31
33
  # @private
32
- def initialize(payload,
34
+ def initialize(id,
35
+ payload,
33
36
  warnings,
34
37
  cql,
35
38
  params_metadata,
@@ -44,6 +47,7 @@ module Cassandra
44
47
  retries,
45
48
  client,
46
49
  connection_options)
50
+ @id = id
47
51
  @payload = payload
48
52
  @warnings = warnings
49
53
  @cql = cql
@@ -131,7 +135,8 @@ module Cassandra
131
135
 
132
136
  partition_key = create_partition_key(params)
133
137
 
134
- Bound.new(@cql,
138
+ Bound.new(@id,
139
+ @cql,
135
140
  param_types,
136
141
  @result_metadata,
137
142
  params,
@@ -151,7 +156,7 @@ module Cassandra
151
156
  @consistency,
152
157
  @retries,
153
158
  @trace_id ?
154
- Execution::Trace.new(@trace_id, @client) :
159
+ Execution::Trace.new(@trace_id, @client, @options.load_balancing_policy) :
155
160
  nil)
156
161
  end
157
162
 
@@ -38,6 +38,10 @@ module Cassandra
38
38
  @clustering_order = clustering_order.freeze
39
39
  @indexes = []
40
40
  @indexes_hash = {}
41
+ @materialized_views = []
42
+ @materialized_views_hash = {}
43
+ @triggers = []
44
+ @triggers_hash = {}
41
45
  end
42
46
 
43
47
  # @param name [String] index name
@@ -68,6 +72,62 @@ module Cassandra
68
72
  end
69
73
  alias indexes each_index
70
74
 
75
+ # @param name [String] trigger name
76
+ # @return [Boolean] whether this table has a given trigger
77
+ def has_trigger?(name)
78
+ @triggers_hash.key?(name)
79
+ end
80
+
81
+ # @param name [String] trigger name
82
+ # @return [Cassandra::Trigger, nil] a trigger or nil
83
+ def trigger(name)
84
+ @triggers_hash[name]
85
+ end
86
+
87
+ # Yield or enumerate each trigger bound to this table
88
+ # @overload each_trigger
89
+ # @yieldparam trigger [Cassandra::Index] current trigger
90
+ # @return [Cassandra::Table] self
91
+ # @overload each_trigger
92
+ # @return [Array<Cassandra::Trigger>] a list of triggers
93
+ def each_trigger(&block)
94
+ if block_given?
95
+ @triggers.each(&block)
96
+ self
97
+ else
98
+ @triggers.freeze
99
+ end
100
+ end
101
+ alias triggers each_trigger
102
+
103
+ # @param name [String] materialized view name
104
+ # @return [Boolean] whether this table has a given materialized view
105
+ def has_materialized_view?(name)
106
+ @materialized_views_hash.key?(name)
107
+ end
108
+
109
+ # @param name [String] materialized view name
110
+ # @return [Cassandra::MaterializedView, nil] a materialized view or nil
111
+ def materialized_view(name)
112
+ @materialized_views_hash[name]
113
+ end
114
+
115
+ # Yield or enumerate each materialized view bound to this table
116
+ # @overload each_materialized_view
117
+ # @yieldparam materialized_view [Cassandra::MaterializedView] current materialized view
118
+ # @return [Cassandra::Table] self
119
+ # @overload each_materialized_view
120
+ # @return [Array<Cassandra::MaterializedView>] a list of materialized views
121
+ def each_materialized_view(&block)
122
+ if block_given?
123
+ @materialized_views.each(&block)
124
+ self
125
+ else
126
+ @materialized_views.freeze
127
+ end
128
+ end
129
+ alias materialized_views each_materialized_view
130
+
71
131
  # @return [String] a cql representation of this table
72
132
  def to_cql
73
133
  cql = "CREATE TABLE #{Util.escape_name(@keyspace.name)}.#{Util.escape_name(@name)} (\n"
@@ -134,6 +194,18 @@ module Cassandra
134
194
  @indexes_hash[index.name] = index
135
195
  end
136
196
 
197
+ # @private
198
+ def add_view(view)
199
+ @materialized_views << view
200
+ @materialized_views_hash[view.name] = view
201
+ end
202
+
203
+ # @private
204
+ def add_trigger(trigger)
205
+ @triggers << trigger
206
+ @triggers_hash[trigger.name] = trigger
207
+ end
208
+
137
209
  # @private
138
210
  def eql?(other)
139
211
  other.is_a?(Table) &&
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2016 DataStax, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #++
18
+
19
+ module Cassandra
20
+ # Represents a trigger on a cassandra table
21
+ class Trigger
22
+ # @return [Cassandra::Table] table that the trigger applies to.
23
+ attr_reader :table
24
+ # @return [String] name of the trigger.
25
+ attr_reader :name
26
+ # @return [Hash] options of the trigger.
27
+ attr_reader :options
28
+
29
+ # @private
30
+ def initialize(table,
31
+ name,
32
+ options)
33
+ @table = table
34
+ @name = name.freeze
35
+ @options = options.freeze
36
+ end
37
+
38
+ # @return [String] name of the trigger class
39
+ def custom_class_name
40
+ @options['class']
41
+ end
42
+
43
+ # @return [String] a cql representation of this trigger
44
+ def to_cql
45
+ keyspace_name = Util.escape_name(@table.keyspace.name)
46
+ table_name = Util.escape_name(@table.name)
47
+ trigger_name = Util.escape_name(@name)
48
+
49
+ "CREATE TRIGGER #{trigger_name} ON #{keyspace_name}.#{table_name} USING '#{@options['class']}';"
50
+ end
51
+
52
+ # @private
53
+ def eql?(other)
54
+ other.is_a?(Trigger) &&
55
+ @table == other.table &&
56
+ @name == other.name &&
57
+ @options == other.options
58
+ end
59
+ alias == eql?
60
+
61
+ # @private
62
+ def inspect
63
+ "#<#{self.class.name}:0x#{object_id.to_s(16)} " \
64
+ "@name=#{@name.inspect} @table=#{@table.inspect} @options=#{@options.inspect}>"
65
+ end
66
+ end
67
+ end
@@ -1518,8 +1518,7 @@ module Cassandra
1518
1518
  # @return [Cassandra::Types::List] list type
1519
1519
  def list(value_type)
1520
1520
  Util.assert_instance_of(Cassandra::Type, value_type,
1521
- "list type must be a Cassandra::Type, #{value_type.inspect} given"
1522
- )
1521
+ "list type must be a Cassandra::Type, #{value_type.inspect} given")
1523
1522
 
1524
1523
  List.new(value_type)
1525
1524
  end
@@ -1529,11 +1528,9 @@ module Cassandra
1529
1528
  # @return [Cassandra::Types::Map] map type
1530
1529
  def map(key_type, value_type)
1531
1530
  Util.assert_instance_of(Cassandra::Type, key_type,
1532
- "map key type must be a Cassandra::Type, #{key_type.inspect} given"
1533
- )
1531
+ "map key type must be a Cassandra::Type, #{key_type.inspect} given")
1534
1532
  Util.assert_instance_of(Cassandra::Type, value_type,
1535
- "map value type must be a Cassandra::Type, #{value_type.inspect} given"
1536
- )
1533
+ "map value type must be a Cassandra::Type, #{value_type.inspect} given")
1537
1534
 
1538
1535
  Map.new(key_type, value_type)
1539
1536
  end
@@ -1542,8 +1539,7 @@ module Cassandra
1542
1539
  # @return [Cassandra::Types::Set] set type
1543
1540
  def set(value_type)
1544
1541
  Util.assert_instance_of(Cassandra::Type, value_type,
1545
- "set type must be a Cassandra::Type, #{value_type.inspect} given"
1546
- )
1542
+ "set type must be a Cassandra::Type, #{value_type.inspect} given")
1547
1543
 
1548
1544
  Set.new(value_type)
1549
1545
  end
@@ -1555,8 +1551,7 @@ module Cassandra
1555
1551
  members.each do |member|
1556
1552
  Util.assert_instance_of(Cassandra::Type, member,
1557
1553
  'each tuple member must be a Cassandra::Type, ' \
1558
- "#{member.inspect} given"
1559
- )
1554
+ "#{member.inspect} given")
1560
1555
  end
1561
1556
 
1562
1557
  Tuple.new(*members)
@@ -1598,40 +1593,33 @@ module Cassandra
1598
1593
  fields = Array(fields.first) if fields.one?
1599
1594
 
1600
1595
  Util.assert_not_empty(fields,
1601
- 'user-defined type must contain at least one field'
1602
- )
1596
+ 'user-defined type must contain at least one field')
1603
1597
 
1604
1598
  if fields.first.is_a?(::Array)
1605
1599
  fields = fields.map do |pair|
1606
1600
  Util.assert(pair.size == 2,
1607
1601
  'fields of a user-defined type must be an Array of name and ' \
1608
- "value pairs, #{pair.inspect} given"
1609
- )
1602
+ "value pairs, #{pair.inspect} given")
1610
1603
  Util.assert_instance_of(::String, pair[0],
1611
1604
  'each field name for a user-defined type must be a String, ' \
1612
- "#{pair[0].inspect} given"
1613
- )
1605
+ "#{pair[0].inspect} given")
1614
1606
  Util.assert_instance_of(Cassandra::Type, pair[1],
1615
1607
  'each field type for a user-defined type must be a ' \
1616
- "Cassandra::Type, #{pair[1].inspect} given"
1617
- )
1608
+ "Cassandra::Type, #{pair[1].inspect} given")
1618
1609
 
1619
1610
  UserDefined::Field.new(*pair)
1620
1611
  end
1621
1612
  else
1622
1613
  Util.assert(fields.size.even?,
1623
1614
  'fields of a user-defined type must be an Array of alternating ' \
1624
- "names and values pairs, #{fields.inspect} given"
1625
- )
1615
+ "names and values pairs, #{fields.inspect} given")
1626
1616
  fields = fields.each_slice(2).map do |field_name, field_type|
1627
1617
  Util.assert_instance_of(::String, field_name,
1628
1618
  'each field name for a user-defined type must be a String, ' \
1629
- "#{field_name.inspect} given"
1630
- )
1619
+ "#{field_name.inspect} given")
1631
1620
  Util.assert_instance_of(Cassandra::Type, field_type,
1632
1621
  'each field type for a user-defined type must be a ' \
1633
- "Cassandra::Type, #{field_type.inspect} given"
1634
- )
1622
+ "Cassandra::Type, #{field_type.inspect} given")
1635
1623
 
1636
1624
  UserDefined::Field.new(field_name, field_type)
1637
1625
  end
@@ -224,15 +224,13 @@ module Cassandra
224
224
  values = Array(values.first) if values.one?
225
225
 
226
226
  Util.assert_not_empty(values,
227
- 'user-defined type must contain at least one value'
228
- )
227
+ 'user-defined type must contain at least one value')
229
228
 
230
229
  if values.first.is_a?(::Array)
231
230
  @values = values.map do |pair|
232
231
  Util.assert(pair.size == 2,
233
232
  'values of a user-defined type must be an Array of name and ' \
234
- "value pairs, #{pair.inspect} given"
235
- )
233
+ "value pairs, #{pair.inspect} given")
236
234
  name, value = pair
237
235
 
238
236
  [String(name), value]
@@ -240,8 +238,7 @@ module Cassandra
240
238
  else
241
239
  Util.assert(values.size.even?,
242
240
  'values of a user-defined type must be an Array of alternating ' \
243
- "names and values pairs, #{values.inspect} given"
244
- )
241
+ "names and values pairs, #{values.inspect} given")
245
242
  @values = values.each_slice(2).map do |(name, value)|
246
243
  [String(name), value]
247
244
  end