yugabyte-ycql-driver 3.2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +13 -0
  3. data/README.md +242 -0
  4. data/ext/cassandra_murmur3/cassandra_murmur3.c +178 -0
  5. data/ext/cassandra_murmur3/extconf.rb +2 -0
  6. data/lib/cassandra/address_resolution.rb +36 -0
  7. data/lib/cassandra/address_resolution/policies.rb +2 -0
  8. data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +56 -0
  9. data/lib/cassandra/address_resolution/policies/none.rb +35 -0
  10. data/lib/cassandra/aggregate.rb +123 -0
  11. data/lib/cassandra/argument.rb +51 -0
  12. data/lib/cassandra/attr_boolean.rb +33 -0
  13. data/lib/cassandra/auth.rb +100 -0
  14. data/lib/cassandra/auth/providers.rb +17 -0
  15. data/lib/cassandra/auth/providers/password.rb +65 -0
  16. data/lib/cassandra/cassandra_logger.rb +80 -0
  17. data/lib/cassandra/cluster.rb +331 -0
  18. data/lib/cassandra/cluster/client.rb +1612 -0
  19. data/lib/cassandra/cluster/connection_pool.rb +78 -0
  20. data/lib/cassandra/cluster/connector.rb +372 -0
  21. data/lib/cassandra/cluster/control_connection.rb +962 -0
  22. data/lib/cassandra/cluster/failed_connection.rb +35 -0
  23. data/lib/cassandra/cluster/metadata.rb +142 -0
  24. data/lib/cassandra/cluster/options.rb +145 -0
  25. data/lib/cassandra/cluster/registry.rb +284 -0
  26. data/lib/cassandra/cluster/schema.rb +405 -0
  27. data/lib/cassandra/cluster/schema/cql_type_parser.rb +112 -0
  28. data/lib/cassandra/cluster/schema/fetchers.rb +1627 -0
  29. data/lib/cassandra/cluster/schema/fqcn_type_parser.rb +175 -0
  30. data/lib/cassandra/cluster/schema/partitioners.rb +21 -0
  31. data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +45 -0
  32. data/lib/cassandra/cluster/schema/partitioners/ordered.rb +37 -0
  33. data/lib/cassandra/cluster/schema/partitioners/random.rb +37 -0
  34. data/lib/cassandra/cluster/schema/replication_strategies.rb +21 -0
  35. data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +102 -0
  36. data/lib/cassandra/cluster/schema/replication_strategies/none.rb +39 -0
  37. data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +44 -0
  38. data/lib/cassandra/column.rb +66 -0
  39. data/lib/cassandra/column_container.rb +326 -0
  40. data/lib/cassandra/compression.rb +69 -0
  41. data/lib/cassandra/compression/compressors/lz4.rb +73 -0
  42. data/lib/cassandra/compression/compressors/snappy.rb +69 -0
  43. data/lib/cassandra/custom_data.rb +53 -0
  44. data/lib/cassandra/driver.rb +260 -0
  45. data/lib/cassandra/errors.rb +784 -0
  46. data/lib/cassandra/execution/info.rb +69 -0
  47. data/lib/cassandra/execution/options.rb +267 -0
  48. data/lib/cassandra/execution/profile.rb +153 -0
  49. data/lib/cassandra/execution/profile_manager.rb +71 -0
  50. data/lib/cassandra/execution/trace.rb +192 -0
  51. data/lib/cassandra/executors.rb +113 -0
  52. data/lib/cassandra/function.rb +156 -0
  53. data/lib/cassandra/function_collection.rb +85 -0
  54. data/lib/cassandra/future.rb +794 -0
  55. data/lib/cassandra/host.rb +102 -0
  56. data/lib/cassandra/index.rb +118 -0
  57. data/lib/cassandra/keyspace.rb +473 -0
  58. data/lib/cassandra/listener.rb +87 -0
  59. data/lib/cassandra/load_balancing.rb +121 -0
  60. data/lib/cassandra/load_balancing/policies.rb +20 -0
  61. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +172 -0
  62. data/lib/cassandra/load_balancing/policies/round_robin.rb +141 -0
  63. data/lib/cassandra/load_balancing/policies/token_aware.rb +149 -0
  64. data/lib/cassandra/load_balancing/policies/white_list.rb +100 -0
  65. data/lib/cassandra/materialized_view.rb +92 -0
  66. data/lib/cassandra/null_logger.rb +56 -0
  67. data/lib/cassandra/protocol.rb +102 -0
  68. data/lib/cassandra/protocol/coder.rb +1085 -0
  69. data/lib/cassandra/protocol/cql_byte_buffer.rb +418 -0
  70. data/lib/cassandra/protocol/cql_protocol_handler.rb +448 -0
  71. data/lib/cassandra/protocol/request.rb +41 -0
  72. data/lib/cassandra/protocol/requests/auth_response_request.rb +51 -0
  73. data/lib/cassandra/protocol/requests/batch_request.rb +117 -0
  74. data/lib/cassandra/protocol/requests/credentials_request.rb +51 -0
  75. data/lib/cassandra/protocol/requests/execute_request.rb +122 -0
  76. data/lib/cassandra/protocol/requests/options_request.rb +39 -0
  77. data/lib/cassandra/protocol/requests/prepare_request.rb +59 -0
  78. data/lib/cassandra/protocol/requests/query_request.rb +112 -0
  79. data/lib/cassandra/protocol/requests/register_request.rb +38 -0
  80. data/lib/cassandra/protocol/requests/startup_request.rb +49 -0
  81. data/lib/cassandra/protocol/requests/void_query_request.rb +24 -0
  82. data/lib/cassandra/protocol/response.rb +28 -0
  83. data/lib/cassandra/protocol/responses/already_exists_error_response.rb +50 -0
  84. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +36 -0
  85. data/lib/cassandra/protocol/responses/auth_success_response.rb +36 -0
  86. data/lib/cassandra/protocol/responses/authenticate_response.rb +36 -0
  87. data/lib/cassandra/protocol/responses/error_response.rb +142 -0
  88. data/lib/cassandra/protocol/responses/event_response.rb +30 -0
  89. data/lib/cassandra/protocol/responses/function_failure_error_response.rb +52 -0
  90. data/lib/cassandra/protocol/responses/prepared_result_response.rb +62 -0
  91. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +59 -0
  92. data/lib/cassandra/protocol/responses/read_failure_error_response.rb +71 -0
  93. data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +61 -0
  94. data/lib/cassandra/protocol/responses/ready_response.rb +43 -0
  95. data/lib/cassandra/protocol/responses/result_response.rb +42 -0
  96. data/lib/cassandra/protocol/responses/rows_result_response.rb +39 -0
  97. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +73 -0
  98. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +70 -0
  99. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +37 -0
  100. data/lib/cassandra/protocol/responses/status_change_event_response.rb +39 -0
  101. data/lib/cassandra/protocol/responses/supported_response.rb +36 -0
  102. data/lib/cassandra/protocol/responses/topology_change_event_response.rb +33 -0
  103. data/lib/cassandra/protocol/responses/unavailable_error_response.rb +58 -0
  104. data/lib/cassandra/protocol/responses/unprepared_error_response.rb +48 -0
  105. data/lib/cassandra/protocol/responses/void_result_response.rb +34 -0
  106. data/lib/cassandra/protocol/responses/write_failure_error_response.rb +73 -0
  107. data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +63 -0
  108. data/lib/cassandra/protocol/v1.rb +326 -0
  109. data/lib/cassandra/protocol/v3.rb +358 -0
  110. data/lib/cassandra/protocol/v4.rb +478 -0
  111. data/lib/cassandra/reconnection.rb +49 -0
  112. data/lib/cassandra/reconnection/policies.rb +20 -0
  113. data/lib/cassandra/reconnection/policies/constant.rb +46 -0
  114. data/lib/cassandra/reconnection/policies/exponential.rb +79 -0
  115. data/lib/cassandra/result.rb +276 -0
  116. data/lib/cassandra/retry.rb +154 -0
  117. data/lib/cassandra/retry/policies.rb +21 -0
  118. data/lib/cassandra/retry/policies/default.rb +53 -0
  119. data/lib/cassandra/retry/policies/downgrading_consistency.rb +73 -0
  120. data/lib/cassandra/retry/policies/fallthrough.rb +39 -0
  121. data/lib/cassandra/session.rb +270 -0
  122. data/lib/cassandra/statement.rb +32 -0
  123. data/lib/cassandra/statements.rb +23 -0
  124. data/lib/cassandra/statements/batch.rb +146 -0
  125. data/lib/cassandra/statements/bound.rb +65 -0
  126. data/lib/cassandra/statements/prepared.rb +235 -0
  127. data/lib/cassandra/statements/simple.rb +118 -0
  128. data/lib/cassandra/statements/void.rb +38 -0
  129. data/lib/cassandra/table.rb +240 -0
  130. data/lib/cassandra/time.rb +103 -0
  131. data/lib/cassandra/time_uuid.rb +78 -0
  132. data/lib/cassandra/timestamp_generator.rb +37 -0
  133. data/lib/cassandra/timestamp_generator/simple.rb +38 -0
  134. data/lib/cassandra/timestamp_generator/ticking_on_duplicate.rb +58 -0
  135. data/lib/cassandra/trigger.rb +67 -0
  136. data/lib/cassandra/tuple.rb +131 -0
  137. data/lib/cassandra/types.rb +1704 -0
  138. data/lib/cassandra/udt.rb +443 -0
  139. data/lib/cassandra/util.rb +464 -0
  140. data/lib/cassandra/uuid.rb +110 -0
  141. data/lib/cassandra/uuid/generator.rb +212 -0
  142. data/lib/cassandra/version.rb +21 -0
  143. data/lib/datastax/cassandra.rb +47 -0
  144. data/lib/ycql.rb +842 -0
  145. metadata +243 -0
