Skip to content

Commit

Permalink
fix: Make executeUpdate return only the number of modified rows. (#780
Browse files Browse the repository at this point in the history
)

Added the most simple Hibernate smoke test and discovered that the JDBC spec dictates that executeUpdate returns the number of affected rows, not the total number of changes in a row.

We approximate this now by just counting labels and types.
  • Loading branch information
michael-simons authored Nov 14, 2024
1 parent 52133da commit fef8468
Show file tree
Hide file tree
Showing 13 changed files with 358 additions and 20 deletions.
96 changes: 96 additions & 0 deletions neo4j-jdbc-it/hibernate-smoke-tests/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2023-2024 "Neo4j,"
Neo4j Sweden AB [https://neo4j.com]
This file is part of Neo4j.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<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.neo4j</groupId>
<artifactId>neo4j-jdbc-it</artifactId>
<version>6.0.2-SNAPSHOT</version>
</parent>
<artifactId>neo4j-jdbc-hibernate-smoke-tests</artifactId>

<name>Neo4j JDBC Driver (Hibernate Smoke tests)</name>

<properties>
<hibernate-platform.version>6.6.1.Final</hibernate-platform.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-platform</artifactId>
<version>${hibernate-platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
<version>2.1.3</version>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>jakarta.transaction</groupId>
<artifactId>jakarta.transaction-api</artifactId>
</dependency>

<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-jdbc-full-bundle</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>neo4j</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2023-2024 "Neo4j,"
* Neo4j Sweden AB [https://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.neo4j.jdbc.it.hibernate;

import java.util.UUID;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "Movie")
public class Movie {

@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;

private String title;

public UUID getId() {
return this.id;
}

public void setId(UUID id) {
this.id = id;
}

public String getTitle() {
return this.title;
}

public void setTitle(String title) {
this.title = title;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2023-2024 "Neo4j,"
* Neo4j Sweden AB [https://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Hibernate based entities.
*/
package org.neo4j.jdbc.it.hibernate;
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright (c) 2023-2024 "Neo4j,"
* Neo4j Sweden AB [https://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.neo4j.jdbc.it.hibernate;

import org.hibernate.SessionFactory;
import org.hibernate.annotations.processing.GenericDialect;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.neo4j.jdbc.Neo4jDriver;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Testcontainers;

import static org.assertj.core.api.Assertions.assertThat;

@Testcontainers(disabledWithoutDocker = true)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class HibernateIT {

@SuppressWarnings("resource") // On purpose to reuse this
protected final Neo4jContainer<?> neo4j = new Neo4jContainer<>(System.getProperty("neo4j-jdbc.default-neo4j-image"))
.withEnv("NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes")
.waitingFor(Neo4jContainer.WAIT_FOR_BOLT)
.withReuse(true);

protected SessionFactory sessionFactory;

@BeforeAll
void startNeo4j() {
this.neo4j.start();
this.sessionFactory = new Configuration().addAnnotatedClass(Movie.class)
.setProperty(AvailableSettings.JAKARTA_JDBC_DRIVER, Neo4jDriver.class)
.setProperty(AvailableSettings.JAKARTA_JDBC_URL,
"jdbc:neo4j://localhost:" + this.neo4j.getMappedPort(7687) + "?enableSQLTranslation=true")
.setProperty(AvailableSettings.JAKARTA_JDBC_USER, "neo4j")
.setProperty(AvailableSettings.JAKARTA_JDBC_PASSWORD, this.neo4j.getAdminPassword())
.setProperty(AvailableSettings.SHOW_SQL, true)
.setProperty(AvailableSettings.FORMAT_SQL, true)
.setProperty(AvailableSettings.HIGHLIGHT_SQL, true)
.setProperty(AvailableSettings.DIALECT, GenericDialect.class)

.buildSessionFactory();
}

@BeforeEach
void clearDatabase() {
try (var session = this.sessionFactory.openSession();) {
session.doWork(connection -> {
connection.setAutoCommit(true);
try (var stmt = connection.createStatement()) {
stmt.execute("""
/*+ NEO4J FORCE_CYPHER */
MATCH (n)
CALL {
WITH n DETACH DELETE n
}
IN TRANSACTIONS OF 1000 ROWs""");
}
});
}
}

@AfterAll
void closeSf() {
this.sessionFactory.close();
}

@Test
void shouldBeAbleToCRUDMovies() {

var id = this.sessionFactory.fromSession(session -> {
var movie = new Movie();
var tx = session.beginTransaction();
movie.setTitle("Winter is coming.");
session.persist(movie);
tx.commit();
return movie.getId();
});

this.sessionFactory.inSession(session -> {
var tx = session.beginTransaction();
var movies = session.createSelectionQuery("from Movie", Movie.class).getResultList();
assertThat(movies).hasSize(1).first().satisfies(m -> {
assertThat(m.getId()).isNotNull();
assertThat(m.getTitle()).isEqualTo("Winter is coming.");
});
movies.get(0).setTitle("We hibernated.");
tx.commit();
});

this.sessionFactory.inSession(session -> {
var tx = session.beginTransaction();
var movie = session.find(Movie.class, id);
assertThat(movie.getTitle()).isEqualTo("We hibernated.");
session.remove(movie);
tx.commit();
});

this.sessionFactory.inSession(session -> {
var movies = session.createSelectionQuery("from Movie", Movie.class).getResultList();
assertThat(movies).isEmpty();
});
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#
# Copyright (c) 2023-2024 "Neo4j,"
# Neo4j Sweden AB [https://neo4j.com]
#
# This file is part of Neo4j.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

org.slf4j.simpleLogger.log.org.testcontainers=error
Loading

0 comments on commit fef8468

Please sign in to comment.