gocassa

package module
v0.0.0-...-01d56be Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2023 License: MIT Imports: 15 Imported by: 0

README

gocassa

GoDoc Build Status

Gocassa is a high-level library on top of gocql.

Current version: v2.0.2

Compared to gocql it provides query building, adds data binding, and provides easy-to-use "recipe" tables for common query use-cases. Unlike cqlc, it does not use code generation.

For docs, see: https://godoc.org/github.com/stut/gocassa

Usage

Below is a basic example showing how to connect to a Cassandra cluster and setup a simple table. For more advanced examples see the "Table Types" section below.

package main

import(
    "fmt"
    "time"

    "github.com/stut/gocassa"
)

type Sale struct {
    Id          string
    CustomerId  string
    SellerId    string
    Price       int
    Created     time.Time
}

func main() {
    keySpace, err := gocassa.ConnectToKeySpace("test", []string{"127.0.0.1"}, "", "")
    if err != nil {
        panic(err)
    }
    salesTable := keySpace.Table("sale", &Sale{}, gocassa.Keys{
        PartitionKeys: []string{"Id"},
    })

    err = salesTable.Set(Sale{
        Id: "sale-1",
        CustomerId: "customer-1",
        SellerId: "seller-1",
        Price: 42,
        Created: time.Now(),
    }).Run()
    if err != nil {
        panic(err)
    }

    result := Sale{}
    if err := salesTable.Where(gocassa.Eq("Id", "sale-1")).ReadOne(&result).Run(); err != nil {
        panic(err)
    }
    fmt.Println(result)
}

link to this example

You can pass additional options to a gocassa Op to further configure your queries, for example the following query orders the results by the field "Name" in descending order and limits the results to a total of 100.

err := salesTable.List("seller-1", nil, 0, &results).WithOptions(gocassa.Options{
    ClusteringOrder: []ClusteringOrderColumn{
        {DESC, "Name"},
    },
    Limit: 100,
}).Run()
Running the tests

As a prerequisite for the tests, you need to have cassandra running locally. To download and install open-source Cassandra, see Apache Cassandra documentation. On a macOS, you simply install using brew install cassandra.

Then you can run all the unit tests with the following command-

go test ./...
Table Types

Gocassa provides multiple table types with their own unique interfaces:

  • a raw CQL table called simply Table - this lets you do pretty much any query imaginable
  • and a number of single purpose 'recipe' tables (Map, Multimap, TimeSeries, MultiTimeSeries, MultiMapMultiKey), which aims to help the user by having a simplified interface tailored to a given common query use case
Table
    salesTable := keySpace.Table("sale", &Sale{}, gocassa.Keys{
        PartitionKeys: []string{"Id"},
    })
    result := Sale{}
    err := salesTable.Where(gocassa.Eq("Id", "sale-1")).ReadOne(&result).Run()

link to this example

MapTable

MapTable provides only very simple CRUD functionality:

    // …
    salesTable := keySpace.MapTable("sale", "Id", &Sale{})
    result := Sale{}
    salesTable.Read("sale-1", &result).Run()
}

link to this example

Read, Set, Update, and Delete all happen by "Id".

MultimapTable

MultimapTable can list rows filtered by equality of a single field (eg. list sales based on their sellerId):

    salesTable := keySpace.MultimapTable("sale", "SellerId", "Id", &Sale{})
    // …
    results := []Sale{}
    err := salesTable.List("seller-1", nil, 0, &results).Run()

link to this example

For examples on how to do pagination or Update with this table, refer to the example (linked under code snippet).

TimeSeriesTable

TimeSeriesTable provides an interface to list rows within a time interval:

    salesTable := keySpace.TimeSeriesTable("sale", "Created", "Id", &Sale{}, 24 * time.Hour)
    //...
    results := []Sale{}
    err := salesTable.List(yesterdayTime, todayTime, &results).Run()
MultiTimeSeriesTable

MultiTimeSeriesTable is like a cross between MultimapTable and TimeSeriesTable. It can list rows within a time interval, and filtered by equality of a single field. The following lists sales in a time interval, by a certain seller:

    salesTable := keySpace.MultiTimeSeriesTable("sale", "SellerId", "Created", "Id", &Sale{}, 24 * time.Hour)
    //...
    results := []Sale{}
    err := salesTable.List("seller-1", yesterdayTime, todayTime, &results).Run()
MultiMapMultiKeyTable

MultiMapMultiKeyTable can perform CRUD operations on rows filtered by equality of multiple fields (eg. read a sale based on their city , sellerId and Id of the sale):

    salePartitionKeys := []string{"City"}
    saleClusteringKeys := []string{"SellerId","Id"}
    salesTable := keySpace.MultimapMultiKeyTable("sale", salePartitionKeys, saleClusteringKeys, Sale{})
    // …
    result := Sale{}
    saleFieldCity = salePartitionKeys[0]
    saleFieldSellerId = saleClusteringKeys[0]
    saleFieldSaleId = saleClusteringKeys[1]

    field := make(map[string]interface{})
    id := make(map[string]interface{})


    field[saleFieldCity] = "London"
    id[saleFieldSellerId] = "141-dasf1-124"
    id[saleFieldSaleId] = "512hha232"

    err := salesTable.Read(field, id , &result).Run()

Encoding/Decoding data structures

When setting structs in gocassa the library first converts your value to a map. Each exported field is added to the map unless

  • the field's tag is "-", or
  • the field is empty and its tag specifies the "omitempty" option

Each fields default name in the map is the field name but can be specified in the struct field's tag value. The "cql" key in the struct field's tag value is the key name, followed by an optional comma and options. Examples:

