Helenus is collection of Scala utilities for Apache Cassandra. Its goal is to make interacting with Cassandra easier, in a type-safe manner, while trying to avoid introducing a complex API.
We also provide integration against several streaming libraries:
- Akka v2.6 (Apache License)
- Akka BUSL
- Flink (Experimental)
- Pekko
This is the Scala 3 version of Helenus. For Scala 2, go here.
Include the library into you project definition:
libraryDependencies += "net.nmoncho" %% "helenus-core" % "1.0.0"
We tried using libraries such as Phantom and Quill, which are great by the way, but they didn't fit entirely our mindset of workflow. We believe the best way to use Cassandra, or any DB for that matter, is to use its Query Language directly.
Helenus takes inspiration from libraries such as Anorm, trying to provide a similar experience by putting CQL first. Our goals are:
- Give users control over the queries that are actually executed.
- Keep the library simple with a concise API.
TypeCodec
s for Scala types. Every type extendingAnyVal
, most Scala Collections, ScalaEnumeration
, etc.- CQL templating, with String Interpolation. See usage.
PreparedStatement
s andBoundStatement
s extension methods
As of this version, Helenus supports the following types:
- Java types:
String
,UUID
,Instant
,LocalDate
,LocalTime
,InetAddress
. AnyVal
types:Boolean
,Byte
,Double
,Float
,Int
,Long
,Short
.- This means, if used properly, no more boxing.
- Collections:
Seq
,List
,Vector
,Map
,Set
,SortedMap
,SortedSet
.- If you need a codec that isn't provided out of the box, please read this guide on how to add it.
- Enumerations: Can be encoded by name or by order. See Enumeration Codecs.
- Tuples: Encoded as regular Cassandra tuples
- Case Classes: Encoded as regular Cassandra UDTs
- Others:
Option
, andEither
(encoded as a tuple).
// First import helenus...
import net.nmoncho.helenus.*
// Then mark your session implicit
given CqlSession = getSession
// We can derive Cassandra TypeCodecs used to map UDTs to case classes
case class Address(
street: String,
city: String,
stateOrProvince: String,
postalCode: String,
country: String
) derives UDTCodec
// We can derive how query results map to case classes
case class Hotel(
id: String,
name: String,
phone: String,
address: Address,
pois: Set[String]
) derives RowMapper
val hotelId = "h1"
// hotelId: String = "h1"
// We can prepare queries with parameters that don't require boxing
val hotelsById = "SELECT * FROM hotels WHERE id = ?".toCQL
.prepare[String]
.as[Hotel]
// hotelsById: ScalaPreparedStatement1[String, Hotel] = net.nmoncho.helenus.internal.cql.ScalaPreparedStatement1@4843a29e
// We can extract a single result using `nextOption()`, or
// use `to(Coll)` to transform the result to a collection
hotelsById.execute("h1").nextOption()
// res0: Option[Hotel] = Some(
// value = Hotel(
// id = "h1",
// name = "The New York Hotel Rotterdam",
// phone = "+31 10 217 3000",
// address = Address(
// street = "Meent 78-82",
// city = "Rotterdam",
// stateOrProvince = "Zuid-Holland",
// postalCode = "3011 JM",
// country = "Netherlands"
// ),
// pois = Set("Erasmus Bridge", "Markthal Rotterdam", "Rotterdam Zoo")
// )
// )
// We can also run the same using CQL interpolated queries
val interpolatedHotelsById = cql"SELECT * FROM hotels WHERE id = $hotelId"
// interpolatedHotelsById: WrappedBoundStatement[Row] = net.nmoncho.helenus.api.cql.WrappedBoundStatement@3efc071e
interpolatedHotelsById.as[Hotel].execute().nextOption()
// res1: Option[Hotel] = Some(
// value = Hotel(
// id = "h1",
// name = "The New York Hotel Rotterdam",
// phone = "+31 10 217 3000",
// address = Address(
// street = "Meent 78-82",
// city = "Rotterdam",
// stateOrProvince = "Zuid-Holland",
// postalCode = "3011 JM",
// country = "Netherlands"
// ),
// pois = Set("Erasmus Bridge", "Markthal Rotterdam", "Rotterdam Zoo")
// )
// )
For a more detailed guide on how to use Helenus, please read our wiki. We also provide example projects.