Skip to content

Commit

Permalink
jakartaee/persistence#457 - add union/intersect/except to JPQL and cr…
Browse files Browse the repository at this point in the history
…iteria

Fixed failing tests, code cleanup.

Signed-off-by: Tomáš Kraus <tomas.kraus@oracle.com>
  • Loading branch information
Tomas-Kraus authored and lukasj committed Nov 30, 2023
1 parent 4b8b11c commit 87f54d9
Show file tree
Hide file tree
Showing 17 changed files with 217 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ protected static FieldDefinition createNumericPk(
field.setSize(size);
field.setShouldAllowNull(false);
field.setIsPrimaryKey(true);
field.setUnique(true);
field.setUnique(false);
field.setIsIdentity(true);
return field;
}
Expand All @@ -210,7 +210,6 @@ protected static FieldDefinition createNumericPk(final String name) {
* @param fkName Foreign key name (e.g. {@code "MY_TABLE.ID"}.
* @param allowNull Allow {@code null} values for column.
* @return Initialized {@link FieldDefinition} instance.
* @noinspection SameParameterValue
*/
protected static FieldDefinition createNumericFk(
final String name, final int size, final String fkName, final boolean allowNull) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,13 @@ protected Expression prepareJoinExpression(Expression expression, AbstractSessio
}
objectExpression.getBuilder().setSession(session.getRootSession(null));

// Sometimes current expression builder does not support expression class mapping.
// Try ExpressionBuilder for the descriptor's class
if (objectExpression.getMapping() == null && objectExpression.getBuilder().getQueryClass() != descriptor.getJavaClass()) {
objectExpression = (QueryKeyExpression)objectExpression.rebuildOn(new ExpressionBuilder(descriptor.getJavaClass()));
objectExpression.getBuilder().setSession(session.getRootSession(null));
}

// Can only join relationships.
if ((objectExpression.getMapping() == null) || (!objectExpression.getMapping().isJoiningSupported())) {
throw QueryException.mappingForExpressionDoesNotSupportJoining(objectExpression);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ private enum ResultStatus { IGNORED };
* The builder should be provided.
*/
public ReportQuery() {
super();
this.queryMechanism = new ExpressionQueryMechanism(this);
this.items = new ArrayList<>();
this.shouldRetrievePrimaryKeys = NO_PRIMARY_KEY;
Expand Down Expand Up @@ -770,15 +769,15 @@ public Object clone() {
* Each call to copiedVersionFrom() will take O(1) time as the expression was
* already cloned.
*/
public void copyReportItems(Map alreadyDone) {
public void copyReportItems(Map<Expression, Expression> alreadyDone) {
this.items = new ArrayList<>(this.items);
for (int i = this.items.size() - 1; i >= 0; i--) {
ReportItem item = this.items.get(i);
Expression expression = item.getAttributeExpression();
if ((expression != null) && (alreadyDone.get(expression.getBuilder()) != null)) {
expression = expression.copiedVersionFrom(alreadyDone);
if (item.isConstructorItem()) {
this.items.set(i, copyConstructorReportItem((ConstructorReportItem) item, alreadyDone));
} else {
this.items.set(i, copyReportItem(item, alreadyDone));
}
this.items.set(i, (ReportItem) item.clone());
}
if (this.groupByExpressions != null) {
this.groupByExpressions = new ArrayList<>(this.groupByExpressions);
Expand All @@ -802,6 +801,39 @@ public void copyReportItems(Map alreadyDone) {
}
}

// copyReportItems helper
private static ConstructorReportItem copyConstructorReportItem(ConstructorReportItem reportItem, Map<Expression, Expression> alreadyDone) {
// Copy ReportItems list if exists
List<ReportItem> reportItems = reportItem.getReportItems();
List<ReportItem> newReportItems = reportItems != null ? new ArrayList<>(reportItems.size()) : null;
if (reportItems != null) {
for (ReportItem item : reportItems) {
newReportItems.add(copyReportItem(item, alreadyDone));
}
}
// Create new ConstructorReportItem
ConstructorReportItem newItem = new ConstructorReportItem(reportItem.getName());
newItem.setConstructor(reportItem.getConstructor());
newItem.setResultType(reportItem.getResultType());
newItem.setReportItems(newReportItems);
newItem.setAttributeExpression(copyAttributeExpression(reportItem, alreadyDone));
return newItem;
}

// copyReportItems helper
private static Expression copyAttributeExpression(ReportItem reportItem, Map<Expression, Expression> alreadyDone) {
Expression expression = reportItem.getAttributeExpression();
if ((expression != null) && (alreadyDone.get(expression.getBuilder()) != null)) {
expression = expression.copiedVersionFrom(alreadyDone);
}
return expression;
}

// copyReportItems helper
private static ReportItem copyReportItem(ReportItem reportItem, Map<Expression, Expression> alreadyDone) {
return new ReportItem(reportItem.getName(), copyAttributeExpression(reportItem, alreadyDone));
}

/**
* PUBLIC:
* Set if the query results should contain the primary keys or each associated object.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

package org.eclipse.persistence.testing.models.jpa.persistence32;

import org.eclipse.persistence.testing.framework.TogglingFastTableCreator;
Expand All @@ -19,18 +18,28 @@ public class Persistence32TableCreator extends TogglingFastTableCreator {

public Persistence32TableCreator() {
setName("Persistence32Project");
addTableDefinition(buildTeamTable());
addTableDefinition(buildTrainerTable());
addTableDefinition(buildTypeTable());
addTableDefinition(buildPokemonTable());
addTableDefinition(buildPokemonTypeTable());
addTableDefinition(buildSyntaxEntityTable());
}

public static TableDefinition buildTeamTable() {
TableDefinition table = new TableDefinition();
table.setName("PERSISTENCE32_TEAM");
table.addField(createNumericPk("ID"));
table.addField(createStringColumn("NAME", 64, false));
return table;
}

public static TableDefinition buildTrainerTable() {
TableDefinition table = new TableDefinition();
table.setName("PERSISTENCE32_TRAINER");
table.addField(createNumericPk("ID"));
table.addField(createStringColumn("NAME", 64, false));
table.addField(createNumericFk("TEAM_ID", 15,"PERSISTENCE32_TEAM.ID", false));
return table;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

package org.eclipse.persistence.testing.models.jpa.persistence32;

import java.util.Collection;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
package org.eclipse.persistence.testing.models.jpa.persistence32;

import java.time.LocalDate;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
package org.eclipse.persistence.testing.models.jpa.persistence32;

import java.util.Objects;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.NamedNativeQuery;
import jakarta.persistence.Table;

@Entity
@Table(name="PERSISTENCE32_TEAM")
@NamedNativeQuery(name="Team.deleteAll", query="DELETE FROM PERSISTENCE32_TEAM")
public class Team {

// ID is assigned in tests to avoid collisions
@Id
private int id;

private String name;

public Team() {
}

public Team(int id, String name) {
this.id = id;
this.name = name;
}

public int getId() {
return id;
}

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

public String getName() {
return name;
}

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

@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
return id == ((Team) obj).id
&& Objects.equals(name, ((Team) obj).name);
}

@Override
public int hashCode() {
int result = Objects.hash(id, name);
return result;
}


}
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
package org.eclipse.persistence.testing.models.jpa.persistence32;

import java.util.List;
import java.util.Objects;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.NamedNativeQuery;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import org.eclipse.persistence.annotations.JoinFetch;
import org.eclipse.persistence.annotations.JoinFetchType;
import org.eclipse.persistence.annotations.Property;

import static jakarta.persistence.FetchType.EAGER;

@Entity
@Table(name="PERSISTENCE32_TRAINER")
Expand All @@ -20,12 +40,19 @@ public class Trainer {

private String name;

@ManyToOne
private Team team;

@OneToMany(mappedBy = "trainer")
private List<Pokemon> pokemons;

public Trainer() {
}

public Trainer(int id, String name) {
public Trainer(int id, String name, Team team) {
this.id = id;
this.name = name;
this.team = team;
}

public int getId() {
Expand All @@ -44,6 +71,22 @@ public void setName(String name) {
this.name = name;
}

public Team getTeam() {
return team;
}

public void setTeam(Team team) {
this.team = team;
}

public List<Pokemon> getPokemons() {
return pokemons;
}

public void setPokemons(List<Pokemon> pokemons) {
this.pokemons = pokemons;
}

@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != this.getClass()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

package org.eclipse.persistence.testing.models.jpa.persistence32;

import java.util.Objects;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
-->

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
Expand All @@ -21,6 +20,7 @@
<!-- This is the default persistence unit -->
<persistence-unit name="persistence32" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>org.eclipse.persistence.testing.models.jpa.persistence32.Team</class>
<class>org.eclipse.persistence.testing.models.jpa.persistence32.Trainer</class>
<class>org.eclipse.persistence.testing.models.jpa.persistence32.Pokemon</class>
<class>org.eclipse.persistence.testing.models.jpa.persistence32.Type</class>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

package org.eclipse.persistence.testing.tests.jpa.persistence32;

import java.util.HashMap;
Expand All @@ -21,6 +20,7 @@
import org.eclipse.persistence.jpa.JpaEntityManagerFactory;
import org.eclipse.persistence.testing.framework.jpa.junit.JUnitTestCase;
import org.eclipse.persistence.testing.models.jpa.persistence32.Persistence32TableCreator;
import org.eclipse.persistence.testing.models.jpa.persistence32.Team;
import org.eclipse.persistence.testing.models.jpa.persistence32.Trainer;
import org.eclipse.persistence.testing.models.jpa.persistence32.Type;

Expand All @@ -29,12 +29,18 @@
*/
public abstract class AbstractPokemon extends JUnitTestCase {

// Trainer's teams
static final Team[] TEAMS = new Team[] {
null, // Skip array index 0
new Team(1, "Kanto")
};

// Pokemon trainers. Array index is ID value.
// Value of ID = 0 does not exist so it's array instance is set to null.
static final Trainer[] TRAINERS = new Trainer[] {
null, // Skip array index 0
new Trainer(1, "Ash"),
new Trainer(2, "Brock")
new Trainer(1, "Ash", TEAMS[1]),
new Trainer(2, "Brock", TEAMS[1])
};

// Pokemon types. Array index is ID value.
Expand Down Expand Up @@ -125,6 +131,9 @@ public void testSetup() {
new Persistence32TableCreator().replaceTables(JUnitTestCase.getServerSession(getPersistenceUnitName()));
clearCache();
emf.runInTransaction(em -> {
for (int i = 1; i < TEAMS.length; i++) {
em.persist(TEAMS[i]);
}
for (int i = 1; i < TRAINERS.length; i++) {
em.persist(TRAINERS[i]);
}
Expand All @@ -144,6 +153,7 @@ public void testCleanup() {
em.createNamedQuery("Pokemon.deleteAll").executeUpdate();
em.createNamedQuery("Type.deleteAll").executeUpdate();
em.createNamedQuery("Trainer.deleteAll").executeUpdate();
em.createNamedQuery("Team.deleteAll").executeUpdate();
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

package org.eclipse.persistence.testing.tests.jpa.persistence32;

import java.time.LocalDate;
Expand Down

0 comments on commit 87f54d9

Please sign in to comment.