// Field is ignored by this package.
Field int `cql:"-"`
// Field appears as key "myName".
Field int `cql:"myName"`
// Field appears as key "myName" and
// the field is omitted from the object if its value is empty,
// as defined above.
Field int `cql:"myName,omitempty"`
// Field appears as key "Field" (the default), but
// the field is skipped if empty.
// Note the leading comma.
Field int `cql:",omitempty"`
// All fields in the EmbeddedType are squashed into the parent type.
EmbeddedType `cql:",squash"`

When encoding maps with non-string keys the key values are automatically converted to strings where possible, however it is recommended that you use strings where possible (for example map[string]T).

Troubleshooting

Too long table names

In case you get the following error:

Column family names shouldn't be more than 48 characters long (got "somelongishtablename_multitimeseries_start_id_24h0m0s")

You can use the TableName options to override the default internal ones:

tbl = tbl.WithOptions(Options{TableName: "somelongishtablename_mts_start_id_24h0m0s"})

Documentation

Overview

Package gocassa is a high-level library on top of gocql

Current version: v2.0.1 Compared to gocql it provides query building, adds data binding, and provides easy-to-use "recipe" tables for common query use-cases. Unlike cqlc, it does not use code generation.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ClusteringSentinel represents a placeholder value to be used for cases
	// where a value needs to be present (ie: a stand-in representing a
	// clustering key that is empty)
	ClusteringSentinel = "<gocassa.ClusteringSentinel>"

	// ClusteringSentinelTimestamp represents a placeholder time value for
	// cases where we have a null timestamp column. We've chosen the time
	// 1753-01-01 which ironically is the minimum date in SQL Server
	ClusteringSentinelTimestamp = time.Unix(-6847804725, 0)
)

Functions

func ClusteringFieldOrSentinel

func ClusteringFieldOrSentinel(term interface{}) interface{}

ClusteringFieldOrSentinel will check if we should substitute in our sentinel value for empty clustering fields

func ErrorInjectorContext

func ErrorInjectorContext(parent context.Context, strategy ErrorInjector) context.Context

ErrorInjectorContext returns a context which when passed to mockMultiOp.RunWithContext(...), will inject an error before one of the operations to simulate a partial failure in the query execution. The ErrorInjector determines when in the sequence the error is injected

func ExampleFailOnEachOperation

func ExampleFailOnEachOperation()

func IsClusteringSentinelValue

func IsClusteringSentinelValue(term interface{}) (bool, interface{})

IsClusteringSentinelValue returns a boolean on whether the value passed in is the clustering sentinel value and what the non-sentinel value is

Types

type Buckets

type Buckets interface {
	Filter() Filter
	Bucket() time.Time
	Next() Buckets
	Prev() Buckets
}

Buckets is an iterator over a timeseries' buckets

type CQLTyper

type CQLTyper interface {
	CQLType() gocql.Type
}

type ClusteringOrderColumn

type ClusteringOrderColumn struct {
	Direction ColumnDirection
	Column    string
}

ClusteringOrderColumn specifies a clustering column and whether its clustering order is ASC or DESC.

func (ClusteringOrderColumn) Field

func (c ClusteringOrderColumn) Field() string

type ColumnDirection

type ColumnDirection bool
const (
	ASC  ColumnDirection = false
	DESC                 = true
)

func (ColumnDirection) String

func (d ColumnDirection) String() string

type Comparator

type Comparator int

Comparator represents a comparison operand

const (
	// These comparison types represent the comparison types supported
	// when generating a relation between a field and it's terms
	CmpEquality            Comparator = iota // direct equality (foo = bar)
	CmpIn                                    // membership (foo IN (bar, bing, baz))
	CmpGreaterThan                           // larger than (foo > 1)
	CmpGreaterThanOrEquals                   // larger than or equal (foo >= 1)
	CmpLesserThan                            // less than (foo < 1)
	CmpLesserThanOrEquals                    // less than or equal (foo <= 1)
)

type Connection

type Connection interface {
	CreateKeySpace(name string) error
	DropKeySpace(name string) error
	KeySpace(name string) KeySpace
}

Connection exists because one can not connect to a keyspace if it does not exist, thus having a Create on KeySpace is not possible. Use ConnectToKeySpace to acquire an instance of KeySpace without getting a Connection.

func Connect

func Connect(nodeIps []string, username, password string) (Connection, error)

Connect to a cluster. If you are happy with default the options use this, if you need anything fancier, use `NewConnection`

func NewConnection

func NewConnection(q QueryExecutor) Connection

NewConnection creates a Connection with a custom query executor. Use `Connect` if you just want to talk to Cassandra with the default options. See `GoCQLSessionToQueryExecutor` if you want to use a gocql session with your own options as a `QueryExecutor`

type Counter

type Counter int

type DeleteStatement

type DeleteStatement struct {
	// contains filtered or unexported fields
}

DeleteStatement represents a DELETE query to delete some data in C* It satisfies the Statement interface

func NewDeleteStatement

func NewDeleteStatement(keyspace, table string, rel []Relation, keys Keys) (DeleteStatement, error)

NewDeleteStatement adds the ability to craft a new DeleteStatement This function will error if the parameters passed in are invalid

func (DeleteStatement) Keys

func (s DeleteStatement) Keys() Keys

Keys provides the Partition / Clustering keys defined by the table recipe

func (DeleteStatement) Keyspace

func (s DeleteStatement) Keyspace() string

Keyspace returns the name of the Keyspace for the statement

func (DeleteStatement) Query

func (s DeleteStatement) Query() string

Query provides the CQL query string for a DELETE query

func (DeleteStatement) QueryAndValues

func (s DeleteStatement) QueryAndValues() (string, []interface{})

QueryAndValues returns the CQL query and any bind values

func (DeleteStatement) Relations

func (s DeleteStatement) Relations() []Relation

Relations provides the WHERE clause Relation items used to evaluate this query

