-
Notifications
You must be signed in to change notification settings - Fork 186
Querying
The query syntax is inspired by the Foursquare Rogue library and aims to replicate CQL 3 as much as possible.
Phantom works with both Scala Futures and Twitter Futures, the later being available as a separate module dependency and import via "com.websudos" %% "phantom-finagle" % phantomVersion"
and import com.websudos.phantom.finagle._
.
The full list can be found in CQLQuery.scala.
Method name | Description |
---|
|
| consistencyLevel_=
| Sets the consistency level to use. |
Method name | Description |
---|---|
where |
The WHERE clause in CQL |
and |
Chains several clauses, creating a WHERE ... AND query |
orderBy |
Adds an ORDER_BY column_name to the query |
allowFiltering |
Allows Cassandra to filter records in memory. This is an expensive operation. |
limit |
Sets the exact number of records to retrieve. |
Select queries are very straightforward and enforce most limitations at compile time.
Operator name | Description |
---|---|
eqs | The "equals" operator. Will match if the objects are equal |
in | The "in" operator. Will match if the object is found the list of arguments |
gt | The "greater than" operator. Will match a the record is greater than the argument and exists |
gte | The "greater than or equals" operator. Will match a the record is greater than the argument and exists |
lt | The "lower than" operator. Will match a the record that is less than the argument and exists |
lte | The "lower than or equals" operator. Will match a the record that is less than the argument and exists |
All partial select queries will return Tuples and are therefore limited to 22 fields for Scala 2.10 compilation.
def getNameById(id: UUID): Future[Option[String]] = {
select(_.name).where(_.id eqs someId).one()
}
def getNameAndPropsById(id: UUID): Future[Option(String, Map[String, String])] {
select(_.name, _.props).where(_.id eqs someId).one()
}
Method name | Description |
---|---|
value |
A type safe Insert query builder. Throws an error for null values. |
valueOrNull |
This will accept a null without throwing an error. |
ttl |
Sets the "Time-To-Live" for the record. |
Method name | Description |
---|---|
where |
The WHERE clause in CQL |
and |
Chains several clauses, creating a WHERE ... AND query |
modify |
The actual update query builder |
onlyIf |
Addition update condition. Used on non-primary columns |
Example:
ExampleRecord.update
.where(_.id eqs myUuid)
.modify(_.name setTo "Barack Obama")
.and(_.props put ("title" -> "POTUS"))
.future()
Method name | Description |
---|---|
where |
The WHERE clause in CQL |
and |
Chains several clauses, creating a WHERE ... AND query |
Delete queries are very simple ways to either delete a row or alternatively set a column to null
. For instance:
BasicTable.update.where(_.id eqs someId).modify(_.someSet setTo Set.empty[String])
// is actually equivalent to
BasicTable.delete(_.someSet).where(_.id eqs someId)
Phantom offers a dual query API based on Scala concurrency primitives, which makes it trivial to use phantom in most known frameworks, such as Play!, Spray, Akka, Scruffy, Lift, and many others. Integration is trivial and easily achievable, all you have to do is to use the Scala API methods and you get out of the box integration.
Phantom also offers another API based on Twitter proprietary concurrency primitives. This is due to the fact that internally we rely very heavily on the Twitter eco-system. It's why phantom also offers Finagle-Thrift support out of the box and integrates with Twitter Scrooge. It fits in perfectly with applications powered by Finagle RPC, Zipkin, Thrift, Ostrich, Aurora, Mesos, and the rest of the Twitter lot.
Method name | Description | Scala result type |
---|---|---|
future |
Executes a command and returns a ResultSet . This is useful when you don't need to return a value. |
scala.concurrent.Future[ResultSet] |
execute |
Executes a command and returns a ResultSet . This is useful when you don't need to return a value. |
com.twitter.util.Future[ResultSet] |
one |
Executes a command and returns an Option[T] . Use this when you are selecting and you only need one value. Adds LIMIT 1 to the CQL query. |
scala.concurrent.Future[Option[Record]] |
get |
Executes a command and returns an Option[T] . Use this when you are selecting and you only need one value. AddsLIMIT 1 to the CQL query. |
com.twitter.util.Future[Option[Record]] |
fetch |
Returns a sequence of matches. Use when you expect more than 1 match. | scala.concurrent.Future[Seq[Record]] |
collect |
Returns a sequence of matches. Use when you expect more than 1 match. | com.twitter.util.Future[Seq[Record] |
fetchSpool |
This is useful when you need the underlying ResultSpool. | com.twitter.concurrent.Spool[T]] |
fetchEnumerator |
This is useful when you need the underlying Play based enumerator. | play.api.libs.iteratee.Enumerator[T] |
Phantom offers a dual asynchronous Future API for the completion of tasks, scala.concurrent.Future
and com.twitter.util.Future
via the phantom-finagle
module, as well as support for Iteratees and reactive-streams via the relevant modules.
However, the concurrency primitives are all based on Google Guava executors and listening decorators. The future API is just for the convenience of users, to satisfy known return types. Scala futures and executors only come into play when you map results, they don't however do the job of actually talking to the database.
The Scala Future methods are:
ExampleRecord.select.one() // When you only want to select one record
ExampleRecord.update.where(_.name eqs name).modify(_.name setTo "someOtherName").future() // When you don't care about the return type.
ExampleRecord.select.fetchEnumerator // when you need an Enumerator
ExampleRecord.select.fetch
ExampleRecord.select.fetchRecord // When you want to fetch a Seq[Record]
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
object ExampleRecord extends ExampleRecord {
override val tableName = "examplerecord"
// now define a session, a normal Datastax cluster connection
implicit val session = SomeCassandraClient.session;
def getRecordsByName(name: String): Future[Seq[ExampleModel]] = {
ExampleRecord.select.where(_.name eqs name).fetch
}
def getOneRecordByName(name: String, someId: UUID): Future[Option[ExampleModel]] = {
ExampleRecord.select.where(_.name eqs name).and(_.id eqs someId).one()
}
}
Phantom doesn't depend on Finagle for this, we are simply using "com.twitter" %% "util-core" % Version"
to return a com.twitter.util.Future
.
However, the concurrency primitives are all based on Google Guava executors and listening decorators. The future API is just for the convenience of users.
ExampleRecord.select.get() // When you only want to select one record
ExampleRecord.update.where(_.name eqs name).modify(_.name setTo "someOtherName").execute() // When you don't care about the return type.
ExampleRecord.select.enumerate // when you need an Enumerator
ExampleRecord.select.collect // When you want to fetch a Seq[Record]
import com.twitter.util.Future
object ExampleRecord extends ExampleRecord {
override val tableName = "examplerecord"
// now define a session, a normal Datastax cluster connection
implicit val session = SomeCassandraClient.session;
def getRecordsByName(name: String): Future[Seq[ExampleModel]] = {
ExampleRecord.select.where(_.name eqs name).collect
}
def getOneRecordByName(name: String, someId: UUID): Future[Option[ExampleModel]] = {
ExampleRecord.select.where(_.name eqs name).and(_.id eqs someId).get()
}
}
To stay up-to-date with our latest releases and news, follow us on Twitter: @outworkers.
- Issues and questions
- Adopters
- Roadmap
- Changelog
- Tutorials
- Commercial support
- Using phantom in your project
- Primitive columns
- Optional primitive columns
- Collection columns
- Collection operators
- Automated schema generation
- Indexing columns
- Data modeling with phantom
- Querying with phantom
- Asynchronous iterators
- Batch statements
- Apache Thrift integration
- Apache ZooKeeper integration
- The phantom testkit