From af3a91c9eb537579deafe8de65c1ee91dc2422c9 Mon Sep 17 00:00:00 2001 From: Ondro Mihalyi Date: Sun, 30 Jun 2024 23:28:25 +0200 Subject: [PATCH 1/5] feat: Jakarta Persistence Driver - initial commit Implements several select operators. Jakarta Data TCK runner TCK tests: 15 passed, 21 failed, 48 in error --- README.adoc | 4 + jnosql-jakarta-persistence/README.adoc | 52 +++ .../README.adoc | 17 + .../logging.properties | 41 +++ .../pom.xml | 201 +++++++++++ .../EntityManagerProducer.java | 35 ++ .../jakartapersistence/JNoSqlEntityTests.java | 43 +++ .../JNoSqlPersistenceEntityTests.java | 45 +++ .../JNoSqlSignatureTests.java | 21 ++ .../TransactionExtension.java | 39 ++ .../test/resources/META-INF/persistence.xml | 45 +++ .../README.adoc | 4 + .../jnosql-jakarta-persistence-driver/pom.xml | 131 +++++++ .../PersistenceClassScanner.java | 53 +++ .../PersistenceClassScannerSingleton.java | 155 ++++++++ .../PersistenceDatabaseManager.java | 93 +++++ .../PersistenceRepositoryFilter.java | 69 ++++ .../mapping/PersistenceDocumentTemplate.java | 333 ++++++++++++++++++ .../query/RepositoryPersistenceBean.java | 108 ++++++ .../spi/JakartaPersistenceExtension.java | 51 +++ .../src/main/resources/META-INF/beans.xml | 23 ++ .../jakarta.enterprise.inject.spi.Extension | 15 + .../EntityManagerProducer.java | 35 ++ .../jnosql/jakartapersistence/Person.java | 74 ++++ .../jakartapersistence/PersonRepository.java | 27 ++ .../PersonRepositoryTest.java | 91 +++++ .../test/resources/META-INF/persistence.xml | 40 +++ jnosql-jakarta-persistence/pom.xml | 32 ++ 28 files changed, 1877 insertions(+) create mode 100644 jnosql-jakarta-persistence/README.adoc create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/README.adoc create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/logging.properties create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/pom.xml create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/EntityManagerProducer.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlPersistenceEntityTests.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlSignatureTests.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/TransactionExtension.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/resources/META-INF/persistence.xml create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/README.adoc create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/pom.xml create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceClassScanner.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceClassScannerSingleton.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceDatabaseManager.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceRepositoryFilter.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/RepositoryPersistenceBean.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/spi/JakartaPersistenceExtension.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/resources/META-INF/beans.xml create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/resources/META-INF/services/jakarta.enterprise.inject.spi.Extension create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/EntityManagerProducer.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/Person.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepository.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepositoryTest.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/resources/META-INF/persistence.xml create mode 100644 jnosql-jakarta-persistence/pom.xml diff --git a/README.adoc b/README.adoc index 506a45a5..029f6c85 100644 --- a/README.adoc +++ b/README.adoc @@ -359,6 +359,10 @@ The Criteria API can be used via CriteriaDocumentTemplate. ---- +== Driver for Jakarta Persistence entities + +Provides a driver for Eclipse JNoSQL that supports Jakarta Persistence entities over a Jakarta Persistence provider. This project also contains a runner for the Jakarta Data TCK. + == TCK Runners The Eclipse JNoSQL project provides Technology Compatibility Kit (TCK) runners for Jakarta Data. These runners allow you to run the TCK tests against the Eclipse JNoSQL implementation to verify its compatibility with the Jakarta Data specifications. diff --git a/jnosql-jakarta-persistence/README.adoc b/jnosql-jakarta-persistence/README.adoc new file mode 100644 index 00000000..fa12dbe0 --- /dev/null +++ b/jnosql-jakarta-persistence/README.adoc @@ -0,0 +1,52 @@ += Eclipse JNoSQL driver for Jakarta Persistence +:toc: auto + +This project provides a driver for Eclipse JNoSQL that supports Jakarta Persistence entities over a Jakarta Persistence provider. + +Sub projects: + +* link:jnosql-jakarta-persistence-driver[Jakarta Persistence Driver] - the actual implementation +* link:jnosql-jakarta-persistence-data-tck-runner[Jakarta Data TCK Runner] - the project to run the Jakarta Data TCK + +=== How To Install + +You can use either the Maven or Gradle dependencies: + +[source,xml] +---- + + org.eclipse.jnosql.mapping + jnosql-jakarta-persistence + +---- + +Then you need to provide an EntityManager instance using a CDI producer, e.g.: + +[source,java] +---- +@ApplicationScoped +public class EntityManagerProducer { + @Produces + @ApplicationScoped + public EntityManager createEntityManager() { + return Persistence.createEntityManagerFactory("testPersistenceUnit") + .createEntityManager(); + } + + public void closeEntityManager(@Disposes EntityManager entityManager) { + entityManager.close(); + } +} +---- + +Then you need to configure the persistence unit ("testPersistenceUnit") via standard Jakarta Persistence means, e.g.: + +[source,xml] +---- + + + ... custom configuration ... + + + +For an example configuration, with EclipseLink and DerbyDB, look into the test setup of the link:jnosql-jakarta-persistence-connector[Jakarta Persistence Connector] project. \ No newline at end of file diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/README.adoc b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/README.adoc new file mode 100644 index 00000000..383c8943 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/README.adoc @@ -0,0 +1,17 @@ += Jakarta Data TCK Eclipse JNoSQL Implementation via Jakarta Persistence +:toc: auto + +This project runs the Jakarta Data Technology Compatibility Kit (TCK) on standalone mode with Eclipse JNoSQL with the Jakarta Persistence connector. It uses EclipseLink and Derby DB as an implementation for Jakarta Persistence. Before running this project it is recommended to read the documentation located in the base link:https://github.com/jakartaee/data/blob/main/tck-dist/src/main/asciidoc/data-tck-reference-guide.adoc[TCK distribution project, _target=_blank]. + +== Overview + +This project is configured specifically to allow the feature developers to run the TCK against the Eclipse JNoSQL implementation with the Jakarta Persistence backend. + +== Running the TCK for Verification + +Run the following command to execute the TCK: + +[source,shell] +---- +mvn clean test -B +---- diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/logging.properties b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/logging.properties new file mode 100644 index 00000000..14c8ba20 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/logging.properties @@ -0,0 +1,41 @@ +#Handlers we plan to use +handlers=java.util.logging.FileHandler,java.util.logging.ConsoleHandler + +#Global logger - By default only log warnings +.level=WARNING + +#Jakarta Data TCK logger - By default log everything for ee.jakarta.tck.data +ee.jakarta.tck.data.level=ALL + +# Arquillian and JNoSQL - By default log everything, might reduce after development is complete. +org.jboss.level=ALL +org.eclipse.jnosql.level=ALL + +#Formatting for the simple formatter +java.util.logging.SimpleFormatter.class.log=true +java.util.logging.SimpleFormatter.class.full=false +java.util.logging.SimpleFormatter.class.length=10 + +java.util.logging.SimpleFormatter.level.log=true + +java.util.logging.SimpleFormatter.method.log=true +java.util.logging.SimpleFormatter.method.length=30 + +java.util.logging.SimpleFormatter.thread.log=true +java.util.logging.SimpleFormatter.thread.length=3 + +java.util.logging.SimpleFormatter.time.log=true +java.util.logging.SimpleFormatter.time.format=[MM/dd/yyyy HH:mm:ss:SSS z] + +java.util.logging.SimpleFormatter.format=[%1$tF %1$tT] %4$.1s %3$s %5$s %n + +# Log warnings to console +java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter +java.util.logging.ConsoleHandler.level=WARNING + +# Log everything else to file +java.util.logging.FileHandler.pattern=target/DataTCK%g%u.log +java.util.logging.FileHandler.limit = 500000 +java.util.logging.FileHandler.count = 5 +java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter +java.util.logging.FileHandler.level=CONFIG \ No newline at end of file diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/pom.xml b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/pom.xml new file mode 100644 index 00000000..82b36cb8 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/pom.xml @@ -0,0 +1,201 @@ + + + + + 4.0.0 + Eclipse JNoSQL Jakarta Persistence Runner For Jakarta Data TCK + + + org.eclipse.jnosql.mapping + jnosql-jakarta-persistence-parent + 1.1.2-SNAPSHOT + + jnosql-jakarta-persistence-data-tck-runner + + + + + sonatype-nexus-staging + Sonatype Nexus Staging + https://jakarta.oss.sonatype.org/content/repositories/staging/ + + true + + + true + + + + + + ${project.basedir}/target + + + 1.0.0-RC1 + 6.1.0 + 4.1.0 + + 1.8.0.Final + 5.10.2 + 1.2.6 + 2.3 + 4.0.3.Final + 1.19.8 + + ${project.basedir}/logging.properties + jdk + + + + + + + + + org.junit + junit-bom + ${junit.version} + pom + import + + + + + + + + + jakarta.data + jakarta.data-tck + ${jakarta.data.version} + + + + jakarta.data + jakarta.data-api + ${jakarta.data.version} + + + + org.eclipse.persistence + eclipselink + 5.0.0-B02 + test + + + org.apache.derby + derby + 10.17.1.0 + test + + + org.apache.derby + derbytools + 10.17.1.0 + + + org.apache.derby + derbyclient + 10.17.1.0 + + + org.eclipse.jnosql.mapping + jnosql-jakarta-persistence + ${project.version} + + + + org.junit.jupiter + junit-jupiter + ${junit.version} + + + jakarta.tck + sigtest-maven-plugin + ${sigtest.version} + + + + org.jboss.weld + weld-junit5 + ${weld.junit5.version} + + + + org.jboss.shrinkwrap + shrinkwrap-api + ${shrinkwrap.version} + + + org.jboss.arquillian.junit5 + arquillian-junit5-core + ${arquillian.version} + + + jakarta.servlet + jakarta.servlet-api + ${jakarta.servlet.version} + + + + jakarta.enterprise + jakarta.enterprise.cdi-api + ${jakarta.enterprise.cdi.version} + + + + org.testcontainers + testcontainers + ${testcontainers.version} + test + + + + + + ${targetDirectory} + + + maven-surefire-plugin + 3.0.0 + + false + true + + true + true + + + ${logging.config} + target/tck-classes + + ${project.build.directory}/dependency/jakarta.data-api-${jakarta.data.api.version}.jar + + true + + ${included.groups} + standalone + + + + + \ No newline at end of file diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/EntityManagerProducer.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/EntityManagerProducer.java new file mode 100644 index 00000000..93e98914 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/EntityManagerProducer.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.tck.jakartapersistence; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Disposes; +import jakarta.enterprise.inject.Produces; +import jakarta.persistence.EntityManager; +import jakarta.persistence.Persistence; + +@ApplicationScoped +public class EntityManagerProducer { + @Produces + @ApplicationScoped + public EntityManager createEntityManager() { + return Persistence.createEntityManagerFactory("testPersistenceUnit") + .createEntityManager(); + } + + public void closeEntityManager(@Disposes EntityManager entityManager) { + entityManager.close(); + } +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java new file mode 100644 index 00000000..e7aa479b --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.tck.jakartapersistence; + +import ee.jakarta.tck.data.standalone.entity.EntityTests; +import org.eclipse.jnosql.mapping.core.spi.EntityMetadataExtension; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.document.DocumentTemplate; +import org.eclipse.jnosql.mapping.document.DocumentTemplateProducer; +import org.eclipse.jnosql.mapping.document.spi.DocumentExtension; +import org.eclipse.jnosql.mapping.reflection.Reflections; +import org.eclipse.jnosql.mapping.semistructured.EntityConverter; +import org.jboss.weld.junit5.auto.AddExtensions; +import org.jboss.weld.junit5.auto.AddPackages; +import org.jboss.weld.junit5.auto.EnableAutoWeld; + +import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; +import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; +import org.junit.jupiter.api.extension.ExtendWith; + +@EnableAutoWeld +@AddPackages(value = {Converters.class, EntityConverter.class, DocumentTemplate.class}) +@AddPackages(DocumentTemplateProducer.class) +@AddPackages(Reflections.class) +@AddExtensions({EntityMetadataExtension.class, DocumentExtension.class}) +@AddPackages({PersistenceDocumentTemplate.class, PersistenceDatabaseManager.class}) +@AddPackages({JNoSqlEntityTests.class, EntityTests.class}) +@ExtendWith(TransactionExtension.class) +public class JNoSqlEntityTests extends EntityTests { + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlPersistenceEntityTests.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlPersistenceEntityTests.java new file mode 100644 index 00000000..cc84b204 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlPersistenceEntityTests.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.tck.jakartapersistence; + +import ee.jakarta.tck.data.standalone.persistence.PersistenceEntityTests; +import org.eclipse.jnosql.mapping.core.spi.EntityMetadataExtension; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.document.DocumentTemplate; +import org.eclipse.jnosql.mapping.document.DocumentTemplateProducer; +import org.eclipse.jnosql.mapping.document.spi.DocumentExtension; +import org.eclipse.jnosql.mapping.reflection.Reflections; +import org.eclipse.jnosql.mapping.semistructured.EntityConverter; +import org.jboss.weld.junit5.auto.AddExtensions; +import org.jboss.weld.junit5.auto.AddPackages; +import org.jboss.weld.junit5.auto.EnableAutoWeld; + + + +import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; +import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; +import org.junit.jupiter.api.extension.ExtendWith; + +@EnableAutoWeld +@AddPackages(value = {Converters.class, EntityConverter.class, DocumentTemplate.class}) +@AddPackages(DocumentTemplateProducer.class) +@AddPackages(Reflections.class) +@AddExtensions({EntityMetadataExtension.class, DocumentExtension.class}) +@AddPackages({PersistenceDocumentTemplate.class, PersistenceDatabaseManager.class}) +@AddPackages({JNoSqlPersistenceEntityTests.class, PersistenceEntityTests.class}) +@ExtendWith(TransactionExtension.class) +public class JNoSqlPersistenceEntityTests extends PersistenceEntityTests { + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlSignatureTests.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlSignatureTests.java new file mode 100644 index 00000000..a0bd51f4 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlSignatureTests.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.tck.jakartapersistence; + +import ee.jakarta.tck.data.standalone.signature.SignatureTests; + +public class JNoSqlSignatureTests extends SignatureTests { + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/TransactionExtension.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/TransactionExtension.java new file mode 100644 index 00000000..3c5ff22b --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/TransactionExtension.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.tck.jakartapersistence; + +import jakarta.enterprise.inject.spi.CDI; +import jakarta.persistence.EntityManager; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +public class TransactionExtension implements BeforeEachCallback, AfterEachCallback { + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + getEntityManager().getTransaction().begin(); + } + + private static EntityManager getEntityManager() { + return CDI.current().select(EntityManager.class).get(); + } + + @Override + public void afterEach(ExtensionContext context) throws Exception { + getEntityManager().getTransaction().commit(); + } + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/resources/META-INF/persistence.xml b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/resources/META-INF/persistence.xml new file mode 100644 index 00000000..6ca67fb2 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/resources/META-INF/persistence.xml @@ -0,0 +1,45 @@ + + + + + org.eclipse.persistence.jpa.PersistenceProvider + ee.jakarta.tck.data.core.cdi.Person + ee.jakarta.tck.data.framework.read.only.AsciiCharacter + ee.jakarta.tck.data.framework.read.only.NaturalNumber + ee.jakarta.tck.data.standalone.entity.Box + ee.jakarta.tck.data.standalone.entity.Coordinate + ee.jakarta.tck.data.standalone.persistence.Product + ee.jakarta.tck.data.web.validation.Rectangle + true + + + + + + + + + + + + + + + + + diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/README.adoc b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/README.adoc new file mode 100644 index 00000000..49cbd938 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/README.adoc @@ -0,0 +1,4 @@ += Eclipse JNoSQL driver implementation for Jakarta Persistence +:toc: auto + +This project provides a driver for Eclipse JNoSQL that supports Jakarta Persistence entities over a Jakarta Persistence provider. \ No newline at end of file diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/pom.xml b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/pom.xml new file mode 100644 index 00000000..ccfbca77 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/pom.xml @@ -0,0 +1,131 @@ + + + + 4.0.0 + Eclipse JNoSQL Jakarta Persistence Driver + + org.eclipse.jnosql.mapping + jnosql-jakarta-persistence-parent + 1.1.2-SNAPSHOT + + jnosql-jakarta-persistence + jar + + UTF-8 + 17 + 17 + + + + org.eclipse.jnosql.mapping + jnosql-mapping-document + + + org.eclipse.jnosql.databases + jnosql-database-commons + ${project.version} + + + jakarta.persistence + jakarta.persistence-api + 3.2.0 + + + + + org.jboss.weld.se + weld-se-core + 6.0.0.Beta1 + test + + + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.hamcrest + hamcrest-all + 1.3 + test + + + org.apache.derby + derby + 10.17.1.0 + test + + + org.apache.derby + derbytools + 10.17.1.0 + test + + + org.apache.derby + derbyclient + 10.17.1.0 + test + + + org.eclipse.persistence + eclipselink + 5.0.0-B02 + test + + + + + + + + + maven-surefire-plugin + + + default-test + + + ${project.build.directory}${file.separator}derbydb + + + + + + + + + \ No newline at end of file diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceClassScanner.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceClassScanner.java new file mode 100644 index 00000000..5bc95d03 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceClassScanner.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.jakartapersistence.communication; + +import jakarta.data.repository.DataRepository; +import java.util.Set; +import org.eclipse.jnosql.mapping.metadata.ClassScanner; + +public class PersistenceClassScanner implements ClassScanner { + + @Override + public Set> entities() { + return PersistenceClassScannerSingleton.INSTANCE.entities(); + } + + @Override + public Set> repositories() { + return PersistenceClassScannerSingleton.INSTANCE.repositories(); + } + + @Override + public Set> embeddables() { + return PersistenceClassScannerSingleton.INSTANCE.embeddables(); + } + + @Override + public > Set> repositories(Class filter) { + return PersistenceClassScannerSingleton.INSTANCE.repositories(filter); + } + + @Override + public Set> repositoriesStandard() { + return PersistenceClassScannerSingleton.INSTANCE.repositoriesStandard(); + } + + @Override + public Set> customRepositories() { + return PersistenceClassScannerSingleton.INSTANCE.customRepositories(); + } + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceClassScannerSingleton.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceClassScannerSingleton.java new file mode 100644 index 00000000..11fbd012 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceClassScannerSingleton.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2022, 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Otavio Santana + * Ondro Mihalyi + */ +package org.eclipse.jnosql.jakartapersistence.communication; + + +import static java.util.Collections.unmodifiableSet; +import static java.util.stream.Collectors.toUnmodifiableSet; + +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ScanResult; +import jakarta.data.repository.BasicRepository; +import jakarta.data.repository.CrudRepository; +import jakarta.data.repository.DataRepository; +import jakarta.data.repository.Repository; +import jakarta.nosql.Embeddable; +import jakarta.nosql.Entity; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import org.eclipse.jnosql.mapping.NoSQLRepository; +import org.eclipse.jnosql.mapping.metadata.ClassScanner; + +/** + * Scanner classes that will load entities with both Entity and Embeddable + * annotations and repositories: interfaces that extend DataRepository + * and has the Repository annotation. + */ +enum PersistenceClassScannerSingleton implements ClassScanner { + + INSTANCE; + + private final Set> entities; + private final Set> repositories; + private final Set> embeddables; + private final Set> customRepositories; + + + PersistenceClassScannerSingleton() { + entities = new HashSet<>(); + embeddables = new HashSet<>(); + repositories = new HashSet<>(); + customRepositories = new HashSet<>(); + + Logger logger = Logger.getLogger(PersistenceClassScannerSingleton.class.getName()); + logger.fine("Starting scan class to find entities, embeddable and repositories."); + try (ScanResult result = new ClassGraph().enableAllInfo().scan()) { + var notSupportedRepositories = loadNotSupportedRepositories(result); + logger.warning(() -> "The following repositories are not supported: " + notSupportedRepositories); + this.entities.addAll(loadEntities(result)); + this.embeddables.addAll(loadEmbeddable(result)); + this.repositories.addAll(loadRepositories(result)); + this.customRepositories.addAll(loadCustomRepositories(result)); + notSupportedRepositories.forEach(this.repositories::remove); + } + logger.fine(String.format("Finished the class scan with entities %d, embeddables %d and repositories: %d" + , entities.size(), embeddables.size(), repositories.size())); + + } + + + @Override + public Set> entities() { + return unmodifiableSet(entities); + } + + @Override + public Set> repositories() { + return unmodifiableSet(repositories); + } + + + @Override + public Set> embeddables() { + return unmodifiableSet(embeddables); + } + + @Override + public > Set> repositories(Class filter) { + Objects.requireNonNull(filter, "filter is required"); + return repositories.stream().filter(filter::isAssignableFrom) + .filter(c -> Arrays.asList(c.getInterfaces()).contains(filter)) + .collect(toUnmodifiableSet()); + } + + + @Override + public Set> repositoriesStandard() { + return repositories.stream() + .filter(c -> { + List> interfaces = Arrays.asList(c.getInterfaces()); + return interfaces.contains(CrudRepository.class) + || interfaces.contains(BasicRepository.class) + || interfaces.contains(NoSQLRepository.class) + || interfaces.contains(DataRepository.class); + }).collect(Collectors.toUnmodifiableSet()); + } + + @Override + public Set> customRepositories() { + return customRepositories; + } + + + @SuppressWarnings("rawtypes") + private static List> loadRepositories(ScanResult scan) { + return scan.getClassesWithAnnotation(Repository.class) + .getInterfaces() + .filter(c -> c.implementsInterface(DataRepository.class)) + .loadClasses(DataRepository.class) + .stream().filter(PersistenceRepositoryFilter.INSTANCE) + .toList(); + } + + private static List> loadCustomRepositories(ScanResult scan) { + return scan.getClassesWithAnnotation(Repository.class) + .getInterfaces() + .filter(c -> !c.implementsInterface(DataRepository.class)) + .loadClasses().stream().toList(); + } + + @SuppressWarnings("rawtypes") + private static List> loadNotSupportedRepositories(ScanResult scan) { + return scan.getClassesWithAnnotation(Repository.class) + .getInterfaces() + .filter(c -> c.implementsInterface(DataRepository.class)) + .loadClasses(DataRepository.class) + .stream().filter(PersistenceRepositoryFilter.INSTANCE.negate()) + .toList(); + } + + private static List> loadEmbeddable(ScanResult scan) { + return scan.getClassesWithAnnotation(Embeddable.class).loadClasses(); + } + + private static List> loadEntities(ScanResult scan) { + return scan.getClassesWithAnnotation(Entity.class).loadClasses(); + } +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceDatabaseManager.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceDatabaseManager.java new file mode 100644 index 00000000..ab951799 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceDatabaseManager.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.jakartapersistence.communication; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.persistence.EntityManager; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Root; +import jakarta.persistence.metamodel.EntityType; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; +import org.eclipse.jnosql.communication.Value; +import org.eclipse.jnosql.communication.semistructured.CommunicationEntity; +import org.eclipse.jnosql.communication.semistructured.Element; +import org.eclipse.jnosql.communication.semistructured.SelectQuery; + +@ApplicationScoped +public class PersistenceDatabaseManager { + + private final EntityManager em; + + private final Map> entityTypesByName = new HashMap<>(); + + @Inject + public PersistenceDatabaseManager(EntityManager em) { + this.em = em; + cacheEntityTypes(); + } + + PersistenceDatabaseManager() { + em = null; + } + + public EntityManager getEntityManager() { + return em; + } + + public Stream select(SelectQuery sq) { + final String entityName = sq.name(); + final EntityType entityType = findEntityType(entityName); + final CriteriaQuery criteriaQuery = em.getCriteriaBuilder().createQuery(); + final Root from = criteriaQuery.from(entityType.getJavaType()); + criteriaQuery.select(from); + + final TypedQuery query = em.createQuery(criteriaQuery); + return query.getResultStream() + .map(persistenceEntity -> CommunicationEntity.of(entityName, List.of( + Element.of("1", Value.of(persistenceEntity)) + ))); + } + + public void close() { + } + + public EntityType findEntityType(String entityName) { + try { + return (EntityType) em.getMetamodel().entity(entityName); + } catch (IllegalArgumentException e) { + // EclipseLink expects full class name in MM.entity() method. We need to find out the type otherwise + EntityType entityType = entityTypesByName.get(entityName); + if (entityType != null) { + return (EntityType)entityType; + } else { + final IllegalArgumentException ex = new IllegalArgumentException("Entity with name " + entityName + " not found in the list of known entities"); + ex.addSuppressed(e); + throw ex; + } + } + } + + private void cacheEntityTypes() { + em.getMetamodel().getEntities().forEach(type -> { + entityTypesByName.put(type.getName(), type); + }); + } + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceRepositoryFilter.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceRepositoryFilter.java new file mode 100644 index 00000000..2911e683 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceRepositoryFilter.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023, 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Otavio Santana + * Ondro Mihalyi + */ +package org.eclipse.jnosql.jakartapersistence.communication; + +import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Optional; +import java.util.function.Predicate; + +/** + * A filter to validate Repository that either Eclipse JNoSQL or the Jakarta Persistence extension support. It will + * check the first parameter on the repository, and if the entity has not had an unsupported annotation, it will return + * false and true to supported Repository. + */ +enum PersistenceRepositoryFilter implements Predicate> { + + INSTANCE; + + @Override + public boolean test(Class type) { + Optional> entity = getEntityClass(type); + return entity.map(this::toSupportedAnnotation) + .isPresent(); + } + + private Annotation toSupportedAnnotation(Class c) { + final Annotation annotation = c.getAnnotation(jakarta.persistence.Entity.class); + return annotation != null ? annotation : c.getAnnotation(jakarta.nosql.Entity.class); + } + + private Optional> getEntityClass(Class repository) { + Type[] interfaces = repository.getGenericInterfaces(); + if (interfaces.length == 0) { + return Optional.empty(); + } + if (interfaces[0] instanceof ParameterizedType interfaceType) { + return Optional.ofNullable(getEntityFromInterface(interfaceType)); + } else { + return Optional.empty(); + } + } + + private Class getEntityFromInterface(ParameterizedType param) { + Type[] arguments = param.getActualTypeArguments(); + if (arguments.length == 0) { + return null; + } + Type argument = arguments[0]; + if (argument instanceof Class entity) { + return entity; + } + return null; + } + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java new file mode 100644 index 00000000..e26b3fcc --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.jakartapersistence.mapping; + +import static org.eclipse.jnosql.communication.Condition.LESSER_EQUALS_THAN; +import static org.eclipse.jnosql.communication.Condition.LESSER_THAN; + +import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; +import jakarta.annotation.Priority; +import jakarta.data.page.CursoredPage; +import jakarta.data.page.PageRequest; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Alternative; +import jakarta.enterprise.inject.Default; +import jakarta.inject.Inject; +import jakarta.interceptor.Interceptor; +import jakarta.nosql.QueryMapper; +import jakarta.persistence.EntityManager; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Path; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; +import jakarta.persistence.metamodel.EntityType; +import java.time.Duration; +import java.util.Collection; +import java.util.Iterator; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; +import org.eclipse.jnosql.communication.Value; +import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; +import org.eclipse.jnosql.communication.semistructured.DeleteQuery; +import org.eclipse.jnosql.communication.semistructured.Element; +import org.eclipse.jnosql.communication.semistructured.SelectQuery; +import org.eclipse.jnosql.mapping.Database; +import org.eclipse.jnosql.mapping.DatabaseType; +import org.eclipse.jnosql.mapping.PreparedStatement; +import org.eclipse.jnosql.mapping.document.DocumentTemplate; + +@Alternative +@Priority(Interceptor.Priority.APPLICATION) +@Default +@ApplicationScoped +@Database(DatabaseType.DOCUMENT) +public class PersistenceDocumentTemplate implements DocumentTemplate { + + private final PersistenceDatabaseManager manager; + + @Inject + PersistenceDocumentTemplate(PersistenceDatabaseManager manager) { + this.manager = manager; + } + + PersistenceDocumentTemplate() { + this(null); + } + + @Override + public long count(String entity) { + final EntityType entityType = manager.findEntityType(entity); + return count(entityType.getJavaType()); + } + + @Override + public long count(Class type) { + TypedQuery query = buildQuery(type, Long.class, ctx -> ctx.query.select(ctx.builder.count(ctx.root))); + return query.getSingleResult(); + } + + @Override + public Stream findAll(Class type) { + TypedQuery query = buildQuery(type, type, ctx -> ctx.query.select((Root) ctx.root)); + return query.getResultStream(); + } + + record QuaryContext(CriteriaQuery query, Root root, CriteriaBuilder builder) { + + } + + private TypedQuery buildQuery(Class fromType, Class resultType, + Function, CriteriaQuery> queryModifier) { + final EntityManager em = entityManager(); + final CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(resultType); + final Root from = criteriaQuery.from(fromType); + criteriaQuery = queryModifier.apply(new QuaryContext(criteriaQuery, from, criteriaBuilder)); + return em.createQuery(criteriaQuery); + } + + @Override + public Stream query(String query) { + final EntityManager em = entityManager(); + return em.createQuery(query).getResultStream(); + } + + @Override + public Stream query(String query, String entity) { + return query(query); + } + + @Override + public Optional singleResult(String query) { + final EntityManager em = entityManager(); + return Optional.ofNullable((T) em.createQuery(query).getSingleResultOrNull()); + } + + private EntityManager entityManager() { + return manager.getEntityManager(); + } + + @Override + public Optional singleResult(String query, String entity) { + return singleResult(query); + } + + @Override + public Optional find(Class type, K k) { + return Optional.ofNullable(entityManager().find(type, k)); + } + + @Override + public T insert(T t) { + entityManager().persist(t); + return t; + } + + @Override + public T update(T t) { + return entityManager().merge(t); + } + + @Override + public PreparedStatement prepare(String query) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public PreparedStatement prepare(String query, String entity) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public void delete(DeleteQuery query) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public Stream select(SelectQuery selectQuery) { + final String entityName = selectQuery.name(); + final EntityType entityType = manager.findEntityType(entityName); + if (selectQuery.condition().isEmpty()) { + return findAll(entityType.getJavaType()); + } else { + final CriteriaCondition criteria = selectQuery.condition().get(); + TypedQuery query = buildQuery(entityType.getJavaType(), entityType.getJavaType(), ctx -> { + CriteriaQuery q = ctx.query.select(ctx.root); + q = q.where(parseCriteria(criteria, ctx)); + return q; + }); + return query.getResultStream(); + } + } + + @Override + public long count(SelectQuery selectQuery) { + final String entityName = selectQuery.name(); + if (selectQuery.condition().isEmpty()) { + return count(entityName); + } else { + final EntityType entityType = manager.findEntityType(entityName); + final CriteriaCondition criteria = selectQuery.condition().get(); + TypedQuery query = buildQuery(entityType.getJavaType(), Long.class, ctx -> { + CriteriaQuery q = ctx.query.select(ctx.builder.count(ctx.root)); + q = q.where(parseCriteria(criteria, ctx)); + return q; + }); + return query.getSingleResult(); + } + } + + record ComparableContext(Path field, Comparable fieldValue) { + + public static ComparableContext from(Root root, CriteriaCondition criteria) { + Element element = (Element) criteria.element(); + final Path field = root.get(getName(element)); + final Comparable fieldValue = element.value().get(Comparable.class); + return new ComparableContext(field, fieldValue); + } + } + + record BiComparableContext(Path field, Comparable fieldValue1, Comparable fieldValue2) { + + public static BiComparableContext from(Root root, CriteriaCondition criteria) { + Element element = (Element) criteria.element(); + final Path field = root.get(getName(element)); + Iterator iterator = elementIterator(criteria); + final Comparable fieldValue1 = ((Value) iterator.next()).get(Comparable.class); + final Comparable fieldValue2 = ((Value) iterator.next()).get(Comparable.class); + return new BiComparableContext(field, fieldValue1, fieldValue2); + } + + } + + private static String getName(Element element) { + final String name = element.name(); + // NoSQL DBs translate id field into "_id" but we don't want it + return name.equals("_id") ? "id" : name; + } + + private Predicate parseCriteria(Object value, QuaryContext ctx) { + if (value instanceof CriteriaCondition criteria) { + return switch (criteria.condition()) { + case NOT -> + ctx.builder().not(parseCriteria(criteria.element(), ctx)); + case EQUALS -> { + Element element = (Element) criteria.element(); + if (element.value().isNull()) { + yield ctx.builder().isNull(ctx.root().get(getName(element))); + } else { + yield ctx.builder().equal(ctx.root().get(getName(element)), element.value().get()); + } + } + case AND -> { + Iterator iterator = elementIterator(criteria); + yield ctx.builder().and(parseCriteria(iterator.next(), ctx), parseCriteria(iterator.next(), ctx)); + } + case LESSER_THAN -> { + final ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); + yield ctx.builder().lessThan(comparableContext.field(), comparableContext.fieldValue()); + } + case LESSER_EQUALS_THAN -> { + final ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); + yield ctx.builder().lessThanOrEqualTo(comparableContext.field(), comparableContext.fieldValue()); + } + case GREATER_THAN -> { + final ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); + yield ctx.builder().greaterThan(comparableContext.field(), comparableContext.fieldValue()); + } + case GREATER_EQUALS_THAN -> { + final ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); + yield ctx.builder().greaterThanOrEqualTo(comparableContext.field(), comparableContext.fieldValue()); + } + case BETWEEN -> { + final BiComparableContext comparableContext = BiComparableContext.from(ctx.root(), criteria); + yield ctx.builder().between(comparableContext.field(), comparableContext.fieldValue1(), comparableContext.fieldValue2()); + } + + default -> + throw new UnsupportedOperationException("Not supported yet."); + }; + } else if (value instanceof Element element) { + return parseCriteria(element.value().get(), ctx); + } + throw new UnsupportedOperationException("Not supported yet."); + } + + private static Iterator elementIterator(CriteriaCondition criteria) { + Element element = (Element) criteria.element(); + Collection elements = (Collection) element.value().get(); + final Iterator iterator = elements.iterator(); + return iterator; + } + + @Override + public boolean exists(SelectQuery query) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public Optional singleResult(SelectQuery query) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public void deleteAll(Class type) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public CursoredPage selectCursor(SelectQuery query, PageRequest pageRequest) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public T insert(T t, Duration drtn) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public Iterable insert(Iterable itrbl) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public Iterable insert(Iterable itrbl, Duration drtn) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public Iterable update(Iterable itrbl) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public void delete(Class type, K k) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public QueryMapper.MapperFrom select(Class type) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + + @Override + public QueryMapper.MapperDeleteFrom delete(Class type) { + throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + } + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/RepositoryPersistenceBean.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/RepositoryPersistenceBean.java new file mode 100644 index 00000000..e2241d8a --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/RepositoryPersistenceBean.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2022 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Otavio Santana + */ +package org.eclipse.jnosql.jakartapersistence.mapping.query; + +import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; +import jakarta.data.repository.DataRepository; +import jakarta.enterprise.context.spi.CreationalContext; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.DatabaseType; +import org.eclipse.jnosql.mapping.core.spi.AbstractBean; +import org.eclipse.jnosql.mapping.core.util.AnnotationLiteralUtil; +import org.eclipse.jnosql.mapping.semistructured.query.SemiStructuredRepositoryProxy; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Proxy; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; + + +/** + * This class serves as a JNoSQL discovery bean for CDI extension, responsible for registering Repository instances for Jakarta Persistence entities. + * It extends {@link AbstractBean} and is parameterized with type {@code T} representing the repository type. + *