func (DeleteStatement) Table

func (s DeleteStatement) Table() string

Table returns the name of the table for this statement

func (DeleteStatement) Values

func (s DeleteStatement) Values() []interface{}

Values provide the binding values for a DELETE query

func (DeleteStatement) WithClusteringSentinel

func (s DeleteStatement) WithClusteringSentinel(enabled bool) DeleteStatement

WithClusteringSentinel allows you to specify whether the use of the clustering sentinel value is enabled

type ErrorInjector

type ErrorInjector interface {
	// contains filtered or unexported methods
}

func FailOnNthOperation

func FailOnNthOperation(n int, err error) ErrorInjector

FailOnNthOperation returns an ErrorInjector which injects the provided err on the nth operation of a mockMultiOp. n is 0 indexed so an n value of 0 will fail on the first operation. If there are fewer than n-1 operations in the mockMultiOp, no error will be injected

type FailOnEachOperationErrorInjector

type FailOnEachOperationErrorInjector struct {
	// contains filtered or unexported fields
}

FailOnEachOperationErrorInjector is a stateful ErrorInjector which fails on each each operation of a mockMultiOp. The caller should repeatedly call the function under test until ShouldContinue returns false.

func FailOnEachOperation

func FailOnEachOperation(err error) *FailOnEachOperationErrorInjector

FailOnEachOperation returns an ErrorInjector which fails on each operation of a mockMultiOp in turn

func (*FailOnEachOperationErrorInjector) LastErrorInjectedAtIdx

func (f *FailOnEachOperationErrorInjector) LastErrorInjectedAtIdx() int

LastErrorInjectedAtIdx indicates the index of the operation the error injector last injected an error at. Returns -1 if no error was injected

func (*FailOnEachOperationErrorInjector) ShouldContinue

func (f *FailOnEachOperationErrorInjector) ShouldContinue() bool

ShouldContinue indicates whether there are more operations in the mockMultiOp in which to inject errors. Returns false when the final operation in the mockMultiOp succeeded

type Filter

type Filter interface {
	// Update does a partial update. Use this if you don't want to overwrite your whole row, but you want to modify fields atomically.
	Update(valuesToUpdate map[string]interface{}) Op // Probably this is danger zone (can't be implemented efficiently) on a selectuinb with more than 1 document
	// Delete all rows matching the filter.
	Delete() Op
	// Reads all results. Make sure you pass in a pointer to a slice.
	Read(pointerToASlice interface{}) Op
	// ReadOne reads a single result. Make sure you pass in a pointer.
	ReadOne(pointer interface{}) Op
	// Table on which this filter operates.
	Table() Table
	// Relations which make up this filter. These should not be modified.
	Relations() []Relation
}

Filter is a subset of a Table, filtered by Relations. You can do writes or reads on a filter.

type FlakeSeriesTable

type FlakeSeriesTable interface {
	// Set Inserts, or Replaces your row with the supplied struct. Be aware that what is not in your struct
	// will be deleted. To only overwrite some of the fields, Update()
	Set(rowStruct interface{}) Op
	Update(id string, valuesToUpdate map[string]interface{}) Op
	Delete(id string) Op
	Read(id string, pointer interface{}) Op
	List(start, end time.Time, pointerToASlice interface{}) Op
	Buckets(start time.Time) Buckets
	// ListSince queries the flakeSeries for the items after the specified ID but within the time window,
	// if the time window is zero then it lists up until 5 minutes in the future
	ListSince(id string, window time.Duration, pointerToASlice interface{}) Op
	WithOptions(Options) FlakeSeriesTable
	Table() Table
	TableChanger
}

type IgnoreFieldType

type IgnoreFieldType struct{}

IgnoreFieldType struct is for fields we want to ignore, we specify a custom unmarshal type which literally is a no-op and does nothing with this data. In the future, maybe we can be smarter of only extracting fields which we are able to unmarshal into our target struct and get rid of this

func (*IgnoreFieldType) UnmarshalCQL

func (i *IgnoreFieldType) UnmarshalCQL(_ gocql.TypeInfo, _ []byte) error

type InsertStatement

type InsertStatement struct {
	// contains filtered or unexported fields
}

InsertStatement represents an INSERT query to write some data in C* It satisfies the Statement interface

func NewInsertStatement

func NewInsertStatement(keyspace, table string, fieldMap map[string]interface{}, keys Keys) (InsertStatement, error)

NewInsertStatement adds the ability to craft a new InsertStatement This function will error if the parameters passed in are invalid

func (InsertStatement) FieldMap

func (s InsertStatement) FieldMap() map[string]interface{}

FieldMap gives a map of all the fields to be inserted. In an INSERT statement, none of these will be Modifier types

func (InsertStatement) Keys

func (s InsertStatement) Keys() Keys

Keys provides the Partition / Clustering keys defined by the table recipe

func (InsertStatement) Keyspace

func (s InsertStatement) Keyspace() string

Keyspace returns the name of the Keyspace for the statement

func (InsertStatement) Query

func (s InsertStatement) Query() string

Query provides the CQL query string for an INSERT INTO query

func (InsertStatement) QueryAndValues

func (s InsertStatement) QueryAndValues() (string, []interface{})

QueryAndValues returns the CQL query and any bind values

func (InsertStatement) TTL

func (s InsertStatement) TTL() time.Duration

TTL returns the Time-To-Live for this row statement. A duration of 0 means there is no TTL

func (InsertStatement) Table

func (s InsertStatement) Table() string

Table returns the name of the table for this statement

func (InsertStatement) Values

func (s InsertStatement) Values() []interface{}

Values provide the binding values for an INSERT INTO query

func (InsertStatement) WithClusteringSentinel

func (s InsertStatement) WithClusteringSentinel(enabled bool) InsertStatement