@@ -0,0 +1,443 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 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
+ # A user-defined type value representation
21
+ class UDT
22
+ # @private
23
+ class Strict < UDT
24
+ def initialize(keyspace, name, fields, values)
25
+ @keyspace = keyspace
26
+ @name = name
27
+ @fields = fields
28
+ @values = values
29
+ @name_to_type = fields.each_with_object(::Hash.new) do |f, index|
30
+ index[f.name] = f.type
31
+ end
32
+ end
33
+
34
+ def method_missing(method, *args, &block)
35
+ return super if block_given? || args.size > 1
36
+
37
+ field = method.to_s
38
+ assign = !field.chomp!('=').nil?
39
+
40
+ return super if assign && args.empty?
41
+ return super unless @name_to_type.key?(field)
42
+
43
+ if assign
44
+ value = args.first
45
+ Util.assert_type(@name_to_type[field], value)
46
+ @values[field] = value
47
+ else
48
+ @values[field]
49
+ end
50
+ end
51
+
52
+ # Returns true if a field with a given name is present in this value
53
+ #
54
+ # @param method [Symbol] name of the field
55
+ #
56
+ # @return [Boolean] whether a field is present
57
+ def respond_to?(method)
58
+ field = method.to_s
59
+ field.chomp!('=')
60
+
61
+ return true if @name_to_type.key?(field)
62
+ super
63
+ end
64
+
65
+ # Returns value of the field.
66
+ #
67
+ # @param field [String, Integer] name or numeric index of the field
68
+ # @return [Object] value of the field
69
+ def [](field)
70
+ case field
71
+ when ::Integer
72
+ return nil if field < 0 || field >= @fields.size
73
+ @values[@fields[field][0]]
74
+ when ::String
75
+ @values[field]
76
+ else
77
+ raise ::ArgumentError, "unrecognized field #{field} in UDT: " \
78
+ "#{Util.escape_name(@keyspace)}.#{Util.escape_name(@name)}"
79
+ end
80
+ end
81
+
82
+ # Returns value of the field.
83
+ #
84
+ # @param field [String, Integer] name or numeric index of the field to
85
+ # lookup
86
+ #
87
+ # @raise [IndexError] when numeric index given is out of bounds
88
+ # @raise [KeyError] when field with a given name is not present
89
+ # @raise [ArgumentError] when neither a numeric index nor a field name given
90
+ #
91
+ # @return [Object] value of the field
92
+ def fetch(field)
93
+ case field
94
+ when ::Integer
95
+ if field < 0 || field >= @fields.size
96
+ raise ::IndexError,
97
+ "field index #{field} is not present in UDT: " \
98
+ "#{Util.escape_name(@keyspace)}.#{Util.escape_name(@name)}"
99
+ end
100
+ @values[@fields[field][0]]
101
+ when ::String
102
+ unless @name_to_type.key?(field)
103
+ raise ::KeyError,
104
+ "field #{field} is not defined in UDT: " \
105
+ "#{Util.escape_name(@keyspace)}.#{Util.escape_name(@name)}"
106
+ end
107
+ @values[field]
108
+ else
109
+ raise ::ArgumentError, "unrecognized field #{field} in UDT: " \
110
+ "#{Util.escape_name(@keyspace)}.#{Util.escape_name(@name)}"
111
+ end
112
+ end
113
+
114
+ # Sets value of the field.
115
+ #
116
+ # @param field [String, Integer] name or numeric index of the field
117
+ # @param value [Object] new value for the field
118
+ #
119
+ # @raise [IndexError] when numeric index given is out of bounds
120
+ # @raise [KeyError] when field with a given name is not present
121
+ # @raise [ArgumentError] when neither a numeric index nor a field name
122
+ # given
123
+ #
124
+ # @return [Object] value.
125
+ def []=(field, value)
126
+ case field
127
+ when ::Integer
128
+ if field < 0 || field >= @fields.size
129
+ raise ::IndexError,
130
+ "field index #{field} is not present in UDT: " \
131
+ "#{Util.escape_name(@keyspace)}.#{Util.escape_name(@name)}"
132
+ end
133
+ Util.assert_type(@fields[field][1], value)
134
+ @values[@fields[field][0]] = value
135
+ when ::String
136
+ unless @name_to_type.key?(field)
137
+ raise ::KeyError,
138
+ "field #{field} is not defined in UDT: " \
139
+ "#{Util.escape_name(@keyspace)}.#{Util.escape_name(@name)}"
140
+ end
141
+ Util.assert_type(@name_to_type[field], value)
142
+ @values[field] = value
143
+ else
144
+ raise ::ArgumentError, "unrecognized field #{field} in UDT: " \
145
+ "#{Util.escape_name(@keyspace)}.#{Util.escape_name(@name)}"
146
+ end
147
+ end
148
+
149
+ # Iterates over all fields of the UDT
150
+ # @yieldparam name [String] field name
151
+ # @yieldparam value [Object] field value
152
+ # @return [Cassandra::UDT] self
153
+ def each(&block)
154
+ @fields.each do |f|
155
+ n = f.name
156
+ yield(n, @values[n])
157
+ end
158
+ self
159
+ end
160
+
161
+ # Returns UDT size
162
+ # @return [Integer] UDT size
163
+ def size
164
+ @fields.size
165
+ end
166
+
167
+ def inspect
168
+ "#<Cassandra::UDT:0x#{object_id.to_s(16)} #{self}>"
169
+ end
170
+
171
+ def eql?(other)
172
+ (other.is_a?(Strict) && @values.all? {|n, v| v == other[n]}) ||
173
+ (other.is_a?(UDT) && other == self)
174
+ end
175
+ alias == eql?
176
+ end
177
+
178
+ include Enumerable
179
+
180
+ # Creates a UDT instance
181
+ # @param values [Hash<String, Object>, Array<Array<String, Object>>,
182
+ # *Object, *Array<String, Object>] - UDT field values
183
+ # @example Various ways of creating the same UDT instance
184
+ # Cassandra::UDT.new({'street' => '123 Main St.',
185
+ # 'city' => 'Whatever',
186
+ # 'state' => 'XZ',
187
+ # 'zip' => '10020'})
188
+ #
189
+ # Cassandra::UDT.new(street: '123 Main St.',
190
+ # city: 'Whatever',
191
+ # state: 'XZ',
192
+ # zip: '10020')
193
+ #
194
+ # Cassandra::UDT.new('street', '123 Main St.',
195
+ # 'city', 'Whatever',
196
+ # 'state', 'XZ',
197
+ # 'zip', '10020')
198
+ #
199
+ # Cassandra::UDT.new(:street, '123 Main St.',
200
+ # :city, 'Whatever',
201
+ # :state, 'XZ',
202
+ # :zip, '10020')
203
+ #
204
+ # Cassandra::UDT.new(['street', '123 Main St.'],
205
+ # ['city', 'Whatever'],
206
+ # ['state', 'XZ'],
207
+ # ['zip', '10020'])
208
+ #
209
+ # Cassandra::UDT.new([:street, '123 Main St.'],
210
+ # [:city, 'Whatever'],
211
+ # [:state, 'XZ'],
212
+ # [:zip, '10020'])
213
+ #
214
+ # Cassandra::UDT.new([['street', '123 Main St.'],
215
+ # ['city', 'Whatever'],
216
+ # ['state', 'XZ'],
217
+ # ['zip', '10020']])
218
+ #
219
+ # Cassandra::UDT.new([[:street, '123 Main St.'],
220
+ # [:city, 'Whatever'],
221
+ # [:state, 'XZ'],
222
+ # [:zip, '10020']])
223
+ def initialize(*values)
224
+ values = Array(values.first) if values.one?
225
+
226
+ Util.assert_not_empty(values,
227
+ 'user-defined type must contain at least one value')
228
+
229
+ if values.first.is_a?(::Array)
230
+ @values = values.map do |pair|
231
+ Util.assert(pair.size == 2,
232
+ 'values of a user-defined type must be an Array of name and ' \
233
+ "value pairs, #{pair.inspect} given")
234
+ name, value = pair
235
+
236
+ [String(name), value]
237
+ end
238
+ else
239
+ Util.assert(values.size.even?,
240
+ 'values of a user-defined type must be an Array of alternating ' \
241
+ "names and values pairs, #{values.inspect} given")
242
+ @values = values.each_slice(2).map do |(name, value)|
243
+ [String(name), value]
244
+ end
245
+ end
246
+ end
247
+
248
+ # @!visibility public
249
+ # Allows access to properties of a User-Defined Type.
250
+ #
251
+ # @example Getting and setting field values
252
+ # session.execute("CREATE TYPE address (street text, zipcode int)")
253
+ # session.execute("CREATE TABLE users (id int PRIMARY KEY, location frozen<address>)")
254
+ # row = session.execute("SELECT * FROM users WHERE id = 123").first
255
+ # address = row['address']
256
+ #
257
+ # puts address.street
258
+ # address.street = '123 SomePlace Cir'
259
+ #
260
+ # @overload method_missing(field)
261
+ # @param field [Symbol] name of the field to lookup
262
+ # @raise [NoMethodError] if the field is not present
263
+ # @return [Object] value of the field if present
264
+ # @overload method_missing(field, value)
265
+ # @param field [Symbol] name of the field (suffixed with `=`) to set
266
+ # the value for
267
+ # @param value [Symbol] new value for the field
268
+ # @raise [NoMethodError] if the field is not present
269
+ # @return [Cassandra::UDT] self.
270
+ def method_missing(field, *args, &block)
271
+ return super if block_given? || args.size > 1
272
+
273
+ key = field.to_s
274
+ set = !key.chomp!('=').nil?
275
+
276
+ return super if set && args.empty?
277
+
278
+ index = @values.index {|(name, _)| name == key}
279
+ return super unless index
280
+
281
+ if set
282
+ @values[index][1] = args.first
283
+ else
284
+ @values[index][1]
285
+ end
286
+ end
287
+
288
+ # Returns true if a field with a given name is present
289
+ #
290
+ # @param field [Symbol] method or name of the field
291
+ #
292
+ # @return [Boolean] whether a field is present
293
+ def respond_to?(field)
294
+ key = field.to_s
295
+ key.chomp!('=')
296
+
297
+ return true if @values.any? {|(name, _)| name == key}
298
+ super
299
+ end
300
+
301
+ # Returns value of the field.
302
+ #
303
+ # @param field [String, Integer] name or numeric index of the field to
304
+ # lookup
305
+ #
306
+ # @raise [ArgumentError] when neither a numeric index nor a field name given
307
+ #
308
+ # @return [Object] value of the field, or nil if the field is not present
309
+ def [](field)
310
+ case field
311
+ when ::Integer
312
+ return nil if field >= 0 && field < @values.size
313
+
314
+ @values[field][1]
315
+ when ::String
316
+ index = @values.index {|(n, _)| field == n}
317
+
318
+ index && @values[index][1]
319
+ else
320
+ raise ::ArgumentError, "Unrecognized field #{field.inspect}"
321
+ end
322
+ end
323
+
324
+ # Returns value of the field.
325
+ #
326
+ # @param field [String, Integer] name or numeric index of the field to
327
+ # lookup
328
+ #
329
+ # @raise [IndexError] when numeric index given is out of bounds
330
+ # @raise [KeyError] when field with a given name is not present
331
+ # @raise [ArgumentError] when neither a numeric index nor a field name given
332
+ #
333
+ # @return [Object] value of the field
334
+ def fetch(field)
335
+ case field
336
+ when ::Integer
337
+ raise ::IndexError, "Field index #{field.inspect} is not present" if field >= 0 && field < @values.size
338
+
339
+ @values[field][1]
340
+ when ::String
341
+ index = @values.index {|(n, _)| field == n}
342
+
343
+ raise ::KeyError, "Unsupported field #{field.inspect}" unless index
344
+
345
+ @values[index][1]
346
+ else
347
+ raise ::ArgumentError, "Unrecognized field #{field.inspect}"
348
+ end
349
+ end
350
+
351
+ # @param field [String, Integer] name or numeric index of the field to
352
+ # lookup
353
+ #
354
+ # @return [Boolean] whether the field is present in this UDT
355
+ def has_field?(field)
356
+ case field
357
+ when ::Integer
358
+ return false if field < 0 || field >= @values.size
359
+ when ::String
360
+ return false unless @values.index {|(n, _)| field == n}
361
+ else
362
+ return false
363
+ end
364
+
365
+ true
366
+ end
367
+
368
+ alias include? has_field?
369
+
370
+ # Sets value of the field.
371
+ #
372
+ # @param field [String] name of the field to set
373
+ # @param value [Object] new value for the field
374
+ #
375
+ # @raise [IndexError] when numeric index given is out of bounds
376
+ # @raise [KeyError] when field with a given name is not present
377
+ # @raise [ArgumentError] when neither a numeric index nor a field name given
378
+ #
379
+ # @return [Object] value.
380
+ def []=(field, value)
381
+ case field
382
+ when ::Integer
383
+ raise ::IndexError, "Field index #{field.inspect} is not present" if field < 0 || field >= @values.size
384
+
385
+ @values[field][1] = value
386
+ when ::String
387
+ index = @values.index {|(n, _)| field == n}
388
+
389
+ raise ::KeyError, "Unsupported field #{field.inspect}" unless index
390
+
391
+ @values[index][1] = value
392
+ else
393
+ raise ::ArgumentError, "Unrecognized field #{field.inspect}"
394
+ end
395
+ end
396
+
397
+ # Iterates over all fields of the UDT
398
+ # @yieldparam name [String] field name
399
+ # @yieldparam value [Object] field value
400
+ # @return [Cassandra::UDT] self
401
+ def each(&block)
402
+ @values.each {|(n, v)| yield(n, v)}
403
+ self
404
+ end
405
+
406
+ # Returns UDT size
407
+ # @return [Integer] UDT size
408
+ def size
409
+ @values.size
410
+ end
411
+
412
+ # Hash representation of the UDT
413
+ def to_h
414
+ @values.each_with_object(::Hash.new) do |(n, v), hash|
415
+ hash[n] = v
416
+ end
417
+ end
418
+
419
+ # String representation of the UDT
420
+ def to_s
421
+ '{ ' + @values.map {|(n, v)| "#{n}: #{v.inspect}"}.join(', ') + ' }'
422
+ end
423
+
424
+ # @private
425
+ def inspect
426
+ "#<Cassandra::UDT:0x#{object_id.to_s(16)} #{self}>"
427
+ end
428
+
429
+ # @private
430
+ def eql?(other)
431
+ other.is_a?(UDT) && @values.all? {|(n, v)| v == other[n]}
432
+ end
433
+ alias == eql?
434
+
435
+ # @private
436
+ def hash
437
+ @values.inject(17) do |h, (n, v)|
438
+ h = 31 * h + n.hash
439
+ 31 * h + v.hash
440
+ end
441
+ end
442
+ end
443
+ end
@@ -0,0 +1,464 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 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
+ # @private
21
+ module Util
22
+ module_function
23
+
24
+ def encode_hash(hash, io = StringIO.new)
25
+ first = true
26
+
27
+ io.putc(CRL_OPN)
28
+ hash.each do |k, v|
29
+ if first
30
+ first = false
31
+ else
32
+ io.print(COMMA)
33
+ end
34
+
35
+ encode_object(k, io)
36
+ io.print(COLON)
37
+ encode_object(v, io)
38
+ end
39
+ io.putc(CRL_CLS)
40
+
41
+ io.string
42
+ end
43
+
44
+ def encode_set(set, io = StringIO.new)
45
+ first = true
46
+
47
+ io.putc(CRL_OPN)
48
+ set.each do |object|
49
+ if first
50
+ first = false
51
+ else
52
+ io.print(COMMA)
53
+ end
54
+
55
+ encode_object(object, io)
56
+ end
57
+ io.putc(CRL_CLS)
58
+
59
+ io.string
60
+ end
61
+
62
+ def encode_array(array, io = StringIO.new)
63
+ first = true
64
+
65
+ io.putc(SQR_OPN)
66
+ array.each do |object|
67
+ if first
68
+ first = false
69
+ else
70
+ io.print(COMMA)
71
+ end
72
+
73
+ encode_object(object, io)
74
+ end
75
+ io.putc(SQR_CLS)
76
+
77
+ io.string
78
+ end
79
+
80
+ def encode_string(string, io = StringIO.new)
81
+ io.putc(QUOT)
82
+ string.chars do |c|
83
+ case c
84
+ when QUOT then io.print(ESC_QUOT)
85
+ else
86
+ io.putc(c)
87
+ end
88
+ end
89
+ io.putc(QUOT)
90
+
91
+ io.string
92
+ end
93
+
94
+ def encode_object(object, io = StringIO.new)
95
+ case object
96
+ when ::Hash then encode_hash(object, io)
97
+ when ::Array then encode_array(object, io)
98
+ when ::Set then encode_set(object, io)
99
+ when ::String then encode_string(object, io)
100
+ when ::Time then encode_timestamp(object, io)
101
+ when ::Numeric then encode_number(object, io)
102
+ when ::IPAddr then encode_inet(object, io)
103
+ when Uuid then encode_uuid(object, io)
104
+ when Tuple then encode_tuple(object, io)
105
+ when Time then encode_time(object, io)
106
+ when UDT then encode_udt(object, io)
107
+ when nil then io.print(NULL_STR)
108
+ when false then io.print(FALSE_STR)
109
+ when true then io.print(TRUE_STR)
110
+ else
111
+ raise ::ArgumentError, "unsupported type: #{object.inspect}"
112
+ end
113
+
114
+ io.string
115
+ end
116
+ alias encode encode_object
117
+
118
+ def encode_time(time, io = StringIO.new)
119
+ encode_string(time.to_s, io)
120
+ end
121
+
122
+ def encode_udt(udt, io = StringIO.new)
123
+ encode_hash(udt.to_h, io)
124
+ end
125
+
126
+ def encode_timestamp(time, io = StringIO.new)
127
+ io.print(time.to_i)
128
+ io.string
129
+ end
130
+
131
+ def encode_number(number, io = StringIO.new)
132
+ io.print(number)
133
+ io.string
134
+ end
135
+
136
+ def encode_uuid(uuid, io = StringIO.new)
137
+ io.print(uuid)
138
+ io.string
139
+ end
140
+
141
+ def encode_inet(inet, io = StringIO.new)
142
+ io.putc(QUOT)
143
+ io.print(inet)
144
+ io.putc(QUOT)
145
+ io.string
146
+ end
147
+
148
+ def encode_tuple(tuple, io = StringIO.new)
149
+ first = true
150
+
151
+ io.putc(PRN_OPN)
152
+ tuple.each do |object|
153
+ if first
154
+ first = false
155
+ else
156
+ io.print(COMMA)
157
+ end
158
+
159
+ encode_object(object, io)
160
+ end
161
+ io.putc(PRN_CLS)
162
+ end
163
+
164
+ def escape_name(name)
165
+ # If name only contains lower-case chars and it's not a reserved word, return it
166
+ # as-is. Otherwise, quote.
167
+ return name if name[LOWERCASE_REGEXP] == name && !RESERVED_WORDS.include?(name)
168
+
169
+ # Replace double-quotes within name with two double-quotes (if any) and surround the whole
170
+ # thing with double-quotes
171
+ DBL_QUOT + name.gsub('"', '""') + DBL_QUOT
172
+ end
173
+
174
+ def guess_type(object)
175
+ case object
176
+ when ::String then Types.varchar
177
+ when ::Integer then object.size > 8 ? Types.varint : Types.bigint
178
+ when ::Float then Types.double
179
+ when ::BigDecimal then Types.decimal
180
+ when ::TrueClass then Types.boolean
181
+ when ::FalseClass then Types.boolean
182
+ when ::NilClass then Types.bigint
183
+ when Uuid then Types.uuid
184
+ when TimeUuid then Types.timeuuid
185
+ when ::IPAddr then Types.inet
186
+ when ::Time then Types.timestamp
187
+ when ::Hash
188
+ pair = object.first
189
+ Types.map(guess_type(pair[0]), guess_type(pair[1]))
190
+ when ::Array then Types.list(guess_type(object.first))
191
+ when ::Set then Types.set(guess_type(object.first))
192
+ when Tuple::Strict then Types.tuple(*object.types)
193
+ when Tuple then Types.tuple(*object.map {|v| guess_type(v)})
194
+ when UDT::Strict
195
+ Types.udt(object.keyspace, object.name, object.types)
196
+ when UDT
197
+ Types.udt('unknown', 'unknown', object.map {|k, v| [k, guess_type(v)]})
198
+ when Cassandra::CustomData then object.class.type
199
+ else
200
+ raise ::ArgumentError,
201
+ "Unable to guess the type of the argument: #{object.inspect}"
202
+ end
203
+ end
204
+
205
+ def assert_type(type, value, message = nil, &block)
206
+ assert_instance_of(Cassandra::Type, type, message, &block)
207
+ return if value.nil?
208
+ type.assert(value, message, &block)
209
+ end
210
+
211
+ def assert_instance_of(kind, value, message = nil, &block)
212
+ unless value.is_a?(kind)
213
+ message = yield if block_given?
214
+ message ||= "value must be an instance of #{kind}, #{value.inspect} given"
215
+
216
+ raise ::ArgumentError, message
217
+ end
218
+ end
219
+
220
+ def assert_instance_of_one_of(kinds, value, message = nil, &block)
221
+ unless kinds.any? {|kind| value.is_a?(kind)}
222
+ message = yield if block_given?
223
+ message ||= "value must be an instance of one of #{kinds.inspect}, " \
224
+ "#{value.inspect} given"
225
+
226
+ raise ::ArgumentError, message
227
+ end
228
+ end
229
+
230
+ def assert_responds_to(method, value, message = nil, &block)
231
+ unless value.respond_to?(method)
232
+ message = yield if block_given?
233
+ message ||= "value #{value.inspect} must respond to #{method.inspect}, " \
234
+ "but doesn't"
235
+
236
+ raise ::ArgumentError, message
237
+ end
238
+ end
239
+
240
+ def assert_responds_to_all(methods, value, message = nil, &block)
241
+ unless methods.all? {|method| value.respond_to?(method)}
242
+ message = yield if block_given?
243
+ message ||= "value #{value.inspect} must respond to all methods " \
244
+ "#{methods.inspect}, but doesn't"
245
+
246
+ raise ::ArgumentError, message
247
+ end
248
+ end
249
+
250
+ def assert_not_empty(value, message = nil, &block)
251
+ if value.empty?
252
+ message = yield if block_given?
253
+ message ||= 'value cannot be empty'
254
+
255
+ raise ::ArgumentError, message
256
+ end
257
+ end
258
+
259
+ def assert_file_exists(path, message = nil, &block)
260
+ unless ::File.exist?(path)
261
+ message = yield if block_given?
262
+ message ||= "expected file at #{path.inspect} to exist, but it doesn't"
263
+
264
+ raise ::ArgumentError, message
265
+ end
266
+ end
267
+
268
+ def assert_one_of(range, value, message = nil, &block)
269
+ unless range.include?(value)
270
+ message = yield if block_given?
271
+ message ||= "value must be included in #{value.inspect}, #{value.inspect} given"
272
+
273
+ raise ::ArgumentError, message
274
+ end
275
+ end
276
+
277
+ def assert_size(size, value, message = nil, &block)
278
+ unless value.size == size
279
+ message = yield if block_given?
280
+ message ||= "value #{value.inspect} must have size equal to " \
281
+ "#{size.inspect}, but doesn't"
282
+
283
+ raise ::ArgumentError, message
284
+ end
285
+ end
286
+
287
+ def assert(condition, message = nil, &block)
288
+ unless condition
289
+ message = yield if block_given?
290
+ message ||= 'assertion failed'
291
+
292
+ raise ::ArgumentError, message
293
+ end
294
+ end
295
+
296
+ def assert_equal(expected, actual, message = nil, &block)
297
+ unless expected == actual
298
+ message = yield if block_given?
299
+ message ||= "expected #{actual.inspect} to equal #{expected.inspect}"
300
+
301
+ raise ::ArgumentError, message
302
+ end
303
+ end
304
+
305
+ # @private
306
+ LOWERCASE_REGEXP = /[[:lower:]\_]*/
307
+ # @private
308
+ NULL_STR = 'null'.freeze
309
+ # @private
310
+ FALSE_STR = 'false'.freeze
311
+ # @private
312
+ TRUE_STR = 'true'.freeze
313
+ # @private
314
+ CRL_OPN = '{'.freeze
315
+ # @private
316
+ CRL_CLS = '}'.freeze
317
+ # @private
318
+ SQR_OPN = '['.freeze
319
+ # @private
320
+ SQR_CLS = ']'.freeze
321
+ # @private
322
+ COMMA = ', '.freeze
323
+ # @private
324
+ COLON = ': '.freeze
325
+ # @private
326
+ QUOT = "'".freeze
327
+ # @private
328
+ ESC_QUOT = "''".freeze
329
+ # @private
330
+ DBL_QUOT = '"'.freeze
331
+ # @private
332
+ PRN_OPN = '('.freeze
333
+ # @private
334
+ PRN_CLS = ')'.freeze
335
+ RESERVED_WORDS = Set.new(%w(
336
+ add
337
+ aggregate
338
+ all
339
+ allow
340
+ alter
341
+ and
342
+ apply
343
+ as
344
+ asc
345
+ ascii
346
+ authorize
347
+ batch
348
+ begin
349
+ bigint
350
+ blob
351
+ boolean
352
+ by
353
+ called
354
+ clustering
355
+ columnfamily
356
+ compact
357
+ contains
358
+ count
359
+ counter
360
+ create
361
+ custom
362
+ date
363
+ decimal
364
+ delete
365
+ desc
366
+ describe
367
+ distinct
368
+ double
369
+ drop
370
+ entries
371
+ execute
372
+ exists
373
+ filtering
374
+ finalfunc
375
+ float
376
+ from
377
+ frozen
378
+ full
379
+ function
380
+ functions
381
+ grant
382
+ if
383
+ in
384
+ index
385
+ inet
386
+ infinity
387
+ initcond
388
+ input
389
+ insert
390
+ int
391
+ into
392
+ is
393
+ json
394
+ key
395
+ keys
396
+ keyspace
397
+ keyspaces
398
+ language
399
+ limit
400
+ list
401
+ login
402
+ map
403
+ materialized
404
+ modify
405
+ nan
406
+ nologin
407
+ norecursive
408
+ nosuperuser
409
+ not
410
+ null
411
+ of
412
+ on
413
+ options
414
+ or
415
+ order
416
+ password
417
+ permission
418
+ permissions
419
+ primary
420
+ rename
421
+ replace
422
+ returns
423
+ revoke
424
+ role
425
+ roles
426
+ schema
427
+ select
428
+ set
429
+ sfunc
430
+ smallint
431
+ static
432
+ storage
433
+ stype
434
+ superuser
435
+ table
436
+ text
437
+ time
438
+ timestamp
439
+ timeuuid
440
+ tinyint
441
+ to
442
+ token
443
+ trigger
444
+ truncate
445
+ ttl
446
+ tuple
447
+ type
448
+ unlogged
449
+ update
450
+ use
451
+ user
452
+ users
453
+ using
454
+ uuid
455
+ values
456
+ varchar
457
+ varint
458
+ view
459
+ where
460
+ with
461
+ writetime
462
+ )).freeze
463
+ end
464
+ end