Permalink
Browse files

Documentation galore

  • Loading branch information...
1 parent 54a0667 commit 76c870b42177b8e871904725d95d4291270d7a86 @iconara committed Feb 24, 2013
Showing with 267 additions and 1 deletion.
  1. +4 −0 .yardopts
  2. +123 −1 lib/cql/client.rb
  3. +75 −0 lib/cql/future.rb
  4. +46 −0 lib/cql/io/io_reactor.rb
  5. +1 −0 lib/cql/protocol.rb
  6. +18 −0 lib/cql/uuid.rb
View
@@ -0,0 +1,4 @@
+--no-private
+--markup markdown
+lib/**/*.rb
+-- README
View
@@ -13,7 +13,54 @@ def initialize(code, message)
end
end
+ ClientError = Class.new(CqlError)
+
+ # A CQL client manages connections to one or more Cassandra nodes and you use
+ # it run queries, insert and update data.
+ #
+ # @example Connecting and changing to a keyspace
+ # # create a client that will connect to two Cassandra nodes
+ # client = Cql::Client.new(host: 'node01.cassandra.local,node02.cassandra.local')
+ # # establish node connections
+ # client.start!
+ # # change to a keyspace
+ # client.use('stuff')
+ #
+ # @example Query for data
+ # rows = client.execute('SELECT * FROM things WHERE id = 2')
+ # rows.each do |row|
+ # p row
+ # end
+ #
+ # @example Inserting and updating data
+ # client.execute("INSERT INTO things (id, value) VALUES (4, 'foo')")
+ # client.execute("UPDATE things SET value = 'bar' WHERE id = 5")
+ #
+ # @example Prepared statements
+ # statement = client.prepare('INSERT INTO things (id, value) VALUES (?, ?)')
+ # statement.execute(9, 'qux')
+ # statement.execute(8, 'baz')
+ #
+ # Client instances are threadsafe.
+ #
class Client
+ NotConnectedError = Class.new(ClientError)
+ InvalidKeyspaceNameError = Class.new(ClientError)
+
+ # Create a new client.
+ #
+ # Creating a client does not automatically connect to Cassandra, you need to
+ # call {#start!} to connect. `#start!` returns `self` so you can chain that
+ # call after `new`.
+ #
+ # @param [Hash] options
+ # @option options [String] :host ('localhost') One or more (comma separated)
+ # hostnames for the Cassandra nodes you want to connect to.
+ # @option options [String] :port (9042) The port to connect to
+ # @option options [Integer] :connection_timeout (5) Max time to wait for a
+ # connection, in seconds
+ # @option options [String] :keyspace The keyspace to change to immediately
+ # after all connections have been established, this is optional.
def initialize(options={})
connection_timeout = options[:connection_timeout]
@host = options[:host] || 'localhost'
@@ -26,6 +73,17 @@ def initialize(options={})
@connection_keyspaces = {}
end
+ # Connect to all nodes.
+ #
+ # You must call this method before you call any of the other methods of a
+ # client. Calling it again will have no effect.
+ #
+ # If `:keyspace` was specified when the client was created the current
+ # keyspace will also be changed (otherwise the current keyspace will not
+ # be set).
+ #
+ # @return self
+ #
def start!
@lock.synchronize do
return if @started
@@ -44,6 +102,10 @@ def start!
self
end
+ # Disconnect from all nodes.
+ #
+ # @return self
+ #
def shutdown!
@lock.synchronize do
return if @shut_down
@@ -54,12 +116,27 @@ def shutdown!
self
end
+ # Returns whether or not the client is connected.
+ #
+ def connected?
+ @started
+ end
+
+ # Returns the name of the current keyspace, or `nil` if no keyspace has been
+ # set yet.
+ #
def keyspace
@lock.synchronize do
return @connection_ids.map { |id| @connection_keyspaces[id] }.first
end
end
+ # Changes keyspace by sending a `USE` statement to all connections.
+ #
+ # The the second parameter is meant for internal use only.
+ #
+ # @raise [Cql::NotConnectedError] raised when the client is not connected
+ #
def use(keyspace, connection_ids=@connection_ids)
raise NotConnectedError unless @started
if check_keyspace_name!(keyspace)
@@ -77,16 +154,32 @@ def use(keyspace, connection_ids=@connection_ids)
end
end
+ # Execute a CQL statement
+ #
+ # @raise [Cql::NotConnectedError] raised when the client is not connected
+ # @raise [Cql::QueryError] raised when the CQL has syntax errors or for
+ # other situations when the server complains.
+ # @return [nil, Enumerable<Hash>] Most statements have no result and return
+ # `nil`, but `SELECT` statements return an `Enumerable` of rows
+ # (see {QueryResult}).
+ #
def execute(cql, consistency=:quorum)
result = execute_request(Protocol::QueryRequest.new(cql, consistency)).value
ensure_keyspace!
result
end
+ # @private
def execute_statement(connection_id, statement_id, metadata, values, consistency)
execute_request(Protocol::ExecuteRequest.new(statement_id, metadata, values, consistency), connection_id).value
end
+ # Returns a prepared statement that can be run over and over again with
+ # different values.
+ #
+ # @raise [Cql::NotConnectedError] raised when the client is not connected
+ # @return [Cql::PreparedStatement] an object encapsulating the prepared statement
+ #
def prepare(cql)
execute_request(Protocol::PrepareRequest.new(cql)).value
end
@@ -137,29 +230,43 @@ def ensure_keyspace!
end
class PreparedStatement
+ # @return [ResultMetadata]
+ attr_reader :metadata
+
def initialize(*args)
@client, @connection_id, @statement_id, @metadata = args
end
def execute(*args)
+ # Execute the prepared statement with a list of values for the bound parameters.
+ #
@client.execute_statement(@connection_id, @statement_id, @metadata, args, :quorum)
end
end
class QueryResult
include Enumerable
+ # @return [ResultMetadata]
attr_reader :metadata
+ # @private
def initialize(metadata, rows)
@metadata = ResultMetadata.new(metadata)
@rows = rows
end
+ # Returns whether or not there are any rows in this result set
+ #
def empty?
@rows.empty?
end
+ # Iterates over each row in the result set.
+ #
+ # @yieldparam [Hash] row each row in the result set as a hash
+ # @return [Enumerable<Hash>]
+ #
def each(&block)
@rows.each(&block)
end
@@ -168,26 +275,41 @@ def each(&block)
class ResultMetadata
include Enumerable
+ # @private
def initialize(metadata)
@metadata = Hash[metadata.map { |m| mm = ColumnMetadata.new(*m); [mm.column_name, mm] }]
end
def [](column_name)
@metadata[column_name]
+ # Returns the column metadata
+ #
+ # @return [ColumnMetadata] column_metadata the metadata for the column
+ #
end
+ # Iterates over the metadata for each column
+ #
+ # @yieldparam [ColumnMetadata] metadata the metadata for each column
+ # @return [Enumerable<ColumnMetadata>]
+ #
def each(&block)
@metadata.each_value(&block)
end
end
+ # Represents metadata about a column in a query result set or prepared
+ # statement. Apart from the keyspace, table and column names there's also
+ # the type as a symbol (e.g. `:varchar`, `:int`, `:date`).
class ColumnMetadata
- attr_reader :keyspace, :table, :table, :column_name, :type
+ attr_reader :keyspace, :table, :column_name, :type
+ # @private
def initialize(*args)
@keyspace, @table, @column_name, @type = args
end
+ # @private
def to_ary
[@keyspace, @table, @column_name, @type]
end
Oops, something went wrong.

0 comments on commit 76c870b

Please sign in to comment.