WithClusteringSentinel allows you to specify whether the use of the clustering sentinel value is enabled

func (InsertStatement) WithTTL

WithTTL allows setting of the time-to-live for this insert statement. A duration of 0 means there is no TTL

type KeySpace

type KeySpace interface {
	// MapTable is a simple key-value store.
	MapTable(prefixForTableName, partitionKey string, rowDefinition interface{}) MapTable
	/*
		MultimapTable lets you list rows based on a field equality but allows for a single partitionKey.
		It uses the partitionKey for partitioning the data.
		The ordering within a partition is determined using the clusteringKey.
	*/
	MultimapTable(prefixForTableName, partitionKey, clusteringKey string, rowDefinition interface{}) MultimapTable
	/*
		MultimapMultiKeyTable lets you list rows based on several fields equality but allows for more than one partitionKey.
		It uses the partitionKeys for partitioning the data.
		The ordering within a partition is determined by a set of clusteringKeys.
	*/
	MultimapMultiKeyTable(prefixForTableName string, partitionKeys, clusteringKeys []string, rowDefinition interface{}) MultimapMkTable
	/*
		TimeSeriesTable lets you list rows which have a field value between two date ranges.
		timeField is used as the partition key alongside the bucket.
		bucketSize is used to determine for what duration the data will be stored on the same partition.
	*/
	TimeSeriesTable(prefixForTableName, timeField, clusteringKey string, bucketSize time.Duration, rowDefinition interface{}) TimeSeriesTable
	/*
		MultiTimeSeriesTable is a cross between TimeSeries and Multimap tables.
		The partitionKey and timeField make up the composite partitionKey.
		The ordering within a partition is decided by the clusteringKey.
		bucketSize is used to determine for what duration the data will be stored on the same partition.
	*/
	MultiTimeSeriesTable(prefixForTableName, partitionKey, timeField, clusteringKey string, bucketSize time.Duration, rowDefinition interface{}) MultiTimeSeriesTable
	/*
		MultiKeyTimeSeriesTable is a cross between TimeSeries and MultimapMultikey tables.
		The partitionKeys and timeField make up the composite partitionKey.
		The ordering within a partition is decided by the clusteringKey.
		bucketSize is used to determine for what duration the data will be stored on the same partition.
	*/
	MultiKeyTimeSeriesTable(prefixForTableName string, partitionKeys []string, timeField string, clusteringKeys []string, bucketSize time.Duration, rowDefinition interface{}) MultiKeyTimeSeriesTable
	/*
		FlakeSeriesTable is similar to TimeSeriesTable.
		flakeIDField is used as the partition key along with the bucket field.
		(FlakeIDs encode time of ID generation within them and can be used as a replacement for timestamps)
		bucketSize is used to determine for what duration the data will be stored on the same partition.
	*/
	FlakeSeriesTable(prefixForTableName, flakeIDField string, bucketSize time.Duration, rowDefinition interface{}) FlakeSeriesTable
	MultiFlakeSeriesTable(prefixForTableName, partitionKey, flakeIDField string, bucketSize time.Duration, rowDefinition interface{}) MultiFlakeSeriesTable
	Table(prefixForTableName string, rowDefinition interface{}, keys Keys) Table
	// DebugMode enables/disables debug mode depending on the value of the input boolean.
	// When DebugMode is enabled, all built CQL statements are printe to stdout.
	DebugMode(bool)
	// Name returns the keyspace name as in C*
	Name() string
	// Tables returns the name of all configured column families in this keyspace
	Tables() ([]string, error)
	// Exists returns whether the specified column family exists within the keyspace
	Exists(string) (bool, error)
}

KeySpace is used to obtain tables from.

func ConnectToKeySpace

func ConnectToKeySpace(keySpace string, nodeIps []string, username, password string) (KeySpace, error)

Connect to a certain keyspace directly. Same as using Connect().KeySpace(keySpaceName)

func NewMockKeySpace

func NewMockKeySpace() KeySpace

type Keys

type Keys struct {
	PartitionKeys     []string
	ClusteringColumns []string
	Compound          bool //indicates if the partitions keys are gereated as compound key when no clustering columns are set
}

Keys is used with the raw CQL Table type. It is implicit when using recipe tables.

type MapTable

type MapTable interface {
	// Set Inserts, or Replaces your row with the supplied struct. Be aware that what is not in your struct
	// will be deleted. To only overwrite some of the fields, Update()
	Set(rowStruct interface{}) Op
	Update(partitionKey interface{}, valuesToUpdate map[string]interface{}) Op
	Delete(partitionKey interface{}) Op
	Read(partitionKey, pointer interface{}) Op
	MultiRead(partitionKeys []interface{}, pointerToASlice interface{}) Op
	WithOptions(Options) MapTable
	Table() Table
	TableChanger
}

MapTable gives you basic CRUD functionality. If you need fancier ways to query your data set have a look at the other tables.

type MockFilter

type MockFilter struct {
	// contains filtered or unexported fields
}

MockFilter implements the Filter interface and works with MockTable.

func (*MockFilter) Delete

func (f *MockFilter) Delete() Op

func (*MockFilter) Read

func (q *MockFilter) Read(out interface{}) Op

func (*MockFilter) ReadOne

func (q *MockFilter) ReadOne(out interface{}) Op

func (*MockFilter) Relations

func (f *MockFilter) Relations() []Relation

func (*MockFilter) Table

func (f *MockFilter) Table() Table

func (*MockFilter) Update

func (f *MockFilter) Update(m map[string]interface{}) Op

func (*MockFilter) UpdateWithOptions

func (f *MockFilter) UpdateWithOptions(m map[string]interface{}, options Options) Op

type MockTable

type MockTable struct {
	*sync.RWMutex
	// contains filtered or unexported fields
}

