2
votes
  1. Datastax driver Cassandra version: 3.3.2
  2. Scala version: 2.12.4

I'm playing with creating a scala wrapper for the mappingmanager in the datastax java driver for Cassandra.

For this I have the following simple table:

CREATE TABLE todo (
    id UUID,
    title TEXT,
    completed boolean,
    PRIMARY KEY((id), completed, title)
)  WITH CLUSTERING ORDER BY (completed ASC, title ASC);

The createAsync, saveAsync and deleteAsync functions are working fine now. Now I want to implement the more general executeAsync functionality. Therefore I have the following code:

private def executeAsync(query: String, params: Any*): Future[ResultSet] = {
    params match {
      case Seq() =>
        session.executeAsync(query) // had a problem with empty params varargs
      case _ =>
        prepareAsync(query).map(preparedStatement =>
          preparedStatement.bind(
            params
              .map(x => {
                println(x) // correctly prints the param
                x.asInstanceOf[Object]
              })
          )
        ).flatMap(x => {
          println("here") // never gets printed
          session.executeAsync(x)
        })
    }
  }

  private def prepareAsync(query: String): Future[PreparedStatement] = {
    session.prepareAsync(query)
  }

The following query retrieves the values correctly:

val future: Future[List[TodoCassandra]] = customMappingManager.executeQueryAsync("SELECT * FROM todo;")
    future.onComplete {
      case Success(x) =>
        println(x)
    }

The following examples:

val future: Future[List[TodoCassandra]] = customMappingManager.executeQueryAsync("INSERT INTO todo (id, title, completed) VALUES (uuid(), ?, ?)", "prepared statement test", false)

val future: Future[List[TodoCassandra]] = customMappingManager.executeQueryAsync("INSERT INTO todo (id, completed, title) VALUES (uuid(), ?, ?)", false, "prepared statement test")

val future: Future[List[TodoCassandra]] = customMappingManager.executeQueryAsync("SELECT * FROM todo WHERE id = ?", "a8a6da8b-3d0e-40b3-99e5-fe2f664f50d0")

Result in:

  1. Codec not found for requested operation: [varchar <-> scala.collection.mutable.ArrayBuffer]) (of class scala.util.Failure)
  2. Codec not found for requested operation: [boolean <-> scala.collection.mutable.ArrayBuffer]) (of class scala.util.Failure)
  3. Codec not found for requested operation: [uuid <-> scala.collection.mutable.ArrayBuffer]) (of class scala.util.Failure)

Why is it always 'converting' from a scala.collection.mutable.ArrayBuffer? What can be the solution to fix this?

1

1 Answers

1
votes

I have encountered a similar problem to yours while using Querying Cassandra from Scala tutorial.

What is the mistake

Your executeAsync method looks like the one in the article and it has the same defect. Namely, during preparedStatement.bind you pass a Seq[Object], after casting each of Any item to Object. And this seems to fail.

Fix

The easy fix is, to pass this sequence as var-args, as the Java method actually expects.

Code:

def execute(statement: Future[PreparedStatement], params: Any*)
           (implicit executionContext: ExecutionContext, session: Session): Future[ResultSet] = {
  val p = params.map(_.asInstanceOf[Object])
  statement
    .map(_.bind(p: _*))
    .flatMap(session.executeAsync(_))
}