Skip to content

Commit 773951f

Browse files
author
Vijay Ramesh
committed
adding type_hints for simple statements, to override Util.guess_type
1 parent 4900ef4 commit 773951f

File tree

6 files changed

+58
-12
lines changed

6 files changed

+58
-12
lines changed

lib/cassandra/execution/options.rb

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class Options
3232
attr_reader :timeout
3333
# @return [Array] positional arguments for the statement
3434
attr_reader :arguments
35+
# @return [Array] type hints for positional arguments for the statement
36+
attr_reader :type_hints
3537

3638
# @return [String] paging state
3739
#
@@ -56,6 +58,7 @@ def initialize(options)
5658
serial_consistency = options[:serial_consistency]
5759
paging_state = options[:paging_state]
5860
arguments = options[:arguments]
61+
type_hints = options[:type_hints]
5962

6063
Util.assert_one_of(CONSISTENCIES, consistency) { ":consistency must be one of #{CONSISTENCIES.inspect}, #{consistency.inspect} given" }
6164

@@ -85,13 +88,20 @@ def initialize(options)
8588
Util.assert_instance_of_one_of([::Array, ::Hash], arguments) { ":arguments must be an Array or a Hash, #{arguments.inspect} given" }
8689
end
8790

91+
if type_hints.nil?
92+
type_hints = EMPTY_LIST
93+
else
94+
Util.assert_instance_of_one_of([::Array, ::Hash], type_hints) { ":type_hints must be an Array or a Hash, #{type_hints.inspect} given" }
95+
end
96+
8897
@consistency = consistency
8998
@page_size = page_size
9099
@trace = !!trace
91100
@timeout = timeout
92101
@serial_consistency = serial_consistency
93102
@paging_state = paging_state
94103
@arguments = arguments
104+
@type_hints = type_hints
95105
end
96106

97107
# @return [Boolean] whether request tracing was enabled
@@ -107,7 +117,8 @@ def eql?(other)
107117
other.timeout == @timeout &&
108118
other.serial_consistency == @serial_consistency &&
109119
other.paging_state == @paging_state &&
110-
other.arguments == @arguments
120+
other.arguments == @arguments &&
121+
other.type_hints == @type_hints
111122
end
112123
alias :== :eql?
113124

@@ -130,7 +141,8 @@ def to_h
130141
:trace => @trace,
131142
:timeout => @timeout,
132143
:serial_consistency => @serial_consistency,
133-
:arguments => @arguments || EMPTY_LIST
144+
:arguments => @arguments || EMPTY_LIST,
145+
:type_hints => @type_hints || EMPTY_LIST
134146
}
135147
end
136148
end