MockTable implements the Table interface and stores rows in-memory.

func (*MockTable) Create

func (t *MockTable) Create() error

func (*MockTable) CreateIfNotExist

func (t *MockTable) CreateIfNotExist() error

func (*MockTable) CreateIfNotExistStatement

func (t *MockTable) CreateIfNotExistStatement() (Statement, error)

func (*MockTable) CreateStatement

func (t *MockTable) CreateStatement() (Statement, error)

func (*MockTable) Name

func (t *MockTable) Name() string

func (*MockTable) Recreate

func (t *MockTable) Recreate() error

func (*MockTable) Set

func (t *MockTable) Set(i interface{}) Op

func (*MockTable) SetWithOptions

func (t *MockTable) SetWithOptions(i interface{}, options Options) Op

func (*MockTable) Where

func (t *MockTable) Where(relations ...Relation) Filter

func (*MockTable) WithOptions

func (t *MockTable) WithOptions(o Options) Table

type Modifier

type Modifier struct {
	// contains filtered or unexported fields
}

func CounterIncrement

func CounterIncrement(value int) Modifier

CounterIncrement increments the value of the counter with the given value. Negative value results in decrementing.

func ListAppend

func ListAppend(value interface{}) Modifier

ListAppend appends a value to the end of the list

func ListPrepend

func ListPrepend(value interface{}) Modifier

ListPrepend prepends a value to the front of the list

func ListRemove

func ListRemove(value interface{}) Modifier

ListRemove removes all elements from a list having a particular value

func ListSetAtIndex

func ListSetAtIndex(index int, value interface{}) Modifier

ListSetAtIndex sets the list element at a given index to a given value

func MapSetField

func MapSetField(key, value interface{}) Modifier

MapSetField updates the map with the given key and value

func MapSetFields

func MapSetFields(fields map[string]interface{}) Modifier

MapSetFields updates the map with keys and values in the given map

func (Modifier) Args

func (m Modifier) Args() []interface{}

Args provides the arguments for this operation when generating the CQL statement, the actual arguments will depend on the Operation that this modifier represents

  • ModifierListPrepend returns 1 element with the value (interface{}) to be prepended
  • ModifierListAppend returns 1 element with the value (interface{}) to be appended
  • ModifierListSetAtIndex returns two elements, the index (int) and value (interface{}) to be set
  • ModifierListRemove returns 1 element with the value (interface{}) to be removed
  • ModifierMapSetFields returns 1 element with a map (map[string]interface{}) with the keys and values to be set
  • MapSetField returns 2 elements, the key (string) and value (interface{}) to be set in the underlying map
  • ModifierCounterIncrement returns 1 element (int) with how much the value should be incremented by (or decremented if the value is negative)

func (Modifier) Operation

func (m Modifier) Operation() ModifierOp

Operation returns the operation this modifier represents

type ModifierOp

type ModifierOp int

ModifierOp represents a modifier operand

const (
	// These modifier types represent the field modification operations
	// on list/map types such as append/remove/map set to be used with
	// UPDATE CQL statements
	ModifierListPrepend      ModifierOp = iota // prepend to beginning of a list
	ModifierListAppend                         // append to the end of a list
	ModifierListSetAtIndex                     //	set a value for a specific list index
	ModifierListRemove                         // remove an item from the list
	ModifierMapSetFields                       // set values from the provided map
	ModifierMapSetField                        // update a value for a specific key
	ModifierCounterIncrement                   // increment a counter
)

type MultiFlakeSeriesTable

type MultiFlakeSeriesTable interface {
	// Set Inserts, or Replaces your row with the supplied struct. Be aware that what is not in your struct
	// will be deleted. To only overwrite some of the fields, Update()
	Set(rowStruct interface{}) Op
	Update(v interface{}, id string, valuesToUpdate map[string]interface{}) Op
	Delete(v interface{}, id string) Op
	Read(v interface{}, id string, pointer interface{}) Op
	List(v interface{}, start, end time.Time, pointerToASlice interface{}) Op
	Buckets(v interface{}, start time.Time) Buckets
	// ListSince queries the flakeSeries for the items after the specified ID but within the time window,
	// if the time window is zero then it lists up until 5 minutes in the future
	ListSince(v interface{}, id string, window time.Duration, pointerToASlice interface{}) Op
	WithOptions(Options) MultiFlakeSeriesTable
	Table() Table
	TableChanger
}

type MultiKeyTimeSeriesTable

type MultiKeyTimeSeriesTable interface {

	// Set Inserts, or Replaces your row with the supplied struct. Be aware that what is not in your struct
	// will be deleted. To only overwrite some of the fields, Update()
	Set(rowStruct interface{}) Op
	Update(v map[string]interface{}, timeStamp time.Time, id map[string]interface{}, valuesToUpdate map[string]interface{}) Op
	Delete(v map[string]interface{}, timeStamp time.Time, id map[string]interface{}) Op
	Read(v map[string]interface{}, timeStamp time.Time, id map[string]interface{}, pointer interface{}) Op
	List(v map[string]interface{}, start, end time.Time, pointerToASlice interface{}) Op
	Buckets(v map[string]interface{}, start time.Time) Buckets
	WithOptions(Options) MultiKeyTimeSeriesTable
	Table() Table
	TableChanger
}

MultiKeyTimeSeriesTable is a cross between TimeSeries and MultimapMkTable tables.

type MultiTimeSeriesTable

