This is an automated email from the ASF dual-hosted git repository.

pcristof pushed a commit to branch OPENJPA-2940
in repository https://gitbox.apache.org/repos/asf/openjpa.git


The following commit(s) were added to refs/heads/OPENJPA-2940 by this push:
     new bef97d808 [WIP][OPENJPA-2940] Implemented ID(obj) FUNCTION on JPQL
bef97d808 is described below

commit bef97d80837cfa209f1e01a8761c9ab293acdc54
Author: Paulo Cristovão de Araújo Silva Filho <[email protected]>
AuthorDate: Mon Nov 17 08:43:38 2025 -0300

    [WIP][OPENJPA-2940] Implemented ID(obj) FUNCTION on JPQL
---
 .../jdbc/kernel/exps/GetNativeObjectId.java        | 99 ++++++++++++++++++++++
 .../openjpa/jdbc/kernel/exps/GetObjectId.java      |  2 +-
 .../jdbc/kernel/exps/JDBCExpressionFactory.java    |  8 ++
 .../openjpa/kernel/exps/ExpressionFactory.java     | 12 ++-
 .../kernel/exps/InMemoryExpressionFactory.java     |  5 ++
 .../openjpa/kernel/jpql/JPQLExpressionBuilder.java |  5 +-
 .../org/apache/openjpa/util/ApplicationIds.java    |  9 +-
 .../jpql/functions/TestEJBQLFunction.java          | 30 ++++++-
 8 files changed, 161 insertions(+), 9 deletions(-)

diff --git 
a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetNativeObjectId.java
 
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetNativeObjectId.java
new file mode 100644
index 000000000..6b22fdd50
--- /dev/null
+++ 
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetNativeObjectId.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ * http://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.apache.openjpa.jdbc.kernel.exps;
+
+import java.sql.SQLException;
+
+import org.apache.openjpa.jdbc.meta.ClassMapping;
+import org.apache.openjpa.jdbc.meta.Joinable;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.kernel.Filters;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.util.ApplicationIds;
+import org.apache.openjpa.util.Id;
+import org.apache.openjpa.util.OpenJPAId;
+
+/**
+ * Select the id value of an object; typically used in projections.
+ *
+ * @author Abe White
+ * @author Paulo Cristovão Filho
+ */
+class GetNativeObjectId
+    extends GetObjectId {
+
+    
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Constructor. Provide the value whose id to extract.
+     */
+    public GetNativeObjectId(PCPath path) {
+       super(path);
+    }
+
+    @Override
+    public Object toDataStoreValue(Select sel, ExpContext ctx, ExpState state,
+        Object val) {
+        // if datastore identity, try to convert to a long value
+        ClassMapping mapping = _path.getClassMapping(state);
+        if (mapping.getIdentityType() == ClassMetaData.ID_DATASTORE) {
+            if (val instanceof Id)
+                return ((Id) val).getId();
+            return Filters.convert(val, long.class);
+        }
+
+        // if unknown identity, can't do much
+        if (mapping.getIdentityType() == ClassMetaData.ID_UNKNOWN)
+            return (val instanceof OpenJPAId) ? ((OpenJPAId) 
val).getIdObject() : val;
+
+        // application identity; convert to pk values in the same order as
+        // the mapping's primary key columns will be returned
+        Object[] pks = ApplicationIds.toPKValues(val, mapping);
+        if (pks.length == 1)
+            return pks[0];
+        if (val == null)
+            return pks;
+        while (!mapping.isPrimaryKeyObjectId(false))
+            mapping = mapping.getJoinablePCSuperclassMapping();
+
+        Column[] cols = mapping.getPrimaryKeyColumns();
+        Object[] vals = new Object[cols.length];
+        Joinable join;
+        for (int i = 0; i < cols.length; i++) {
+            join = mapping.assertJoinable(cols[i]);
+            vals[i] = pks[mapping.getField(join.getFieldIndex()).
+                getPrimaryKeyIndex()];
+            vals[i] = join.getJoinValue(vals[i], cols[i], ctx.store);
+        }
+        return vals;
+    }
+
+    @Override
+    public Object load(ExpContext ctx, ExpState state, Result res)
+        throws SQLException {
+       Object ret = super.load(ctx, state, res);
+       return (ret != null && OpenJPAId.class.isAssignableFrom(ret.getClass()))
+                       ? ((OpenJPAId) ret).getIdObject() : ret;
+    }
+
+}
+
diff --git 
a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetObjectId.java
 
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetObjectId.java
index d3db9f8a7..b7ed40e87 100644
--- 
a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetObjectId.java
+++ 
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetObjectId.java
@@ -49,7 +49,7 @@ class GetObjectId
     private static final Localizer _loc = Localizer.forPackage
         (GetObjectId.class);
 
