Skip to content
This repository has been archived by the owner on Mar 24, 2020. It is now read-only.

liquigraph/trinity

Repository files navigation

Trinity

Neo4j is a graph database.

Cypher is Neo4j’s query language.

Trinity is the preferred choice to run Cypher queries for client applications and libraries running on the Java Virtual Machine.

Build status

Build Status Maven Central

Why Trinity?

While working on Liquigraph, we realized that having to keep several branches per Neo4j version was a pain.

This was mainly due to the fact there was no JDBC driver supporting both Neo4j v2 and Neo4j v3.

Moreover, we did not need a full-fledged JDBC implementation, we just needed to run Cypher queries.

And then, Trinity was born! With a simple API in mind, some build and implementation tricks to work around Neo4j incompatibilities, we achieved what we wanted: having a single way to run Cypher with any Neo4j setup.

Why the name?

  1. Because badass women for the win!

  2. And also because Twitter!

Minimum Viable Snippet

Bolt

package in.da.matrix;

import org.liquigraph.trinity.bolt.BoltClient;
import org.neo4j.driver.v1.AuthToken;
import org.neo4j.driver.v1.AuthTokens;
import org.neo4j.driver.v1.GraphDatabase;

import java.util.List;

public class TrinityBoltExample {

    public static void main(String[] args) {
        AuthToken authentication = AuthTokens.basic("neo4j", "toto");
        try (BoltClient trinity =
             new BoltClient(GraphDatabase.driver("bolt://localhost:7687", authentication))) {

            trinity.runSingleTransaction("MATCH (n:Crew) RETURN COUNT(n)")
               .consume(
                   (List<Fault> errors) -> {
                       // do something amazingly useful
                   },
                   (List<Data> data) -> {
                       // do something usefully amazing with it
                   }
               );
        }
    }
}

HTTP

package in.da.matrix;

import org.liquigraph.trinity.Data;
import org.liquigraph.trinity.Either;
import org.liquigraph.trinity.Fault;
import org.liquigraph.trinity.http.BasicAuthenticator;
import org.liquigraph.trinity.http.HttpClient;
import java.util.List;
import okhttp3.OkHttpClient;

public class TrinityHttpExample {

    public static void main(String... args) {
        // if auth is disabled, just use: new HttpClient("http://localhost:7474")
        HttpClient trinity = new HttpClient(
            "http://localhost:7474",
            okHttpClient("neo4j", "s3cr3t")
        );

        Either<List<Fault>, List<Data>> either =
            trinity.runSingleTransaction("MATCH (n:Crew) RETURN COUNT(n)");

        if (either.isRight()) {
            List<Data> data = either.getRight();
            // do something usefully amazing with it
        }
        else {
            List<Fault> errors = either.getLeft();
            // do something amazingly useful
        }
    }

    private static OkHttpClient okHttpClient(String username, String password) {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder = builder.authenticator(new BasicAuthenticator(username, password));
        return builder.build();
    }
}

Embedded for Neo4j v3

package in.da.matrix;

import org.liquigraph.trinity.neo4jv3.EmbeddedClient;
import org.liquigraph.trinity.Data;
import org.liquigraph.trinity.Either;
import org.liquigraph.trinity.Fault;
import java.nio.file.Paths;
import java.util.List;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;

public class TrinityEmbeddedV3Example {

    public static void main(String... args) {
        File path = Paths.get("some", "path").toFile();
        EmbeddedClient trinity = new EmbeddedClient(graphDatabase(path));

        Either<List<Fault>, List<Data>> either =
            trinity.runSingleTransaction("MATCH (n:Crew) RETURN COUNT(n)");

        if (either.isRight()) {
            List<Data> data = either.getRight();
            // do something usefully amazing with it
        }
        else {
            List<Fault> errors = either.getLeft();
            // do something amazingly useful
        }
    }

    private static GraphDatabaseService graphDatabase(File path) {
        return new GraphDatabaseFactory().newEmbeddedDatabase(path);
    }
}

Embedded for Neo4j v2

package in.da.matrix;