type MultiTimeSeriesTable interface {

	// Set Inserts, or Replaces your row with the supplied struct. Be aware that what is not in your struct
	// will be deleted. To only overwrite some of the fields, Update()
	Set(rowStruct interface{}) Op
	Update(v interface{}, timeStamp time.Time, id interface{}, valuesToUpdate map[string]interface{}) Op
	Delete(v interface{}, timeStamp time.Time, id interface{}) Op
	Read(v interface{}, timeStamp time.Time, id, pointer interface{}) Op
	List(v interface{}, start, end time.Time, pointerToASlice interface{}) Op
	Buckets(v interface{}, start time.Time) Buckets
	WithOptions(Options) MultiTimeSeriesTable
	Table() Table
	TableChanger
}

type MultimapMkTable

type MultimapMkTable interface {
	// Set Inserts, or Replaces your row with the supplied struct. Be aware that what is not in your struct
	// will be deleted. To only overwrite some of the fields, Update()
	Set(rowStruct interface{}) Op
	Update(v, id map[string]interface{}, valuesToUpdate map[string]interface{}) Op
	Delete(v, id map[string]interface{}) Op
	DeleteAll(v map[string]interface{}) Op
	// List populates the provided pointer to a slice with the results matching the keys provided.
	// To disable the limit, set limit to 0
	List(v, startId map[string]interface{}, limit int, pointerToASlice interface{}) Op
	Read(v, id map[string]interface{}, pointer interface{}) Op
	MultiRead(v, id map[string]interface{}, pointerToASlice interface{}) Op
	WithOptions(Options) MultimapMkTable
	Table() Table
	TableChanger
}

type MultimapTable

type MultimapTable interface {
	// Set Inserts, or Replaces your row with the supplied struct. Be aware that what is not in your struct
	// will be deleted. To only overwrite some of the fields, Update()
	Set(rowStruct interface{}) Op
	Update(value, id interface{}, valuesToUpdate map[string]interface{}) Op
	Delete(value, id interface{}) Op
	DeleteAll(value interface{}) Op
	// List populates the provided pointer to a slice with the results matching the keys provided.
	// To disable the limit, set limit to 0
	List(partitionKey, clusteringKey interface{}, limit int, pointerToASlice interface{}) Op
	Read(partitionKey, clusteringKey, pointer interface{}) Op
	WithOptions(Options) MultimapTable
	Table() Table
	TableChanger
}

type Op

type Op interface {
	// Run the operation.
	//
	// Deprecated: Run is deprecated and all usages should be replaced with RunWithContext. If there
	// is no appropriate context to pass to RunWithContext, one should use context.TODO().
	Run() error
	// RunWithContext runs the operation, providing context to the executor.
	RunWithContext(context.Context) error

	// Run the operation as a logged batch. This provides some atomicity guarantees (all writes will complete,
	// or none at all) but not all (it does not provide isolation, for example)
	//
	// This comes at a performance cost
	RunLoggedBatchWithContext(context.Context) error

	// Deprecated: The name "RunAtomically" is a misnomer, and "RunLoggedBatchWithContext" should be used instead
	RunAtomically() error
	// Deprecated: The name "RunAtomically" is a misnomer, and "RunLoggedBatchWithContext" should be used instead
	RunAtomicallyWithContext(context.Context) error
	// Add an other Op to this one.
	Add(...Op) Op
	// WithOptions lets you specify `Op` level `Options`.
	// The `Op` level Options and the `Table` level `Options` will be merged in a way that Op level takes precedence.
	// All queries in an `Op` will have the specified `Options`.
	// When using Add(), the existing options are preserved.
	// For example:
	//
	//    op1.WithOptions(Options{Limit:3}).Add(op2.WithOptions(Options{Limit:2})) // op1 has a limit of 3, op2 has a limit of 2
	//    op1.WithOptions(Options{Limit:3}).Add(op2).WithOptions(Options{Limit:2}) // op1 and op2 both have a limit of 2
	//
	WithOptions(Options) Op
	// Options lets you read the `Options` for this `Op`
	Options() Options
	// Preflight performs any pre-execution validation that confirms the op considers itself "valid".
	// NOTE: Run() and RunLoggedBatch() should call this method before execution, and abort if any errors are returned.
	Preflight() error
	// GenerateStatement generates the statement to perform the operation
	GenerateStatement() Statement
	// QueryExecutor returns the QueryExecutor
	QueryExecutor() QueryExecutor
}

Op is returned by both read and write methods, you have to run them explicitly to take effect. It represents one or more operations.

func Noop

func Noop() Op

type Options

type Options struct {
	// TTL specifies a duration over which data is valid. It will be truncated to second precision upon statement
	// execution.
	TTL time.Duration
	// Limit query result set
	Limit int
	// TableName overrides the default internal table name. When naming a table 'users' the internal table name becomes 'users_someTableSpecificMetaInformation'.
	TableName string
	// ClusteringOrder specifies the clustering order during table creation. If empty, it is omitted and the defaults are used.
	ClusteringOrder []ClusteringOrderColumn
	// Indicates if allow filtering should be appended at the end of the query
	AllowFiltering bool
	// Select allows you to do partial reads, ie. retrieve only a subset of fields
	Select []string
	// Consistency specifies the consistency level. If nil, it is considered not set
	Consistency *gocql.Consistency
	// Setting CompactStorage to true enables table creation with compact storage
	CompactStorage bool
	// Compressor specifies the compressor (if any) to use on a newly created table
	Compressor string
	// Context allows a request context to passed, which is propagated to the QueryExecutor
	Context context.Context
}

Options can contain table or statement specific options. The reason for this is because statement specific (TTL, Limit) options make sense as table level options (eg. have default TTL for every Update without specifying it all the time)

func (Options) AppendClusteringOrder

func (o Options) AppendClusteringOrder(column string, direction ColumnDirection) Options

AppendClusteringOrder adds a clustering order. If there already clustering orders, the new one is added to the end.

func (Options) Merge

func (o Options) Merge(neu Options) Options

Merge returns a new Options which is a right biased merge of the two initial Options.

