cql-rb 2.0.0.pre0 → 2.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|