-    private final PCPath _path;
+    protected final PCPath _path;
     private ClassMetaData _meta = null;
 
     /**
diff --git 
a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
 
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
index a77cb9f9d..ded7d807b 100644
--- 
a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
+++ 
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
@@ -652,6 +652,14 @@ public class JDBCExpressionFactory
             return new ConstGetObjectId((Const) val);
         return new GetObjectId((PCPath) val);
     }
+    
+    @Override
+    public Value getNativeObjectId(Value val) {
+       if (val instanceof Const) {
+               return new ConstGetObjectId((Const) val);
+       }
+       return new GetNativeObjectId((PCPath) val);
+    }
 
     @Override
     public Value getMapValue(Value map, Value arg) {
diff --git 
a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
 
b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
index 80ca1ddbc..a4b19defd 100644
--- 
a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
+++ 
b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
@@ -527,14 +527,19 @@ public interface ExpressionFactory {
         *
         * @since 0.4.0.0
         */
-       Value distinct (Value obj);
+       Value distinct(Value obj);
 
        /**
         * Return the object id of the given value.
         */
-       Value getObjectId (Value val);
+       Value getObjectId(Value val);
 
-    /**
+       /**
+        * Returns the id of the given value
+        */
+       Value getNativeObjectId(Value val);
+
+       /**
      * Return a simple case expression
      */
     Value simpleCaseExpression(Value caseOperand,
@@ -580,4 +585,5 @@ public interface ExpressionFactory {
      * Return true if the Value is a Type expression and the Type uses joined 
table strategy.
      */
     boolean isVerticalType(Value val);
+
 }
diff --git 
a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
 
b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
index b0e7c0e20..654839d46 100644
--- 
a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
+++ 
b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
@@ -815,6 +815,11 @@ public class InMemoryExpressionFactory
     public Value getObjectId(Value val) {
         return new GetObjectId((Val) val);
     }
+    
+    @Override
+    public Value getNativeObjectId(Value val) {
+       return new GetObjectId((Val) val);
+    }
 
     /**
      * Key that implements hashCode and equals methods for object arrays.
diff --git 
a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
 
b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
index 4be7a8ff3..91726cd44 100644
--- 
a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
+++ 
b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
@@ -1566,7 +1566,10 @@ public class JPQLExpressionBuilder
             case JJTCASTTONUMBER:
                return factory.newTypecastAsNumber(getValue(firstChild(node)), 
                                resolveNumberTargetType((TypecastAsNumberPart) 
eval(secondChild(node))));
-
+            
+            case JJTIDFUNCTION:
+               return factory.getNativeObjectId(getValue(firstChild(node)));
+               
             default:
                 throw parseException(EX_FATAL, "bad-tree",
                     new Object[]{ node }, null);
diff --git 
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java 
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java
index 81bdd57e4..09d2731b3 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java
@@ -68,8 +68,13 @@ public class ApplicationIds {
         Object[] pks;
         if (meta.isOpenJPAIdentity()) {
             pks = new Object[1];
-            if (oid != null)
-                pks[0] = ((OpenJPAId) oid).getIdObject();
+            if (oid != null) {
+               if (oid instanceof OpenJPAId ojid) {
+                       pks[0] = ojid.getIdObject();
+               } else {
+                       pks[0]= wrap(meta, oid);
+               }
+            }
             return pks;
         }
 
diff --git 
a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java
 
b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java
index efb40cf7d..29ef52078 100644
--- 
a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java
+++ 
b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java
@@ -24,8 +24,6 @@ import java.time.LocalTime;
 import java.time.temporal.ChronoField;
 import java.util.List;
 
-import jakarta.persistence.EntityManager;
-
 import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
 import org.apache.openjpa.jdbc.sql.DBDictionary;
 import org.apache.openjpa.jdbc.sql.DerbyDictionary;
@@ -39,6 +37,8 @@ import org.apache.openjpa.persistence.common.apps.MaleUser;
 import org.apache.openjpa.persistence.common.utils.AbstractTestCase;
 import org.apache.openjpa.persistence.common.utils.DatabaseHelper;
 
+import jakarta.persistence.EntityManager;
+
 public class TestEJBQLFunction extends AbstractTestCase {
 
     private int userid1, userid2, userid3, userid4, userid5, userid6;
@@ -992,6 +992,32 @@ public class TestEJBQLFunction extends AbstractTestCase {
        
        endEm(em);
     }
+    
+    public void testIdFunction() {
+       EntityManager em = currentEntityManager();
+       
+       String query = "SELECT ID(u) FROM CompUser AS u WHERE u.name = :name";
+       
+       List result = em.createQuery(query, Integer.class).setParameter("name", 
"Seetha").getResultList();
+       
+       assertEquals(1, result.size());
+       assertEquals(userid1, result.get(0));
+       
+       endEm(em);
+    }
+
+    public void testIdFunctionOnWhere() {
+       EntityManager em = currentEntityManager();
+       
+       String query = "SELECT u.name FROM CompUser AS u WHERE id(u)= :code";
+       
+       List result = em.createQuery(query).setParameter("code", 
userid1).getResultList();
+       
+       assertEquals(1, result.size());
+       assertEquals("Seetha", (String) result.get(0));
+       
+       endEm(em);
+    }
 
     public CompUser createUser(String name, String cName, Address add, int age,
         boolean isMale) {

Reply via email to