type QueryExecutor

type QueryExecutor interface {
	// Query executes a query and returns the results. It also takes Options to do things like set consistency
	QueryWithOptions(opts Options, stmt Statement, scanner Scanner) error
	// Query executes a query and returns the results
	Query(stmt Statement, scanner Scanner) error
	// Execute executes a DML query. It also takes Options to do things like set consistency
	ExecuteWithOptions(opts Options, stmt Statement) error
	// Execute executes a DML query
	Execute(stmt Statement) error
	// ExecuteAtomically executes multiple DML queries with a logged batch
	ExecuteAtomically(stmt []Statement) error
	// ExecuteAtomically executes multiple DML queries with a logged batch, and takes options
	ExecuteAtomicallyWithOptions(opts Options, stmts []Statement) error
}

QueryExecutor actually executes the queries - this is mostly useful for testing/mocking purposes, ignore this otherwise. This library is using github.com/gocql/gocql as the query executor by default.

func GoCQLSessionToQueryExecutor

func GoCQLSessionToQueryExecutor(sess *gocql.Session) QueryExecutor

GoCQLSessionToQueryExecutor enables you to supply your own gocql session with your custom options Then you can use NewConnection to mint your own thing See #90 for more details

type Relation

type Relation struct {
	// contains filtered or unexported fields
}

Relation describes the comparison of a field against a list of terms that need to satisfy a comparator

func Eq

func Eq(field string, term interface{}) Relation

func GT

func GT(field string, term interface{}) Relation

func GTE

func GTE(field string, term interface{}) Relation

func In

func In(field string, terms ...interface{}) Relation

In allows a field to be queried with multiple terms simultaneously Note: In should only be used for Primary Key columns. Usage for clustering key columns may result in an error depending on backing storage implementation

func LT

func LT(field string, term interface{}) Relation

func LTE

func LTE(field string, term interface{}) Relation

func (Relation) Comparator

func (r Relation) Comparator() Comparator

Comparator provides the comparator for this relation

func (Relation) Field

func (r Relation) Field() string

Field provides the field name for this relation

func (Relation) Terms

func (r Relation) Terms() []interface{}

Terms provides a list of values to compare against. A valid relation will always have at least one term present

type RowNotFoundError

type RowNotFoundError struct {
	// contains filtered or unexported fields
}

RowNotFoundError is returned by Reads if the Row is not found.

func (RowNotFoundError) Error

func (r RowNotFoundError) Error() string

type Scannable

type Scannable interface {
	// Next advances the row pointer to point at the next row, the row is valid until
	// the next call of Next. It returns true if there is a row which is available to be
	// scanned into with Scan.
	// Next must be called before every call to Scan.
	Next() bool

	// Scan copies the current row's columns into dest. If the length of dest does not equal
	// the number of columns returned in the row an error is returned. If an error is encountered
	// when unmarshalling a column into the value in dest an error is returned and the row is invalidated
	// until the next call to Next.
	// Next must be called before calling Scan, if it is not an error is returned.
	Scan(dest ...interface{}) error

	// Err returns the if there was one during iteration that resulted in iteration being unable to complete.
	// Err will also release resources held by the iterator, the Scanner should not used after being called.
	Err() error
}

Scannable is an interface which matches the interface found in GoCQL Scannable

type Scanner

type Scanner interface {
	// ScanIter takes in a Scannable iterator found in GoCQL and scans until
	// the iterator giveth no more. It number of rows read and an optional
	// error if anything goes wrong
	ScanIter(iter Scannable) (int, error)
	// Result returns the result object that the scanner decodes into.
	Result() interface{}
}

A Scanner scans row(s) from a GoCQL iterator into a result object.

func NewScanner

func NewScanner(stmt SelectStatement, result interface{}) Scanner

type SelectStatement

type SelectStatement struct {
	// contains filtered or unexported fields
}

SelectStatement represents a read (SELECT) query for some data in C* It satisfies the Statement interface

func NewSelectStatement

func NewSelectStatement(keyspace, table string, fields []string, rel []Relation, keys Keys) (SelectStatement, error)

NewSelectStatement adds the ability to craft a new SelectStatement This function will error if the parameters passed in are invalid

func (SelectStatement) AllowFiltering

func (s SelectStatement) AllowFiltering() bool

AllowFiltering returns whether data filtering (ALLOW FILTERING) is enabled

func (SelectStatement) Fields

func (s SelectStatement) Fields() []string

Fields returns the list of fields to be selected

func (SelectStatement) Keys

func (s SelectStatement) Keys() Keys

Keys provides the Partition / Clustering keys defined by the table recipe

func (SelectStatement) Keyspace

func (s SelectStatement) Keyspace() string

Keyspace returns the name of the Keyspace for the statement

func (SelectStatement) Limit

func (s SelectStatement) Limit() int

Limit returns the number of rows to be returned, a value of zero means no limit

func (SelectStatement) OrderBy

func (s SelectStatement) OrderBy() []ClusteringOrderColumn

OrderBy returns the ClusteringOrderColumn clauses used

func (SelectStatement) Query

func (s SelectStatement) Query() string

Query provides the CQL query string for an SELECT query

func (SelectStatement) QueryAndValues

func (s SelectStatement) QueryAndValues() (string, []interface{})

QueryAndValues returns the CQL query and any bind values

func (SelectStatement) Relations

func (s SelectStatement) Relations() []Relation

Relations provides the WHERE clause Relation items used to evaluate this query

func (SelectStatement) Table

func (s SelectStatement) Table() string

Table returns the name of the table for this statement

func (SelectStatement) Values

func (s SelectStatement) Values() []interface{}

Values provide the binding values for an SELECT query

func (SelectStatement) WithAllowFiltering

