Java/Scala facade to datomic.client.api/api.async
This project contains thin Java and Scala facades to the Datomic Clojure Client api:
You can then use the various Datomic systems depending on the Client api from Java and Scala:
- Peer Server
- Dev local
- Cloud
Using the facade in a live Cloud setting has not yet been tested. But since dev-local is equivalent and works fine, Cloud should too.
Note that this library is an independent release not associated with Datomic/Cognitect.
Java/Scala
Code is written in Scala but compiles to the same bytecode as Java.
Each language has been given its own exclusive namespace to ensure full compatibility and to accommodate for differences.
- In the
datomicJava
namespace all interfaces take java-compatible types as input and return only java-compatible types. - In the
datomicScala
namespace most types are java-compatible but where collections are iterated for instance, a Scala collection type is returned.
Code organization
The implementation has largely followed the structure of the Datomic Java api.
Clojure functions of the Client api taking a Connection object are encapsulated in a Connection
class and so on. We end up with 4 classes and their methods:
- Datomic (similar to
Peer
)clientCloud
(providing AWSCredentialsProviderChain)clientCloud
(providing creds-profile name)clientDevLocal
clientPeerServer
q
qseq
- Client:
administerSystem
connect
createDatabase
deleteDatabase
listDatabases
- Connection:
db
sync
transact
txRange
txRangeArray
(convenience method for populated Array)widh
(convenience method for single invocation)withDb
- Db:
dbStats
asOf
since
with
history
datoms
indexRange
pull
indexPull
Various helper classes are added too.
Sync/async
Each language namespace has a sync
and async
package which corresponds to the two Datomic client api sync/async versions. All the above methods are implemented for each package.
Java async
The datomic client async api for Java generally returns a CompletableFutue
of a custom Channel
type.
Once the Future has completed, chunked results can be retrieved by calling chunk
one or more times on the Channel
object until the Clojure Channel is empty.
Each chunk is a custom Either
type that can be either a Left
projection with a CognitectAnomaly
or a Right
projection containing the successful result of a type T
for the operation in question. That way, the result can be type checked for an anomaly or a success.
When the Clojure Channel is empty, Right(null)
is returned. Consuming Java code might therefore want to check for such terminating null value (when needed).
- See Java async tests
Java sync
The datomic client sync api for Java returns the result as is (equivalent to the type T
of the async api).
Cognitect anomalies are thrown as runtime exceptions.
- See Java sync tests
Scala async
The datomic client async api for Scala returns a Future
of a LazyList
of chunks of data. The first (head) chunk of the LazyList
is eargerly evaluated and subsequent chunks can be retrieved lazily by simply looping the LazyList
.
Each chunk in the LazyList
is an Either
of either a Left[CognitectAnomaly]
or a Right[T]
where T
is the main result type.
Scala sync
The datomic client sync api for Scala returns the result as is (equivalent to the type T
of the async api).
Cognitect anomalies are thrown as runtime exceptions.
- See Scala sync tests
Setup
Clone this project and open in your IDE to explore.
git clone https://github.com/scalamolecule/datomic-client-api-java-scala.git
This library presumes that you have a Datomic installation downloaded. It can be a free/starter/pro version, although the free version is a bit behind and won't provide all functionality. It's recommended to download an up-to-date version of starter/pro. On older versions of Datomic, some functionality might not be available. The qseq
method was added in version 1.0.6165 for instance.
Start by creating a test database hello
from within the Datomic installation folder. This only has to be done once:
cd <datomic-installation>
// Create `hello` database (if it has not already been created)
bin/shell
datomic % Peer.createDatabase("datomic:dev://localhost:4334/hello");
<ctrl-c>
Peer-server in-mem
Running a peer-server in-mem doesn't require a transactor process to be running. So you can simply start the Peer Server directly from within the datomic installation directory:
bin/run -m datomic.peer-server -a k,s -d hello,datomic:mem://hello
Peer-server against transactor
To use a peer-server against a transacor, please start a transactor in one process, and the Peer Server in another process:
process 1:
bin/transactor config/samples/dev-transactor-template.properties
process 2:
bin/run -m datomic.peer-server -h localhost -p 8998 -a k,s -d hello,datomic:dev://localhost:4334/hello
Dev-local / Cloud
To run tests against dev-local, please download the dev-tools and follow the instructions to install on your local machine.
Testing
Run the Java tests by right-clicking on the test.java.datomicJava.client
package in the project view (in IntelliJ) and choose Run -> Tests in 'client' (or run individual tests similarly).
Run the Scala tests by right-clicking on the test.scala.datomicScala.client
package in the project view (in IntelliJ) and choose Run -> Specs2 in 'client' (or run individual tests similarly).
Or run tests with sbt:
sbt
// Single test
sbt:datomic-client-api-java-scala> testOnly datomicScala.client.api.sync.DatomicTest
// Tests for Java
sbt:datomic-client-api-java-scala> testOnly datomicJava.client.api.*
// Tests for Scala 2.13 (default)
sbt:datomic-client-api-java-scala> testOnly datomicScala.client.api.*
// Tests for scala 2.12
sbt:datomic-client-api-java-scala> ++2.12.12; testOnly datomicJava.client.api.*
sbt:datomic-client-api-java-scala> ++2.12.12; testOnly datomicScala.client.api.*
Temporary limitation
Due to a bug in the Peer Server async implementation, all asynchronous Peer Server tests won't pass since we can't build a Client with map data. Hopefully this will be solved soon, and then all asynchronous Peer Server tests should pass.
Use with your project
This library is available on Maven Central.
Add Java dependency in POM file:
<dependency>
<groupId>org.scalamolecule</groupId>
<artifactId>datomic-client-api-java-scala</artifactId>
<version>0.6.1</version>
</dependency>
<!-- If using dev-local -->
<dependency>
<groupId>com.datomic</groupId>
<artifactId>dev-local</artifactId>
<version>0.9.229</version>
</dependency>
<!-- If using peer-server -->
<dependency>
<groupId>com.datomic</groupId>
<artifactId>datomic-pro</artifactId>
<version>1.0.6222</version>
</dependency>
Add Scala dependency in sbt build file (crosscompiles to Scala 2.12 and 2.13):
libraryDependencies ++= Seq(
"org.scalamolecule" %% "datomic-client-api-java-scala" % "0.6.1",
// If using dev-local
"com.datomic" % "dev-local" % "0.9.229",
// If using peer-server
"com.datomic" % "datomic-pro" % "1.0.6222"
)
To use dev-local, please download from https://cognitect.com/dev-tools and install locally per included instructions and same for datomic pro.
Author / License
Marc Grue. Licensed under the Apache License 2.0.