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

[master] Jakarta Persistence 3.2 new feature - JPQL functions ID(), VERSION() #2108

Merged
merged 3 commits into from
Apr 9, 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
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@
* @author John Bracken
*/
@SuppressWarnings("nls")
final class ExpressionBuilderVisitor implements EclipseLinkExpressionVisitor {
final class ExpressionBuilderVisitor extends JPQLFunctionsAbstractBuilder implements EclipseLinkExpressionVisitor {

/**
* This visitor creates a list by retrieving either the single child or the children of the
Expand All @@ -197,11 +197,6 @@ final class ExpressionBuilderVisitor implements EclipseLinkExpressionVisitor {
*/
private Comparator<Class<?>> numericTypeComparator;

/**
* The context used to query information about the application metadata.
*/
private final JPQLQueryContext queryContext;

/**
* The EclipseLink {@link Expression} that represents a visited parsed
* {@link org.eclipse persistence.jpa.query.parser.Expression Expression}
Expand All @@ -226,9 +221,8 @@ final class ExpressionBuilderVisitor implements EclipseLinkExpressionVisitor {
* cached information
*/
ExpressionBuilderVisitor(JPQLQueryContext queryContext) {
super();
super(queryContext);
this.type = new Class<?>[1];
this.queryContext = queryContext;
}

private void appendJoinVariables(org.eclipse.persistence.jpa.jpql.parser.Expression expression,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright (c) 2024 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
*/

// Contributors:
// Oracle - initial API and implementation
//
package org.eclipse.persistence.internal.jpa.jpql;

import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.VersionLockingPolicy;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.jpa.jpql.parser.EclipseLinkAnonymousExpressionVisitor;
import org.eclipse.persistence.jpa.jpql.parser.IdExpression;
import org.eclipse.persistence.jpa.jpql.parser.IdentificationVariable;
import org.eclipse.persistence.jpa.jpql.parser.StateFieldPathExpression;
import org.eclipse.persistence.jpa.jpql.parser.VersionExpression;
import org.eclipse.persistence.mappings.DatabaseMapping;

import java.util.List;

/**
* JPQL exclusive ID(), VERSION() functions/expressions are transformed there to StateFieldPathExpression.
* It should be used in the future for another JPQL functions/expressions which are not available at the DB level.
* E.g. For Entity e with idAttr as a primary key: <code>SELECT ID(e) FROM Entity e -> SELECT e.idAttr FROM Entity e</code>
* For Entity e with versionAttr as a version attribute: <code>SELECT VERSION(e) FROM Entity e -> SELECT e.versionAttr FROM Entity e</code>
*
* @author Radek Felcman
* @since 5.0
*/
public abstract class JPQLFunctionsAbstractBuilder extends EclipseLinkAnonymousExpressionVisitor {

/**
* The {@link JPQLQueryContext} is used to query information about the application metadata and
* cached information.
*/
final JPQLQueryContext queryContext;

protected JPQLFunctionsAbstractBuilder(JPQLQueryContext queryContext) {
this.queryContext = queryContext;
}

/**
* For Entity e with idAttr as a primary key: <code>SELECT ID(e) FROM Entity e -> SELECT e.idAttr FROM Entity e</code>
*
* @param expression The {@link IdExpression} to visit
*/
@Override
public void visit(IdExpression expression) {
//Fetch identification variable info
IdentificationVariable identificationVariable = (IdentificationVariable) expression.getExpression();
String variableText = identificationVariable.getText();
String variableName = identificationVariable.getVariableName();

//Get id attribute name
ClassDescriptor descriptor = this.queryContext.getDeclaration(variableName).getDescriptor();
List<DatabaseField> primaryKeyFields = descriptor.getPrimaryKeyFields();
String idAttributeName = getIdAttributeNameByField(descriptor.getMappings(), primaryKeyFields.get(0));
StateFieldPathExpression stateFieldPathExpression = new StateFieldPathExpression(expression.getParent(), variableText + "." + idAttributeName);
expression.setStateFieldPathExpression(stateFieldPathExpression);

//Continue with created StateFieldPathExpression
//It handle by ObjectBuilder booth @Id/primary key types (simple/composite)
expression.getStateFieldPathExpression().accept(this);
}

/**
* For Entity e with versionAttr as a version attribute: <code>SELECT VERSION(e) FROM Entity e -> SELECT e.versionAttr FROM Entity e</code>
*
* @param expression The {@link VersionExpression} to visit
*/
@Override
public void visit(VersionExpression expression) {
//Fetch identification variable info
IdentificationVariable identificationVariable = (IdentificationVariable) expression.getExpression();
String variableText = identificationVariable.getText();
String variableName = identificationVariable.getVariableName();

//Get version attribute name
ClassDescriptor descriptor = this.queryContext.getDeclaration(variableName).getDescriptor();
String versionAttributeName = ((VersionLockingPolicy) descriptor.getOptimisticLockingPolicy()).getVersionMapping().getAttributeName();
StateFieldPathExpression stateFieldPathExpression = new StateFieldPathExpression(expression.getParent(), variableText + "." + versionAttributeName);
expression.setStateFieldPathExpression(stateFieldPathExpression);

//Continue with created StateFieldPathExpression
expression.getStateFieldPathExpression().accept(this);
}

private String getIdAttributeNameByField(List<DatabaseMapping> databaseMappings, DatabaseField field) {
for (DatabaseMapping mapping : databaseMappings) {
if (field.equals(mapping.getField()) || mapping.isPrimaryKeyMapping()) {
return mapping.getAttributeName();
}
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2024 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
Expand All @@ -16,7 +16,6 @@
package org.eclipse.persistence.internal.jpa.jpql;

import org.eclipse.persistence.jpa.jpql.parser.CollectionExpression;
import org.eclipse.persistence.jpa.jpql.parser.EclipseLinkAnonymousExpressionVisitor;
import org.eclipse.persistence.jpa.jpql.parser.Expression;
import org.eclipse.persistence.jpa.jpql.parser.IdentificationVariable;
import org.eclipse.persistence.jpa.jpql.parser.NullExpression;
Expand All @@ -36,19 +35,13 @@
* @author Pascal Filion
* @author John Bracken
*/
final class ReadAllQueryBuilder extends EclipseLinkAnonymousExpressionVisitor {
final class ReadAllQueryBuilder extends JPQLFunctionsAbstractBuilder {

/**
* The query that was created based on the type of select clause.
*/
ReadAllQuery query;

/**
* The {@link JPQLQueryContext} is used to query information about the application metadata and
* cached information.
*/
private final JPQLQueryContext queryContext;

/**
* The {@link Expression} being visited.
*/
Expand All @@ -61,8 +54,7 @@ final class ReadAllQueryBuilder extends EclipseLinkAnonymousExpressionVisitor {
* cached information
*/
ReadAllQueryBuilder(JPQLQueryContext queryContext) {
super();
this.queryContext = queryContext;
super(queryContext);
}

private void initializeReadAllQuery() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2024 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019 IBM Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand Down Expand Up @@ -94,7 +94,7 @@
* @author John Bracken
*/
@SuppressWarnings("nls")
final class ReportItemBuilder extends EclipseLinkAnonymousExpressionVisitor {
final class ReportItemBuilder extends JPQLFunctionsAbstractBuilder {

/**
* The visitor responsible to visit the constructor items.
Expand All @@ -111,12 +111,6 @@ final class ReportItemBuilder extends EclipseLinkAnonymousExpressionVisitor {
*/
private ReportQuery query;

/**
* The {@link JPQLQueryContext} is used to query information about the application metadata and
* cached information.
*/
private final JPQLQueryContext queryContext;

/**
* If the select expression is aliased with a result variable, then temporarily cache it so it
* can be used as the attribute name.
Expand All @@ -138,10 +132,9 @@ final class ReportItemBuilder extends EclipseLinkAnonymousExpressionVisitor {
* tree representation of the JPQL query
*/
ReportItemBuilder(JPQLQueryContext queryContext, ReportQuery query) {
super();
super(queryContext);
this.query = query;
this.type = new Class<?>[1];
this.queryContext = queryContext;
}

private void addAttribute(String generateName, Expression queryExpression) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@
* @author Pascal Filion
*/
@SuppressWarnings("nls")
final class TypeResolver implements EclipseLinkExpressionVisitor {
final class TypeResolver extends JPQLFunctionsAbstractBuilder implements EclipseLinkExpressionVisitor {

/**
* This visitor is responsible to retrieve the {@link CollectionExpression} if it is visited.
Expand All @@ -179,11 +179,6 @@ final class TypeResolver implements EclipseLinkExpressionVisitor {
*/
private PathResolver pathResolver;

/**
* The context used to query information about the application metadata and cached information.
*/
private final JPQLQueryContext queryContext;

/**
* The well defined type, which does not have to be calculated.
*/
Expand All @@ -201,8 +196,7 @@ final class TypeResolver implements EclipseLinkExpressionVisitor {
* cached information
*/
TypeResolver(JPQLQueryContext queryContext) {
super();
this.queryContext = queryContext;
super(queryContext);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ public class TestVersioning {
value = "UseNationalCharacterVaryingTypeForString=true")})
private EntityManagerFactory emf;

private final static String qStr1 = "UPDATE TemporalVersionedEntity " +
private final static String qStr1 = "UPDATE TemporalVersionedEntity " +
"SET updatetimestamp = ?3 " +
"WHERE id = ?1 AND updatetimestamp = ?2";

private final static String qStr2 = "UPDATE TemporalVersionedEntity2 " +
private final static String qStr2 = "UPDATE TemporalVersionedEntity2 " +
"SET version = ?3 " +
"WHERE id = ?1 AND version = ?2";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!--

Copyright (c) 2018, 2022 Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2018, 2024 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
Expand Down Expand Up @@ -40,6 +40,7 @@
<class>org.eclipse.persistence.testing.models.jpa.advanced.Room</class>
<class>org.eclipse.persistence.testing.models.jpa.advanced.SmallProject</class>
<class>org.eclipse.persistence.testing.models.jpa.advanced.SimpleRoom</class>
<class>org.eclipse.persistence.testing.models.jpa.advanced.Vegetable</class>
<class>org.eclipse.persistence.testing.models.jpa.advanced.Woman</class>
<class>org.eclipse.persistence.testing.models.jpa.advanced.WorldRank</class>
<class>org.eclipse.persistence.testing.models.jpa.advanced.entities.EntyA</class>
Expand Down
Loading
Loading