func (s SelectStatement) WithAllowFiltering(enabled bool) SelectStatement

WithAllowFiltering allows toggling of data filtering (including ALLOW FILTERING in the CQL)

func (SelectStatement) WithClusteringSentinel

func (s SelectStatement) WithClusteringSentinel(enabled bool) SelectStatement

WithClusteringSentinel allows you to specify whether the use of the clustering sentinel value is enabled

func (SelectStatement) WithLimit

func (s SelectStatement) WithLimit(limit int) SelectStatement

WithLimit allows the setting of a limit. Using a value of zero or a negative value removes the limit

func (SelectStatement) WithOrderBy

func (s SelectStatement) WithOrderBy(order []ClusteringOrderColumn) SelectStatement

WithOrderBy allows the setting of the clustering order columns

func (SelectStatement) WithRelations

func (s SelectStatement) WithRelations(rel []Relation) SelectStatement

WithRelations sets the relations (WHERE conditions) for this statement

type Statement

type Statement interface {
	// Values encapsulates binding values to be set within the CQL
	// query string as binding parameters. If there are no binding
	// parameters in the query, this will be the empty slice
	Values() []interface{}
	// Query returns the CQL query for this statement
	Query() string
}

Statement encapsulates a gocassa generated statement to be passed via the QueryExecutor.

type Table

type Table interface {
	// Set Inserts, or Replaces your row with the supplied struct. Be aware that what is not in your struct
	// will be deleted. To only overwrite some of the fields, use Query.Update.
	Set(rowStruct interface{}) Op
	// Where accepts a bunch of realtions and returns a filter. See the documentation for Relation and Filter to understand what that means.
	Where(relations ...Relation) Filter // Because we provide selections
	// Name returns the underlying table name, as stored in C*
	WithOptions(Options) Table
	TableChanger
}

Table is the only non-recipe table, it is the "raw CQL table", it lets you do pretty much whatever you want with the downside that you have to know what you are doing - eg. you have to know what queries can you make on a certain partition key - clustering column combination.

type TableChanger

type TableChanger interface {
	// Create creates the table in the keySpace, but only if it does not exist already.
	// If the table already exists, it returns an error.
	Create() error
	// CreateStatement returns you the CQL query which can be used to create the table manually in cqlsh
	CreateStatement() (Statement, error)
	// Create creates the table in the keySpace, but only if it does not exist already.
	// If the table already exists, then nothing is created.
	CreateIfNotExist() error
	// CreateStatement returns you the CQL query which can be used to create the table manually in cqlsh
	CreateIfNotExistStatement() (Statement, error)
	// Recreate drops the table if exists and creates it again.
	// This is useful for test purposes only.
	Recreate() error
	// Name returns the name of the table, as in C*
	Name() string
}

Danger zone! Do not use this interface unless you really know what you are doing

type TimeSeriesTable

type TimeSeriesTable interface {

	// Set Inserts, or Replaces your row with the supplied struct. Be aware that what is not in your struct
	// will be deleted. To only overwrite some of the fields, Update()
	Set(rowStruct interface{}) Op
	Update(timeStamp time.Time, id interface{}, valuesToUpdate map[string]interface{}) Op
	Delete(timeStamp time.Time, id interface{}) Op
	Read(timeStamp time.Time, id, pointer interface{}) Op
	List(start, end time.Time, pointerToASlice interface{}) Op
	Buckets(start time.Time) Buckets
	WithOptions(Options) TimeSeriesTable
	Table() Table
	TableChanger
}

type UpdateStatement

type UpdateStatement struct {
	// contains filtered or unexported fields
}

UpdateStatement represents an UPDATE query to update some data in C* It satisfies the Statement interface

func NewUpdateStatement

func NewUpdateStatement(keyspace, table string, fieldMap map[string]interface{}, rel []Relation, keys Keys) (UpdateStatement, error)

NewUpdateStatement adds the ability to craft a new UpdateStatement This function will error if the parameters passed in are invalid

func (UpdateStatement) FieldMap

func (s UpdateStatement) FieldMap() map[string]interface{}

FieldMap gives a map of all the fields to be inserted. In an UPDATE statement, the values may be Modifier types

func (UpdateStatement) Keys

func (s UpdateStatement) Keys() Keys

Keys provides the Partition / Clustering keys defined by the table recipe

func (UpdateStatement) Keyspace

func (s UpdateStatement) Keyspace() string

Keyspace returns the name of the Keyspace for the statement

func (UpdateStatement) Query

func (s UpdateStatement) Query() string

Query provides the CQL query string for an UPDATE query

func (UpdateStatement) QueryAndValues

func (s UpdateStatement) QueryAndValues() (string, []interface{})

QueryAndValues returns the CQL query and any bind values

func (UpdateStatement) Relations

func (s UpdateStatement) Relations() []Relation

Relations provides the WHERE clause Relation items used to evaluate this query

func (UpdateStatement) TTL

func (s UpdateStatement) TTL() time.Duration

TTL returns the Time-To-Live for this row statement. A duration of 0 means there is no TTL

func (UpdateStatement) Table

func (s UpdateStatement) Table() string

Table returns the name of the table for this statement

func (UpdateStatement) Values

func (s UpdateStatement) Values() []interface{}

Values provide the binding values for an UPDATE query

func (UpdateStatement) WithClusteringSentinel

func (s UpdateStatement) WithClusteringSentinel(enabled bool) UpdateStatement

WithClusteringSentinel allows you to specify whether the use of the clustering sentinel value is enabled

func (UpdateStatement) WithTTL

WithTTL allows setting of the time-to-live for this insert statement. A duration of 0 means there is no TTL

Directories

Path Synopsis
examples
This package provides some punk-rock reflection which is not in the stdlib.
This package provides some punk-rock reflection which is not in the stdlib.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL