cql-rb 1.0.0.pre6 → 1.0.0.pre7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/bin/cqlexec +2 -2
  2. data/lib/cql/protocol.rb +26 -1
  3. data/lib/cql/protocol/decoding.rb +3 -0
  4. data/lib/cql/protocol/request_body.rb +15 -0
  5. data/lib/cql/protocol/request_frame.rb +1 -266
  6. data/lib/cql/protocol/requests/credentials_request.rb +31 -0
  7. data/lib/cql/protocol/requests/execute_request.rb +129 -0
  8. data/lib/cql/protocol/requests/options_request.rb +19 -0
  9. data/lib/cql/protocol/requests/prepare_request.rb +31 -0
  10. data/lib/cql/protocol/requests/query_request.rb +33 -0
  11. data/lib/cql/protocol/requests/register_request.rb +20 -0
  12. data/lib/cql/protocol/requests/startup_request.rb +27 -0
  13. data/lib/cql/protocol/response_body.rb +13 -0
  14. data/lib/cql/protocol/response_frame.rb +1 -533
  15. data/lib/cql/protocol/responses/authenticate_response.rb +21 -0
  16. data/lib/cql/protocol/responses/detailed_error_response.rb +44 -0
  17. data/lib/cql/protocol/responses/error_response.rb +28 -0
  18. data/lib/cql/protocol/responses/event_response.rb +21 -0
  19. data/lib/cql/protocol/responses/prepared_result_response.rb +23 -0
  20. data/lib/cql/protocol/responses/ready_response.rb +24 -0
  21. data/lib/cql/protocol/responses/result_response.rb +29 -0
  22. data/lib/cql/protocol/responses/rows_result_response.rb +100 -0
  23. data/lib/cql/protocol/responses/schema_change_event_result_response.rb +40 -0
  24. data/lib/cql/protocol/responses/schema_change_result_response.rb +21 -0
  25. data/lib/cql/protocol/responses/set_keyspace_result_response.rb +21 -0
  26. data/lib/cql/protocol/responses/status_change_event_result_response.rb +24 -0
  27. data/lib/cql/protocol/responses/supported_response.rb +21 -0
  28. data/lib/cql/protocol/responses/topology_change_event_result_response.rb +14 -0
  29. data/lib/cql/protocol/responses/void_result_response.rb +19 -0
  30. data/lib/cql/protocol/type_converter.rb +165 -0
  31. data/lib/cql/version.rb +1 -1
  32. data/spec/cql/protocol/response_frame_spec.rb +31 -0
  33. data/spec/integration/regression_spec.rb +56 -9
  34. metadata +27 -2
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module Cql
4
+ module Protocol
5
+ class OptionsRequest < RequestBody
6
+ def initialize
7
+ super(5)
8
+ end
9
+
10
+ def write(io)
11
+ io
12
+ end
13
+
14
+ def to_s
15
+ %(OPTIONS)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ module Cql
4
+ module Protocol
5
+ class PrepareRequest < RequestBody
6
+ attr_reader :cql
7
+
8
+ def initialize(cql)
9
+ super(9)
10
+ @cql = cql
11
+ end
12
+
13
+ def write(io)
14
+ write_long_string(io, @cql)
15
+ end
16
+
17
+ def to_s
18
+ %(PREPARE "#@cql")
19
+ end
20
+
21
+ def eql?(rq)
22
+ self.class === rq && rq.cql == self.cql
23
+ end
24
+ alias_method :==, :eql?
25
+
26
+ def hash
27
+ @h ||= @cql.hash
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ module Cql
4
+ module Protocol
5
+ class QueryRequest < RequestBody
6
+ attr_reader :cql, :consistency
7
+
8
+ def initialize(cql, consistency)
9
+ super(7)
10
+ @cql = cql
11
+ @consistency = consistency
12
+ end
13
+
14
+ def write(io)
15
+ write_long_string(io, @cql)
16
+ write_consistency(io, @consistency)
17
+ end
18
+
19
+ def to_s
20
+ %(QUERY "#@cql" #{@consistency.to_s.upcase})
21
+ end
22
+
23
+ def eql?(rq)
24
+ self.class === rq && rq.cql.eql?(self.cql) && rq.consistency.eql?(self.consistency)
25
+ end
26
+ alias_method :==, :eql?
27
+
28
+ def hash
29
+ @h ||= (@cql.hash * 31) ^ consistency.hash
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ module Cql
4
+ module Protocol
5
+ class RegisterRequest < RequestBody
6
+ def initialize(*events)
7
+ super(11)
8
+ @events = events
9
+ end
10
+
11
+ def write(io)
12
+ write_string_list(io, @events)
13
+ end
14
+
15
+ def to_s
16
+ %(REGISTER #@events)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+
3
+ module Cql
4
+ module Protocol
5
+ class StartupRequest < RequestBody
6
+ def initialize(cql_version='3.0.0', compression=nil)
7
+ super(1)
8
+ @arguments = {CQL_VERSION => cql_version}
9
+ @arguments[COMPRESSION] = compression if compression
10
+ end
11
+
12
+ def write(io)
13
+ write_string_map(io, @arguments)
14
+ io
15
+ end
16
+
17
+ def to_s
18
+ %(STARTUP #@arguments)
19
+ end
20
+
21
+ private
22
+
23
+ CQL_VERSION = 'CQL_VERSION'.freeze
24
+ COMPRESSION = 'COMPRESSION'.freeze
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+
4
+ module Cql
5
+ module Protocol
6
+ class ResponseBody
7
+ extend Decoding
8
+
9
+ def self.decode!(buffer)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,10 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'ipaddr'
4
- require 'bigdecimal'
5
- require 'set'
6
-
7
-
8
3
  module Cql
9
4
  module Protocol
10
5
  class ResponseFrame
@@ -130,532 +125,5 @@ module Cql
130
125
  end
131
126
  end
132
127
  end
133
-
134
- class ResponseBody
135
- extend Decoding
136
-
137
- def self.decode!(buffer)
138
- end
139
- end
140
-
141
- class ErrorResponse < ResponseBody
142
- attr_reader :code, :message
143
-
144
- def initialize(*args)
145
- @code, @message = args
146
- end
147
-
148
- def self.decode!(buffer)
149
- code = read_int!(buffer)
150
- message = read_string!(buffer)
151
- case code
152
- when 0x1000, 0x1100, 0x1200, 0x2400, 0x2500
153
- DetailedErrorResponse.decode!(code, message, buffer)
154
- else
155
- new(code, message)
156
- end
157
- end
158
-
159
- def to_s
160
- %(ERROR #@code "#@message")
161
- end
162
- end
163
-
164
- class DetailedErrorResponse < ErrorResponse
165
- attr_reader :details
166
-
167
- def initialize(code, message, details)
168
- super(code, message)
169
- @details = details
170
- end
171
-
172
- def self.decode!(code, message, buffer)
173
- details = {}
174
- case code
175
- when 0x1000 # unavailable
176
- details[:cl] = read_consistency!(buffer)
177
- details[:required] = read_int!(buffer)
178
- details[:alive] = read_int!(buffer)
179
- when 0x1100 # write_timeout
180
- details[:cl] = read_consistency!(buffer)
181
- details[:received] = read_int!(buffer)
182
- details[:blockfor] = read_int!(buffer)
183
- details[:write_type] = read_string!(buffer)
184
- when 0x1200 # read_timeout
185
- details[:cl] = read_consistency!(buffer)
186
- details[:received] = read_int!(buffer)
187
- details[:blockfor] = read_int!(buffer)
188
- details[:data_present] = read_byte!(buffer) != 0
189
- when 0x2400 # already_exists
190
- details[:ks] = read_string!(buffer)
191
- details[:table] = read_string!(buffer)
192
- when 0x2500
193
- details[:id] = read_short_bytes!(buffer)
194
- end
195
- new(code, message, details)
196
- end
197
-
198
- def to_s
199
- %(ERROR #@code "#@message" #@details)
200
- end
201
- end
202
-
203
- class ReadyResponse < ResponseBody
204
- def self.decode!(buffer)
205
- new
206
- end
207
-
208
- def eql?(rs)
209
- self.class === rs
210
- end
211
- alias_method :==, :eql?
212
-
213
- def hash
214
- @h ||= to_s.hash ^ 0xbadc0de
215
- end
216
-
217
- def to_s
218
- 'READY'
219
- end
220
- end
221
-
222
- class AuthenticateResponse < ResponseBody
223
- attr_reader :authentication_class
224
-
225
- def self.decode!(buffer)
226
- new(read_string!(buffer))
227
- end
228
-
229
- def initialize(authentication_class)
230
- @authentication_class = authentication_class
231
- end
232
-
233
- def to_s
234
- %(AUTHENTICATE #{authentication_class})
235
- end
236
- end
237
-
238
- class SupportedResponse < ResponseBody
239
- attr_reader :options
240
-
241
- def initialize(options)
242
- @options = options
243
- end
244
-
245
- def self.decode!(buffer)
246
- new(read_string_multimap!(buffer))
247
- end
248
-
249
- def to_s
250
- %(SUPPORTED #{options})
251
- end
252
- end
253
-
254
- class ResultResponse < ResponseBody
255
- def self.decode!(buffer)
256
- kind = read_int!(buffer)
257
- case kind
258
- when 0x01
259
- VoidResultResponse.decode!(buffer)
260
- when 0x02
261
- RowsResultResponse.decode!(buffer)
262
- when 0x03
263
- SetKeyspaceResultResponse.decode!(buffer)
264
- when 0x04
265
- PreparedResultResponse.decode!(buffer)
266
- when 0x05
267
- SchemaChangeResultResponse.decode!(buffer)
268
- else
269
- raise UnsupportedResultKindError, %(Unsupported result kind: #{kind})
270
- end
271
- end
272
-
273
- def void?
274
- false
275
- end
276
- end
277
-
278
- class VoidResultResponse < ResultResponse
279
- def self.decode!(buffer)
280
- new
281
- end
282
-
283
- def to_s
284
- %(RESULT VOID)
285
- end
286
-
287
- def void?
288
- true
289
- end
290
- end
291
-
292
- class RowsResultResponse < ResultResponse
293
- attr_reader :rows, :metadata
294
-
295
- def initialize(*args)
296
- @rows, @metadata = args
297
- end
298
-
299
- def self.decode!(buffer)
300
- column_specs = read_metadata!(buffer)
301
- new(read_rows!(buffer, column_specs), column_specs)
302
- end
303
-
304
- def to_s
305
- %(RESULT ROWS #@metadata #@rows)
306
- end
307
-
308
- private
309
-
310
- COLUMN_TYPES = [
311
- nil,
312
- :ascii,
313
- :bigint,
314
- :blob,
315
- :boolean,
316
- :counter,
317
- :decimal,
318
- :double,
319
- :float,
320
- :int,
321
- :text,
322
- :timestamp,
323
- :uuid,
324
- :varchar,
325
- :varint,
326
- :timeuuid,
327
- :inet,
328
- ].freeze
329
-
330
- def self.read_column_type!(buffer)
331
- id, type = read_option!(buffer) do |id, b|
332
- if id > 0 && id <= 0x10
333
- COLUMN_TYPES[id]
334
- elsif id == 0x20
335
- sub_type = read_column_type!(buffer)
336
- [:list, sub_type]
337
- elsif id == 0x21
338
- key_type = read_column_type!(buffer)
339
- value_type = read_column_type!(buffer)
340
- [:map, key_type, value_type]
341
- elsif id == 0x22
342
- sub_type = read_column_type!(buffer)
343
- [:set, sub_type]
344
- else
345
- raise UnsupportedColumnTypeError, %(Unsupported column type: #{id})
346
- end
347
- end
348
- type
349
- end
350
-
351
- def self.read_metadata!(buffer)
352
- flags = read_int!(buffer)
353
- columns_count = read_int!(buffer)
354
- if flags & 0x01 == 0x01
355
- global_keyspace_name = read_string!(buffer)
356
- global_table_name = read_string!(buffer)
357
- end
358
- column_specs = columns_count.times.map do
359
- if global_keyspace_name
360
- keyspace_name = global_keyspace_name
361
- table_name = global_table_name
362
- else
363
- keyspace_name = read_string!(buffer)
364
- table_name = read_string!(buffer)
365
- end
366
- column_name = read_string!(buffer)
367
- type = read_column_type!(buffer)
368
- [keyspace_name, table_name, column_name, type]
369
- end
370
- end
371
-
372
- class TypeConverter
373
- include Decoding
374
-
375
- def initialize
376
- @conversions = conversions
377
- end
378
-
379
- def convert_type(buffer, type, size_bytes=4)
380
- return nil if buffer.empty?
381
- case type
382
- when Array
383
- buffer.discard(size_bytes)
384
- case type.first
385
- when :list
386
- convert_list(buffer, @conversions[type[1]])
387
- when :map
388
- convert_map(buffer, @conversions[type[1]], @conversions[type[2]])
389
- when :set
390
- convert_set(buffer, @conversions[type[1]])
391
- end
392
- else
393
- @conversions[type].call(buffer, size_bytes)
394
- end
395
- end
396
-
397
- def conversions
398
- {
399
- :ascii => method(:convert_ascii),
400
- :bigint => method(:convert_bigint),
401
- :blob => method(:convert_blob),
402
- :boolean => method(:convert_boolean),
403
- :counter => method(:convert_bigint),
404
- :decimal => method(:convert_decimal),
405
- :double => method(:convert_double),
406
- :float => method(:convert_float),
407
- :int => method(:convert_int),
408
- :timestamp => method(:convert_timestamp),
409
- :varchar => method(:convert_varchar),
410
- :text => method(:convert_varchar),
411
- :varint => method(:convert_varint),
412
- :timeuuid => method(:convert_uuid),
413
- :uuid => method(:convert_uuid),
414
- :inet => method(:convert_inet),
415
- }
416
- end
417
-
418
- def convert_ascii(buffer, size_bytes)
419
- bytes = size_bytes == 4 ? read_bytes!(buffer) : read_short_bytes!(buffer)
420
- bytes ? bytes.force_encoding(::Encoding::ASCII) : nil
421
- end
422
-
423
- def convert_bigint(buffer, size_bytes)
424
- buffer.discard(size_bytes)
425
- read_long!(buffer)
426
- end
427
-
428
- def convert_blob(buffer, size_bytes)
429
- bytes = size_bytes == 4 ? read_bytes!(buffer) : read_short_bytes!(buffer)
430
- bytes ? bytes : nil
431
- end
432
-
433
- def convert_boolean(buffer, size_bytes)
434
- buffer.discard(size_bytes)
435
- buffer.read(1) == Constants::TRUE_BYTE
436
- end
437
-
438
- def convert_counter(buffer, size_bytes)
439
- buffer.discard(size_bytes)
440
- read_long!(buffer)
441
- end
442
-
443
- def convert_decimal(buffer, size_bytes)
444
- read_decimal!(buffer, buffer.read_int)
445
- end
446
-
447
- def convert_double(buffer, size_bytes)
448
- buffer.discard(size_bytes)
449
- read_double!(buffer)
450
- end
451
-
452
- def convert_float(buffer, size_bytes)
453
- buffer.discard(size_bytes)
454
- read_float!(buffer)
455
- end
456
-
457
- def convert_int(buffer, size_bytes)
458
- buffer.discard(size_bytes)
459
- read_int!(buffer)
460
- end
461
-
462
- def convert_timestamp(buffer, size_bytes)
463
- buffer.discard(size_bytes)
464
- timestamp = read_long!(buffer)
465
- Time.at(timestamp/1000.0)
466
- end
467
-
468
- def convert_varchar(buffer, size_bytes)
469
- bytes = size_bytes == 4 ? read_bytes!(buffer) : read_short_bytes!(buffer)
470
- bytes ? bytes.force_encoding(::Encoding::UTF_8) : nil
471
- end
472
-
473
- def convert_varint(buffer, size_bytes)
474
- read_varint!(buffer, buffer.read_int)
475
- end
476
-
477
- def convert_uuid(buffer, size_bytes)
478
- buffer.discard(size_bytes)
479
- read_uuid!(buffer)
480
- end
481
-
482
- def convert_inet(buffer, size_bytes)
483
- size = size_bytes == 4 ? buffer.read_int : buffer.read_short
484
- IPAddr.new_ntoh(buffer.read(size))
485
- end
486
-
487
- def convert_list(buffer, value_converter)
488
- list = []
489
- size = buffer.read_short
490
- size.times do
491
- list << value_converter.call(buffer, 2)
492
- end
493
- list
494
- end
495
-
496
- def convert_map(buffer, key_converter, value_converter)
497
- map = {}
498
- size = buffer.read_short
499
- size.times do
500
- key = key_converter.call(buffer, 2)
501
- value = value_converter.call(buffer, 2)
502
- map[key] = value
503
- end
504
- map
505
- end
506
-
507
- def convert_set(buffer, value_converter)
508
- set = Set.new
509
- size = buffer.read_short
510
- size.times do
511
- set << value_converter.call(buffer, 2)
512
- end
513
- set
514
- end
515
- end
516
-
517
- def self.read_rows!(buffer, column_specs)
518
- type_converter = TypeConverter.new
519
- rows_count = read_int!(buffer)
520
- rows = []
521
- rows_count.times do |row_index|
522
- row = {}
523
- column_specs.each do |column_spec|
524
- row[column_spec[2]] = type_converter.convert_type(buffer, column_spec[3])
525
- end
526
- rows << row
527
- end
528
- rows
529
- end
530
- end
531
-
532
- class SetKeyspaceResultResponse < ResultResponse
533
- attr_reader :keyspace
534
-
535
- def initialize(keyspace)
536
- @keyspace = keyspace
537
- end
538
-
539
- def self.decode!(buffer)
540
- new(read_string!(buffer))
541
- end
542
-
543
- def to_s
544
- %(RESULT SET_KEYSPACE "#@keyspace")
545
- end
546
- end
547
-
548
- class PreparedResultResponse < ResultResponse
549
- attr_reader :id, :metadata
550
-
551
- def initialize(*args)
552
- @id, @metadata = args
553
- end
554
-
555
- def self.decode!(buffer)
556
- id = read_short_bytes!(buffer)
557
- metadata = RowsResultResponse.read_metadata!(buffer)
558
- new(id, metadata)
559
- end
560
-
561
- def to_s
562
- %(RESULT PREPARED #{id.each_byte.map { |x| x.to_s(16) }.join('')} #@metadata)
563
- end
564
- end
565
-
566
- class SchemaChangeResultResponse < ResultResponse
567
- attr_reader :change, :keyspace, :table
568
-
569
- def initialize(*args)
570
- @change, @keyspace, @table = args
571
- end
572
-
573
- def self.decode!(buffer)
574
- new(read_string!(buffer), read_string!(buffer), read_string!(buffer))
575
- end
576
-
577
- def to_s
578
- %(RESULT SCHEMA_CHANGE #@change "#@keyspace" "#@table")
579
- end
580
- end
581
-
582
- class EventResponse < ResultResponse
583
- def self.decode!(buffer)
584
- type = read_string!(buffer)
585
- case type
586
- when SchemaChangeEventResponse::TYPE
587
- SchemaChangeEventResponse.decode!(buffer)
588
- when StatusChangeEventResponse::TYPE
589
- StatusChangeEventResponse.decode!(buffer)
590
- when TopologyChangeEventResponse::TYPE
591
- TopologyChangeEventResponse.decode!(buffer)
592
- else
593
- raise UnsupportedEventTypeError, %(Unsupported event type: "#{type}")
594
- end
595
- end
596
- end
597
-
598
- class SchemaChangeEventResponse < EventResponse
599
- TYPE = 'SCHEMA_CHANGE'.freeze
600
-
601
- attr_reader :type, :change, :keyspace, :table
602
-
603
- def initialize(*args)
604
- @change, @keyspace, @table = args
605
- @type = TYPE
606
- end
607
-
608
- def self.decode!(buffer)
609
- new(read_string!(buffer), read_string!(buffer), read_string!(buffer))
610
- end
611
-
612
- def eql?(rs)
613
- rs.type == self.type && rs.change == self.change && rs.keyspace == self.keyspace && rs.table == self.table
614
- end
615
- alias_method :==, :eql?
616
-
617
- def hash
618
- @h ||= begin
619
- h = 0
620
- h = ((h & 33554431) * 31) ^ @type.hash
621
- h = ((h & 33554431) * 31) ^ @change.hash
622
- h = ((h & 33554431) * 31) ^ @keyspace.hash
623
- h = ((h & 33554431) * 31) ^ @table.hash
624
- h
625
- end
626
- end
627
-
628
- def to_s
629
- %(EVENT #@type #@change "#@keyspace" "#@table")
630
- end
631
- end
632
-
633
- class StatusChangeEventResponse < EventResponse
634
- TYPE = 'STATUS_CHANGE'.freeze
635
-
636
- attr_reader :type, :change, :address, :port
637
-
638
- def initialize(*args)
639
- @change, @address, @port = args
640
- @type = TYPE
641
- end
642
-
643
- def self.decode!(buffer)
644
- new(read_string!(buffer), *read_inet!(buffer))
645
- end
646
-
647
- def to_s
648
- %(EVENT #@type #@change #@address:#@port)
649
- end
650
- end
651
-
652
- class TopologyChangeEventResponse < StatusChangeEventResponse
653
- TYPE = 'TOPOLOGY_CHANGE'.freeze
654
-
655
- def initialize(*args)
656
- super
657
- @type = TYPE
658
- end
659
- end
660
128
  end
661
- end
129
+ end