Skip to content

Commit

Permalink
Merge pull request #28339 from njr-11/22762-jdql-update-and-delete-wi…
Browse files Browse the repository at this point in the history
…th-record-entity

JDQL update and delete with record entity, and omitted select clause returning different type
  • Loading branch information
njr-11 committed May 4, 2024
2 parents c810a5d + 15c8f48 commit 0c892b3
Show file tree
Hide file tree
Showing 10 changed files with 273 additions and 172 deletions.
Expand Up @@ -36,6 +36,7 @@
import com.ibm.websphere.ras.annotation.Trivial;
import com.ibm.ws.ffdc.annotation.FFDCIgnore;

import io.openliberty.data.internal.persistence.cdi.DataExtensionProvider;
import jakarta.persistence.EntityManager;
import jakarta.persistence.metamodel.Attribute;
import jakarta.persistence.metamodel.Attribute.PersistentAttributeType;
Expand Down Expand Up @@ -65,13 +66,19 @@ public abstract class EntityManagerBuilder implements Runnable {
*/
final ConcurrentHashMap<Class<?>, CompletableFuture<EntityInfo>> entityInfoMap = new ConcurrentHashMap<>();

/**
* OSGi service component that provides the CDI extension for Data.
*/
final DataExtensionProvider provider;

/**
* The class loader for repository classes.
*/
private final ClassLoader repositoryClassLoader;

@Trivial
protected EntityManagerBuilder(ClassLoader repositoryClassLoader) {
protected EntityManagerBuilder(DataExtensionProvider provider, ClassLoader repositoryClassLoader) {
this.provider = provider;
this.repositoryClassLoader = repositoryClassLoader;
}

Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Expand Up @@ -204,7 +204,7 @@ public void afterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager b
EntityManagerFactory emf = instance.get();

if (emBuilder == null)
emBuilder = new PUnitEMBuilder(emf, loader);
emBuilder = new PUnitEMBuilder(emf, loader, provider);
else
throw new UnsupportedOperationException//
("The " + method.getName() + " resource accessor method of the " +
Expand All @@ -225,7 +225,7 @@ public void afterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager b
try {
Object resource = InitialContext.doLookup(dataStore);
if (resource instanceof EntityManagerFactory)
emBuilder = new PUnitEMBuilder((EntityManagerFactory) resource, dataStore, loader);
emBuilder = new PUnitEMBuilder((EntityManagerFactory) resource, dataStore, loader, provider);

if (trace && tc.isDebugEnabled())
Tr.debug(this, tc, dataStore + " is the JNDI name for " + resource);
Expand All @@ -238,7 +238,7 @@ public void afterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager b
Object resource = InitialContext.doLookup(javaCompName);

if (resource instanceof EntityManagerFactory)
emBuilder = new PUnitEMBuilder((EntityManagerFactory) resource, javaCompName, loader);
emBuilder = new PUnitEMBuilder((EntityManagerFactory) resource, javaCompName, loader, provider);

if (emBuilder != null || resource instanceof DataSource) {
isJNDIName = true;
Expand Down
Expand Up @@ -20,6 +20,7 @@
import com.ibm.ws.threadContext.ComponentMetaDataAccessorImpl;

import io.openliberty.data.internal.persistence.EntityManagerBuilder;
import io.openliberty.data.internal.persistence.cdi.DataExtensionProvider;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;

Expand All @@ -37,8 +38,8 @@ public class PUnitEMBuilder extends EntityManagerBuilder {

private final String persistenceUnitRef;

public PUnitEMBuilder(EntityManagerFactory emf, ClassLoader repositoryClassLoader) {
super(repositoryClassLoader);
public PUnitEMBuilder(EntityManagerFactory emf, ClassLoader repositoryClassLoader, DataExtensionProvider provider) {
super(provider, repositoryClassLoader);
this.emf = emf;
this.persistenceUnitRef = emf.toString();

Expand All @@ -52,8 +53,9 @@ public PUnitEMBuilder(EntityManagerFactory emf, ClassLoader repositoryClassLoade
// DataStoreTestApp#DataStoreTestWeb.war, org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl@3708cabf]
}

public PUnitEMBuilder(EntityManagerFactory emf, String persistenceUnitRef, ClassLoader repositoryClassLoader) {
super(repositoryClassLoader);
public PUnitEMBuilder(EntityManagerFactory emf, String persistenceUnitRef,
ClassLoader repositoryClassLoader, DataExtensionProvider provider) {
super(provider, repositoryClassLoader);
this.emf = emf;
this.persistenceUnitRef = persistenceUnitRef;

Expand Down
Expand Up @@ -121,7 +121,7 @@ public class DBStoreEMBuilder extends EntityManagerBuilder {
public DBStoreEMBuilder(String dataStore, boolean isConfigDisplayId, boolean isJNDIName,
AnnotatedType<?> type, ClassLoader repositoryClassLoader,
DataExtensionProvider provider) {
super(repositoryClassLoader);
super(provider, repositoryClassLoader);
final boolean trace = TraceComponent.isAnyTracingEnabled();

ComponentMetaData cData = ComponentMetaDataAccessorImpl.getComponentMetaDataAccessor().getComponentMetaData();
Expand Down
Expand Up @@ -3592,7 +3592,11 @@ public void testRecordInFromClause() {
assertEquals(20.98f, receipts.totalOf(2000L), 0.001f);
assertEquals(15.99f, receipts.totalOf(2001L), 0.001f);

receipts.deleteByTotalLessThan(2000.0f);
assertEquals(true, receipts.addTax(2001L, 0.0813f));

assertEquals(17.29f, receipts.totalOf(2001L), 0.001f);

assertEquals(2, receipts.removeIfTotalUnder(2000.0f));
}

/**
Expand Down
Expand Up @@ -26,6 +26,9 @@
*/
@Repository
public interface Receipts extends CrudRepository<Receipt, Long> {
@Query("UPDATE Receipt SET total = total * (1.0 + :taxRate) WHERE purchaseId = :id")
boolean addTax(long id, float taxRate);

@Query("SELECT COUNT(this)")
long count();

Expand All @@ -42,6 +45,9 @@ public interface Receipts extends CrudRepository<Receipt, Long> {

Stream<Receipt> findByPurchaseIdIn(Iterable<Long> ids);

@Query("DELETE FROM Receipt WHERE total < :max")
int removeIfTotalUnder(float max);

@Query("SELECT total FROM Receipt WHERE purchaseId=:id")
float totalOf(long id);
}
Expand Up @@ -2458,6 +2458,66 @@ public void testParenthesisInsertionForCursorPagination() {
assertEquals(false, page3.hasNext());
}

/**
* Use a repository method that runs a query without specifying an entity type
* and returns a record entity. The repository must be able to infer the record type
* to use from the return value and generate the proper select clause so that the
* generated entity type is converted to the record type.
*/
@Test
public void testRecordQueryInfersSelectClause() {

Rebate r1 = new Rebate(10, 10.00, "testRecordEntityInferredFromReturnType-CustomerA", //
LocalTime.of(15, 40, 0), //
LocalDate.of(2024, Month.MAY, 1), //
Rebate.Status.PAID, //
LocalDateTime.of(2024, Month.MAY, 1, 15, 40, 0), //
null);

Rebate r2 = new Rebate(12, 12.00, "testRecordEntityInferredFromReturnType-CustomerA", //
LocalTime.of(12, 46, 30), //
LocalDate.of(2024, Month.APRIL, 5), //
Rebate.Status.PAID, //
LocalDateTime.of(2024, Month.MAY, 2, 10, 18, 0), //
null);

Rebate r3 = new Rebate(13, 3.00, "testRecordEntityInferredFromReturnType-CustomerB", //
LocalTime.of(9, 15, 0), //
LocalDate.of(2024, Month.MAY, 2), //
Rebate.Status.PAID, //
LocalDateTime.of(2024, Month.MAY, 2, 9, 15, 0), //
null);

Rebate r4 = new Rebate(14, 4.00, "testRecordEntityInferredFromReturnType-CustomerA", //
LocalTime.of(10, 55, 0), //
LocalDate.of(2024, Month.MAY, 1), //
Rebate.Status.VERIFIED, //
LocalDateTime.of(2024, Month.MAY, 2, 14, 27, 45), //
null);

Rebate r5 = new Rebate(15, 5.00, "testRecordEntityInferredFromReturnType-CustomerA", //
LocalTime.of(17, 50, 0), //
LocalDate.of(2024, Month.MAY, 1), //
Rebate.Status.PAID, //
LocalDateTime.of(2024, Month.MAY, 5, 15, 5, 0), //
null);

Rebate[] all = rebates.addAll(r1, r2, r3, r4, r5);

List<Rebate> paid = rebates.paidTo("testRecordEntityInferredFromReturnType-CustomerA");

assertEquals(paid.toString(), 3, paid.size());
Rebate r;
r = paid.get(0);
assertEquals(12.0f, r.amount(), 0.001);
r = paid.get(1);
assertEquals(10.0f, r.amount(), 0.001);
r = paid.get(2);
assertEquals(5.0f, r.amount(), 0.001);

rebates.removeAll(all);
}

/**
* Tests lifecycle methods returning a single record.
*/
Expand Down
Expand Up @@ -18,6 +18,7 @@

import jakarta.data.repository.Delete;
import jakarta.data.repository.Insert;
import jakarta.data.repository.Query;
import jakarta.data.repository.Repository;
import jakarta.data.repository.Save;
import jakarta.data.repository.Update;
Expand Down Expand Up @@ -45,6 +46,9 @@ public interface Rebates { // Do not allow this interface to inherit from other
@Update
List<Rebate> modifyMultiple(List<Rebate> r);

@Query("WHERE customerId=?1 AND status=test.jakarta.data.jpa.web.Rebate.Status.PAID ORDER BY amount DESC, id ASC")
List<Rebate> paidTo(String customerId);

@Save
Rebate process(Rebate r);

Expand Down

0 comments on commit 0c892b3

Please sign in to comment.