TYPESCRIPT · NODE.JS
Drivine
Built on NestJS. Decorated classes, a typed query DSL whose references come from the classes themselves, and injection with @InjectGraphObjectManager.
npm install @liberation-data/drivine
Graph database client for TypeScript & the JVM
Community project by Liberation Data.
npm install @liberation-data/drivineorg.drivine:drivine4jTHE DIVINE DRIVER
Drivine maps graphs to objects by composition. Declare the view a use case needs, made of node fragments and the relationships between them, and Drivine writes the statement. When you would rather write the Cypher yourself, the persistence manager is still there.
TYPESCRIPT · NODE.JS
Built on NestJS. Decorated classes, a typed query DSL whose references come from the classes themselves, and injection with @InjectGraphObjectManager.
npm install @liberation-data/drivineKOTLIN · JAVA · SPRING BOOT
The graph client for Embabel. Annotated models in Kotlin or Java, a DSL generated by KSP, and Spring Boot auto-configuration with test containers built in.
implementation("org.drivine:drivine4j:<version>")COMPOSITION OVER INHERITANCE
A person can play many roles. Rather than one model that serves every use case, declare a view for each, and load it in a single statement.
@NodeFragment maps one node.@GraphView composes fragments and relationships from a @Root.@NodeFragment({ labels: ['Person'] }) export class Person { @NodeId() uuid: string; name: string; bio?: string; } @GraphView() export class PersonCareer { @Root() person: Person; @GraphRelationship({ type: 'WORKS_FOR', target: () => WorkHistory }) employmentHistory: WorkHistory[] = []; } // Everyone whose bio mentions leading const leads = await gom.loadAll(PersonCareer, (q) => ({ where: q.person.bio.contains('Lead') }));
@NodeFragment data class Person( @NodeId val uuid: String, val name: String, val bio: String? ) @GraphView data class PersonCareer( @Root val person: Person, @GraphRelationship(type = "WORKS_FOR") val employmentHistory: List<WorkHistory> ) // Everyone whose bio mentions leading val leads = graphObjectManager.loadAll<PersonCareer> { where { person.bio contains "Lead" } }
IN BOTH LIBRARIES
Filters, ordering, keyset paging and index advice, accepted by loads, counts, deletes, patches and grouped reads.
save and saveAll with null policies and replace modes, update, create, patch, cascading deletes, relate and unrelate.
@NodeStamp refuses a save when the node changed since it was loaded, in a stamp format Node and the JVM share.
loadNearest and loadMatching on views and fragments, with one score scale on every engine.
Range, uniqueness, vector and full-text indexes declared on your classes, enforced at startup, with drift detection.
A container for each datasource in CI. While you iterate, USE_LOCAL_NEO4J=true points tests at your own instance.
ENGINES
Dashed: through the persistence manager.
Configure a connection, inject the object manager, load your first view.