cql-rb 2.0.0.pre0 → 2.0.0.pre1
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.
- checksums.yaml +4 -4
- data/README.md +14 -2
- data/lib/cql.rb +8 -3
- data/lib/cql/client.rb +21 -356
- data/lib/cql/client/authenticators.rb +70 -0
- data/lib/cql/client/batch.rb +54 -0
- data/lib/cql/client/{asynchronous_client.rb → client.rb} +241 -6
- data/lib/cql/client/connector.rb +3 -2
- data/lib/cql/client/{asynchronous_prepared_statement.rb → prepared_statement.rb} +103 -0
- data/lib/cql/protocol.rb +1 -2
- data/lib/cql/protocol/cql_byte_buffer.rb +285 -0
- data/lib/cql/protocol/cql_protocol_handler.rb +3 -3
- data/lib/cql/protocol/frame_decoder.rb +3 -3
- data/lib/cql/protocol/frame_encoder.rb +2 -2
- data/lib/cql/protocol/request.rb +0 -2
- data/lib/cql/protocol/requests/auth_response_request.rb +2 -2
- data/lib/cql/protocol/requests/batch_request.rb +10 -10
- data/lib/cql/protocol/requests/credentials_request.rb +2 -2
- data/lib/cql/protocol/requests/execute_request.rb +13 -13
- data/lib/cql/protocol/requests/options_request.rb +2 -2
- data/lib/cql/protocol/requests/prepare_request.rb +2 -2
- data/lib/cql/protocol/requests/query_request.rb +13 -13
- data/lib/cql/protocol/requests/register_request.rb +2 -2
- data/lib/cql/protocol/requests/startup_request.rb +2 -2
- data/lib/cql/protocol/response.rb +2 -4
- data/lib/cql/protocol/responses/auth_challenge_response.rb +2 -2
- data/lib/cql/protocol/responses/auth_success_response.rb +2 -2
- data/lib/cql/protocol/responses/authenticate_response.rb +2 -2
- data/lib/cql/protocol/responses/detailed_error_response.rb +15 -15
- data/lib/cql/protocol/responses/error_response.rb +4 -4
- data/lib/cql/protocol/responses/event_response.rb +3 -3
- data/lib/cql/protocol/responses/prepared_result_response.rb +4 -4
- data/lib/cql/protocol/responses/raw_rows_result_response.rb +1 -1
- data/lib/cql/protocol/responses/ready_response.rb +1 -1
- data/lib/cql/protocol/responses/result_response.rb +3 -3
- data/lib/cql/protocol/responses/rows_result_response.rb +22 -22
- data/lib/cql/protocol/responses/schema_change_event_response.rb +2 -2
- data/lib/cql/protocol/responses/schema_change_result_response.rb +2 -2
- data/lib/cql/protocol/responses/set_keyspace_result_response.rb +2 -2
- data/lib/cql/protocol/responses/status_change_event_response.rb +2 -2
- data/lib/cql/protocol/responses/supported_response.rb +2 -2
- data/lib/cql/protocol/responses/void_result_response.rb +1 -1
- data/lib/cql/protocol/type_converter.rb +78 -81
- data/lib/cql/time_uuid.rb +6 -0
- data/lib/cql/uuid.rb +2 -1
- data/lib/cql/version.rb +1 -1
- data/spec/cql/client/batch_spec.rb +8 -8
- data/spec/cql/client/{asynchronous_client_spec.rb → client_spec.rb} +162 -0
- data/spec/cql/client/connector_spec.rb +13 -3
- data/spec/cql/client/{asynchronous_prepared_statement_spec.rb → prepared_statement_spec.rb} +148 -1
- data/spec/cql/client/request_runner_spec.rb +2 -2
- data/spec/cql/protocol/cql_byte_buffer_spec.rb +895 -0
- data/spec/cql/protocol/cql_protocol_handler_spec.rb +1 -1
- data/spec/cql/protocol/frame_decoder_spec.rb +14 -14
- data/spec/cql/protocol/frame_encoder_spec.rb +7 -7
- data/spec/cql/protocol/requests/auth_response_request_spec.rb +4 -4
- data/spec/cql/protocol/requests/batch_request_spec.rb +21 -21
- data/spec/cql/protocol/requests/credentials_request_spec.rb +2 -2
- data/spec/cql/protocol/requests/execute_request_spec.rb +13 -13
- data/spec/cql/protocol/requests/options_request_spec.rb +1 -1
- data/spec/cql/protocol/requests/prepare_request_spec.rb +2 -2
- data/spec/cql/protocol/requests/query_request_spec.rb +13 -13
- data/spec/cql/protocol/requests/register_request_spec.rb +2 -2
- data/spec/cql/protocol/requests/startup_request_spec.rb +4 -4
- data/spec/cql/protocol/responses/auth_challenge_response_spec.rb +5 -5
- data/spec/cql/protocol/responses/auth_success_response_spec.rb +5 -5
- data/spec/cql/protocol/responses/authenticate_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/detailed_error_response_spec.rb +15 -15
- data/spec/cql/protocol/responses/error_response_spec.rb +5 -5
- data/spec/cql/protocol/responses/event_response_spec.rb +8 -8
- data/spec/cql/protocol/responses/prepared_result_response_spec.rb +7 -7
- data/spec/cql/protocol/responses/raw_rows_result_response_spec.rb +1 -1
- data/spec/cql/protocol/responses/ready_response_spec.rb +2 -2
- data/spec/cql/protocol/responses/result_response_spec.rb +16 -16
- data/spec/cql/protocol/responses/rows_result_response_spec.rb +21 -21
- data/spec/cql/protocol/responses/schema_change_event_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/set_keyspace_result_response_spec.rb +2 -2
- data/spec/cql/protocol/responses/status_change_event_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/supported_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/topology_change_event_response_spec.rb +3 -3
- data/spec/cql/protocol/responses/void_result_response_spec.rb +2 -2
- data/spec/cql/protocol/type_converter_spec.rb +25 -13
- data/spec/cql/time_uuid_spec.rb +17 -4
- data/spec/cql/uuid_spec.rb +5 -1
- data/spec/integration/protocol_spec.rb +48 -42
- data/spec/spec_helper.rb +0 -1
- metadata +27 -39
- data/lib/cql/byte_buffer.rb +0 -177
- data/lib/cql/client/synchronous_client.rb +0 -79
- data/lib/cql/client/synchronous_prepared_statement.rb +0 -63
- data/lib/cql/future.rb +0 -515
- data/lib/cql/io.rb +0 -15
- data/lib/cql/io/connection.rb +0 -220
- data/lib/cql/io/io_reactor.rb +0 -349
- data/lib/cql/protocol/decoding.rb +0 -187
- data/lib/cql/protocol/encoding.rb +0 -114
- data/spec/cql/byte_buffer_spec.rb +0 -337
- data/spec/cql/client/synchronous_client_spec.rb +0 -170
- data/spec/cql/client/synchronous_prepared_statement_spec.rb +0 -155
- data/spec/cql/future_spec.rb +0 -737
- data/spec/cql/io/connection_spec.rb +0 -484
- data/spec/cql/io/io_reactor_spec.rb +0 -402
- data/spec/cql/protocol/decoding_spec.rb +0 -547
- data/spec/cql/protocol/encoding_spec.rb +0 -386
- data/spec/integration/io_spec.rb +0 -283
- data/spec/support/fake_server.rb +0 -106
@@ -2,6 +2,76 @@
|
|
2
2
|
|
3
3
|
module Cql
|
4
4
|
module Client
|
5
|
+
# An auth provider is a factory for {Cql::Client::Authenticator} instances
|
6
|
+
# (or objects matching that interface). Its {#create_authenticator} will be
|
7
|
+
# called once for each connection that requires authentication.
|
8
|
+
#
|
9
|
+
# If the authentication requires keeping state, keep that in the
|
10
|
+
# authenticator instances, not in the auth provider.
|
11
|
+
#
|
12
|
+
# @note Creating an authenticator must absolutely not block, or the whole
|
13
|
+
# connection process will block.
|
14
|
+
#
|
15
|
+
# @note Auth providers given to {Cql::Client.connect} as the `:auth_provider`
|
16
|
+
# option don't need to be subclasses of this class, but need to
|
17
|
+
# implement the same methods. This class exists only for documentation
|
18
|
+
# purposes.
|
19
|
+
class AuthProvider
|
20
|
+
# @!method create_authenticator(authentication_class, protocol_version)
|
21
|
+
#
|
22
|
+
# Create a new authenticator object. This method will be called once per
|
23
|
+
# connection that requires authentication. The auth provider can create
|
24
|
+
# different authenticators for different authentication classes, or return
|
25
|
+
# nil if it does not support the authentication class.
|
26
|
+
#
|
27
|
+
# @note This method must absolutely not block.
|
28
|
+
#
|
29
|
+
# @param authentication_class [String] the authentication class used by
|
30
|
+
# the server.
|
31
|
+
# @return [Cql::Client::Authenticator, nil] an object with an interface
|
32
|
+
# matching {Cql::Client::Authenticator} or nil if the authentication
|
33
|
+
# class is not supported.
|
34
|
+
end
|
35
|
+
|
36
|
+
# An authenticator handles the authentication challenge/response cycles of
|
37
|
+
# a single connection. It can be stateful, but it must not for any reason
|
38
|
+
# block. If any of the method calls block, the whole connection process
|
39
|
+
# will be blocked.
|
40
|
+
#
|
41
|
+
# @note Authenticators created by auth providers don't need to be subclasses
|
42
|
+
# of this class, but need to implement the same methods. This class exists
|
43
|
+
# only for documentation purposes.
|
44
|
+
class Authenticator
|
45
|
+
# @!method initial_response
|
46
|
+
#
|
47
|
+
# This method must return the initial authentication token to be sent to
|
48
|
+
# the server.
|
49
|
+
#
|
50
|
+
# @note This method must absolutely not block.
|
51
|
+
#
|
52
|
+
# @return [String] the initial authentication token
|
53
|
+
|
54
|
+
# @!method challenge_response(token)
|
55
|
+
#
|
56
|
+
# If the authentication requires multiple challenge/response cycles this
|
57
|
+
# method will be called when a challenge is returned by the server. A
|
58
|
+
# response token must be created and will be sent back to the server.
|
59
|
+
#
|
60
|
+
# @note This method must absolutely not block.
|
61
|
+
#
|
62
|
+
# @param token [String] a challenge token sent by the server
|
63
|
+
# @return [String] the authentication token to send back to the server
|
64
|
+
|
65
|
+
# @!method authentication_successful(token)
|
66
|
+
#
|
67
|
+
# Called when the authentication is successful.
|
68
|
+
#
|
69
|
+
# @note This method must absolutely not block.
|
70
|
+
#
|
71
|
+
# @param token [String] a token sent by the server
|
72
|
+
# @return [nil]
|
73
|
+
end
|
74
|
+
|
5
75
|
# Auth provider used for Cassandra's built in authentication.
|
6
76
|
#
|
7
77
|
# There is no need to create instances of this class to pass as `:auth_provider`
|
data/lib/cql/client/batch.rb
CHANGED
@@ -2,6 +2,60 @@
|
|
2
2
|
|
3
3
|
module Cql
|
4
4
|
module Client
|
5
|
+
class Batch
|
6
|
+
# @!method add(cql_or_prepared_statement, *bound_values)
|
7
|
+
#
|
8
|
+
# Add a query or a prepared statement to the batch.
|
9
|
+
#
|
10
|
+
# @example Adding a mix of statements to a batch
|
11
|
+
# batch.add(%(UPDATE people SET name = 'Miriam' WHERE id = 3435))
|
12
|
+
# batch.add(%(UPDATE people SET name = ? WHERE id = ?), 'Miriam', 3435)
|
13
|
+
# batch.add(prepared_statement, 'Miriam', 3435)
|
14
|
+
#
|
15
|
+
# @param [String, Cql::Client::PreparedStatement] cql_or_prepared_statement
|
16
|
+
# a CQL string or a prepared statement object (obtained through
|
17
|
+
# {Cql::Client::Client#prepare})
|
18
|
+
# @param [Array] bound_values a list of bound values -- only applies when
|
19
|
+
# adding prepared statements and when there are binding markers in the
|
20
|
+
# given CQL. If the last argument is a hash and it has the key
|
21
|
+
# `:type_hints` this will be passed as type hints to the request encoder
|
22
|
+
# (if the last argument is any other hash it will be assumed to be a
|
23
|
+
# bound value of type MAP). See {Cql::Client::Client#execute} for more
|
24
|
+
# info on type hints.
|
25
|
+
# @return [nil]
|
26
|
+
|
27
|
+
# @!method execute(options={})
|
28
|
+
#
|
29
|
+
# Execute the batch and return the result.
|
30
|
+
#
|
31
|
+
# @param options [Hash] an options hash or a symbol (as a shortcut for
|
32
|
+
# specifying the consistency), see {Cql::Client::Client#execute} for
|
33
|
+
# full details about how this value is interpreted.
|
34
|
+
# @raise [Cql::QueryError] raised when there is an error on the server side
|
35
|
+
# @raise [Cql::NotPreparedError] raised in the unlikely event that a
|
36
|
+
# prepared statement was not prepared on the chosen connection
|
37
|
+
# @return [Cql::Client::VoidResult] a batch always returns a void result
|
38
|
+
end
|
39
|
+
|
40
|
+
class PreparedStatementBatch
|
41
|
+
# @!method add(*bound_values)
|
42
|
+
#
|
43
|
+
# Add the statement to the batch with the specified bound values.
|
44
|
+
#
|
45
|
+
# @param [Array] bound_values the values to bind to the added statement,
|
46
|
+
# see {Cql::Client::PreparedStatement#execute}.
|
47
|
+
# @return [nil]
|
48
|
+
|
49
|
+
# @!method execute(options={})
|
50
|
+
#
|
51
|
+
# Execute the batch and return the result.
|
52
|
+
#
|
53
|
+
# @raise [Cql::QueryError] raised when there is an error on the server side
|
54
|
+
# @raise [Cql::NotPreparedError] raised in the unlikely event that a
|
55
|
+
# prepared statement was not prepared on the chosen connection
|
56
|
+
# @return [Cql::Client::VoidResult] a batch always returns a void result
|
57
|
+
end
|
58
|
+
|
5
59
|
# @private
|
6
60
|
class AsynchronousBatch < Batch
|
7
61
|
def initialize(type, execute_options_decoder, connection_manager, options=nil)
|
@@ -2,6 +2,188 @@
|
|
2
2
|
|
3
3
|
module Cql
|
4
4
|
module Client
|
5
|
+
class Client
|
6
|
+
# @!method connect
|
7
|
+
#
|
8
|
+
# Connect to all nodes. See {Cql::Client.connect} for the full
|
9
|
+
# documentation.
|
10
|
+
#
|
11
|
+
# This method needs to be called before any other. Calling it again will
|
12
|
+
# have no effect.
|
13
|
+
#
|
14
|
+
# @see Cql::Client.connect
|
15
|
+
# @return [Cql::Client]
|
16
|
+
|
17
|
+
# @!method close
|
18
|
+
#
|
19
|
+
# Disconnect from all nodes.
|
20
|
+
#
|
21
|
+
# @return [Cql::Client]
|
22
|
+
|
23
|
+
# @!method connected?
|
24
|
+
#
|
25
|
+
# Returns whether or not the client is connected.
|
26
|
+
#
|
27
|
+
# @return [true, false]
|
28
|
+
|
29
|
+
# @!method keyspace
|
30
|
+
#
|
31
|
+
# Returns the name of the current keyspace, or `nil` if no keyspace has been
|
32
|
+
# set yet.
|
33
|
+
#
|
34
|
+
# @return [String]
|
35
|
+
|
36
|
+
# @!method use(keyspace)
|
37
|
+
#
|
38
|
+
# Changes keyspace by sending a `USE` statement to all connections.
|
39
|
+
#
|
40
|
+
# The the second parameter is meant for internal use only.
|
41
|
+
#
|
42
|
+
# @param [String] keyspace
|
43
|
+
# @raise [Cql::NotConnectedError] raised when the client is not connected
|
44
|
+
# @return [nil]
|
45
|
+
|
46
|
+
# @!method execute(cql, *values, options_or_consistency={})
|
47
|
+
#
|
48
|
+
# Execute a CQL statement, optionally passing bound values.
|
49
|
+
#
|
50
|
+
# When passing bound values the request encoder will have to guess what
|
51
|
+
# types to encode the values as. For most types this will be no problem,
|
52
|
+
# but for integers and floating point numbers the larger size will be
|
53
|
+
# chosen (e.g. `BIGINT` and `DOUBLE` and not `INT` and `FLOAT`). You can
|
54
|
+
# override the guessing with the `:type_hint` option. Don't use on-the-fly
|
55
|
+
# bound values when you will issue the request multiple times, prepared
|
56
|
+
# statements are almost always a better choice.
|
57
|
+
#
|
58
|
+
# @note On-the-fly bound values are not supported in Cassandra 1.2
|
59
|
+
#
|
60
|
+
# @example A simple CQL query
|
61
|
+
# result = client.execute("SELECT * FROM users WHERE user_name = 'sue'")
|
62
|
+
# result.each do |row|
|
63
|
+
# p row
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# @example Using on-the-fly bound values
|
67
|
+
# client.execute('INSERT INTO users (user_name, full_name) VALUES (?, ?)', 'sue', 'Sue Smith')
|
68
|
+
#
|
69
|
+
# @example Using on-the-fly bound values with type hints
|
70
|
+
# client.execute('INSERT INTO users (user_name, age) VALUES (?, ?)', 'sue', 33, type_hints: [nil, :int])
|
71
|
+
#
|
72
|
+
# @example Specifying the consistency as a symbol
|
73
|
+
# client.execute("UPDATE users SET full_name = 'Sue S. Smith' WHERE user_name = 'sue'", consistency: :one)
|
74
|
+
#
|
75
|
+
# @example Specifying the consistency and other options
|
76
|
+
# client.execute("SELECT * FROM users", consistency: :all, timeout: 1.5)
|
77
|
+
#
|
78
|
+
# @example Activating tracing for a query
|
79
|
+
# result = client.execute("SELECT * FROM users", tracing: true)
|
80
|
+
# p result.trace_id
|
81
|
+
#
|
82
|
+
# @param [String] cql
|
83
|
+
# @param [Array] values Values to bind to any binding markers in the
|
84
|
+
# query (i.e. "?" placeholders) -- using this feature is similar to
|
85
|
+
# using a prepared statement, but without the type checking. The client
|
86
|
+
# needs to guess which data types to encode the values as, and will err
|
87
|
+
# on the side of caution, using types like BIGINT instead of INT for
|
88
|
+
# integers, and DOUBLE instead of FLOAT for floating point numbers. It
|
89
|
+
# is not recommended to use this feature for anything but convenience,
|
90
|
+
# and the algorithm used to guess types is to be considered experimental.
|
91
|
+
# @param [Hash] options_or_consistency Either a consistency as a symbol
|
92
|
+
# (e.g. `:quorum`), or a options hash (see below). Passing a symbol is
|
93
|
+
# equivalent to passing the options `consistency: <symbol>`.
|
94
|
+
# @option options_or_consistency [Symbol] :consistency (:quorum) The
|
95
|
+
# consistency to use for this query.
|
96
|
+
# @option options_or_consistency [Symbol] :serial_consistency (nil) The
|
97
|
+
# consistency to use for conditional updates (`:serial` or
|
98
|
+
# `:local_serial`), see the CQL documentation for the semantics of
|
99
|
+
# serial consistencies and conditional updates. The default is assumed
|
100
|
+
# to be `:serial` by the server if none is specified. Ignored for non-
|
101
|
+
# conditional queries.
|
102
|
+
# @option options_or_consistency [Integer] :timeout (nil) How long to wait
|
103
|
+
# for a response. If this timeout expires a {Cql::TimeoutError} will
|
104
|
+
# be raised.
|
105
|
+
# @option options_or_consistency [Boolean] :trace (false) Request tracing
|
106
|
+
# for this request. See {Cql::Client::QueryResult} and
|
107
|
+
# {Cql::Client::VoidResult} for how to retrieve the tracing data.
|
108
|
+
# @option options_or_consistency [Array] :type_hints (nil) When passing
|
109
|
+
# on-the-fly bound values the request encoder will have to guess what
|
110
|
+
# types to encode the values as. Using this option you can give it hints
|
111
|
+
# and avoid it guessing wrong. The hints must be an array that has the
|
112
|
+
# same number of arguments as the number of bound values, and each
|
113
|
+
# element should be the type of the corresponding value, or nil if you
|
114
|
+
# prefer the encoder to guess. The types should be provided as lower
|
115
|
+
# case symbols, e.g. `:int`, `:time_uuid`, etc.
|
116
|
+
# @raise [Cql::NotConnectedError] raised when the client is not connected
|
117
|
+
# @raise [Cql::TimeoutError] raised when a timeout was specified and no
|
118
|
+
# response was received within the timeout.
|
119
|
+
# @raise [Cql::QueryError] raised when the CQL has syntax errors or for
|
120
|
+
# other situations when the server complains.
|
121
|
+
# @return [nil, Cql::Client::QueryResult, Cql::Client::VoidResult] Some
|
122
|
+
# queries have no result and return `nil`, but `SELECT` statements
|
123
|
+
# return an `Enumerable` of rows (see {Cql::Client::QueryResult}), and
|
124
|
+
# `INSERT` and `UPDATE` return a similar type
|
125
|
+
# (see {Cql::Client::VoidResult}).
|
126
|
+
|
127
|
+
# @!method prepare(cql)
|
128
|
+
#
|
129
|
+
# Returns a prepared statement that can be run over and over again with
|
130
|
+
# different values.
|
131
|
+
#
|
132
|
+
# @see Cql::Client::PreparedStatement
|
133
|
+
# @param [String] cql The CQL to prepare
|
134
|
+
# @raise [Cql::NotConnectedError] raised when the client is not connected
|
135
|
+
# @raise [Cql::Io::IoError] raised when there is an IO error, for example
|
136
|
+
# if the server suddenly closes the connection
|
137
|
+
# @raise [Cql::QueryError] raised when there is an error on the server
|
138
|
+
# side, for example when you specify a malformed CQL query
|
139
|
+
# @return [Cql::Client::PreparedStatement] an object encapsulating the
|
140
|
+
# prepared statement
|
141
|
+
|
142
|
+
# @!method batch(type=:logged, options={})
|
143
|
+
#
|
144
|
+
# Yields a batch when called with a block. The batch is automatically
|
145
|
+
# executed at the end of the block and the result is returned.
|
146
|
+
#
|
147
|
+
# Returns a batch when called wihtout a block. The batch will remember
|
148
|
+
# the options given and merge these with any additional options given
|
149
|
+
# when {Cql::Client::Batch#execute} is called.
|
150
|
+
#
|
151
|
+
# Please note that the batch object returned by this method _is not thread
|
152
|
+
# safe_.
|
153
|
+
#
|
154
|
+
# The type parameter can be ommitted and the options can then be given
|
155
|
+
# as first parameter.
|
156
|
+
#
|
157
|
+
# @example Executing queries in a batch
|
158
|
+
# client.batch do |batch|
|
159
|
+
# batch.add(%(INSERT INTO metrics (id, time, value) VALUES (1234, NOW(), 23423)))
|
160
|
+
# batch.add(%(INSERT INTO metrics (id, time, value) VALUES (2346, NOW(), 13)))
|
161
|
+
# batch.add(%(INSERT INTO metrics (id, time, value) VALUES (2342, NOW(), 2367)))
|
162
|
+
# batch.add(%(INSERT INTO metrics (id, time, value) VALUES (4562, NOW(), 1231)))
|
163
|
+
# end
|
164
|
+
#
|
165
|
+
# @example Using the returned batch object
|
166
|
+
# batch = client.batch(:counter, trace: true)
|
167
|
+
# batch.add('UPDATE counts SET value = value + ? WHERE id = ?', 4, 87654)
|
168
|
+
# batch.add('UPDATE counts SET value = value + ? WHERE id = ?', 3, 6572)
|
169
|
+
# result = batch.execute(timeout: 10)
|
170
|
+
# puts result.trace_id
|
171
|
+
#
|
172
|
+
# @example Providing type hints for on-the-fly bound values
|
173
|
+
# batch = client.batch
|
174
|
+
# batch.add('UPDATE counts SET value = value + ? WHERE id = ?', 4, type_hints: [:int])
|
175
|
+
# batch.execute
|
176
|
+
#
|
177
|
+
# @see Cql::Client::Batch
|
178
|
+
# @param [Symbol] type the type of batch, must be one of `:logged`,
|
179
|
+
# `:unlogged` and `:counter`. The precise meaning of these is defined
|
180
|
+
# in the CQL specification.
|
181
|
+
# @yieldparam [Cql::Client::Batch] batch the batch
|
182
|
+
# @return [Cql::Client::VoidResult, Cql::Client::Batch] when no block is
|
183
|
+
# given the batch is returned, when a block is given the result of
|
184
|
+
# executing the batch is returned (see {Cql::Client::Batch#execute}).
|
185
|
+
end
|
186
|
+
|
5
187
|
# @private
|
6
188
|
class AsynchronousClient < Client
|
7
189
|
def initialize(options={})
|
@@ -9,7 +191,7 @@ module Cql
|
|
9
191
|
@cql_version = options[:cql_version]
|
10
192
|
@logger = options[:logger] || NullLogger.new
|
11
193
|
@protocol_version = options[:protocol_version] || 2
|
12
|
-
@io_reactor = options[:io_reactor] || Io::IoReactor.new
|
194
|
+
@io_reactor = options[:io_reactor] || Io::IoReactor.new
|
13
195
|
@hosts = extract_hosts(options)
|
14
196
|
@initial_keyspace = options[:keyspace]
|
15
197
|
@connections_per_node = options[:connections_per_node] || 1
|
@@ -131,10 +313,6 @@ module Cql
|
|
131
313
|
DEFAULT_CONNECTION_TIMEOUT = 10
|
132
314
|
MAX_RECONNECTION_ATTEMPTS = 5
|
133
315
|
|
134
|
-
def protocol_handler_factory
|
135
|
-
lambda { |connection, timeout| Protocol::CqlProtocolHandler.new(connection, timeout, @protocol_version, @compressor) }
|
136
|
-
end
|
137
|
-
|
138
316
|
def extract_hosts(options)
|
139
317
|
if options[:hosts]
|
140
318
|
options[:hosts].uniq
|
@@ -148,9 +326,10 @@ module Cql
|
|
148
326
|
def create_cluster_connector
|
149
327
|
cql_version = @cql_version || DEFAULT_CQL_VERSIONS[@protocol_version]
|
150
328
|
authentication_step = @protocol_version == 1 ? CredentialsAuthenticationStep.new(@credentials) : SaslAuthenticationStep.new(@auth_provider)
|
329
|
+
protocol_handler_factory = lambda { |connection| Protocol::CqlProtocolHandler.new(connection, @io_reactor, @protocol_version, @compressor) }
|
151
330
|
ClusterConnector.new(
|
152
331
|
Connector.new([
|
153
|
-
ConnectStep.new(@io_reactor, @port, @connection_timeout, @logger),
|
332
|
+
ConnectStep.new(@io_reactor, protocol_handler_factory, @port, @connection_timeout, @logger),
|
154
333
|
CacheOptionsStep.new,
|
155
334
|
InitializeStep.new(cql_version, @compressor, @logger),
|
156
335
|
authentication_step,
|
@@ -308,5 +487,61 @@ module Cql
|
|
308
487
|
end
|
309
488
|
end
|
310
489
|
end
|
490
|
+
|
491
|
+
# @private
|
492
|
+
class SynchronousClient < Client
|
493
|
+
include SynchronousBacktrace
|
494
|
+
|
495
|
+
def initialize(async_client)
|
496
|
+
@async_client = async_client
|
497
|
+
end
|
498
|
+
|
499
|
+
def connect
|
500
|
+
synchronous_backtrace { @async_client.connect.value }
|
501
|
+
self
|
502
|
+
end
|
503
|
+
|
504
|
+
def close
|
505
|
+
synchronous_backtrace { @async_client.close.value }
|
506
|
+
self
|
507
|
+
end
|
508
|
+
|
509
|
+
def connected?
|
510
|
+
@async_client.connected?
|
511
|
+
end
|
512
|
+
|
513
|
+
def keyspace
|
514
|
+
@async_client.keyspace
|
515
|
+
end
|
516
|
+
|
517
|
+
def use(keyspace)
|
518
|
+
synchronous_backtrace { @async_client.use(keyspace).value }
|
519
|
+
end
|
520
|
+
|
521
|
+
def execute(cql, *args)
|
522
|
+
synchronous_backtrace do
|
523
|
+
result = @async_client.execute(cql, *args).value
|
524
|
+
result = SynchronousPagedQueryResult.new(result) if result.is_a?(PagedQueryResult)
|
525
|
+
result
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
def prepare(cql)
|
530
|
+
async_statement = synchronous_backtrace { @async_client.prepare(cql).value }
|
531
|
+
SynchronousPreparedStatement.new(async_statement)
|
532
|
+
end
|
533
|
+
|
534
|
+
def batch(type=:logged, options={}, &block)
|
535
|
+
if block_given?
|
536
|
+
synchronous_backtrace { @async_client.batch(type, options, &block).value }
|
537
|
+
else
|
538
|
+
SynchronousBatch.new(@async_client.batch(type, options))
|
539
|
+
end
|
540
|
+
end
|
541
|
+
|
542
|
+
def async
|
543
|
+
@async_client
|
544
|
+
end
|
545
|
+
end
|
311
546
|
end
|
312
547
|
end
|
data/lib/cql/client/connector.rb
CHANGED
@@ -72,8 +72,9 @@ module Cql
|
|
72
72
|
|
73
73
|
# @private
|
74
74
|
class ConnectStep
|
75
|
-
def initialize(io_reactor, port, connection_timeout, logger)
|
75
|
+
def initialize(io_reactor, protocol_handler_factory, port, connection_timeout, logger)
|
76
76
|
@io_reactor = io_reactor
|
77
|
+
@protocol_handler_factory = protocol_handler_factory
|
77
78
|
@port = port
|
78
79
|
@connection_timeout = connection_timeout
|
79
80
|
@logger = logger
|
@@ -81,7 +82,7 @@ module Cql
|
|
81
82
|
|
82
83
|
def run(pending_connection)
|
83
84
|
@logger.debug('Connecting to node at %s:%d' % [pending_connection.host, @port])
|
84
|
-
@io_reactor.connect(pending_connection.host, @port, @connection_timeout).map do |connection|
|
85
|
+
@io_reactor.connect(pending_connection.host, @port, @connection_timeout, &@protocol_handler_factory).map do |connection|
|
85
86
|
pending_connection.with_connection(connection)
|
86
87
|
end
|
87
88
|
end
|
@@ -2,6 +2,51 @@
|
|
2
2
|
|
3
3
|
module Cql
|
4
4
|
module Client
|
5
|
+
class PreparedStatement
|
6
|
+
# Metadata describing the bound values
|
7
|
+
#
|
8
|
+
# @return [ResultMetadata]
|
9
|
+
attr_reader :metadata
|
10
|
+
|
11
|
+
# Metadata about the result (i.e. rows) that is returned when executing
|
12
|
+
# this prepared statement.
|
13
|
+
#
|
14
|
+
# @return [ResultMetadata]
|
15
|
+
attr_reader :result_metadata
|
16
|
+
|
17
|
+
# Execute the prepared statement with a list of values to be bound to the
|
18
|
+
# statements parameters.
|
19
|
+
#
|
20
|
+
# The number of arguments must equal the number of bound parameters. You
|
21
|
+
# can also specify options as the last argument, or a symbol as a shortcut
|
22
|
+
# for just specifying the consistency.
|
23
|
+
#
|
24
|
+
# Because you can specify options, or not, there is an edge case where if
|
25
|
+
# the last parameter of your prepared statement is a map, and you forget
|
26
|
+
# to specify a value for your map, the options will end up being sent to
|
27
|
+
# Cassandra. Most other cases when you specify the wrong number of
|
28
|
+
# arguments should result in an `ArgumentError` or `TypeError` being
|
29
|
+
# raised.
|
30
|
+
#
|
31
|
+
# @param args [Array] the values for the bound parameters. The last
|
32
|
+
# argument can also be an options hash or a symbol (as a shortcut for
|
33
|
+
# specifying the consistency), see {Cql::Client::Client#execute} for
|
34
|
+
# full details.
|
35
|
+
# @raise [ArgumentError] raised when number of argument does not match
|
36
|
+
# the number of parameters needed to be bound to the statement.
|
37
|
+
# @raise [Cql::NotConnectedError] raised when the client is not connected
|
38
|
+
# @raise [Cql::Io::IoError] raised when there is an IO error, for example
|
39
|
+
# if the server suddenly closes the connection
|
40
|
+
# @raise [Cql::QueryError] raised when there is an error on the server side
|
41
|
+
# @return [nil, Cql::Client::QueryResult, Cql::Client::VoidResult] Some
|
42
|
+
# queries have no result and return `nil`, but `SELECT` statements
|
43
|
+
# return an `Enumerable` of rows (see {Cql::Client::QueryResult}), and
|
44
|
+
# `INSERT` and `UPDATE` return a similar type
|
45
|
+
# (see {Cql::Client::VoidResult}).
|
46
|
+
def execute(*args)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
5
50
|
# @private
|
6
51
|
class AsynchronousPreparedStatement < PreparedStatement
|
7
52
|
# @private
|
@@ -102,5 +147,63 @@ module Cql
|
|
102
147
|
f
|
103
148
|
end
|
104
149
|
end
|
150
|
+
|
151
|
+
# @private
|
152
|
+
class SynchronousPreparedStatement < PreparedStatement
|
153
|
+
include SynchronousBacktrace
|
154
|
+
|
155
|
+
def initialize(async_statement)
|
156
|
+
@async_statement = async_statement
|
157
|
+
@metadata = async_statement.metadata
|
158
|
+
@result_metadata = async_statement.result_metadata
|
159
|
+
end
|
160
|
+
|
161
|
+
def execute(*args)
|
162
|
+
synchronous_backtrace do
|
163
|
+
result = @async_statement.execute(*args).value
|
164
|
+
result = SynchronousPagedQueryResult.new(result) if result.is_a?(PagedQueryResult)
|
165
|
+
result
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def batch(type=:logged, options=nil, &block)
|
170
|
+
if block_given?
|
171
|
+
synchronous_backtrace { @async_statement.batch(type, options, &block).value }
|
172
|
+
else
|
173
|
+
SynchronousPreparedStatementBatch.new(@async_statement.batch(type, options))
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def pipeline
|
178
|
+
pl = Pipeline.new(@async_statement)
|
179
|
+
yield pl
|
180
|
+
synchronous_backtrace { pl.value }
|
181
|
+
end
|
182
|
+
|
183
|
+
def async
|
184
|
+
@async_statement
|
185
|
+
end
|
186
|
+
|
187
|
+
# @private
|
188
|
+
def add_to_batch(batch, connection, bound_arguments)
|
189
|
+
@async_statement.add_to_batch(batch, connection, bound_arguments)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# @private
|
194
|
+
class Pipeline
|
195
|
+
def initialize(async_statement)
|
196
|
+
@async_statement = async_statement
|
197
|
+
@futures = []
|
198
|
+
end
|
199
|
+
|
200
|
+
def execute(*args)
|
201
|
+
@futures << @async_statement.execute(*args)
|
202
|
+
end
|
203
|
+
|
204
|
+
def value
|
205
|
+
Future.all(*@futures).value
|
206
|
+
end
|
207
|
+
end
|
105
208
|
end
|
106
209
|
end
|