Driver -> Transaction
These two classes are the main points of interactions with a Neo4j database.
A Driver
is basically the connection with the Database,
and provides a context for performing operations (Transaction
s) over the database.
Usually, you would only need one instance per application.
A Transaction
is a logical container for an atomic unit of work.
A single Driver
can start multiple concurrent Transaction
s.
Note: Like its Java counterpart,
neotypes.Driver
is thread safe butneotypes.Transaction
is not.
Transaction management
Each Transaction
has to be started, used, and finally either committed or rolled back.
neotypes provides 3 ways of interacting with Transaction
s, designed for different use cases.
Single query + automatic commit / rollback.
If you only need to perform one query, and want it to be automatically committed in case of success, or rolled back in case of failure.
You can use the Driver
directly.
import neotypes.AsyncDriver
import neotypes.mappers.ResultMapper
import neotypes.syntax.all._ // Provides the query[T] extension method. // Provides the query[T] extension method.
def result(driver: AsyncDriver[F]): F[String] =
"MATCH (p: Person { name: 'Charlize Theron' }) RETURN p.name"
.query(ResultMapper.string)
.single(driver)
Multiple queries + automatic commit / rollback.
Like the previous one, but with the possibility of executing multiple queries in the same Transaction
.
You can use Driver.transact
method.
import neotypes.AsyncDriver
import neotypes.mappers.ResultMapper
import neotypes.syntax.all._ // Provides the query[T] extension method. // Provides the query[T] extension method.
def result(driver: AsyncDriver[F]): F[(String, String)] =
driver.transact { tx =>
for {
r1 <-"MATCH (p: Person { name: 'Charlize Theron' }) RETURN p.name"
.query(ResultMapper.string)
.single(tx)
r2 <-"MATCH (p: Person { name: 'Tom Hanks' }) RETURN p.name"
.query(ResultMapper.string)
.single(tx)
} yield (r1, r2)
}
Note: under the hood, the previous method uses this one. Thus, they are equivalent for single-query operations.
Multiple queries + explicit commit / rollback.
If you want to control when to commit
or rollback
a Transaction
.
You can use the Driver.transaction
method, to create an F[Transaction[F]]
.
import neotypes.AsyncDriver
import neotypes.syntax.all._ // Provides the query[T] extension method. // Provides the query[T] extension method.
def result(driver: AsyncDriver[F]): F[Unit] =
driver.transaction.flatMap { tx =>
for {
_ <-"CREATE (p: Person { name: 'Charlize Theron' })".execute.void(tx)
_ <-"CREATE (p: Person { name: 'Tom Hanks' })".execute.void(tx)
_ <- tx.rollback // Nothing will be done.
} yield ()
}
Note: It is mandatory to only call either
commit
orrollback
once. Calling both or one of them but more than once will leave the system in an undefined state. (probably an error or a deadlock)
Transaction configuration.
You can configure the timeout, access mode, database and metadata of a Transaction
Using a custom TransactionConfig
import neotypes.TransactionConfig
import neotypes.model.query.QueryParam
import scala.concurrent.duration._
val config =
TransactionConfig
.default
.withTimeout(2.seconds)
.withMetadata(Map("foo" -> QueryParam("bar"), "baz" -> QueryParam(10)))
// config: TransactionConfig = neotypes.TransactionConfig@746465cb
Which you can use in operations that explicitly or implicitly create Transaction
s.
import neotypes.{AsyncDriver, AsyncTransaction}
import neotypes.mappers.ResultMapper
import neotypes.syntax.all._ // Provides the query[T] extension method. // Provides the query[T] extension method.
def customTransaction(driver: AsyncDriver[F]): F[AsyncTransaction[F]] =
driver.transaction(config)
def result1(driver: AsyncDriver[F]): F[(String, String)] =
driver.transact(config) { tx =>
for {
r1 <-"MATCH (p:Person {name: 'Charlize Theron'}) RETURN p.name"
.query(ResultMapper.string)
.single(tx)
r2 <-"MATCH (p:Person {name: 'Tom Hanks'}) RETURN p.name"
.query(ResultMapper.string)
.single(tx)
} yield (r1, r2)
}
def result2(driver: AsyncDriver[F]): F[String] =
"MATCH (p:Person {name: 'Charlize Theron'}) RETURN p.name"
.query(ResultMapper.string)
.single(driver, config)