import org.liquigraph.trinity.neo4jv2.EmbeddedClient;
import org.liquigraph.trinity.Data;
import org.liquigraph.trinity.Either;
import org.liquigraph.trinity.Fault;
import java.util.List;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;

public class TrinityEmbeddedV2Example {

    public static void main(String... args) {
        EmbeddedClient trinity = new EmbeddedClient(graphDatabase("/some/path"));

        Either<List<Fault>, List<Data>> either =
            trinity.runSingleTransaction("MATCH (n:Crew) RETURN COUNT(n)");

        if (either.isRight()) {
            List<Data> data = either.getRight();
            // do something usefully amazing with it
        }
        else {
            List<Fault> errors = either.getLeft();
            // do something amazingly useful
        }
    }

    private static GraphDatabaseService graphDatabase(String path) {
        return new GraphDatabaseFactory().newEmbeddedDatabase(path);
    }
}

Download

Application developers

Picking the right implementation is just a matter of selecting the right artifact:

Table 1. Trinity artefact matrix (pun absolutely intended)
Artifact coordinates Version of Neo4j JRE prerequisites

trinity-embedded-2x

2.0.0 to latest 2.x

JRE 7 or later

trinity-embedded-3x

3.0.0 to latest 3.x

JRE 8 or later

trinity-http

2.0.0 to latest 3.x

JRE 7 or later

trinity-bolt

3.0.0 to latest 3.x

JRE 8 or later

Note

Trinity groupId is always org.liquigraph.trinity. If you pick Trinity for Neo4j embedded v2, then you must add the dependency:

<dependency>
    <groupId>org.liquigraph.trinity</groupId>
    <artifactId>trinity-embedded-2x</artifactId>
    <version><!-- CURRENT VERSION --></version>
</dependency>

Library developers

If you develop a library that needs to support several Neo4j setups as well, you can pick any of the two bundles:

  • Neo4j 2:

<dependency>
    <groupId>org.liquigraph.trinity</groupId>
    <artifactId>trinity-neo4j-v2</artifactId>
    <version><!-- CURRENT VERSION --></version>
</dependency>
  • Neo4j 3:

<dependency>
    <groupId>org.liquigraph.trinity</groupId>
    <artifactId>trinity-neo4j-v3</artifactId>
    <version><!-- CURRENT VERSION --></version>
</dependency>
Note

These two bundles cannot be included together, as they require different versions of Neo4j and JRE.

Please note that Trinity instance discovery is implemented via the good old Java Service Provider Interfaces.

To retrieve a Trinity instance, one just needs to include one of the two bundles and use org.liquigraph.trinity.CypherClientLookup like in the example below:

package in.da.matrix;

import org.liquigraph.trinity.CypherClientLookup;
import org.liquigraph.trinity.CypherTransport;
import org.liquigraph.trinity.OngoingTransaction;
import org.liquigraph.trinity.Optional; // for trinity-neo4j-v2
import java.util.Optional; // for trinity-neo4j-v3
import java.util.Properties;

public class TrinityHttpDiscoveryExample {

    public static void main(String... args) {
        CypherClientLookup lookup = new CypherClientLookup();
        Optional<CypherClient<OngoingTransaction>> maybeTrinity = lookup.getInstance(
            CypherTransport.HTTP,
            httpProperties()
        );

        // trinity-neo4j-v3 users can rely on the primitive Java 8 Optional
        // they are encouraged to use instead maybeTrinity.ifPresent(trinity -> ...)
        if (maybeTrinity.isPresent()) {
            CypherClient<OngoingTransaction> trinity = maybeTrinity.get();
            // then you can run Cypher queries as in the above examples
        }
    }

    private static Properties httpProperties() {
        Properties props = new Properties();
        props.setProperty("cypher.http.baseurl", "http://localhost:7474");
        props.setProperty("cypher.http.username", "neo4j");
        props.setProperty("cypher.http.password", "s3cr3t");
        return props;
    }
}

About

Cypher executor in the JVM | Neo4j v2 and v3 | Embedded/HTTP/Bolt

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published