-
Notifications
You must be signed in to change notification settings - Fork 200
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: @query with projection and List<List>
- Loading branch information
Showing
7 changed files
with
392 additions
and
0 deletions.
There are no files selected for viewing
99 changes: 99 additions & 0 deletions
99
...te-jpa/src/test/groovy/io/micronaut/data/hibernate/querygroupby/TaskRepositorySpec.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package io.micronaut.data.hibernate.querygroupby | ||
|
||
import io.micronaut.context.annotation.Property | ||
import io.micronaut.data.hibernate.entities.MicronautProject | ||
import io.micronaut.data.hibernate.entities.MicronautTask | ||
import io.micronaut.test.extensions.spock.annotation.MicronautTest | ||
import jakarta.inject.Inject | ||
import spock.lang.PendingFeature | ||
import spock.lang.Specification | ||
|
||
import java.time.LocalDate | ||
|
||
@MicronautTest(startApplication = false, packages = "io.micronaut.data.hibernate.entities") | ||
@Property(name = "datasources.default.name", value = "mydb") | ||
@Property(name = 'jpa.default.properties.hibernate.hbm2ddl.auto', value = 'create-drop') | ||
class TaskRepositorySpec extends Specification { | ||
|
||
@Inject | ||
MicronautProjectRepository projectRepository | ||
|
||
@Inject | ||
MicronautTaskRepository taskRepository | ||
|
||
@PendingFeature | ||
void "@Query projecting to a POJO"() { | ||
given: | ||
MicronautProject p1 = projectRepository.save(new MicronautProject("P1", "Project 1", "Description of Project 1")) | ||
MicronautProject p2 = projectRepository.save(new MicronautProject("P2", "Project 2", "Description of Project 2")) | ||
MicronautProject p3 = projectRepository.save(new MicronautProject("P3", "Project 3", "Description of Project 3")) | ||
MicronautTask t1 = taskRepository.save(new MicronautTask("Task 1", "Task 1 Description", LocalDate.of(2025, 1, 12), p1, TaskStatus.TO_DO)) | ||
MicronautTask t2 = taskRepository.save(new MicronautTask("Task 2", "Task 2 Description", LocalDate.of(2025, 2, 10), p1, TaskStatus.TO_DO)) | ||
MicronautTask t3 = taskRepository.save(new MicronautTask("Task 3", "Task 3 Description", LocalDate.of(2025, 3, 16), p1, TaskStatus.TO_DO)) | ||
MicronautTask t4 = taskRepository.save(new MicronautTask("Task 4", "Task 4 Description", LocalDate.of(2025, 6, 25), p1, TaskStatus.IN_PROGRESS)) | ||
|
||
expect: | ||
3 == countIterableElements(projectRepository.findAll()) | ||
|
||
4 == countIterableElements(taskRepository.findAll()) | ||
|
||
when: | ||
Iterable<TasksPerYear> tasks = taskRepository.countByDueYear() | ||
|
||
then: | ||
2 == countIterableElements(tasks) | ||
|
||
cleanup: | ||
taskRepository.delete(t4) | ||
taskRepository.delete(t3) | ||
taskRepository.delete(t2) | ||
taskRepository.delete(t1) | ||
projectRepository.delete(p3) | ||
projectRepository.delete(p2) | ||
projectRepository.delete(p1) | ||
} | ||
|
||
@PendingFeature | ||
void "@Query returning List of List"() { | ||
given: | ||
MicronautProject p1 = projectRepository.save(new MicronautProject("P1", "Project 1", "Description of Project 1")) | ||
MicronautProject p2 = projectRepository.save(new MicronautProject("P2", "Project 2", "Description of Project 2")) | ||
MicronautProject p3 = projectRepository.save(new MicronautProject("P3", "Project 3", "Description of Project 3")) | ||
MicronautTask t1 = taskRepository.save(new MicronautTask("Task 1", "Task 1 Description", LocalDate.of(2025, 1, 12), p1, TaskStatus.TO_DO)) | ||
MicronautTask t2 = taskRepository.save(new MicronautTask("Task 2", "Task 2 Description", LocalDate.of(2025, 2, 10), p1, TaskStatus.TO_DO)) | ||
MicronautTask t3 = taskRepository.save(new MicronautTask("Task 3", "Task 3 Description", LocalDate.of(2025, 3, 16), p1, TaskStatus.TO_DO)) | ||
MicronautTask t4 = taskRepository.save(new MicronautTask("Task 4", "Task 4 Description", LocalDate.of(2025, 6, 25), p1, TaskStatus.IN_PROGRESS)) | ||
|
||
expect: | ||
3 == countIterableElements(projectRepository.findAll()) | ||
|
||
4 == countIterableElements(taskRepository.findAll()) | ||
when: | ||
List<List<Integer>> tasks = taskRepository.countByDueYearReturnList() | ||
|
||
then: | ||
2 == tasks.size() | ||
tasks.every { it.size() == 2 } | ||
|
||
cleanup: | ||
taskRepository.delete(t4) | ||
taskRepository.delete(t3) | ||
taskRepository.delete(t2) | ||
taskRepository.delete(t1) | ||
projectRepository.delete(p3) | ||
projectRepository.delete(p2) | ||
projectRepository.delete(p1) | ||
} | ||
|
||
static int countIterableElements(Iterable<?> iterable) { | ||
int count = 0 | ||
Iterator<?> iterator = iterable.iterator() | ||
if (iterator.hasNext()) { | ||
do { | ||
iterator.next() | ||
count++ | ||
} while (iterator.hasNext()) | ||
} | ||
count | ||
} | ||
} |
101 changes: 101 additions & 0 deletions
101
data-hibernate-jpa/src/test/java/io/micronaut/data/hibernate/entities/MicronautProject.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package io.micronaut.data.hibernate.entities; | ||
|
||
import javax.persistence.CascadeType; | ||
import javax.persistence.Column; | ||
import javax.persistence.Entity; | ||
import javax.persistence.FetchType; | ||
import javax.persistence.GeneratedValue; | ||
import javax.persistence.GenerationType; | ||
import javax.persistence.Id; | ||
import javax.persistence.OneToMany; | ||
import java.util.HashSet; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
|
||
@Entity | ||
public class MicronautProject { | ||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
@Column(unique = true, nullable = false, updatable = false) | ||
private String code; | ||
private String name; | ||
private String description; | ||
@OneToMany(mappedBy = "project", orphanRemoval = true, fetch = FetchType.EAGER, cascade = CascadeType.ALL) | ||
private Set<MicronautTask> tasks = new HashSet<>(); | ||
public MicronautProject() { | ||
} | ||
|
||
public MicronautProject(String code, String name, String description) { | ||
this.code = code; | ||
this.name = name; | ||
this.description = description; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hashCode(code); | ||
} | ||
@Override | ||
public boolean equals(Object obj) { | ||
if (this == obj) | ||
return true; | ||
if (obj == null) | ||
return false; | ||
if (getClass() != obj.getClass()) | ||
return false; | ||
MicronautProject other = (MicronautProject) obj; | ||
if (code == null) { | ||
if (other.code != null) | ||
return false; | ||
} else if (!code.equals(other.code)) | ||
return false; | ||
return true; | ||
} | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public void setId(Long id) { | ||
this.id = id; | ||
} | ||
|
||
public String getCode() { | ||
return code; | ||
} | ||
|
||
public void setCode(String code) { | ||
this.code = code; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public void setName(String name) { | ||
this.name = name; | ||
} | ||
|
||
public String getDescription() { | ||
return description; | ||
} | ||
|
||
public void setDescription(String description) { | ||
this.description = description; | ||
} | ||
|
||
public Set<MicronautTask> getTasks() { | ||
return tasks; | ||
} | ||
|
||
public void setTasks(Set<MicronautTask> tasks) { | ||
this.tasks = tasks; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "Project [id=" + id + ", code=" + code + ", name=" + name + ", description=" + description + "]"; | ||
} | ||
|
||
} |
130 changes: 130 additions & 0 deletions
130
data-hibernate-jpa/src/test/java/io/micronaut/data/hibernate/entities/MicronautTask.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
package io.micronaut.data.hibernate.entities; | ||
|
||
import io.micronaut.data.hibernate.querygroupby.TaskStatus; | ||
|
||
import javax.persistence.Column; | ||
import javax.persistence.Entity; | ||
import javax.persistence.GeneratedValue; | ||
import javax.persistence.GenerationType; | ||
import javax.persistence.Id; | ||
import javax.persistence.ManyToOne; | ||
import java.time.LocalDate; | ||
import java.util.Objects; | ||
import java.util.UUID; | ||
|
||
@Entity | ||
public class MicronautTask { | ||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
@Column(unique = true, nullable = false, updatable = false) | ||
private String uuid = UUID.randomUUID().toString(); | ||
private String name; | ||
private String description; | ||
private LocalDate dueDate; | ||
|
||
private TaskStatus status; | ||
|
||
@ManyToOne(optional = false) | ||
private MicronautProject project; | ||
|
||
|
||
public MicronautTask() { | ||
} | ||
public MicronautTask(String name, String description, LocalDate dueDate, MicronautProject project) { | ||
this(name, description, dueDate, project, TaskStatus.TO_DO); | ||
} | ||
|
||
public MicronautTask(String name, String description, LocalDate dueDate, MicronautProject project, TaskStatus status) { | ||
this.name = name; | ||
this.description = description; | ||
this.dueDate = dueDate; | ||
this.status = status; | ||
this.project = project; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (this == obj) | ||
return true; | ||
if (obj == null) | ||
return false; | ||
if (getClass() != obj.getClass()) | ||
return false; | ||
MicronautTask other = (MicronautTask) obj; | ||
if (uuid == null) { | ||
if (other.uuid != null) | ||
return false; | ||
} else if (!uuid.equals(other.uuid)) | ||
return false; | ||
return true; | ||
} | ||
@Override | ||
public int hashCode() { | ||
return Objects.hash(uuid); | ||
} | ||
|
||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public void setId(Long id) { | ||
this.id = id; | ||
} | ||
|
||
public String getUuid() { | ||
return uuid; | ||
} | ||
|
||
public void setUuid(String uuid) { | ||
this.uuid = uuid; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public void setName(String name) { | ||
this.name = name; | ||
} | ||
|
||
public String getDescription() { | ||
return description; | ||
} | ||
|
||
public void setDescription(String description) { | ||
this.description = description; | ||
} | ||
|
||
public LocalDate getDueDate() { | ||
return dueDate; | ||
} | ||
|
||
public void setDueDate(LocalDate dueDate) { | ||
this.dueDate = dueDate; | ||
} | ||
|
||
public TaskStatus getStatus() { | ||
return status; | ||
} | ||
|
||
public void setStatus(TaskStatus status) { | ||
this.status = status; | ||
} | ||
|
||
public MicronautProject getProject() { | ||
return project; | ||
} | ||
|
||
public void setProject(MicronautProject project) { | ||
this.project = project; | ||
} | ||
|
||
|
||
@Override | ||
public String toString() { | ||
return "Task [id=" + id + ", name=" + name + ", description=" + description + ", dueDate=" + dueDate + ", status=" + status + ", project=" + project + "]"; | ||
} | ||
|
||
} |
8 changes: 8 additions & 0 deletions
8
...pa/src/test/java/io/micronaut/data/hibernate/querygroupby/MicronautProjectRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package io.micronaut.data.hibernate.querygroupby; | ||
|
||
import io.micronaut.data.annotation.Repository; | ||
import io.micronaut.data.hibernate.entities.MicronautProject; | ||
import io.micronaut.data.repository.CrudRepository; | ||
@Repository | ||
public interface MicronautProjectRepository extends CrudRepository<MicronautProject, Long> { | ||
} |
16 changes: 16 additions & 0 deletions
16
...e-jpa/src/test/java/io/micronaut/data/hibernate/querygroupby/MicronautTaskRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package io.micronaut.data.hibernate.querygroupby; | ||
|
||
import io.micronaut.data.annotation.Query; | ||
import io.micronaut.data.annotation.Repository; | ||
import io.micronaut.data.hibernate.entities.MicronautTask; | ||
import io.micronaut.data.repository.CrudRepository; | ||
|
||
import java.util.List; | ||
@Repository | ||
public interface MicronautTaskRepository extends CrudRepository<MicronautTask, Long> { | ||
@Query("select count(*), year(t.dueDate) from MicronautTask t group by year(t.dueDate)") | ||
Iterable<TasksPerYear> countByDueYear(); | ||
|
||
@Query("select count(*), year(t.dueDate) from MicronautTask t group by year(t.dueDate)") | ||
List<List<Integer>> countByDueYearReturnList(); | ||
} |
16 changes: 16 additions & 0 deletions
16
data-hibernate-jpa/src/test/java/io/micronaut/data/hibernate/querygroupby/TaskStatus.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package io.micronaut.data.hibernate.querygroupby; | ||
|
||
public enum TaskStatus { | ||
TO_DO("To Do"), | ||
IN_PROGRESS("In Progress"), | ||
ON_HOLD("On Hold"), | ||
DONE("Done"); | ||
private final String label; | ||
|
||
private TaskStatus(String label) { | ||
this.label = label; | ||
} | ||
public String getLabel() { | ||
return label; | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
data-hibernate-jpa/src/test/java/io/micronaut/data/hibernate/querygroupby/TasksPerYear.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package io.micronaut.data.hibernate.querygroupby; | ||
|
||
import io.micronaut.core.annotation.Introspected; | ||
|
||
@Introspected | ||
public class TasksPerYear { | ||
private final String number; | ||
private final String year; | ||
|
||
public TasksPerYear(String number, String year) { | ||
this.number = number; | ||
this.year = year; | ||
} | ||
|
||
public String getNumber() { | ||
return number; | ||
} | ||
|
||
public String getYear() { | ||
return year; | ||
} | ||
} |