Skip to content

Instantly share code, notes, and snippets.

@Podbrushkin
Created November 14, 2023 23:29
Show Gist options
  • Save Podbrushkin/54518ad6c4835706fd3344f01ea6acc9 to your computer and use it in GitHub Desktop.
Save Podbrushkin/54518ad6c4835706fd3344f01ea6acc9 to your computer and use it in GitHub Desktop.
Spring Data Neo4j MRE
package myapp;
import java.io.File;
import java.time.Duration;
import java.time.LocalDate;
import org.neo4j.configuration.GraphDatabaseSettings;
import org.neo4j.configuration.connectors.BoltConnector;
import org.neo4j.cypherdsl.core.renderer.Configuration;
import org.neo4j.cypherdsl.core.renderer.Dialect;
import org.neo4j.dbms.api.DatabaseManagementService;
import org.neo4j.dbms.api.DatabaseManagementServiceBuilder;
import org.neo4j.graphdb.GraphDatabaseService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import myapp.model.Image;
import myapp.model.Person;
import myapp.repo.ImageRepositoryNeo4j;
import myapp.repo.PersonRepositoryNeo4j;
@SpringBootApplication
@EnableNeo4jRepositories
public class DemoApplication {
private Logger log = LoggerFactory.getLogger(getClass());
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
public Configuration cypherDslConfiguration() {
return Configuration.newConfig().withDialect(Dialect.NEO4J_5).build();
}
//https://neo4j.com/docs/java-reference/current/java-embedded/setup/
@Bean
public DatabaseManagementService databaseManagementService() {
DatabaseManagementService managementService = new
DatabaseManagementServiceBuilder(new File("target/mydb").toPath())
.setConfig(GraphDatabaseSettings.transaction_timeout, Duration.ofSeconds( 60 ) )
.setConfig( BoltConnector.enabled, true )
.setConfig(BoltConnector.encryption_level, BoltConnector.EncryptionLevel.DISABLED)
.build();
registerShutdownHook(managementService);
return managementService;
}
@Bean
public GraphDatabaseService graphDatabaseService(DatabaseManagementService managementService) {
GraphDatabaseService graphDb =
managementService.database(GraphDatabaseSettings.DEFAULT_DATABASE_NAME);
log.info("Neo4j database Embedded instance is available: {}", graphDb.isAvailable());
return graphDb;
}
private static void registerShutdownHook(final DatabaseManagementService managementService) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
managementService.shutdown();
}
});
}
@Bean
CommandLineRunner demo(PersonRepositoryNeo4j personRepository,
ImageRepositoryNeo4j imageRepository) {
return args -> {
Person greg = new Person("Greg", LocalDate.of(1991,1,1));
Person roy = new Person("Roy", LocalDate.of(1992,2,2));
Person greg2 = new Person("Greg", LocalDate.of(1993,3,3));
greg = personRepository.save(greg);
roy = personRepository.save(roy);
greg2 = personRepository.save(greg2);
var img1 = new Image("/blabla1.jpg");
var img2 = new Image("/blabla2.jpg");
img1.getPeople().add(greg);
img1.getPeople().add(roy);
img2.getPeople().add(greg);
img2.getPeople().add(greg2);
img1 = imageRepository.save(img1);
img2 = imageRepository.save(img2);
// now greg1991 is depicted in 2 images and greg1993 in 1 image
var freshPerson = personRepository.findOneByBirthday(LocalDate.of(1993,3,3));
// this one should return '1' but brings exception:
var count = imageRepository.countByPeopleContains(freshPerson);
log.info("Greg1993 is depicted in {} images.", count);
};
}
}
package myapp.model;
import java.util.HashSet;
import java.util.Set;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Relationship;
import org.springframework.data.neo4j.core.schema.Relationship.Direction;
@Node("Image")
public class Image {
@Id
@GeneratedValue
private String id;
private String filePath;
@Relationship(type = "DEPICTS", direction = Direction.OUTGOING)
private Set<Person> people = new HashSet<>();
public Image(String filePath) {
this.filePath = filePath;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public Set<Person> getPeople() {
return people;
}
public void setPeople(Set<Person> people) {
this.people = people;
}
}
package myapp.repo;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.query.Query;
import org.springframework.data.repository.query.Param;
import myapp.model.Image;
import myapp.model.Person;
public interface ImageRepositoryNeo4j extends Neo4jRepository<Image, String> {
@Query("""
MATCH (i:Image) -[:DEPICTS] -> (p:Person)
WHERE id(p) = id($person)
RETURN count(i)
""")
// Invalid input for function 'id()': to be a node or relationship, but it was `Map`;
public Integer countByPeopleContains(@Param("person") Person person);
@Query("""
MATCH (i:Image) -[:DEPICTS] -> (p:Person {name: $person})
RETURN count(i)
""")
public Integer countByPeopleContains(@Param("person") String personName);
}
package myapp.model;
import java.time.LocalDate;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
@Node("Person")
public class Person {
@Id
@GeneratedValue
private String id;
private String name;
private LocalDate birthday;
public Person(String name, LocalDate birthday) {
this.name = name;
this.birthday = birthday;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LocalDate getBirthday() {
return birthday;
}
public void setBirthday(LocalDate birthday) {
this.birthday = birthday;
}
}
package myapp.repo;
import java.time.LocalDate;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import myapp.model.Person;
public interface PersonRepositoryNeo4j extends Neo4jRepository<Person, String> {
Person findOneByName(String name);
Person findOneByBirthday(LocalDate name);
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>execute `mvn clean spring-boot:run -e` in this directory to get an exception</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0-rc2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
<version>5.13.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@Podbrushkin
Copy link
Author

In empty dir:

mkdir src/main/java/myapp/repo
mkdir src/main/java/myapp/model
curl -L -O https://gist.github.com/Podbrushkin/54518ad6c4835706fd3344f01ea6acc9/raw/b94881dfeddc0a702a6c796a300c29e715f0fbe5/pom.xml
curl -L https://gist.github.com/Podbrushkin/54518ad6c4835706fd3344f01ea6acc9/raw/b94881dfeddc0a702a6c796a300c29e715f0fbe5/PersonRepositoryNeo4j.java > .\src\main\java\myapp\repo\PersonRepositoryNeo4j.java
curl -L https://gist.github.com/Podbrushkin/54518ad6c4835706fd3344f01ea6acc9/raw/b94881dfeddc0a702a6c796a300c29e715f0fbe5/ImageRepositoryNeo4j.java > .\src\main\java\myapp\repo\ImageRepositoryNeo4j.java
curl -L https://gist.github.com/Podbrushkin/54518ad6c4835706fd3344f01ea6acc9/raw/b94881dfeddc0a702a6c796a300c29e715f0fbe5/Person.java > .\src\main\java\myapp\model\Person.java
curl -L https://gist.github.com/Podbrushkin/54518ad6c4835706fd3344f01ea6acc9/raw/b94881dfeddc0a702a6c796a300c29e715f0fbe5/Image.java > .\src\main\java\myapp\model\Image.java
curl -L https://gist.github.com/Podbrushkin/54518ad6c4835706fd3344f01ea6acc9/raw/b94881dfeddc0a702a6c796a300c29e715f0fbe5/DemoApplication.java > .\src\main\java\myapp\DemoApplication.java

mvn clean spring-boot:run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment