Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Find one with join issue #3137

Merged
merged 6 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 0 additions & 15 deletions data-connection-jdbc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,18 @@ dependencies {

testImplementation mnReactor.micronaut.reactor

testImplementation(mnTestResources.testcontainers.mysql)
testImplementation(mnTestResources.testcontainers.mariadb)
testImplementation(mnTestResources.testcontainers.postgres)
testImplementation(mnTestResources.testcontainers.mssql)
testImplementation(mnTestResources.testcontainers.oracle.xe)

testCompileOnly mn.micronaut.inject.groovy

testImplementation mn.micronaut.http.netty
testRuntimeOnly mnSql.micronaut.jdbc.tomcat
testRuntimeOnly mnSql.h2
testRuntimeOnly mnSql.mariadb.java.client
testRuntimeOnly mnSql.ojdbc11
testRuntimeOnly mnSql.mysql.connector.java
testRuntimeOnly mnSql.postgresql
testRuntimeOnly mnSql.mssql.jdbc
testRuntimeOnly mn.snakeyaml

testResourcesService mnSql.mariadb.java.client
testResourcesService mnSql.ojdbc11
testResourcesService mnSql.mysql.connector.java
testResourcesService mnSql.postgresql
testResourcesService mnSql.mssql.jdbc

testImplementation libs.micronaut.testresources.client

testRuntimeOnly mnSerde.micronaut.serde.oracle.jdbc.json
}

micronaut {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.micronaut.data.jdbc.h2.joinissue;

import io.micronaut.data.annotation.GeneratedValue;
import io.micronaut.data.annotation.Id;
import io.micronaut.data.annotation.MappedEntity;
import io.micronaut.data.annotation.Relation;

import java.util.Set;

@MappedEntity("ji_author")
public record Author(
@Id
@GeneratedValue
Long id,
String name,
@Relation(value = Relation.Kind.ONE_TO_MANY, cascade = Relation.Cascade.ALL, mappedBy = "author")
Set<Book> books) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package io.micronaut.data.jdbc.h2.joinissue;

import io.micronaut.data.annotation.Join;
import io.micronaut.data.annotation.Query;
import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.repository.CrudRepository;

import java.util.List;
import java.util.Optional;

@JdbcRepository(dialect = Dialect.H2)
@Join(value = "books", type = Join.Type.LEFT_FETCH)
public interface AuthorRepository extends CrudRepository<Author, Long> {

Optional<Author> queryByName(String name);

List<Author> queryByNameContains(String partialName);

Optional<Author> findByNameContains(String partialName); //findByNameContainsIgnoreCase has the same issue

//Note: findFirstByNameContains returns only the first row and therefore only one book.

/*
SELECT author_.`id`,
author_.`name`,
author_books_.`id` AS books_id,
author_books_.`title` AS books_title,
author_books_.`author` AS books_author
FROM (
SELECT id,name FROM author
WHERE (`name` LIKE CONCAT('%',:partialName,'%'))
LIMIT 1) author_
LEFT JOIN book author_books_ ON author_.id=author_books_.author;
*/
@Query("SELECT author_.`id`,author_.`name`,author_books_.`id` AS books_id,author_books_.`title` AS books_title,author_books_.`author` AS books_author FROM (SELECT id,name FROM ji_author WHERE (`name` LIKE CONCAT('%',:partialName,'%')) LIMIT 1) author_ LEFT JOIN ji_book author_books_ ON author_.id=author_books_.author;")
Optional<Author> getOneByNameContains(String partialName);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package io.micronaut.data.jdbc.h2.joinissue

import io.micronaut.data.jdbc.h2.H2DBProperties
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import jakarta.inject.Inject
import spock.lang.Specification

@MicronautTest
@H2DBProperties
class AuthorTest extends Specification {

@Inject
AuthorRepository authorRepository

void test() {
given:
var authorList = List.of(
new Author(null, "Joe Doe",
Set.of(new Book(null, "History of nothing"))),
new Author(null, "Jane Doe",
Set.of(new Book(null, "History of everything"),
new Book(null, "Doing awesome things"))))

authorRepository.saveAll(authorList)

when:
Author author = authorRepository.queryByName("Joe Doe").orElse(null)
then:
author.name() == "Joe Doe"
author.books().size() == 1

when:
List<Author> list = authorRepository.queryByNameContains("Doe")
then:
list.size() == 2
list.get(0).name() == "Joe Doe"
list.get(0).books().size() == 1
list.get(1).name() == "Jane Doe"
list.get(1).books().size() == 2

when:
author = authorRepository.getOneByNameContains("Doe").orElse(null)
then:
author.name() == "Joe Doe"
author.books().size() == 1

when:
author = authorRepository.getOneByNameContains("ne Doe").orElse(null)
then:
author.name() == "Jane Doe"
author.books().size() == 2

when:
author = this.authorRepository.findByNameContains("Doe").orElse(null)
then:
author.name() == "Joe Doe"
author.books().size() == 1

when:
author = this.authorRepository.findByNameContains("e Doe").orElse(null)
then:
author.name() == "Joe Doe"
author.books().size() == 1

when:
author = this.authorRepository.findByNameContains("ne Doe").orElse(null)
then:
author.name() == "Jane Doe"
author.books().size() == 2
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.micronaut.data.jdbc.h2.joinissue;

import io.micronaut.core.annotation.Nullable;
import io.micronaut.data.annotation.GeneratedValue;
import io.micronaut.data.annotation.Id;
import io.micronaut.data.annotation.MappedEntity;
import io.micronaut.data.annotation.MappedProperty;
import io.micronaut.data.annotation.Relation;

@MappedEntity("ji_book")
public record Book(
@Id
@GeneratedValue
Long id,
String title,
@Nullable
@Relation(value = Relation.Kind.MANY_TO_ONE)
@MappedProperty("author")
Author author) {
public Book(Long id, String title) {
this(id, title, null);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package io.micronaut.data.jdbc.h2.joinissue;

import io.micronaut.core.annotation.Nullable;
import io.micronaut.data.annotation.GeneratedValue;
import io.micronaut.data.annotation.Id;
import io.micronaut.data.annotation.MappedEntity;
import io.micronaut.data.annotation.Relation;

import java.util.Set;

@MappedEntity("ji_director")
public class Director {

@Id
@GeneratedValue
private Long id;

private String name;

@Relation(value = Relation.Kind.ONE_TO_MANY, cascade = Relation.Cascade.ALL, mappedBy = "director")
Set<Movie> movies;

public Director(String name, @Nullable Set<Movie> movies) {
this.name = name;
this.movies = movies;
}

public Long getId() {
return id;
}

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Set<Movie> getMovies() {
return movies;
}

public void setMovies(Set<Movie> movies) {
this.movies = movies;
}

}

// @Override
// public String toString() {
// return "Director{" +
// "id=" + id +
// ", name='" + name + '\'' +
// ", movies=" + movies +
// '}';
// }
//}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.micronaut.data.jdbc.h2.joinissue;

import io.micronaut.data.annotation.Join;
import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.repository.CrudRepository;

import java.util.List;
import java.util.Optional;

@JdbcRepository(dialect = Dialect.H2)
public interface DirectorRepository extends CrudRepository<Director, Long> {

@Join(value = "movies", type= Join.Type.LEFT_FETCH)
Optional<Director> queryByName(String name);

@Join(value = "movies", type = Join.Type.LEFT_FETCH)
Optional<Director> findByNameContains(String partialName);

@Join(value = "movies", type = Join.Type.LEFT_FETCH)
List<Director> queryByNameContains(String partialName);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package io.micronaut.data.jdbc.h2.joinissue

import io.micronaut.data.jdbc.h2.H2DBProperties
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import jakarta.inject.Inject
import spock.lang.Specification

@MicronautTest
@H2DBProperties
class DirectorSpec extends Specification {

@Inject
DirectorRepository directorRepository

def 'test'() {
given:
var directorList = List.of(
new Director("John Jones",
Set.of(new Movie("Random Movie"))),
new Director("Ann Jones",
Set.of(new Movie("Super Hero Movie"),
new Movie("Anther Movie with Heroes"))))

directorRepository.saveAll(directorList)

when:
var director = directorRepository.queryByName("John Jones").orElse(null)
then:
director.getName() == "John Jones"
director.getMovies().size() == 1

when:
var list = directorRepository.queryByNameContains("n Jones")
then:
list.size() == 2
list.get(0).getName() == "John Jones"
list.get(0).getMovies().size() == 1
list.get(1).getName() == "Ann Jones"
list.get(1).getMovies().size() == 2

when:
director = directorRepository.findByNameContains("n Jones").orElse(null)
then:
director.getName() == "John Jones"
director.getMovies().size() == 1

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package io.micronaut.data.jdbc.h2.joinissue;

import io.micronaut.core.annotation.Nullable;
import io.micronaut.data.annotation.GeneratedValue;
import io.micronaut.data.annotation.Id;
import io.micronaut.data.annotation.MappedEntity;
import io.micronaut.data.annotation.MappedProperty;
import io.micronaut.data.annotation.Relation;

@MappedEntity("ji_movie")
public class Movie {

@Id
@GeneratedValue
private Long id;

private String title;

@Nullable
@Relation(Relation.Kind.MANY_TO_ONE)
@MappedProperty("director")
private Director director;

public Movie(String title) {
this.title = title;
}

public Long getId() {
return id;
}

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

public String getTitle() {
return title;
}

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

public Director getDirector() {
return director;
}

public void setDirector(Director director) {
this.director = director;
}

@Override
public String toString() {
return "Movie{" +
"id=" + id +
", title='" + title + '\'' +
", director=" + director +
'}';
}
}
1 change: 1 addition & 0 deletions data-jdbc/src/test/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ test-resources:
mssql:
accept-license: true
startup-timeout: 300s
image-name: mcr.microsoft.com/mssql/server:2022-latest
mariadb:
startup-timeout: 300s
mysql:
Expand Down
Loading
Loading