Skip to content

Quick Start

@Configuration
@ComponentScan("org.drivine")
class AppConfig {
@Bean
fun dataSourceMap(): DataSourceMap {
val props = ConnectionProperties(
type = DatabaseType.NEO4J,
host = "localhost",
port = 7687,
userName = "neo4j",
password = "password",
databaseName = "neo4j"
)
return DataSourceMap(mapOf("neo" to props))
}
}
data class Person(
val uuid: String,
val firstName: String,
val lastName: String,
val email: String?,
val age: Int
)
@Component
class PersonRepository @Autowired constructor(
@Qualifier("neoManager") val manager: PersistenceManager
) {
@Transactional
fun findByCity(city: String): List<Person> {
return manager.query(
QuerySpecification
.withStatement("MATCH (p:Person {city: \$city}) RETURN properties(p)")
.bind(mapOf("city" to city))
.transform(Person::class.java)
)
}
@Transactional
fun findById(id: String): Person? {
return manager.maybeGetOne(
QuerySpecification
.withStatement("MATCH (p:Person {uuid: \$id}) RETURN properties(p)")
.bind(mapOf("id" to id))
.transform(Person::class.java)
)
}
@Transactional
fun create(person: Person): Person {
return manager.getOne(
QuerySpecification
.withStatement("CREATE (p:Person) SET p = \$props RETURN properties(p)")
.bindObject("props", person)
.transform(Person::class.java)
)
}
@Transactional
fun update(uuid: String, patch: Partial<Person>): Person {
val props = patch.toMap()
return manager.getOne(
QuerySpecification
.withStatement(
"MATCH (p:Person {uuid: \$uuid}) SET p += \$props RETURN properties(p)"
)
.bind(mapOf("uuid" to uuid, "props" to props))
.transform(Person::class.java)
)
}
}

When using PersistenceManager with Cypher queries, always return a single map or scalar value – not multiple columns. This ensures correct mapping with .transform() and avoids issues with NULL values.

-- WRONG: Multiple columns -- hard to map, NULL values cause errors
RETURN a.name, a.age, b.title
-- CORRECT: Return a single map
RETURN { name: a.name, age: a.age, title: b.title } AS result
-- CORRECT: Return a single property map
RETURN properties(p)
-- CORRECT: Return a scalar value
RETURN count(p) AS total

If you need to aggregate across multiple nodes, compose the result into a single map in your RETURN clause:

MATCH (p:Proposition)-[:HAS_MENTION]->(m:Mention)
WITH m.type AS entityType, m.name AS name, count(p) AS mentionCount
ORDER BY mentionCount DESC
LIMIT 30
RETURN {
entityType: entityType,
name: name,
mentionCount: mentionCount
} AS result

This way .transform(MyDto::class.java) can map the result directly to a data class.