lib/cassandra/protocol/coder.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ def read_type_v1(buffer)
433433
when 0x0020 then Types.list(read_type_v1(buffer))
434434
when 0x0021 then Types.map(read_type_v1(buffer), read_type_v1(buffer))
435435
when 0x0022 then Types.set(read_type_v1(buffer))
436-
else
436+
else
437437
raise Errors::DecodingError, %(Unsupported column type: #{kind})
438438
end
439439
end

lib/cassandra/session.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ def initialize(client, default_options, futures_factory)
5757
# initial request.
5858
# @option options [Array, Hash] :arguments (nil) positional or named
5959
# arguments for the statement.
60+
# @option options [Array, Hash] :type_hints (nil) override Util.guess_type to
61+
# determine the CQL type for an argument; nil elements will fall-back
62+
# to Util.guess_type.
6063
#
6164
# @see Cassandra.cluster Options that can be specified on the cluster-level
6265
# and their default values.
@@ -80,7 +83,7 @@ def execute_async(statement, options = nil)
8083

8184
case statement
8285
when ::String
83-
@client.query(Statements::Simple.new(statement, options.arguments), options)
86+
@client.query(Statements::Simple.new(statement, options.arguments, options.type_hints), options)
8487
when Statements::Simple
8588
@client.query(statement, options)
8689
when Statements::Prepared

lib/cassandra/statements/batch.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ def initialize
6363
# @param args [Array, Hash] (nil) positional or named arguments to bind,
6464
# must contain the same number of parameters as the number of positional
6565
# (`?`) or named (`:name`) markers in the CQL passed.
66+
# @param type_hints [Array, Hash] (nil) specified CQL types for positional
67+
# or named arguments to override type guessing.
6668
#
6769
# @note Positional arguments for simple statements are only supported
6870
# starting with Apache Cassandra 2.0 and above.
@@ -71,12 +73,13 @@ def initialize
7173
# starting with Apache Cassandra 2.1 and above.
7274
#
7375
# @return [self]
74-
def add(statement, args = nil)
76+
def add(statement, args = nil, type_hints = nil)
7577
args ||= EMPTY_LIST
78+
type_hints ||= EMPTY_LIST
7679

7780
case statement
7881
when String
79-
@statements << Simple.new(statement, args)
82+
@statements << Simple.new(statement, args, type_hints)
8083
when Prepared
8184
@statements << statement.bind(args)
8285
when Bound, Simple

lib/cassandra/statements/simple.rb

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ class Simple
3333
attr_reader :params_names
3434

3535
# @param cql [String] a cql statement
36-
# @param params [Array] (nil) positional arguments for the query
36+
# @param params [Array, Hash] (nil) positional or named arguments
37+
# for the query
38+
# @param type_hints [Array, Hash] (nil) positional or named types
39+
# to override type guessing for the query
3740
#
3841
# @note Positional arguments for simple statements are only supported
3942
# starting with Apache Cassandra 2.0 and above.
@@ -42,25 +45,37 @@ class Simple
4245
# starting with Apache Cassandra 2.1 and above.
4346
#
4447
# @raise [ArgumentError] if cql statement given is not a String
45-
def initialize(cql, params = nil)
48+
def initialize(cql, params = nil, type_hints = nil)
4649
Util.assert_instance_of(::String, cql) { "cql must be a string, #{cql.inspect} given" }
4750

4851
params ||= EMPTY_LIST
4952

53+
5054
if params.is_a?(::Hash)
5155
params_names = []
5256
params = params.each_with_object([]) do |(name, value), params|
5357
params_names << name
5458
params << value
5559
end
60+
if type_hints && !type_hints.empty?
61+
Util.assert_instance_of(::Hash, type_hints) { "type_hints must be a Hash when using named params" }
62+
end
5663
else
5764
Util.assert_instance_of(::Array, params) { "params must be an Array or a Hash, #{params.inspect} given" }
5865
params_names = EMPTY_LIST
5966
end
6067

68+
type_hints ||= EMPTY_LIST
69+
70+
if type_hints.is_a?(::Hash)
71+
type_hints = params_names.map {|name| type_hints[name] }
72+
else
73+
Util.assert_instance_of(::Array, type_hints) { "type_hints must be an Array or a Hash, #{type_hints.inspect} given" }
74+
end
75+
6176
@cql = cql
6277
@params = params
63-
@params_types = params.map {|value| Util.guess_type(value)}
78+
@params_types = params.each_with_index.map {|value, index| (!type_hints.empty? && type_hints[index]) ? Types::Simple.new(type_hints[index]) : Util.guess_type(value)}
6479
@params_names = params_names
6580
end
6681

spec/cassandra/session_spec.rb

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ module Cassandra
3434
promise = double('promise')
3535
statement = double('simple statement')
3636

37-
expect(Statements::Simple).to receive(:new).once.with(cql, EMPTY_LIST).and_return(statement)
37+
expect(Statements::Simple).to receive(:new).once.with(cql, EMPTY_LIST, EMPTY_LIST).and_return(statement)
3838
expect(client).to receive(:query).once.with(statement, session_options).and_return(promise)
3939
expect(session.execute_async(cql)).to eq(promise)
4040
end
@@ -47,12 +47,25 @@ module Cassandra
4747
promise = double('promise')
4848
statement = double('simple statement')
4949

50-
expect(Statements::Simple).to receive(:new).once.with(cql, [1]).and_return(statement)
50+
expect(Statements::Simple).to receive(:new).once.with(cql, [1], []).and_return(statement)
5151
expect(client).to receive(:query).once.with(statement, session_options.override(arguments: [1])).and_return(promise)
5252
expect(session.execute_async(cql, arguments: [1])).to eq(promise)
5353
end
5454
end
5555

56+
context 'with arguments and type_hints' do
57+
let(:cql) { 'SELECT * FROM songs WHERE id = ?' }
58+
59+
it 'sends query with a simple statement with parameters and type hints' do
60+
promise = double('promise')
61+
statement = double('simple statement')
62+
63+
expect(Statements::Simple).to receive(:new).once.with(cql, [1], [:int]).and_return(statement)
64+
expect(client).to receive(:query).once.with(statement, session_options.override(arguments: [1], type_hints: [:int])).and_return(promise)
65+
expect(session.execute_async(cql, arguments: [1], type_hints: [:int])).to eq(promise)
66+
end
67+
end
68+
5669
context 'with options' do
5770
let(:cql) { 'SELECT * FROM songs' }
5871
let(:options) { {:trace => true} }
@@ -61,7 +74,7 @@ module Cassandra
6174
promise = double('promise')
6275
statement = double('simple statement')
6376

64-
expect(Statements::Simple).to receive(:new).once.with(cql, EMPTY_LIST).and_return(statement)
77+
expect(Statements::Simple).to receive(:new).once.with(cql, EMPTY_LIST, EMPTY_LIST).and_return(statement)
6578
expect(client).to receive(:query).once.with(statement, session_options.override(options)).and_return(promise)
6679
expect(session.execute_async(cql, options)).to eq(promise)
6780
end

0 commit comments

Comments
 (0)