yugabyte-ycql-driver 3.2.3.1

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 (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