akka-http-neo4j
Neo4j Scala library for use with akka-http and spray-json
This library supports Cypher asynchronous queries to the Neo4j Database. It provides several shorthands and useful abstractions for interacting with Neo4j. It relies on akka-http to perform queries to the Neo4j REST API.
spray-json is not required, but to enjoy the full benefits of the library - it is recommended.
Examples
There are three default clients:
StringClient
- returns the HTML response body as isJsonClient
- parses the HTML body to JSONObjectClient
- parse the HTML body to rows on the formStream[Map[String, JsValue]]
Performing queries
import akka.http.neo4j._
val query = """CREATE (m:Message {text: "Hello, world!"}) RETURN m""".n4jQuery
val client = Neo4jClients.objectClient()
client send query
// returns: Future[N4jResponse]
As you can see, String
has the convenience method .n4jQuery
which turns the
string into an N4jQuery
acceptable by the client's send
method.
Parsing result
The future returned by the client is in fact an Either
. Either an N4jError
or an N4jRows
is returned. The latter is just a type alias for
Stream[Map[String,JsValue]]
.
val req = client send query // using same values as the above example
req map {
case Right(rows) => rows foreach println // prints: Map(m -> {text:"Hello, world!"})
case Left(err) => println(s"${err.code} ${err.message}")
}
Case Classes
Case classes can both be read from and to the database given that the case class
has a JsonFormat[T]
. This is easily achievable:
case class Foo(title: String, desc: String)
implicit val formatFoo = jsonFormat2(Foo.apply)
This case class can now be turned into a CQL node.
Writing to DB
Foo("Title!", "Description!").toCQLNode("n")
// returns: (n:Foo {title:"Title!",desc:"Description!"})
The case class can now be inserted into a query:
val fooNode = Foo("Title!", "Description!").toCQLNode("n")
val insert = s"""CREATE $fooNode RETURN n""".n4jQuery
Prepared statements
akka-http-neo4j uses prepared statements in the same way that the REST API for
Neo4j does. In the query string, values wrapped in curly braces will be
regarded as placeholders. Use the on
method on the N4jQuery
object to
create a prepared statement.
val query = "CREATE (n {props}) RETURN n"
.n4jQuery
.on("props" -> Map("name" -> "My Node"))
client send query
Parsing case classes from DB
(client send insert) map {
case Right(rows) => rows map { _.read[Foo]("n") }
case _ => Stream.empty
}
// returns Stream[Foo]
This will give you DeserializationException
(spray-json) if unsuccessful.
As such, any calls that might fail should use the readOpt[T]
method:
(client send insert) map {
case Right(rows) => rows.map( _.readOpt[Foo]("n") ).flatten
case _ => Stream.empty
}
// returns Stream[Foo]