Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add way to create HostInfo objects for testing purposes (CASSGO-71)
- Add missing Context methods on Query and Batch (CASSGO-81)
- Update example and test code for 2.0 release (CASSGO-80)
- Add API docs for 2.0 release (CASSGO-78)

### Changed

Expand Down
1 change: 1 addition & 0 deletions address_translators.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type AddressTranslator interface {
Translate(addr net.IP, port int) (net.IP, int)
}

// AddressTranslatorFunc is a function type that implements AddressTranslator.
type AddressTranslatorFunc func(addr net.IP, port int) (net.IP, int)

func (fn AddressTranslatorFunc) Translate(addr net.IP, port int) (net.IP, int) {
Expand Down
12 changes: 10 additions & 2 deletions cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,11 @@ type ClusterConfig struct {
disableControlConn bool
}

// Dialer is the interface that wraps the DialContext method for establishing network connections to Cassandra nodes.
//
// This interface allows customization of how gocql establishes TCP connections, which is useful for:
// connecting through proxies or load balancers, custom TLS configurations, custom timeouts/keep-alive
// settings, service mesh integration, testing with mocked connections, and corporate network routing.
type Dialer interface {
DialContext(ctx context.Context, network, addr string) (net.Conn, error)
}
Expand Down Expand Up @@ -357,7 +362,10 @@ func (cfg *ClusterConfig) filterHost(host *HostInfo) bool {
}

var (
ErrNoHosts = errors.New("no hosts provided")
// ErrNoHosts is returned when no hosts are provided to the cluster configuration.
ErrNoHosts = errors.New("no hosts provided")
// ErrNoConnectionsStarted is returned when no connections could be established during session creation.
ErrNoConnectionsStarted = errors.New("no connections were made when creating the session")
ErrHostQueryFailed = errors.New("unable to populate Hosts")
// Deprecated: Never used or returned by the driver.
ErrHostQueryFailed = errors.New("unable to populate Hosts")
)
3 changes: 3 additions & 0 deletions compressor.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@

package gocql

// Compressor defines the interface for frame compression and decompression.
// Implementations provide compression algorithms like Snappy and LZ4 that can be used
// to reduce network traffic between the driver and Cassandra nodes.
type Compressor interface {
Name() string

Expand Down
3 changes: 3 additions & 0 deletions conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func JoinHostPort(addr string, port int) string {
return addr
}

// Authenticator handles authentication challenges and responses during connection setup.
type Authenticator interface {
Challenge(req []byte) (resp []byte, auth Authenticator, err error)
Success(data []byte) error
Expand Down Expand Up @@ -132,6 +133,7 @@ type SslOptions struct {
EnableHostVerification bool
}

// ConnConfig contains configuration options for establishing connections to Cassandra nodes.
type ConnConfig struct {
ProtoVersion int
CQLVersion string
Expand All @@ -150,6 +152,7 @@ type ConnConfig struct {
disableCoalesce bool
}

// ConnErrorHandler handles connection errors and state changes for connections.
type ConnErrorHandler interface {
HandleError(conn *Conn, err error, closed bool)
}
Expand Down
1 change: 1 addition & 0 deletions cqltypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

package gocql

// Duration represents a Cassandra duration type, which consists of months, days, and nanoseconds components.
type Duration struct {
Months int32
Days int32
Expand Down
24 changes: 24 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ const (
ErrCodeUnprepared = 0x2500
)

// RequestError represents errors returned by Cassandra server.
type RequestError interface {
Code() int
Message() string
Expand Down Expand Up @@ -140,6 +141,8 @@ func (e errorFrame) String() string {
return fmt.Sprintf("[error code=%x message=%q]", e.code, e.message)
}

// RequestErrUnavailable represents an unavailable error returned by Cassandra.
// This error occurs when there are not enough nodes available to fulfill the request.
type RequestErrUnavailable struct {
errorFrame
Consistency Consistency
Expand All @@ -151,8 +154,14 @@ func (e *RequestErrUnavailable) String() string {
return fmt.Sprintf("[request_error_unavailable consistency=%s required=%d alive=%d]", e.Consistency, e.Required, e.Alive)
}

// ErrorMap maps node IP addresses to their respective error codes for read/write failure responses.
// Each entry represents a node that failed during the operation, with the key being the node's
// IP address as a string and the value being the specific error code returned by that node.
type ErrorMap map[string]uint16

// RequestErrWriteTimeout represents a write timeout error returned by Cassandra.
// This error occurs when a write request times out after the coordinator
// has successfully written to some replicas but not enough to satisfy the required consistency level.
type RequestErrWriteTimeout struct {
errorFrame
Consistency Consistency
Expand All @@ -161,6 +170,8 @@ type RequestErrWriteTimeout struct {
WriteType string
}

// RequestErrWriteFailure represents a write failure error returned by Cassandra.
// This error occurs when a write request fails on one or more replicas.
type RequestErrWriteFailure struct {
errorFrame
Consistency Consistency
Expand All @@ -171,10 +182,15 @@ type RequestErrWriteFailure struct {
ErrorMap ErrorMap
}

// RequestErrCDCWriteFailure represents a CDC write failure error returned by Cassandra.
// This error occurs when a write to the Change Data Capture log fails.
type RequestErrCDCWriteFailure struct {
errorFrame
}

// RequestErrReadTimeout represents a read timeout error returned by Cassandra.
// This error occurs when a read request times out after the coordinator
// has received some responses but not enough to satisfy the required consistency level.
type RequestErrReadTimeout struct {
errorFrame
Consistency Consistency
Expand All @@ -183,17 +199,23 @@ type RequestErrReadTimeout struct {
DataPresent byte
}

// RequestErrAlreadyExists represents an "already exists" error returned by Cassandra.
// This error occurs when attempting to create a keyspace or table that already exists.
type RequestErrAlreadyExists struct {
errorFrame
Keyspace string
Table string
}

// RequestErrUnprepared represents an "unprepared" error returned by Cassandra.
// This error occurs when a prepared statement is no longer available on the server.
type RequestErrUnprepared struct {
errorFrame
StatementId []byte
}

// RequestErrReadFailure represents a read failure error returned by Cassandra.
// This error occurs when a read request fails on one or more replicas.
type RequestErrReadFailure struct {
errorFrame
Consistency Consistency
Expand All @@ -204,6 +226,8 @@ type RequestErrReadFailure struct {
ErrorMap ErrorMap
}

// RequestErrFunctionFailure represents a function failure error returned by Cassandra.
// This error occurs when a user-defined function fails during execution.
type RequestErrFunctionFailure struct {
errorFrame
Keyspace string
Expand Down
3 changes: 3 additions & 0 deletions frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ const (
flagBetaProtocol byte = 0x10
)

// Consistency represents the consistency level for read and write operations.
// Available levels: Any, One, Two, Three, Quorum, All, LocalQuorum, EachQuorum,
// Serial, LocalSerial, LocalOne.
type Consistency uint16

// SerialConsistency is deprecated. Use Consistency instead.
Expand Down
3 changes: 3 additions & 0 deletions gocqlzap/zap.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ import (
gocql "github.com/apache/cassandra-gocql-driver/v2"
)

// DefaultName is the default logger name used when creating a new zap logger.
const DefaultName = "gocql"

// Logger represents a structured logger that integrates zap logging with gocql.
// It extends gocql.StructuredLogger with access to the underlying zap logger.
type Logger interface {
gocql.StructuredLogger
ZapLogger() *zap.Logger
Expand Down
5 changes: 5 additions & 0 deletions gocqlzerolog/zerolog.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,14 @@ import (
gocql "github.com/apache/cassandra-gocql-driver/v2"
)

// DefaultName is the default logger name used when creating a new zerolog logger.
const DefaultName = "gocql"

// DefaultNameField is the default field name used to identify the logger in log entries.
const DefaultNameField = "logger"

// Logger represents a structured logger that integrates zerolog logging with gocql.
// It extends gocql.StructuredLogger with access to the underlying zerolog logger.
type Logger interface {
gocql.StructuredLogger
ZerologLogger() zerolog.Logger
Expand Down
69 changes: 63 additions & 6 deletions helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func dereference(i interface{}) interface{} {
return reflect.Indirect(reflect.ValueOf(i)).Interface()
}

// TupeColumnName will return the column name of a tuple value in a column named
// TupleColumnName will return the column name of a tuple value in a column named
// c at index n. It should be used if a specific element within a tuple is needed
// to be extracted from a map returned from SliceMap or MapScan.
func TupleColumnName(c string, n int) string {
Expand Down Expand Up @@ -81,8 +81,60 @@ func (iter *Iter) RowData() (RowData, error) {
return rowData, nil
}

// SliceMap is a helper function to make the API easier to use
// returns the data from the query in the form of []map[string]interface{}
// SliceMap is a helper function to make the API easier to use.
// It returns the data from the query in the form of []map[string]interface{}.
//
// Columns are automatically converted to Go types based on their CQL type.
// The following table shows exactly what Go type to expect when accessing map values:
//
// CQL Type | Go Type (Non-NULL) | Go Value for NULL | Type Assertion Example
// ascii | string | "" | row["col"].(string)
// bigint | int64 | int64(0) | row["col"].(int64)
// blob | []byte | []byte(nil) | row["col"].([]byte)
// boolean | bool | false | row["col"].(bool)
// counter | int64 | int64(0) | row["col"].(int64)
// date | time.Time | time.Time{} | row["col"].(time.Time)
// decimal | *inf.Dec | (*inf.Dec)(nil) | row["col"].(*inf.Dec)
// double | float64 | float64(0) | row["col"].(float64)
// duration | gocql.Duration | gocql.Duration{} | row["col"].(gocql.Duration)
// float | float32 | float32(0) | row["col"].(float32)
// inet | net.IP | net.IP(nil) | row["col"].(net.IP)
// int | int | int(0) | row["col"].(int)
// list<T> | []T | []T(nil) | row["col"].([]string)
// map<K,V> | map[K]V | map[K]V(nil) | row["col"].(map[string]int)
// set<T> | []T | []T(nil) | row["col"].([]int)
// smallint | int16 | int16(0) | row["col"].(int16)
// text | string | "" | row["col"].(string)
// time | time.Duration | time.Duration(0) | row["col"].(time.Duration)
// timestamp | time.Time | time.Time{} | row["col"].(time.Time)
// timeuuid | gocql.UUID | gocql.UUID{} | row["col"].(gocql.UUID)
// tinyint | int8 | int8(0) | row["col"].(int8)
// tuple<T1,T2,...> | (see below) | (see below) | (see below)
// uuid | gocql.UUID | gocql.UUID{} | row["col"].(gocql.UUID)
// varchar | string | "" | row["col"].(string)
// varint | *big.Int | (*big.Int)(nil) | row["col"].(*big.Int)
// vector<T,N> | []T | []T(nil) | row["col"].([]float32)
//
// Special Cases:
//
// Tuple Types: Tuple elements are split into separate map entries with keys like "column[0]", "column[1]", etc.
// Use TupleColumnName to generate the correct key:
//
// // For tuple<int, text> column named "my_tuple"
// elem0 := row[gocql.TupleColumnName("my_tuple", 0)].(int)
// elem1 := row[gocql.TupleColumnName("my_tuple", 1)].(string)
//
// User-Defined Types (UDTs): Returned as map[string]interface{} with field names as keys:
//
// udt := row["my_udt"].(map[string]interface{})
// name := udt["name"].(string)
// age := udt["age"].(int)
//
// Important Notes:
// - Always use type assertions when accessing map values: row["col"].(ExpectedType)
// - NULL database values return Go zero values or nil for pointer types
// - Collection types (list, set, map, vector) return nil slices/maps for NULL values
// - Migration from v1.x: inet columns now return net.IP instead of string values
func (iter *Iter) SliceMap() ([]map[string]interface{}, error) {
if iter.err != nil {
return nil, iter.err
Expand All @@ -104,11 +156,16 @@ func (iter *Iter) SliceMap() ([]map[string]interface{}, error) {
}

// MapScan takes a map[string]interface{} and populates it with a row
// that is returned from cassandra.
// that is returned from Cassandra.
//
// Each call to MapScan() must be called with a new map object.
// During the call to MapScan() any pointers in the existing map
// are replaced with non pointer types before the call returns
// are replaced with non pointer types before the call returns.
//
// Columns are automatically converted to Go types based on their CQL type.
// See SliceMap for the complete CQL to Go type mapping table and examples.
//
// Usage Examples:
//
// iter := session.Query(`SELECT * FROM mytable`).Iter()
// for {
Expand All @@ -123,7 +180,7 @@ func (iter *Iter) SliceMap() ([]map[string]interface{}, error) {
// }
// }
//
// You can also pass pointers in the map before each call
// You can also pass pointers in the map before each call:
//
// var fullName FullName // Implements gocql.Unmarshaler and gocql.Marshaler interfaces
// var address net.IP
Expand Down
9 changes: 8 additions & 1 deletion logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ func writeLogMsg(buf *bytes.Buffer, prefix string, msg string, fields []LogField
writeFields(buf, fields)
}

// LogLevel represents the level of logging to be performed.
// Higher values indicate more verbose logging.
// Available levels: LogLevelDebug, LogLevelInfo, LogLevelWarn, LogLevelError, LogLevelNone.
type LogLevel int

const (
Expand Down Expand Up @@ -212,6 +215,8 @@ func (recv LogLevel) String() string {
}
}

// LogField represents a structured log field with a name and value.
// It is used to provide structured logging information.
type LogField struct {
Name string
Value LogFieldValue
Expand Down Expand Up @@ -277,7 +282,9 @@ type LogFieldValue struct {
any interface{}
}

// LogFieldValueType is the type of a LogFieldValue.
// LogFieldValueType represents the type of a LogFieldValue.
// It is used to determine how to interpret the value stored in LogFieldValue.
// Available types: LogFieldTypeAny, LogFieldTypeBool, LogFieldTypeInt64, LogFieldTypeString.
type LogFieldValueType int

// It's important that LogFieldTypeAny is 0 so that a zero Value represents nil.
Expand Down
Loading