+ * Upon instantiation, it initializes with the provided repository type, provider name, and qualifiers. + * The provider name specifies the database provider for the repository. + *

+ * + * @param the type of the repository + * @see AbstractBean + */ +public class RepositoryPersistenceBean> extends AbstractBean { + + private final Class type; + + private final Set types; + + private final String provider; + + private final Set qualifiers; + + /** + * Constructor + * + * @param type the tye + * @param provider the provider name, that must be a + */ + @SuppressWarnings("unchecked") + public RepositoryPersistenceBean(Class type, String provider) { + this.type = (Class) type; + this.types = Collections.singleton(type); + this.provider = provider; + this.qualifiers = new HashSet<>(); + qualifiers.add(AnnotationLiteralUtil.DEFAULT_ANNOTATION); + qualifiers.add(AnnotationLiteralUtil.ANY_ANNOTATION); + } + + @Override + public Class getBeanClass() { + return type; + } + + @Override + @SuppressWarnings("unchecked") + public T create(CreationalContext context) { + EntitiesMetadata entities = getInstance(EntitiesMetadata.class); + var template = getInstance(PersistenceDocumentTemplate.class); + + Converters converters = getInstance(Converters.class); + + var handler = new SemiStructuredRepositoryProxy<>(template, + entities, type, converters); + return (T) Proxy.newProxyInstance(type.getClassLoader(), + new Class[]{type}, + handler); + } + + + @Override + public Set getTypes() { + return types; + } + + @Override + public Set getQualifiers() { + return qualifiers; + } + + @Override + public String getId() { + return type.getName() + '@' + DatabaseType.DOCUMENT + "-" + provider; + } + +} \ No newline at end of file diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/spi/JakartaPersistenceExtension.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/spi/JakartaPersistenceExtension.java new file mode 100644 index 00000000..c6fca41e --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/spi/JakartaPersistenceExtension.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Otavio Santana + */ +package org.eclipse.jnosql.jakartapersistence.mapping.spi; + +import org.eclipse.jnosql.jakartapersistence.communication.PersistenceClassScanner; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.spi.AfterBeanDiscovery; +import jakarta.enterprise.inject.spi.Extension; +import org.eclipse.jnosql.mapping.document.query.RepositoryDocumentBean; +import org.eclipse.jnosql.mapping.metadata.ClassScanner; + +import java.util.Set; +import java.util.logging.Logger; + +/** + * This CDI extension, {@code JakartaPersistenceExtension}, observes the CDI container lifecycle events to perform tasks + * related to Jakarta Persistence repository beans. + *

+ */ +public class JakartaPersistenceExtension implements Extension { + + private static final Logger LOGGER = Logger.getLogger(JakartaPersistenceExtension.class.getName()); + + void onAfterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery) { + + ClassScanner scanner = new PersistenceClassScanner(); + + Set> crudTypes = scanner.repositoriesStandard(); + + LOGGER.info(() -> "Processing Jakarta Persistence extension: crud " + + crudTypes.size() + " found"); + LOGGER.fine(() -> "Processing repositories as a Jakarta Persistence implementation: " + crudTypes); + + crudTypes.forEach(type -> { + afterBeanDiscovery.addBean(new RepositoryDocumentBean<>(type, "")); + }); + + } +} \ No newline at end of file diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/resources/META-INF/beans.xml b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000..029572ac --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/resources/META-INF/beans.xml @@ -0,0 +1,23 @@ + + + + \ No newline at end of file diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/resources/META-INF/services/jakarta.enterprise.inject.spi.Extension b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/resources/META-INF/services/jakarta.enterprise.inject.spi.Extension new file mode 100644 index 00000000..ad093ee1 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/resources/META-INF/services/jakarta.enterprise.inject.spi.Extension @@ -0,0 +1,15 @@ +# +# Copyright (c) 2022 Contributors to the Eclipse Foundation +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# and Apache License v2.0 which accompanies this distribution. +# The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html +# and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. +# +# You may elect to redistribute this code under either of these licenses. +# +# Contributors: +# +# Otavio Santana +# +org.eclipse.jnosql.jakartapersistence.mapping.spi.JakartaPersistenceExtension \ No newline at end of file diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/EntityManagerProducer.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/EntityManagerProducer.java new file mode 100644 index 00000000..5c2ffed1 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/EntityManagerProducer.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package ee.omnifish.jnosql.jakartapersistence; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Disposes; +import jakarta.enterprise.inject.Produces; +import jakarta.persistence.EntityManager; +import jakarta.persistence.Persistence; + +@ApplicationScoped +public class EntityManagerProducer { + @Produces + @ApplicationScoped + public EntityManager createEntityManager() { + return Persistence.createEntityManagerFactory("testPersistenceUnit") + .createEntityManager(); + } + + public void closeEntityManager(@Disposes EntityManager entityManager) { + entityManager.close(); + } +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/Person.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/Person.java new file mode 100644 index 00000000..ce53f8ca --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/Person.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package ee.omnifish.jnosql.jakartapersistence; + +import static jakarta.persistence.GenerationType.AUTO; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import java.util.List; + +@Entity(name = "Person") +public class Person { + + @Id + @GeneratedValue(strategy = AUTO) + private long id; + + @Column + private String name; + + @Column + private long age; + + @Column + private List phones; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getPhones() { + return phones; + } + + public void setPhones(List phones) { + this.phones = phones; + } + + public long getAge() { + return age; + } + + public void setAge(long age) { + this.age = age; + } + + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepository.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepository.java new file mode 100644 index 00000000..7593c57b --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package ee.omnifish.jnosql.jakartapersistence; + +import jakarta.data.repository.CrudRepository; +import jakarta.data.repository.Repository; +import java.util.List; + +@Repository +public interface PersonRepository extends CrudRepository { + long countAll(); + long countByNameNotNull(); + List findByNameAndAgeLessThanEqual(String name, long age); +} + diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepositoryTest.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepositoryTest.java new file mode 100644 index 00000000..7036fe5d --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepositoryTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package ee.omnifish.jnosql.jakartapersistence; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.not; + +import jakarta.enterprise.inject.se.SeContainer; +import jakarta.enterprise.inject.se.SeContainerInitializer; +import jakarta.persistence.EntityManager; +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class PersonRepositoryTest { + + private SeContainer cdiContainer; + private PersonRepository personRepo; + + @BeforeEach + void init() { + cdiContainer = SeContainerInitializer.newInstance() + .addBeanClasses(EntityManagerProducer.class) + .initialize(); + assertThat("repository can be resolved", cdiContainer.select(PersonRepository.class).isResolvable()); + personRepo = cdiContainer.select(PersonRepository.class).get(); + getEntityManager().getTransaction().begin(); + } + + private EntityManager getEntityManager() { + return cdiContainer.select(EntityManager.class).get(); + } + + @AfterEach + void cleanup() { + getEntityManager().getTransaction().commit(); + cdiContainer.close(); + } + + @Test + void findAll() { + final List persons = personRepo.findAll().toList(); + assertThat("queryResult", persons, is(empty())); + System.out.println("All persons: " + persons); + } + + @Test + void count() { + personRepo.insert(new Person()); + final long count = personRepo.countAll(); + assertThat(count, greaterThan(0L)); + } + + @Test + void countByNotNull() { + final Person person = new Person(); + person.setName("Jakarta"); + personRepo.insert(person); + final long count = personRepo.countByNameNotNull(); + assertThat(count, greaterThan(0L)); + } + + @Test + void findByXAndYLessThanEqual() { + final Person person = new Person(); + final String NAME = "Jakarta"; + person.setName(NAME); + person.setAge(35); + personRepo.insert(person); + + final List persons = personRepo.findByNameAndAgeLessThanEqual(NAME, 50); + assertThat(persons, is(not(empty()))); + } + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/resources/META-INF/persistence.xml b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/resources/META-INF/persistence.xml new file mode 100644 index 00000000..442bfb96 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/resources/META-INF/persistence.xml @@ -0,0 +1,40 @@ + + + + + org.eclipse.persistence.jpa.PersistenceProvider + ee.omnifish.jnosql.jakartapersistence.Person + true + + + + + + + + + + + + + + + + + + diff --git a/jnosql-jakarta-persistence/pom.xml b/jnosql-jakarta-persistence/pom.xml new file mode 100644 index 00000000..6ef16097 --- /dev/null +++ b/jnosql-jakarta-persistence/pom.xml @@ -0,0 +1,32 @@ + + + + 4.0.0 + Eclipse JNoSQL Jakarta Persistence Parent + + org.eclipse.jnosql.mapping + jnosql-mapping-extensions + 1.1.2-SNAPSHOT + + jnosql-jakarta-persistence-parent + pom + + jnosql-jakarta-persistence-driver + jnosql-jakarta-persistence-data-tck-runner + + \ No newline at end of file From fadc738792b9436548c1dffa9aeb78b66f26e237 Mon Sep 17 00:00:00 2001 From: Ondro Mihalyi Date: Mon, 1 Jul 2024 12:47:20 +0200 Subject: [PATCH 2/5] feat: Jakarta Persistence Driver - IN clause TCK tests: 19 passed, 22 failed, 43 in error --- .../jakartapersistence/JNoSqlEntityTests.java | 14 ++ .../mapping/PersistenceDocumentTemplate.java | 162 +++++++++++++----- .../JakartaPersistenceRepositoryProxy.java | 29 ++++ .../query/RepositoryPersistenceBean.java | 3 +- .../jakartapersistence/PersonRepository.java | 2 + .../PersonRepositoryTest.java | 54 +++++- 6 files changed, 209 insertions(+), 55 deletions(-) create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/JakartaPersistenceRepositoryProxy.java diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java index e7aa479b..5b618fc2 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java @@ -28,6 +28,7 @@ import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @EnableAutoWeld @@ -40,4 +41,17 @@ @ExtendWith(TransactionExtension.class) public class JNoSqlEntityTests extends EntityTests { + @Override + @Test + public void testIn() { + super.testIn(); + } + + @Override + @Test + public void testFindList() { + super.testFindList(); + } + + } diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java index e26b3fcc..258e3906 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java @@ -28,6 +28,7 @@ import jakarta.interceptor.Interceptor; import jakarta.nosql.QueryMapper; import jakarta.persistence.EntityManager; +import jakarta.persistence.Query; import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; @@ -37,7 +38,9 @@ import jakarta.persistence.metamodel.EntityType; import java.time.Duration; import java.util.Collection; +import java.util.HashMap; import java.util.Iterator; +import java.util.Map; import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; @@ -71,7 +74,7 @@ public class PersistenceDocumentTemplate implements DocumentTemplate { @Override public long count(String entity) { - final EntityType entityType = manager.findEntityType(entity); + EntityType entityType = manager.findEntityType(entity); return count(entityType.getJavaType()); } @@ -93,18 +96,26 @@ record QuaryContext(CriteriaQuery query, Root root, private TypedQuery buildQuery(Class fromType, Class resultType, Function, CriteriaQuery> queryModifier) { - final EntityManager em = entityManager(); - final CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); + EntityManager em = entityManager(); + CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(resultType); - final Root from = criteriaQuery.from(fromType); + Root from = criteriaQuery.from(fromType); criteriaQuery = queryModifier.apply(new QuaryContext(criteriaQuery, from, criteriaBuilder)); return em.createQuery(criteriaQuery); } + private Query buildQuery(String query) { + EntityManager em = entityManager(); + return em.createQuery(query); + } + + private EntityManager entityManager() { + return manager.getEntityManager(); + } + @Override public Stream query(String query) { - final EntityManager em = entityManager(); - return em.createQuery(query).getResultStream(); + return buildQuery(query).getResultStream(); } @Override @@ -114,12 +125,7 @@ public Stream query(String query, String entity) { @Override public Optional singleResult(String query) { - final EntityManager em = entityManager(); - return Optional.ofNullable((T) em.createQuery(query).getSingleResultOrNull()); - } - - private EntityManager entityManager() { - return manager.getEntityManager(); + return Optional.ofNullable((T) buildQuery(query).getSingleResultOrNull()); } @Override @@ -144,18 +150,55 @@ public T update(T t) { } @Override - public PreparedStatement prepare(String query) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + public PreparedStatement prepare(String query, String entity) { + return prepare(query); } @Override - public PreparedStatement prepare(String query, String entity) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + public PreparedStatement prepare(String queryString) { + return new PreparedStatement() { + + private Map parameters = new HashMap<>(); + + private void applyParameters(Query query) { + parameters.forEach((name, value) -> query.setParameter(name, value)); + } + + @Override + public PreparedStatement bind(String name, Object value) { + parameters.put(name, value); + return this; + } + + @Override + public Stream result() { + Query query = buildQuery(queryString); + applyParameters(query); + return query.getResultStream(); + } + + @Override + public Optional singleResult() { + Query query = buildQuery(queryString); + applyParameters(query); + return Optional.ofNullable((T) query.getSingleResultOrNull()); + } + + @Override + public long count() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isCount() { + return false; + } + }; } @Override public void delete(DeleteQuery query) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + throw new UnsupportedOperationException("Not supported yet."); } @Override @@ -175,6 +218,25 @@ public Stream select(SelectQuery selectQuery) { } } + @Override + public Optional singleResult(SelectQuery selectQuery) { + final String entityName = selectQuery.name(); + final EntityType entityType = manager.findEntityType(entityName); + final Class type = entityType.getJavaType(); + if (selectQuery.condition().isEmpty()) { + TypedQuery query = buildQuery(type, type, ctx -> ctx.query.select((Root) ctx.root)); + return Optional.ofNullable(query.getSingleResultOrNull()); + } else { + final CriteriaCondition criteria = selectQuery.condition().get(); + TypedQuery query = buildQuery(type, type, ctx -> { + CriteriaQuery q = ctx.query.select(ctx.root); + q = q.where(parseCriteria(criteria, ctx)); + return q; + }); + return Optional.ofNullable(query.getSingleResultOrNull()); + } + } + @Override public long count(SelectQuery selectQuery) { final String entityName = selectQuery.name(); @@ -196,8 +258,8 @@ record ComparableContext(Path field, Comparable fieldValue) { public static ComparableContext from(Root root, CriteriaCondition criteria) { Element element = (Element) criteria.element(); - final Path field = root.get(getName(element)); - final Comparable fieldValue = element.value().get(Comparable.class); + Path field = root.get(getName(element)); + Comparable fieldValue = element.value().get(Comparable.class); return new ComparableContext(field, fieldValue); } } @@ -207,7 +269,7 @@ record BiComparableContext(Path field, Comparable fieldValue1, Compa public static BiComparableContext from(Root root, CriteriaCondition criteria) { Element element = (Element) criteria.element(); final Path field = root.get(getName(element)); - Iterator iterator = elementIterator(criteria); + Iterator iterator = elementCollection(criteria).iterator(); final Comparable fieldValue1 = ((Value) iterator.next()).get(Comparable.class); final Comparable fieldValue2 = ((Value) iterator.next()).get(Comparable.class); return new BiComparableContext(field, fieldValue1, fieldValue2); @@ -215,8 +277,17 @@ public static BiComparableContext from(Root root, CriteriaCondition } + record MultiValueContext(Path field, Collection fieldValues) { + + public static MultiValueContext from(Root root, CriteriaCondition criteria) { + Element element = (Element) criteria.element(); + Path field = root.get(getName(element)); + return new MultiValueContext(field, elementCollection(criteria)); + } + } + private static String getName(Element element) { - final String name = element.name(); + String name = element.name(); // NoSQL DBs translate id field into "_id" but we don't want it return name.equals("_id") ? "id" : name; } @@ -235,29 +306,35 @@ private Predicate parseCriteria(Object value, QuaryContext { - Iterator iterator = elementIterator(criteria); + Iterator iterator = elementCollection(criteria).iterator(); yield ctx.builder().and(parseCriteria(iterator.next(), ctx), parseCriteria(iterator.next(), ctx)); } case LESSER_THAN -> { - final ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); + ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); yield ctx.builder().lessThan(comparableContext.field(), comparableContext.fieldValue()); } case LESSER_EQUALS_THAN -> { - final ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); + ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); yield ctx.builder().lessThanOrEqualTo(comparableContext.field(), comparableContext.fieldValue()); } case GREATER_THAN -> { - final ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); + ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); yield ctx.builder().greaterThan(comparableContext.field(), comparableContext.fieldValue()); } case GREATER_EQUALS_THAN -> { - final ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); + ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); yield ctx.builder().greaterThanOrEqualTo(comparableContext.field(), comparableContext.fieldValue()); } case BETWEEN -> { - final BiComparableContext comparableContext = BiComparableContext.from(ctx.root(), criteria); + BiComparableContext comparableContext = BiComparableContext.from(ctx.root(), criteria); yield ctx.builder().between(comparableContext.field(), comparableContext.fieldValue1(), comparableContext.fieldValue2()); } + case IN -> { + MultiValueContext valueContext = MultiValueContext.from(ctx.root(), criteria); + CriteriaBuilder.In inExpr = ctx.builder().in(valueContext.field()); + valueContext.fieldValues().forEach(v -> inExpr.value(v)); + yield inExpr; + } default -> throw new UnsupportedOperationException("Not supported yet."); @@ -268,66 +345,59 @@ private Predicate parseCriteria(Object value, QuaryContext elementIterator(CriteriaCondition criteria) { + private static Collection elementCollection(CriteriaCondition criteria) { Element element = (Element) criteria.element(); - Collection elements = (Collection) element.value().get(); - final Iterator iterator = elements.iterator(); - return iterator; + return (Collection) element.value().get(); } @Override public boolean exists(SelectQuery query) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody - } - - @Override - public Optional singleResult(SelectQuery query) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + throw new UnsupportedOperationException("Not supported yet."); } @Override public void deleteAll(Class type) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + throw new UnsupportedOperationException("Not supported yet."); } @Override public CursoredPage selectCursor(SelectQuery query, PageRequest pageRequest) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + throw new UnsupportedOperationException("Not supported yet."); } @Override public T insert(T t, Duration drtn) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + throw new UnsupportedOperationException("Not supported yet."); } @Override public Iterable insert(Iterable itrbl) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + throw new UnsupportedOperationException("Not supported yet."); } @Override public Iterable insert(Iterable itrbl, Duration drtn) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + throw new UnsupportedOperationException("Not supported yet."); } @Override public Iterable update(Iterable itrbl) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + throw new UnsupportedOperationException("Not supported yet."); } @Override public void delete(Class type, K k) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + throw new UnsupportedOperationException("Not supported yet."); } @Override public QueryMapper.MapperFrom select(Class type) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + throw new UnsupportedOperationException("Not supported yet."); } @Override public QueryMapper.MapperDeleteFrom delete(Class type) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + throw new UnsupportedOperationException("Not supported yet."); } } diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/JakartaPersistenceRepositoryProxy.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/JakartaPersistenceRepositoryProxy.java new file mode 100644 index 00000000..1677cbdf --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/JakartaPersistenceRepositoryProxy.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.jakartapersistence.mapping.query; + +import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; +import org.eclipse.jnosql.mapping.semistructured.query.SemiStructuredRepositoryProxy; + +public class JakartaPersistenceRepositoryProxy extends SemiStructuredRepositoryProxy { + + public JakartaPersistenceRepositoryProxy(PersistenceDocumentTemplate template, EntitiesMetadata entities, Class repositoryType, Converters converters) { + super(template, entities, repositoryType, converters); + } + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/RepositoryPersistenceBean.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/RepositoryPersistenceBean.java index e2241d8a..c9d1ec14 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/RepositoryPersistenceBean.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/RepositoryPersistenceBean.java @@ -21,7 +21,6 @@ import org.eclipse.jnosql.mapping.DatabaseType; import org.eclipse.jnosql.mapping.core.spi.AbstractBean; import org.eclipse.jnosql.mapping.core.util.AnnotationLiteralUtil; -import org.eclipse.jnosql.mapping.semistructured.query.SemiStructuredRepositoryProxy; import java.lang.annotation.Annotation; import java.lang.reflect.Proxy; @@ -82,7 +81,7 @@ public T create(CreationalContext context) { Converters converters = getInstance(Converters.class); - var handler = new SemiStructuredRepositoryProxy<>(template, + var handler = new JakartaPersistenceRepositoryProxy<>(template, entities, type, converters); return (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepository.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepository.java index 7593c57b..e457b064 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepository.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepository.java @@ -17,11 +17,13 @@ import jakarta.data.repository.CrudRepository; import jakarta.data.repository.Repository; import java.util.List; +import java.util.Set; @Repository public interface PersonRepository extends CrudRepository { long countAll(); long countByNameNotNull(); List findByNameAndAgeLessThanEqual(String name, long age); + List findByNameIn(Set names); } diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepositoryTest.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepositoryTest.java index 7036fe5d..b8aca7ed 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepositoryTest.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepositoryTest.java @@ -18,12 +18,14 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.not; import jakarta.enterprise.inject.se.SeContainer; import jakarta.enterprise.inject.se.SeContainerInitializer; import jakarta.persistence.EntityManager; import java.util.List; +import java.util.Set; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -40,6 +42,12 @@ void init() { .initialize(); assertThat("repository can be resolved", cdiContainer.select(PersonRepository.class).isResolvable()); personRepo = cdiContainer.select(PersonRepository.class).get(); + + // cleanup + getEntityManager().getTransaction().begin(); + getEntityManager().createQuery("delete from Person p").executeUpdate(); + getEntityManager().getTransaction().commit(); + getEntityManager().getTransaction().begin(); } @@ -69,23 +77,55 @@ void count() { @Test void countByNotNull() { - final Person person = new Person(); - person.setName("Jakarta"); - personRepo.insert(person); + new PersonBuilder().name("Jakarta").insert(personRepo); final long count = personRepo.countByNameNotNull(); assertThat(count, greaterThan(0L)); } @Test void findByXAndYLessThanEqual() { - final Person person = new Person(); final String NAME = "Jakarta"; - person.setName(NAME); - person.setAge(35); - personRepo.insert(person); + new PersonBuilder().name(NAME).age(35).insert(personRepo); final List persons = personRepo.findByNameAndAgeLessThanEqual(NAME, 50); assertThat(persons, is(not(empty()))); } + @Test + void findByXIn() { + final String NAME1 = "Jakarta"; + final String NAME2 = "JNoSQL"; + final String NAME3 = "Data"; + new PersonBuilder().name(NAME1).insert(personRepo); + new PersonBuilder().name(NAME2).insert(personRepo); + new PersonBuilder().name(NAME3).insert(personRepo); + new PersonBuilder().name("No name").insert(personRepo); + + final List persons = personRepo.findByNameIn(Set.of(NAME1, NAME2, NAME3)); + assertThat(persons, hasSize(3)); + } + + private class PersonBuilder { + + Person p = new Person(); + + public PersonBuilder name(String name) { + p.setName(name); + return this; + } + + public PersonBuilder age(long age) { + p.setAge(age); + return this; + } + + public Person build() { + return p; + } + + public void insert(PersonRepository personRepo) { + personRepo.insert(p); + } + } + } From 12cab75373d878e6daeaca0a37c4cd6ab3db7437 Mon Sep 17 00:00:00 2001 From: Ondro Mihalyi Date: Tue, 2 Jul 2024 08:50:58 +0200 Subject: [PATCH 3/5] feat: Jakarta Persistence Driver - refactoring Extracted select methods to a separate class Use the latest released Jakarta Data spec artifacts Add Persistence CDI extension to PersistenceUnitTests - it's picked up automatically for EntityTests but not here --- .../pom.xml | 5 +- .../JNoSqlEntitySelectedTests.java | 517 ++++++++++++++++++ .../jakartapersistence/JNoSqlEntityTests.java | 16 +- .../JNoSqlPersistenceEntityTests.java | 5 +- .../test/resources/META-INF/persistence.xml | 5 +- .../PersistenceDatabaseManager.java | 25 +- .../mapping/PersistenceDocumentTemplate.java | 248 +-------- .../mapping/PersistencePreparedStatement.java | 77 +++ .../mapping/SelectQueryParser.java | 254 +++++++++ .../JakartaPersistenceRepositoryProxy.java | 2 +- .../RepositoryPersistenceBean.java | 2 +- 11 files changed, 887 insertions(+), 269 deletions(-) create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntitySelectedTests.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistencePreparedStatement.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/SelectQueryParser.java rename jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/{query => repository}/JakartaPersistenceRepositoryProxy.java (94%) rename jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/{query => repository}/RepositoryPersistenceBean.java (98%) diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/pom.xml b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/pom.xml index 82b36cb8..496ba191 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/pom.xml +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/pom.xml @@ -48,7 +48,8 @@ ${project.basedir}/target - 1.0.0-RC1 + 1.0.0 + 1.0.1 6.1.0 4.1.0 @@ -85,7 +86,7 @@ jakarta.data jakarta.data-tck - ${jakarta.data.version} + ${jakarta.data.tck.version} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntitySelectedTests.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntitySelectedTests.java new file mode 100644 index 00000000..e8d5c57a --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntitySelectedTests.java @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.tck.jakartapersistence; + +import ee.jakarta.tck.data.standalone.entity.EntityTests; +import org.eclipse.jnosql.mapping.core.spi.EntityMetadataExtension; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.document.DocumentTemplate; +import org.eclipse.jnosql.mapping.document.DocumentTemplateProducer; +import org.eclipse.jnosql.mapping.document.spi.DocumentExtension; +import org.eclipse.jnosql.mapping.reflection.Reflections; +import org.eclipse.jnosql.mapping.semistructured.EntityConverter; +import org.jboss.weld.junit5.auto.AddExtensions; +import org.jboss.weld.junit5.auto.AddPackages; +import org.jboss.weld.junit5.auto.EnableAutoWeld; + +import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; +import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@EnableAutoWeld +@AddPackages(value = {Converters.class, EntityConverter.class, DocumentTemplate.class}) +@AddPackages(DocumentTemplateProducer.class) +@AddPackages(Reflections.class) +@AddExtensions({EntityMetadataExtension.class, DocumentExtension.class}) +@AddPackages({PersistenceDocumentTemplate.class, PersistenceDatabaseManager.class}) +@AddPackages({JNoSqlEntitySelectedTests.class, EntityTests.class}) +@ExtendWith(TransactionExtension.class) +public class JNoSqlEntitySelectedTests extends EntityTests { + + @Override +// assertion failed +// @Test + public void testVarargsSort() { + super.testVarargsSort(); + } + + @Override + @Test + public void testUpdateQueryWithWhereClause() { + super.testUpdateQueryWithWhereClause(); + } + + @Override + @Test + public void testUpdateQueryWithoutWhereClause() { + super.testUpdateQueryWithoutWhereClause(); + } + + @Override +// assertion failed +// @Test + public void testTrue() { + super.testTrue(); + } + + @Override +// assertion failed +// @Test + public void testThirdAndFourthSlicesOf5() { + super.testThirdAndFourthSlicesOf5(); + } + + @Override +// assertion failed +// @Test + public void testThirdAndFourthPagesOf10() { + super.testThirdAndFourthPagesOf10(); + } + + @Override + @Test + public void testStreamsFromList() { + super.testStreamsFromList(); + } + + @Override +// EndsWith +// @Test + public void testStaticMetamodelDescendingSortsPreGenerated() { + super.testStaticMetamodelDescendingSortsPreGenerated(); + } + + @Override + @Test + public void testStaticMetamodelDescendingSorts() { + super.testStaticMetamodelDescendingSorts(); + } + + @Override + @Test + public void testStaticMetamodelAttributeNamesPreGenerated() { + super.testStaticMetamodelAttributeNamesPreGenerated(); + } + + @Override + @Test + public void testStaticMetamodelAttributeNames() { + super.testStaticMetamodelAttributeNames(); + } + + @Override +// EndsWith not supported +// @Test + public void testStaticMetamodelAscendingSortsPreGenerated() { + super.testStaticMetamodelAscendingSortsPreGenerated(); + } + + @Override +// assertion failed +// @Test + public void testStaticMetamodelAscendingSorts() { + super.testStaticMetamodelAscendingSorts(); + } + + @Override + @Test + public void testSliceOfNothing() { + super.testSliceOfNothing(); + } + + @Override +// IgnoreCase +// @Test + public void testSingleEntity() { + super.testSingleEntity(); + } + + @Override +// Query not supported +// @Test + public void testQueryWithParenthesis() { + super.testQueryWithParenthesis(); + } + + @Override +// syntax error +// @Test + public void testQueryWithOr() { + super.testQueryWithOr(); + } + + @Override +// query not supported +// @Test + public void testQueryWithNull() { + super.testQueryWithNull(); + } + + @Override +// Query not supported +// @Test + public void testQueryWithNot() { + super.testQueryWithNot(); + } + + @Override +// Not supported by JNoSQL yet +// @Test + public void testPrimaryEntityClassDeterminedByLifeCycleMethods() { + super.testPrimaryEntityClassDeterminedByLifeCycleMethods(); + } + + @Override +// Query not supported +// @Test + public void testPartialQuerySelectAndOrderBy() { + super.testPartialQuerySelectAndOrderBy(); + } + + @Override +// Queyr not supported +// @Test + public void testPartialQueryOrderBy() { + super.testPartialQueryOrderBy(); + } + + @Override +// Not supported by JNoSQL yet +// @Test + public void testPageOfNothing() { + super.testPageOfNothing(); + } + + @Override +// assertion failed +// @Test + public void testOrderByHasPrecedenceOverSorts() { + super.testOrderByHasPrecedenceOverSorts(); + } + + @Override +// assertion failed +// @Test + public void testOrderByHasPrecedenceOverPageRequestSorts() { + super.testOrderByHasPrecedenceOverPageRequestSorts(); + } + + @Override + @Test + public void testOr() { + super.testOr(); + } + + @Override +// ClassCastException +// @Test + public void testNot() { + super.testNot(); + } + + @Override +// non unique result +// @Test + public void testNonUniqueResultException() { + super.testNonUniqueResultException(); + } + + @Override +// ClassCastException +// @Test + public void testMixedSort() { + super.testMixedSort(); + } + + @Override +// Query not supported +// @Test + public void testLiteralTrue() { + super.testLiteralTrue(); + } + + @Override +// Query not supported +// @Test + public void testLiteralString() { + super.testLiteralString(); + } + + @Override +// Query not supported +// @Test + public void testLiteralInteger() { + super.testLiteralInteger(); + } + + @Override +// Query not supported +// @Test + public void testLiteralEnumAndLiteralFalse() { + super.testLiteralEnumAndLiteralFalse(); + } + + @Override +// assertion failed +// @Test + public void testLimitToOneResult() { + super.testLimitToOneResult(); + } + + @Override +// assertion failed +// @Test + public void testLimitedRange() { + super.testLimitedRange(); + } + + @Override +// assertion failed +// @Test + public void testLimit() { + super.testLimit(); + } + + @Override + @Test + public void testLessThanWithCount() { + super.testLessThanWithCount(); + } + + @Override + @Test + public void testCursoredPageWithoutTotalOfNothing() { + super.testCursoredPageWithoutTotalOfNothing(); + } + + @Override + @Test + public void testCursoredPageWithoutTotalOf9FromCursor() { + super.testCursoredPageWithoutTotalOf9FromCursor(); + } + + @Override + @Test + public void testCursoredPageOfNothing() { + super.testCursoredPageOfNothing(); + } + + @Override + @Test + public void testCursoredPageOf7FromCursor() { + super.testCursoredPageOf7FromCursor(); + } + + @Override +// IgnoreCase not supported +// @Test + public void testIgnoreCase() { + super.testIgnoreCase(); + } + + @Override +// assertion failed +// @Test + public void testIn() { + super.testIn(); + } + + @Override + @Test + public void testGreaterThanEqualExists() { + super.testGreaterThanEqualExists(); + } + + @Override +// assertion failed +// @Test + public void testFirstSliceOf5() { + super.testFirstSliceOf5(); + } + + @Override +// assertion failed +// @Test + public void testFirstPageOf10() { + super.testFirstPageOf10(); + } + + @Override + @Test + public void testFirstCursoredPageWithoutTotalOf6AndNextPages() { + super.testFirstCursoredPageWithoutTotalOf6AndNextPages(); + } + + @Override + @Test + public void testFirstCursoredPageOf8AndNextPages() { + super.testFirstCursoredPageOf8AndNextPages(); + } + + @Override +// assertion failed +// @Test + public void testFindPage() { + super.testFindPage(); + } + + @Override + @Test + public void testFindOptional() { + super.testFindOptional(); + } + + @Override + @Test + public void testFindOne() { + super.testFindOne(); + } + + @Override + @Test + public void testFindList() { + super.testFindList(); + } + + @Override +// EndsWith not supported +// @Test + public void testFindFirst3() { + super.testFindFirst3(); + } + + @Override +// Syntax +// @Test + public void testFindFirst() { + super.testFindFirst(); + } + + @Override +// assertion failed +// @Test + public void testFindAllWithPagination() { + super.testFindAllWithPagination(); + } + + @Override +// assertion failed +// @Test + public void testFinalSliceOfUpTo5() { + super.testFinalSliceOfUpTo5(); + } + + @Override +// assertion failed +// @Test + public void testFinalPageOfUpTo10() { + super.testFinalPageOfUpTo10(); + } + + @Override + @Test + public void testFalse() { + super.testFalse(); + } + + @Override +// IgnoreCase not supported +// @Test + public void testEmptyResultException() { + super.testEmptyResultException(); + } + + @Override +// Query not supported +// @Test + public void testEmptyQuery() { + super.testEmptyQuery(); + } + + @Override +// assertion failed +// @Test + public void testDescendingSort() { + super.testDescendingSort(); + } + + @Override +// assertion failed +// @Test + public void testDefaultMethod() { + super.testDefaultMethod(); + } + + @Override +// IgnoreCase +// @Test + public void testDataRepository() { + super.testDataRepository(); + } + + @Override +// Contains not supported by JNoSQL +// @Test + public void testContainsInString() { + super.testContainsInString(); + } + + @Override + @Test + public void testCommonInterfaceQueries() { + super.testCommonInterfaceQueries(); + } + + @Override + @Test + public void testBy() { + super.testBy(); + } + + @Override +// assertion failed +// @Test + public void testBeyondFinalSlice() { + super.testBeyondFinalSlice(); + } + + @Override +// assertion failed +// @Test + public void testBeyondFinalPage() { + super.testBeyondFinalPage(); + } + + @Override + @Test + public void testBasicRepositoryMethods() { + super.testBasicRepositoryMethods(); + } + + @Override + @Test + public void testBasicRepositoryBuiltInMethods() { + super.testBasicRepositoryBuiltInMethods(); + } + + @Override +// assertion failed +// @Test + public void testBasicRepository() { + super.testBasicRepository(); + } + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java index 5b618fc2..d6562588 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java @@ -28,9 +28,10 @@ import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.extension.ExtendWith; +@Disabled @EnableAutoWeld @AddPackages(value = {Converters.class, EntityConverter.class, DocumentTemplate.class}) @AddPackages(DocumentTemplateProducer.class) @@ -41,17 +42,4 @@ @ExtendWith(TransactionExtension.class) public class JNoSqlEntityTests extends EntityTests { - @Override - @Test - public void testIn() { - super.testIn(); - } - - @Override - @Test - public void testFindList() { - super.testFindList(); - } - - } diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlPersistenceEntityTests.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlPersistenceEntityTests.java index cc84b204..769386de 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlPersistenceEntityTests.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlPersistenceEntityTests.java @@ -30,13 +30,16 @@ import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; +import org.eclipse.jnosql.jakartapersistence.mapping.spi.JakartaPersistenceExtension; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.extension.ExtendWith; +@Disabled @EnableAutoWeld @AddPackages(value = {Converters.class, EntityConverter.class, DocumentTemplate.class}) @AddPackages(DocumentTemplateProducer.class) @AddPackages(Reflections.class) -@AddExtensions({EntityMetadataExtension.class, DocumentExtension.class}) +@AddExtensions({EntityMetadataExtension.class, DocumentExtension.class, JakartaPersistenceExtension.class}) @AddPackages({PersistenceDocumentTemplate.class, PersistenceDatabaseManager.class}) @AddPackages({JNoSqlPersistenceEntityTests.class, PersistenceEntityTests.class}) @ExtendWith(TransactionExtension.class) diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/resources/META-INF/persistence.xml b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/resources/META-INF/persistence.xml index 6ca67fb2..2e2505e0 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/resources/META-INF/persistence.xml +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/resources/META-INF/persistence.xml @@ -29,7 +29,10 @@ - + + + + diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceDatabaseManager.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceDatabaseManager.java index ab951799..5c11e5c1 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceDatabaseManager.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceDatabaseManager.java @@ -17,18 +17,12 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.persistence.EntityManager; -import jakarta.persistence.TypedQuery; +import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Root; import jakarta.persistence.metamodel.EntityType; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.stream.Stream; -import org.eclipse.jnosql.communication.Value; -import org.eclipse.jnosql.communication.semistructured.CommunicationEntity; -import org.eclipse.jnosql.communication.semistructured.Element; -import org.eclipse.jnosql.communication.semistructured.SelectQuery; @ApplicationScoped public class PersistenceDatabaseManager { @@ -37,6 +31,9 @@ public class PersistenceDatabaseManager { private final Map> entityTypesByName = new HashMap<>(); + record QueryContext(CriteriaQuery query, Root root, CriteriaBuilder builder) { + } + @Inject public PersistenceDatabaseManager(EntityManager em) { this.em = em; @@ -51,20 +48,6 @@ public EntityManager getEntityManager() { return em; } - public Stream select(SelectQuery sq) { - final String entityName = sq.name(); - final EntityType entityType = findEntityType(entityName); - final CriteriaQuery criteriaQuery = em.getCriteriaBuilder().createQuery(); - final Root from = criteriaQuery.from(entityType.getJavaType()); - criteriaQuery.select(from); - - final TypedQuery query = em.createQuery(criteriaQuery); - return query.getResultStream() - .map(persistenceEntity -> CommunicationEntity.of(entityName, List.of( - Element.of("1", Value.of(persistenceEntity)) - ))); - } - public void close() { } diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java index 258e3906..2646d2ee 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java @@ -14,8 +14,6 @@ */ package org.eclipse.jnosql.jakartapersistence.mapping; -import static org.eclipse.jnosql.communication.Condition.LESSER_EQUALS_THAN; -import static org.eclipse.jnosql.communication.Condition.LESSER_THAN; import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; import jakarta.annotation.Priority; @@ -28,26 +26,10 @@ import jakarta.interceptor.Interceptor; import jakarta.nosql.QueryMapper; import jakarta.persistence.EntityManager; -import jakarta.persistence.Query; -import jakarta.persistence.TypedQuery; -import jakarta.persistence.criteria.CriteriaBuilder; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.Path; -import jakarta.persistence.criteria.Predicate; -import jakarta.persistence.criteria.Root; -import jakarta.persistence.metamodel.EntityType; import java.time.Duration; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; import java.util.Optional; -import java.util.function.Function; import java.util.stream.Stream; -import org.eclipse.jnosql.communication.Value; -import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; import org.eclipse.jnosql.communication.semistructured.DeleteQuery; -import org.eclipse.jnosql.communication.semistructured.Element; import org.eclipse.jnosql.communication.semistructured.SelectQuery; import org.eclipse.jnosql.mapping.Database; import org.eclipse.jnosql.mapping.DatabaseType; @@ -62,80 +44,61 @@ public class PersistenceDocumentTemplate implements DocumentTemplate { private final PersistenceDatabaseManager manager; + private final SelectQueryParser selectParser; @Inject PersistenceDocumentTemplate(PersistenceDatabaseManager manager) { this.manager = manager; + this.selectParser = new SelectQueryParser(manager); } PersistenceDocumentTemplate() { - this(null); + manager = null; + selectParser = null; + } + + private EntityManager entityManager() { + return manager.getEntityManager(); } @Override public long count(String entity) { - EntityType entityType = manager.findEntityType(entity); - return count(entityType.getJavaType()); + return selectParser.count(entity); } @Override public long count(Class type) { - TypedQuery query = buildQuery(type, Long.class, ctx -> ctx.query.select(ctx.builder.count(ctx.root))); - return query.getSingleResult(); + return selectParser.count(type); } @Override public Stream findAll(Class type) { - TypedQuery query = buildQuery(type, type, ctx -> ctx.query.select((Root) ctx.root)); - return query.getResultStream(); - } - - record QuaryContext(CriteriaQuery query, Root root, CriteriaBuilder builder) { - - } - - private TypedQuery buildQuery(Class fromType, Class resultType, - Function, CriteriaQuery> queryModifier) { - EntityManager em = entityManager(); - CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); - CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(resultType); - Root from = criteriaQuery.from(fromType); - criteriaQuery = queryModifier.apply(new QuaryContext(criteriaQuery, from, criteriaBuilder)); - return em.createQuery(criteriaQuery); - } - - private Query buildQuery(String query) { - EntityManager em = entityManager(); - return em.createQuery(query); - } - - private EntityManager entityManager() { - return manager.getEntityManager(); + return selectParser.findAll(type); } @Override public Stream query(String query) { - return buildQuery(query).getResultStream(); + return selectParser.query(query); } @Override public Stream query(String query, String entity) { - return query(query); + return selectParser.query(query, entity); } @Override public Optional singleResult(String query) { - return Optional.ofNullable((T) buildQuery(query).getSingleResultOrNull()); + return selectParser.singleResult(query); } @Override public Optional singleResult(String query, String entity) { - return singleResult(query); + return selectParser.singleResult(query, entity); } @Override public Optional find(Class type, K k) { - return Optional.ofNullable(entityManager().find(type, k)); + return selectParser.find(type, k); } @Override @@ -156,44 +119,7 @@ public PreparedStatement prepare(String query, String entity) { @Override public PreparedStatement prepare(String queryString) { - return new PreparedStatement() { - - private Map parameters = new HashMap<>(); - - private void applyParameters(Query query) { - parameters.forEach((name, value) -> query.setParameter(name, value)); - } - - @Override - public PreparedStatement bind(String name, Object value) { - parameters.put(name, value); - return this; - } - - @Override - public Stream result() { - Query query = buildQuery(queryString); - applyParameters(query); - return query.getResultStream(); - } - - @Override - public Optional singleResult() { - Query query = buildQuery(queryString); - applyParameters(query); - return Optional.ofNullable((T) query.getSingleResultOrNull()); - } - - @Override - public long count() { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public boolean isCount() { - return false; - } - }; + return new PersistencePreparedStatement(queryString, selectParser); } @Override @@ -203,151 +129,17 @@ public void delete(DeleteQuery query) { @Override public Stream select(SelectQuery selectQuery) { - final String entityName = selectQuery.name(); - final EntityType entityType = manager.findEntityType(entityName); - if (selectQuery.condition().isEmpty()) { - return findAll(entityType.getJavaType()); - } else { - final CriteriaCondition criteria = selectQuery.condition().get(); - TypedQuery query = buildQuery(entityType.getJavaType(), entityType.getJavaType(), ctx -> { - CriteriaQuery q = ctx.query.select(ctx.root); - q = q.where(parseCriteria(criteria, ctx)); - return q; - }); - return query.getResultStream(); - } + return selectParser.select(selectQuery); } @Override public Optional singleResult(SelectQuery selectQuery) { - final String entityName = selectQuery.name(); - final EntityType entityType = manager.findEntityType(entityName); - final Class type = entityType.getJavaType(); - if (selectQuery.condition().isEmpty()) { - TypedQuery query = buildQuery(type, type, ctx -> ctx.query.select((Root) ctx.root)); - return Optional.ofNullable(query.getSingleResultOrNull()); - } else { - final CriteriaCondition criteria = selectQuery.condition().get(); - TypedQuery query = buildQuery(type, type, ctx -> { - CriteriaQuery q = ctx.query.select(ctx.root); - q = q.where(parseCriteria(criteria, ctx)); - return q; - }); - return Optional.ofNullable(query.getSingleResultOrNull()); - } + return selectParser.singleResult(selectQuery); } @Override public long count(SelectQuery selectQuery) { - final String entityName = selectQuery.name(); - if (selectQuery.condition().isEmpty()) { - return count(entityName); - } else { - final EntityType entityType = manager.findEntityType(entityName); - final CriteriaCondition criteria = selectQuery.condition().get(); - TypedQuery query = buildQuery(entityType.getJavaType(), Long.class, ctx -> { - CriteriaQuery q = ctx.query.select(ctx.builder.count(ctx.root)); - q = q.where(parseCriteria(criteria, ctx)); - return q; - }); - return query.getSingleResult(); - } - } - - record ComparableContext(Path field, Comparable fieldValue) { - - public static ComparableContext from(Root root, CriteriaCondition criteria) { - Element element = (Element) criteria.element(); - Path field = root.get(getName(element)); - Comparable fieldValue = element.value().get(Comparable.class); - return new ComparableContext(field, fieldValue); - } - } - - record BiComparableContext(Path field, Comparable fieldValue1, Comparable fieldValue2) { - - public static BiComparableContext from(Root root, CriteriaCondition criteria) { - Element element = (Element) criteria.element(); - final Path field = root.get(getName(element)); - Iterator iterator = elementCollection(criteria).iterator(); - final Comparable fieldValue1 = ((Value) iterator.next()).get(Comparable.class); - final Comparable fieldValue2 = ((Value) iterator.next()).get(Comparable.class); - return new BiComparableContext(field, fieldValue1, fieldValue2); - } - - } - - record MultiValueContext(Path field, Collection fieldValues) { - - public static MultiValueContext from(Root root, CriteriaCondition criteria) { - Element element = (Element) criteria.element(); - Path field = root.get(getName(element)); - return new MultiValueContext(field, elementCollection(criteria)); - } - } - - private static String getName(Element element) { - String name = element.name(); - // NoSQL DBs translate id field into "_id" but we don't want it - return name.equals("_id") ? "id" : name; - } - - private Predicate parseCriteria(Object value, QuaryContext ctx) { - if (value instanceof CriteriaCondition criteria) { - return switch (criteria.condition()) { - case NOT -> - ctx.builder().not(parseCriteria(criteria.element(), ctx)); - case EQUALS -> { - Element element = (Element) criteria.element(); - if (element.value().isNull()) { - yield ctx.builder().isNull(ctx.root().get(getName(element))); - } else { - yield ctx.builder().equal(ctx.root().get(getName(element)), element.value().get()); - } - } - case AND -> { - Iterator iterator = elementCollection(criteria).iterator(); - yield ctx.builder().and(parseCriteria(iterator.next(), ctx), parseCriteria(iterator.next(), ctx)); - } - case LESSER_THAN -> { - ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); - yield ctx.builder().lessThan(comparableContext.field(), comparableContext.fieldValue()); - } - case LESSER_EQUALS_THAN -> { - ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); - yield ctx.builder().lessThanOrEqualTo(comparableContext.field(), comparableContext.fieldValue()); - } - case GREATER_THAN -> { - ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); - yield ctx.builder().greaterThan(comparableContext.field(), comparableContext.fieldValue()); - } - case GREATER_EQUALS_THAN -> { - ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); - yield ctx.builder().greaterThanOrEqualTo(comparableContext.field(), comparableContext.fieldValue()); - } - case BETWEEN -> { - BiComparableContext comparableContext = BiComparableContext.from(ctx.root(), criteria); - yield ctx.builder().between(comparableContext.field(), comparableContext.fieldValue1(), comparableContext.fieldValue2()); - } - case IN -> { - MultiValueContext valueContext = MultiValueContext.from(ctx.root(), criteria); - CriteriaBuilder.In inExpr = ctx.builder().in(valueContext.field()); - valueContext.fieldValues().forEach(v -> inExpr.value(v)); - yield inExpr; - } - - default -> - throw new UnsupportedOperationException("Not supported yet."); - }; - } else if (value instanceof Element element) { - return parseCriteria(element.value().get(), ctx); - } - throw new UnsupportedOperationException("Not supported yet."); - } - - private static Collection elementCollection(CriteriaCondition criteria) { - Element element = (Element) criteria.element(); - return (Collection) element.value().get(); + return selectParser.count(selectQuery); } @Override diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistencePreparedStatement.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistencePreparedStatement.java new file mode 100644 index 00000000..afc9b36a --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistencePreparedStatement.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.jakartapersistence.mapping; + +import jakarta.persistence.Query; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; +import org.eclipse.jnosql.mapping.PreparedStatement; + +/** + * + * @author Ondro Mihalyi + */ +class PersistencePreparedStatement implements PreparedStatement { + + private final String queryString; + private final SelectQueryParser selectParser; + private Map parameters = new HashMap<>(); + + public PersistencePreparedStatement(String queryString, final SelectQueryParser selectParser) { + this.selectParser = selectParser; + this.queryString = queryString; + } + + private void applyParameters(Query query) { + parameters.forEach((name, value) -> query.setParameter(name, value)); + } + + @Override + public PreparedStatement bind(String name, Object value) { + parameters.put(name, value); + return this; + } + + @Override + public Stream result() { + return createQuery().getResultStream(); + } + + @Override + public Optional singleResult() { + Query query = createQuery(); + return Optional.ofNullable((T) query.getSingleResultOrNull()); + } + + private Query createQuery() { + Query query = selectParser.buildQuery(queryString); + applyParameters(query); + return query; + } + + @Override + public long count() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isCount() { + return false; + } + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/SelectQueryParser.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/SelectQueryParser.java new file mode 100644 index 00000000..f574df78 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/SelectQueryParser.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.jakartapersistence.mapping; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.Query; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Path; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; +import jakarta.persistence.metamodel.EntityType; +import java.util.Collection; +import java.util.Iterator; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; +import org.eclipse.jnosql.communication.Value; +import org.eclipse.jnosql.communication.semistructured.CriteriaCondition; +import org.eclipse.jnosql.communication.semistructured.Element; +import org.eclipse.jnosql.communication.semistructured.SelectQuery; +import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; + +public class SelectQueryParser { + + private final PersistenceDatabaseManager manager; + + record QueryContext(CriteriaQuery query, Root root, CriteriaBuilder builder) { + + } + + public SelectQueryParser(PersistenceDatabaseManager manager) { + this.manager = manager; + } + + private EntityType findEntityType(String entityName) { + return manager.findEntityType(entityName); + } + + private EntityManager entityManager() { + return manager.getEntityManager(); + } + + public long count(String entity) { + EntityType entityType = findEntityType(entity); + return count(entityType.getJavaType()); + } + + public long count(Class type) { + TypedQuery query = buildQuery(type, Long.class, ctx -> ctx.query.select(ctx.builder.count(ctx.root))); + return query.getSingleResult(); + } + + public Stream findAll(Class type) { + TypedQuery query = buildQuery(type, type, ctx -> ctx.query.select((Root) ctx.root)); + return query.getResultStream(); + } + + public Stream query(String query) { + return buildQuery(query).getResultStream(); + } + + public Stream query(String query, String entity) { + return query(query); + } + + public Optional singleResult(String query) { + return Optional.ofNullable((T) buildQuery(query).getSingleResultOrNull()); + } + + public Optional singleResult(String query, String entity) { + return singleResult(query); + } + + public Optional find(Class type, K k) { + return Optional.ofNullable(entityManager().find(type, k)); + } + + public Stream select(SelectQuery selectQuery) { + final String entityName = selectQuery.name(); + final EntityType entityType = findEntityType(entityName); + if (selectQuery.condition().isEmpty()) { + return findAll(entityType.getJavaType()); + } else { + final CriteriaCondition criteria = selectQuery.condition().get(); + TypedQuery query = buildQuery(entityType.getJavaType(), entityType.getJavaType(), ctx -> { + CriteriaQuery q = ctx.query.select(ctx.root); + q = q.where(parseCriteria(criteria, ctx)); + return q; + }); + return query.getResultStream(); + } + } + + public Optional singleResult(SelectQuery selectQuery) { + final String entityName = selectQuery.name(); + final EntityType entityType = findEntityType(entityName); + final Class type = entityType.getJavaType(); + if (selectQuery.condition().isEmpty()) { + TypedQuery query = buildQuery(type, type, ctx -> ctx.query.select((Root) ctx.root)); + return Optional.ofNullable(query.getSingleResultOrNull()); + } else { + final CriteriaCondition criteria = selectQuery.condition().get(); + TypedQuery query = buildQuery(type, type, ctx -> { + CriteriaQuery q = ctx.query.select(ctx.root); + q = q.where(parseCriteria(criteria, ctx)); + return q; + }); + return Optional.ofNullable(query.getSingleResultOrNull()); + } + } + + public long count(SelectQuery selectQuery) { + final String entityName = selectQuery.name(); + if (selectQuery.condition().isEmpty()) { + return count(entityName); + } else { + final EntityType entityType = findEntityType(entityName); + final CriteriaCondition criteria = selectQuery.condition().get(); + TypedQuery query = buildQuery(entityType.getJavaType(), Long.class, ctx -> { + CriteriaQuery q = ctx.query.select(ctx.builder.count(ctx.root)); + q = q.where(parseCriteria(criteria, ctx)); + return q; + }); + return query.getSingleResult(); + } + } + + record ComparableContext(Path field, Comparable fieldValue) { + + public static ComparableContext from(Root root, CriteriaCondition criteria) { + Element element = (Element) criteria.element(); + Path field = root.get(getName(element)); + Comparable fieldValue = element.value().get(Comparable.class); + return new ComparableContext(field, fieldValue); + } + } + + record BiComparableContext(Path field, Comparable fieldValue1, Comparable fieldValue2) { + + public static BiComparableContext from(Root root, CriteriaCondition criteria) { + Element element = (Element) criteria.element(); + final Path field = root.get(getName(element)); + Iterator iterator = elementCollection(criteria).iterator(); + final Comparable fieldValue1 = ((Value) iterator.next()).get(Comparable.class); + final Comparable fieldValue2 = ((Value) iterator.next()).get(Comparable.class); + return new BiComparableContext(field, fieldValue1, fieldValue2); + } + + } + + record MultiValueContext(Path field, Collection fieldValues) { + + public static MultiValueContext from(Root root, CriteriaCondition criteria) { + Element element = (Element) criteria.element(); + Path field = root.get(getName(element)); + return new MultiValueContext(field, elementCollection(criteria)); + } + } + + public Query buildQuery(String query) { + EntityManager em = entityManager(); + return em.createQuery(query); + } + + public TypedQuery buildQuery(Class fromType, Class resultType, + Function, CriteriaQuery> queryModifier) { + EntityManager em = entityManager(); + CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(resultType); + Root from = criteriaQuery.from(fromType); + criteriaQuery = queryModifier.apply(new QueryContext(criteriaQuery, from, criteriaBuilder)); + return em.createQuery(criteriaQuery); + } + + private static String getName(Element element) { + String name = element.name(); + // NoSQL DBs translate id field into "_id" but we don't want it + return name.equals("_id") ? "id" : name; + } + + private Predicate parseCriteria(Object value, QueryContext ctx) { + if (value instanceof CriteriaCondition criteria) { + return switch (criteria.condition()) { + case NOT -> + ctx.builder().not(parseCriteria(criteria.element(), ctx)); + case EQUALS -> { + Element element = (Element) criteria.element(); + if (element.value().isNull()) { + yield ctx.builder().isNull(ctx.root().get(getName(element))); + } else { + yield ctx.builder().equal(ctx.root().get(getName(element)), element.value().get()); + } + } + case AND -> { + Iterator iterator = elementCollection(criteria).iterator(); + yield ctx.builder().and(parseCriteria(iterator.next(), ctx), parseCriteria(iterator.next(), ctx)); + } + case LESSER_THAN -> { + ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); + yield ctx.builder().lessThan(comparableContext.field(), comparableContext.fieldValue()); + } + case LESSER_EQUALS_THAN -> { + ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); + yield ctx.builder().lessThanOrEqualTo(comparableContext.field(), comparableContext.fieldValue()); + } + case GREATER_THAN -> { + ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); + yield ctx.builder().greaterThan(comparableContext.field(), comparableContext.fieldValue()); + } + case GREATER_EQUALS_THAN -> { + ComparableContext comparableContext = ComparableContext.from(ctx.root(), criteria); + yield ctx.builder().greaterThanOrEqualTo(comparableContext.field(), comparableContext.fieldValue()); + } + case BETWEEN -> { + BiComparableContext comparableContext = BiComparableContext.from(ctx.root(), criteria); + yield ctx.builder().between(comparableContext.field(), comparableContext.fieldValue1(), comparableContext.fieldValue2()); + } + case IN -> { + MultiValueContext valueContext = MultiValueContext.from(ctx.root(), criteria); + CriteriaBuilder.In inExpr = ctx.builder().in(valueContext.field()); + valueContext.fieldValues().forEach(v -> inExpr.value(v)); + yield inExpr; + } + + default -> + throw new UnsupportedOperationException("Not supported yet."); + }; + } else if (value instanceof Element element) { + return parseCriteria(element.value().get(), ctx); + } + throw new UnsupportedOperationException("Not supported yet."); + } + + private static Collection elementCollection(CriteriaCondition criteria) { + Element element = (Element) criteria.element(); + return (Collection) element.value().get(); + } + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/JakartaPersistenceRepositoryProxy.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/repository/JakartaPersistenceRepositoryProxy.java similarity index 94% rename from jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/JakartaPersistenceRepositoryProxy.java rename to jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/repository/JakartaPersistenceRepositoryProxy.java index 1677cbdf..baddb9e4 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/JakartaPersistenceRepositoryProxy.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/repository/JakartaPersistenceRepositoryProxy.java @@ -13,7 +13,7 @@ * * Ondro Mihalyi */ -package org.eclipse.jnosql.jakartapersistence.mapping.query; +package org.eclipse.jnosql.jakartapersistence.mapping.repository; import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; import org.eclipse.jnosql.mapping.core.Converters; diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/RepositoryPersistenceBean.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/repository/RepositoryPersistenceBean.java similarity index 98% rename from jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/RepositoryPersistenceBean.java rename to jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/repository/RepositoryPersistenceBean.java index c9d1ec14..ed8ced19 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/query/RepositoryPersistenceBean.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/repository/RepositoryPersistenceBean.java @@ -12,7 +12,7 @@ * * Otavio Santana */ -package org.eclipse.jnosql.jakartapersistence.mapping.query; +package org.eclipse.jnosql.jakartapersistence.mapping.repository; import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; import jakarta.data.repository.DataRepository; From 856926d716fc8f7be60ea6bc2c492e01afca9fbf Mon Sep 17 00:00:00 2001 From: Ondro Mihalyi Date: Sun, 21 Jul 2024 03:30:04 +0200 Subject: [PATCH 4/5] feat: Jakarta Persistence Driver - Support for some delete statements Depends on Eclipselink snapshot version, which contains a few fixes --- .../pom.xml | 5 +- .../JNoSqlEntitySelectedTests.java | 3 ++ .../jakartapersistence/JNoSqlEntityTests.java | 3 +- .../JNoSqlPersistenceEntityTests.java | 3 +- .../test/resources/META-INF/persistence.xml | 2 +- .../mapping/BaseQueryParser.java | 38 ++++++++++++++ .../mapping/DeleteQueryParser.java | 49 +++++++++++++++++++ .../mapping/PersistenceDocumentTemplate.java | 7 ++- .../mapping/PersistencePreparedStatement.java | 9 +++- .../mapping/SelectQueryParser.java | 14 +----- .../JakartaPersistenceRepositoryProxy.java | 8 +++ .../jakarta.enterprise.inject.spi.Extension | 2 +- .../PersonRepositoryTest.java | 5 ++ 13 files changed, 124 insertions(+), 24 deletions(-) create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/BaseQueryParser.java create mode 100644 jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/DeleteQueryParser.java diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/pom.xml b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/pom.xml index 496ba191..db6b02d8 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/pom.xml +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/pom.xml @@ -97,8 +97,8 @@ org.eclipse.persistence - eclipselink - 5.0.0-B02 + org.eclipse.persistence.jpa + 5.0.0-SNAPSHOT test @@ -159,7 +159,6 @@ jakarta.enterprise jakarta.enterprise.cdi-api - ${jakarta.enterprise.cdi.version} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntitySelectedTests.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntitySelectedTests.java index e8d5c57a..4f1d5c6c 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntitySelectedTests.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntitySelectedTests.java @@ -28,9 +28,12 @@ import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +// selected failing tests that can be worked on next +@Disabled @EnableAutoWeld @AddPackages(value = {Converters.class, EntityConverter.class, DocumentTemplate.class}) @AddPackages(DocumentTemplateProducer.class) diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java index d6562588..5550365f 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlEntityTests.java @@ -28,10 +28,9 @@ import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.extension.ExtendWith; -@Disabled +//@Disabled @EnableAutoWeld @AddPackages(value = {Converters.class, EntityConverter.class, DocumentTemplate.class}) @AddPackages(DocumentTemplateProducer.class) diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlPersistenceEntityTests.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlPersistenceEntityTests.java index 769386de..48a22be1 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlPersistenceEntityTests.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/java/org/eclipse/jnosql/tck/jakartapersistence/JNoSqlPersistenceEntityTests.java @@ -31,10 +31,9 @@ import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; import org.eclipse.jnosql.jakartapersistence.mapping.spi.JakartaPersistenceExtension; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.extension.ExtendWith; -@Disabled +//@Disabled @EnableAutoWeld @AddPackages(value = {Converters.class, EntityConverter.class, DocumentTemplate.class}) @AddPackages(DocumentTemplateProducer.class) diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/resources/META-INF/persistence.xml b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/resources/META-INF/persistence.xml index 2e2505e0..dc6d75b6 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/resources/META-INF/persistence.xml +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-data-tck-runner/src/test/resources/META-INF/persistence.xml @@ -30,7 +30,7 @@ - + diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/BaseQueryParser.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/BaseQueryParser.java new file mode 100644 index 00000000..efb58ea1 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/BaseQueryParser.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.jakartapersistence.mapping; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.metamodel.EntityType; +import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; + +class BaseQueryParser { + + protected final PersistenceDatabaseManager manager; + + protected BaseQueryParser(PersistenceDatabaseManager manager) { + this.manager = manager; + } + + protected EntityType findEntityType(String entityName) { + return manager.findEntityType(entityName); + } + + protected EntityManager entityManager() { + return manager.getEntityManager(); + } + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/DeleteQueryParser.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/DeleteQueryParser.java new file mode 100644 index 00000000..87f67424 --- /dev/null +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/DeleteQueryParser.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php. + * + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * + * Ondro Mihalyi + */ +package org.eclipse.jnosql.jakartapersistence.mapping; + +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaDelete; +import jakarta.persistence.criteria.Root; +import jakarta.persistence.metamodel.EntityType; +import jakarta.persistence.metamodel.SingularAttribute; +import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; + +class DeleteQueryParser extends BaseQueryParser { + + + public DeleteQueryParser(PersistenceDatabaseManager manager) { + super(manager); + } + + public void delete(Class type, K key) { + CriteriaBuilder criteriaBuilder = entityManager().getCriteriaBuilder(); + CriteriaDelete deleteCriteria = criteriaBuilder.createCriteriaDelete(type); + Root root = deleteCriteria.from(type); + String entityIdName = getEntityIdName(type); + deleteCriteria.where(criteriaBuilder.equal(root.get(entityIdName), key)); + entityManager().createQuery(deleteCriteria).executeUpdate(); + } + + private String getEntityIdName(Class type) { + EntityType entityType = entityManager().getMetamodel().entity(type); + SingularAttribute idAttribute = entityType.getId(entityType.getIdType().getJavaType()); + String entityIdName = idAttribute.getName(); + return entityIdName; + } + + +} diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java index 2646d2ee..acc6a253 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistenceDocumentTemplate.java @@ -45,16 +45,19 @@ public class PersistenceDocumentTemplate implements DocumentTemplate { private final PersistenceDatabaseManager manager; private final SelectQueryParser selectParser; + private final DeleteQueryParser deleteParser; @Inject PersistenceDocumentTemplate(PersistenceDatabaseManager manager) { this.manager = manager; this.selectParser = new SelectQueryParser(manager); + this.deleteParser = new DeleteQueryParser(manager); } PersistenceDocumentTemplate() { manager = null; selectParser = null; + deleteParser = null; } private EntityManager entityManager() { @@ -178,8 +181,8 @@ public Iterable update(Iterable itrbl) { } @Override - public void delete(Class type, K k) { - throw new UnsupportedOperationException("Not supported yet."); + public void delete(Class type, K key) { + deleteParser.delete(type, key); } @Override diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistencePreparedStatement.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistencePreparedStatement.java index afc9b36a..022c6af6 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistencePreparedStatement.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/PersistencePreparedStatement.java @@ -19,6 +19,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.stream.IntStream; import java.util.stream.Stream; import org.eclipse.jnosql.mapping.PreparedStatement; @@ -49,7 +50,13 @@ public PreparedStatement bind(String name, Object value) { @Override public Stream result() { - return createQuery().getResultStream(); + Query query = createQuery(); + try { + return query.getResultStream(); + } catch (IllegalStateException e) { + return IntStream.rangeClosed(1, query.executeUpdate()) + .mapToObj(i -> (T)Integer.valueOf(i)); + } } @Override diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/SelectQueryParser.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/SelectQueryParser.java index f574df78..a67a873b 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/SelectQueryParser.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/SelectQueryParser.java @@ -35,24 +35,14 @@ import org.eclipse.jnosql.communication.semistructured.SelectQuery; import org.eclipse.jnosql.jakartapersistence.communication.PersistenceDatabaseManager; -public class SelectQueryParser { - - private final PersistenceDatabaseManager manager; +class SelectQueryParser extends BaseQueryParser { record QueryContext(CriteriaQuery query, Root root, CriteriaBuilder builder) { } public SelectQueryParser(PersistenceDatabaseManager manager) { - this.manager = manager; - } - - private EntityType findEntityType(String entityName) { - return manager.findEntityType(entityName); - } - - private EntityManager entityManager() { - return manager.getEntityManager(); + super(manager); } public long count(String entity) { diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/repository/JakartaPersistenceRepositoryProxy.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/repository/JakartaPersistenceRepositoryProxy.java index baddb9e4..f8954eb3 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/repository/JakartaPersistenceRepositoryProxy.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/mapping/repository/JakartaPersistenceRepositoryProxy.java @@ -15,6 +15,7 @@ */ package org.eclipse.jnosql.jakartapersistence.mapping.repository; +import java.lang.reflect.Method; import org.eclipse.jnosql.jakartapersistence.mapping.PersistenceDocumentTemplate; import org.eclipse.jnosql.mapping.core.Converters; import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; @@ -26,4 +27,11 @@ public JakartaPersistenceRepositoryProxy(PersistenceDocumentTemplate template, E super(template, entities, repositoryType, converters); } + @Override + protected Object executeCursorPagination(Object instance, Method method, Object[] params) { + // We need to override this because SemiStructuredRepositoryProxy + // expects the semistructured.PreparedStatement template + throw new UnsupportedOperationException("Not supported yet."); + } + } diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/resources/META-INF/services/jakarta.enterprise.inject.spi.Extension b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/resources/META-INF/services/jakarta.enterprise.inject.spi.Extension index ad093ee1..f3c4099d 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/resources/META-INF/services/jakarta.enterprise.inject.spi.Extension +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/resources/META-INF/services/jakarta.enterprise.inject.spi.Extension @@ -10,6 +10,6 @@ # # Contributors: # -# Otavio Santana +# Ondro Mihalyi # org.eclipse.jnosql.jakartapersistence.mapping.spi.JakartaPersistenceExtension \ No newline at end of file diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepositoryTest.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepositoryTest.java index b8aca7ed..dcb07f32 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepositoryTest.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/test/java/ee/omnifish/jnosql/jakartapersistence/PersonRepositoryTest.java @@ -105,6 +105,11 @@ void findByXIn() { assertThat(persons, hasSize(3)); } + @Test + void hermesParser() { + getEntityManager().createQuery("UPDATE Person SET length = age + 1"); + } + private class PersonBuilder { Person p = new Person(); From 3434b9f30dc80b6b6943389486c5b34037072170 Mon Sep 17 00:00:00 2001 From: Ondro Mihalyi Date: Thu, 8 Aug 2024 09:58:35 +0200 Subject: [PATCH 5/5] feat: Jakarta Persistence Driver - clean up --- .../jnosql-jakarta-persistence-driver/pom.xml | 2 +- .../PersistenceClassScannerSingleton.java | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/pom.xml b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/pom.xml index ccfbca77..d9573878 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/pom.xml +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/pom.xml @@ -103,7 +103,7 @@ org.eclipse.persistence eclipselink - 5.0.0-B02 + 5.0.0-SNAPSHOT test diff --git a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceClassScannerSingleton.java b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceClassScannerSingleton.java index 11fbd012..f9932088 100644 --- a/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceClassScannerSingleton.java +++ b/jnosql-jakarta-persistence/jnosql-jakarta-persistence-driver/src/main/java/org/eclipse/jnosql/jakartapersistence/communication/PersistenceClassScannerSingleton.java @@ -16,9 +16,6 @@ package org.eclipse.jnosql.jakartapersistence.communication; -import static java.util.Collections.unmodifiableSet; -import static java.util.stream.Collectors.toUnmodifiableSet; - import io.github.classgraph.ClassGraph; import io.github.classgraph.ScanResult; import jakarta.data.repository.BasicRepository; @@ -28,6 +25,7 @@ import jakarta.nosql.Embeddable; import jakarta.nosql.Entity; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -77,18 +75,18 @@ enum PersistenceClassScannerSingleton implements ClassScanner { @Override public Set> entities() { - return unmodifiableSet(entities); + return Collections.unmodifiableSet(entities); } @Override public Set> repositories() { - return unmodifiableSet(repositories); + return Collections.unmodifiableSet(repositories); } @Override public Set> embeddables() { - return unmodifiableSet(embeddables); + return Collections.unmodifiableSet(embeddables); } @Override @@ -96,7 +94,7 @@ public Set> embeddables() { Objects.requireNonNull(filter, "filter is required"); return repositories.stream().filter(filter::isAssignableFrom) .filter(c -> Arrays.asList(c.getInterfaces()).contains(filter)) - .collect(toUnmodifiableSet()); + .collect(Collectors.toUnmodifiableSet()); }