CI Test coverage(%) Code quality Stable version ScalaDoc Chat Open issues Average issue resolution time
Build Status Coverage Status Codacy Rating Maven Central ScalaDoc Gitter Percentage of issues still open Average time to resolve an issue

First some basic setup, a database connection and a few tables to create examples on. The options described here are generic for most Cassandra queries, and they are shared among CRUD queries, but disregarded on queries that don’t require them, such as ALTER.


import com.outworkers.phantom.dsl._
import com.outworkers.util.samplers._

object Connector {
  val default: CassandraConnection = ContactPoint.local
    .noHeartbeat().keySpace(
      KeySpace("phantom").ifNotExists().`with`(
        replication eqs SimpleStrategy.replication_factor(1)
      )
    )
}

case class CarMetric(
  car: UUID,
  id: UUID,
  velocity: Double,
  tirePressure: Double
)

abstract class AnalyticsEntries extends Table[AnalyticsEntries, CarMetric] {
  object car extends UUIDColumn with PartitionKey
  object id extends TimeUUIDColumn with ClusteringOrder with Descending
  object velocity extends DoubleColumn
  object tirePressure extends DoubleColumn
}

class BasicDatabase(override val connector: CassandraConnection) extends Database[BasicDatabase](connector) {
  object entries extends AnalyticsEntries with Connector
}

object db extends BasicDatabase(Connector.default)


Using payloads

The full behaviour is described here. Cassandra makes it possible to implement a custom query handler which relies on custom incoming query payload to function. You can pass additional data to queries using a Payload.

A Payload is a map of properties, where the keys are always strings and the values can be anything that can be encoded on the Cassandra binary protocol, as a java.nio.ByteBuffer. There are several ways to construct a Payload, the easiest being using automated encodings available in phantom, as described below.

Using the convenience apply method requires an implicit ProtocolVersion in scope, because the way the serialization is performed depends on the version of the protocol, and it expects a series of tuples of the form (String, Value), where the type of Value has an implicit Primitive already defined, which will be used for serialization.


import java.util.UUID
import org.joda.time.{ DateTime, DateTimeZone }
import com.datastax.driver.core.ProtocolVersion
import com.outworkers.phantom.dsl._

trait PayloadExample extends db.Connector {

  // Phantom will automatically define this.
  // implicit val version: ProtocolVersion will come from inside the db.Connector.
  // It does however mean a Payload is directly tied to a given Cassandra version/protocol version.
  
  val customPayload = Payload(
    "timestamp" -> DateTime.now(DateTimeZone.UTC),
    "id" -> UUID.randomUUID(),
    "values" -> List(1, 2, 3, 4, 5)
  )
}

And this is how to use a payload inside a query of any kind, using the withOptions method.


import scala.concurrent.Future
import com.outworkers.phantom.dsl._

trait UsingPayloads extends db.Connector {

    def storeWithPayload(metric: CarMetric, payload: Payload): Future[ResultSet] = {
      db.entries.store(metric).withOptions(_.outgoingPayload_=(payload)).future()
    }
}