From 8a36c318f0b6a9cdae0708b081f7c3215c3ed451 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 28 May 2024 20:26:48 +0100 Subject: [PATCH 01/35] docs: enhance changelog about custom repository Signed-off-by: Otavio Santana --- CHANGELOG.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 1a99dccb5..2b63d9071 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -8,6 +8,10 @@ and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Version == [Unreleased] +=== Added + +- Enables custom Repository + == [1.1.1] - 2023-05-25 === Changed From 974f8ea5f4eeec2aba5ad6bc1fe9d04f9c50ac76 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 28 May 2024 20:32:34 +0100 Subject: [PATCH 02/35] chore: create a custom repositories Signed-off-by: Otavio Santana --- .../org/eclipse/jnosql/mapping/metadata/ClassScanner.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/jnosql-mapping/jnosql-mapping-api-core/src/main/java/org/eclipse/jnosql/mapping/metadata/ClassScanner.java b/jnosql-mapping/jnosql-mapping-api-core/src/main/java/org/eclipse/jnosql/mapping/metadata/ClassScanner.java index 8d9beaf0d..1d8dbed85 100644 --- a/jnosql-mapping/jnosql-mapping-api-core/src/main/java/org/eclipse/jnosql/mapping/metadata/ClassScanner.java +++ b/jnosql-mapping/jnosql-mapping-api-core/src/main/java/org/eclipse/jnosql/mapping/metadata/ClassScanner.java @@ -68,6 +68,13 @@ public interface ClassScanner { */ Set> repositoriesStandard(); + /** + * Returns a set of custom repository interfaces that are not standard repositories. + * + * @return A set of custom repository interfaces. + */ + Set> customRepositories(); + /** * Loads and returns an instance of the {@link ClassScanner} implementation using the ServiceLoader mechanism. * From 0b34905b7e2a0fa0e05153f3f026ab0400c4580b Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 28 May 2024 21:02:21 +0100 Subject: [PATCH 03/35] feat: include implementation of repository Signed-off-by: Otavio Santana --- .../reflection/ClassGraphClassScanner.java | 28 ++++++++----------- .../reflection/ReflectionClassScanner.java | 6 ++++ .../ClassGraphClassScannerTest.java | 11 ++++++-- .../mapping/reflection/entities/Library.java | 21 ++++++++++++++ 4 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 jnosql-mapping/jnosql-mapping-reflection/src/test/java/org/eclipse/jnosql/mapping/reflection/entities/Library.java diff --git a/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ClassGraphClassScanner.java b/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ClassGraphClassScanner.java index 3efdc0a1d..d13910697 100644 --- a/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ClassGraphClassScanner.java +++ b/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ClassGraphClassScanner.java @@ -48,20 +48,23 @@ enum ClassGraphClassScanner implements ClassScanner { private final Set> entities; private final Set> repositories; private final Set> embeddables; + private final Set> customRepositories; ClassGraphClassScanner() { entities = new HashSet<>(); embeddables = new HashSet<>(); repositories = new HashSet<>(); + customRepositories = new HashSet<>(); Logger logger = Logger.getLogger(ClassGraphClassScanner.class.getName()); logger.fine("Starting scan class to find entities, embeddable and repositories."); try (ScanResult result = new ClassGraph().enableAllInfo().scan()) { - checkInvalidRepositories(loadInvalidRepositories(result)); + var notSupportedRepositories = loadNotSupportedRepositories(result); this.entities.addAll(loadEntities(result)); this.embeddables.addAll(loadEmbeddable(result)); this.repositories.addAll(loadRepositories(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())); @@ -106,34 +109,27 @@ public Set> repositoriesStandard() { }).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(RepositoryFilter.INSTANCE) .toList(); } @SuppressWarnings("rawtypes") - private static void checkInvalidRepositories(List> classes) { - if (!classes.isEmpty()) { - Logger logger = Logger.getLogger(ClassGraphClassScanner.class.getName()); - String repositories = classes.stream() - .map(Class::getName) - .collect(Collectors.joining(",")); - logger.info("The following repositories cannot be implemented by the Jakarta Data Provider JNoSQL " + - "because the entities do not have the " + jakarta.nosql.Entity.class.getName() + " annotation: " + - repositories); - } - } - - - @SuppressWarnings("rawtypes") - private static List> loadInvalidRepositories(ScanResult scan) { + private static List> loadNotSupportedRepositories(ScanResult scan) { return scan.getClassesWithAnnotation(Repository.class) .getInterfaces() + .filter(c -> c.implementsInterface(DataRepository.class)) .loadClasses(DataRepository.class) .stream().filter(RepositoryFilter.INSTANCE::isInvalid) .toList(); diff --git a/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ReflectionClassScanner.java b/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ReflectionClassScanner.java index 5875e9536..b0bf22f76 100644 --- a/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ReflectionClassScanner.java +++ b/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ReflectionClassScanner.java @@ -17,6 +17,7 @@ import jakarta.data.repository.DataRepository; import org.eclipse.jnosql.mapping.metadata.ClassScanner; +import java.util.Collections; import java.util.Set; /** @@ -49,4 +50,9 @@ public Set> embeddables() { public Set> repositoriesStandard() { return ClassGraphClassScanner.INSTANCE.repositoriesStandard(); } + + @Override + public Set> customRepositories() { + return ClassGraphClassScanner.INSTANCE.customRepositories(); + } } diff --git a/jnosql-mapping/jnosql-mapping-reflection/src/test/java/org/eclipse/jnosql/mapping/reflection/ClassGraphClassScannerTest.java b/jnosql-mapping/jnosql-mapping-reflection/src/test/java/org/eclipse/jnosql/mapping/reflection/ClassGraphClassScannerTest.java index a3dabba4c..5777291a5 100644 --- a/jnosql-mapping/jnosql-mapping-reflection/src/test/java/org/eclipse/jnosql/mapping/reflection/ClassGraphClassScannerTest.java +++ b/jnosql-mapping/jnosql-mapping-reflection/src/test/java/org/eclipse/jnosql/mapping/reflection/ClassGraphClassScannerTest.java @@ -20,6 +20,7 @@ import org.eclipse.jnosql.mapping.reflection.entities.AnimalRepository; import org.eclipse.jnosql.mapping.reflection.entities.Contact; import org.eclipse.jnosql.mapping.reflection.entities.Job; +import org.eclipse.jnosql.mapping.reflection.entities.Library; import org.eclipse.jnosql.mapping.reflection.entities.MovieRepository; import org.eclipse.jnosql.mapping.reflection.entities.NoSQLVendor; import org.eclipse.jnosql.mapping.reflection.entities.Person; @@ -86,8 +87,7 @@ void shouldFieldByNoSQL() { Set> repositories = classScanner.repositories(NoSQLRepository.class); Assertions.assertNotNull(repositories); - assertThat(repositories).hasSize(1) - .contains(PersonRepository.class); + assertThat(repositories).hasSize(1).contains(PersonRepository.class); } @Test @@ -96,4 +96,11 @@ void shouldReturnStandardRepositories() { assertThat(repositories).hasSize(2) .contains(PersonRepository.class, MovieRepository.class); } + + @Test + void shouldReturnCustomRepositories() { + Set> repositories = classScanner.customRepositories(); + assertThat(repositories).hasSize(1) + .contains(Library.class); + } } \ No newline at end of file diff --git a/jnosql-mapping/jnosql-mapping-reflection/src/test/java/org/eclipse/jnosql/mapping/reflection/entities/Library.java b/jnosql-mapping/jnosql-mapping-reflection/src/test/java/org/eclipse/jnosql/mapping/reflection/entities/Library.java new file mode 100644 index 000000000..ee5fea3fa --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-reflection/src/test/java/org/eclipse/jnosql/mapping/reflection/entities/Library.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: + * + * Otavio Santana + */ +package org.eclipse.jnosql.mapping.reflection.entities; + +import jakarta.data.repository.Repository; + +@Repository +public interface Library { +} From 5bead430dac015a2471250b9899bf4852b90fefc Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Tue, 28 May 2024 21:04:29 +0100 Subject: [PATCH 04/35] feat: include load custom repositories Signed-off-by: Otavio Santana --- .../mapping/reflection/ClassGraphClassScanner.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ClassGraphClassScanner.java b/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ClassGraphClassScanner.java index d13910697..b9d89b353 100644 --- a/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ClassGraphClassScanner.java +++ b/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ClassGraphClassScanner.java @@ -61,9 +61,11 @@ enum ClassGraphClassScanner implements ClassScanner { logger.fine("Starting scan class to find entities, embeddable and repositories."); try (ScanResult result = new ClassGraph().enableAllInfo().scan()) { var notSupportedRepositories = loadNotSupportedRepositories(result); + logger.info("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" @@ -125,6 +127,13 @@ private static List> loadRepositories(ScanResult scan) { .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) From e85987f9b3842b558aceaa990c555b9851f0b22f Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Wed, 29 May 2024 20:29:33 +0100 Subject: [PATCH 05/35] style: remove unsed imports Signed-off-by: Otavio Santana --- .../jnosql/mapping/reflection/ReflectionClassScanner.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ReflectionClassScanner.java b/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ReflectionClassScanner.java index b0bf22f76..0a230281c 100644 --- a/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ReflectionClassScanner.java +++ b/jnosql-mapping/jnosql-mapping-reflection/src/main/java/org/eclipse/jnosql/mapping/reflection/ReflectionClassScanner.java @@ -17,7 +17,6 @@ import jakarta.data.repository.DataRepository; import org.eclipse.jnosql.mapping.metadata.ClassScanner; -import java.util.Collections; import java.util.Set; /** From 203e480cd3cc256a2d254303d65bc22e29369d6f Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 30 May 2024 04:38:41 +0100 Subject: [PATCH 06/35] refactor: update method at parameterbasedquery Signed-off-by: Otavio Santana --- .../SemiStructuredParameterBasedQuery.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredParameterBasedQuery.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredParameterBasedQuery.java index 1f97060fe..715345373 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredParameterBasedQuery.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredParameterBasedQuery.java @@ -58,13 +58,7 @@ public org.eclipse.jnosql.communication.semistructured.SelectQuery toQuery(Map> updateSorter = new ArrayList<>(); - for (Sort sort : sorts) { - var name = entityMetadata.fieldMapping(sort.property()) - .map(FieldMetadata::name) - .orElse(sort.property()); - updateSorter.add(sort.isAscending()? Sort.asc(name): Sort.desc(name)); - } + List> updateSorter = getSorts(sorts, entityMetadata); var condition = condition(conditions); var entity = entityMetadata.name(); @@ -87,13 +81,7 @@ public org.eclipse.jnosql.communication.semistructured.SelectQuery toQueryNative conditions.add(condition(entityMetadata, entry)); } - List> updateSorter = new ArrayList<>(); - for (Sort sort : sorts) { - var name = entityMetadata.fieldMapping(sort.property()) - .map(FieldMetadata::name) - .orElse(sort.property()); - updateSorter.add(sort.isAscending()? Sort.asc(name): Sort.desc(name)); - } + List> updateSorter = getSorts(sorts, entityMetadata); var condition = condition(conditions); var entity = entityMetadata.name(); @@ -130,4 +118,15 @@ private CriteriaCondition condition( EntityMetadata entityMetadata, Map.Entry> getSorts(List> sorts, EntityMetadata entityMetadata) { + List> updateSorter = new ArrayList<>(); + for (Sort sort : sorts) { + var name = entityMetadata.fieldMapping(sort.property()) + .map(FieldMetadata::name) + .orElse(sort.property()); + updateSorter.add(sort.isAscending()? Sort.asc(name): Sort.desc(name)); + } + return updateSorter; + } } From f6a1f9b524280abbe8c1dedc8727546e6d90d26d Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 30 May 2024 04:44:28 +0100 Subject: [PATCH 07/35] style: remove extra space Signed-off-by: Otavio Santana --- .../semistructured/query/SemiStructuredRepositoryProxy.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredRepositoryProxy.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredRepositoryProxy.java index be0dd2e0a..4505d25ef 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredRepositoryProxy.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredRepositoryProxy.java @@ -43,8 +43,6 @@ public class SemiStructuredRepositoryProxy extends AbstractSemiStructuredR private final Class repositoryType; - - /** * Creates a new instance of ColumnRepositoryProxy. * From f44741d07a0b0fefdca10110885dc7305c21e99a Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 30 May 2024 06:28:22 +0100 Subject: [PATCH 08/35] feat: fix array convertion Signed-off-by: Otavio Santana --- .../core/query/AnnotationOperation.java | 21 +++- .../core/query/AnnotationOperationTest.java | 4 +- .../query/CustomRepositoryHandler.java | 96 +++++++++++++++++++ .../query/CustomRepositoryHandlerTest.java | 61 ++++++++++++ .../mapping/semistructured/query/People.java | 2 + 5 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java create mode 100644 jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java create mode 100644 jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java diff --git a/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperation.java b/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperation.java index 34719bcc4..8f4f3e91c 100644 --- a/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperation.java +++ b/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperation.java @@ -14,7 +14,9 @@ */ package org.eclipse.jnosql.mapping.core.query; +import java.lang.reflect.Array; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -41,7 +43,7 @@ public Object invoke(Operation operation) { List result = operation.repository.insertAll(stream(entities.spliterator(), false).toList()); return returnInsert(returnType, result); } else if (param.getClass().isArray()) { - Iterable result = operation.repository.insertAll(Arrays.asList((Object[]) param)); + Iterable result = operation.repository.insertAll(getArray(param)); return returnInsert(returnType, result); } else { var result = operation.repository.insert(param); @@ -73,7 +75,7 @@ public Object invoke(Operation operation) { if (param instanceof Iterable entities) { return executeIterable(operation, entities, returnType, false, null); } else if (param.getClass().isArray()) { - List entities = Arrays.asList((Object[]) param); + List entities = getArray(param); return executeIterable(operation, entities, returnType, true, param); } else { return executeSingleEntity(operation, param, returnType); @@ -126,7 +128,7 @@ public Object invoke(Operation operation) { if (param instanceof Iterable entities) { return executeIterable(operation, entities, returnType); } else if (param.getClass().isArray()) { - List entities = Arrays.asList((Object[]) param); + List entities = getArray(param); return executeIterable(operation, entities, returnType); } else { return executeSingleEntity(operation, param, returnType); @@ -175,7 +177,7 @@ public Object invoke(Operation operation) { Iterable result = operation.repository.saveAll(stream(entities.spliterator(), false).toList()); return returnType.isVoid() ? Void.TYPE : result; } else if (param.getClass().isArray()) { - Iterable result = operation.repository.saveAll(Arrays.asList((Object[]) param)); + Iterable result = operation.repository.saveAll(getArray(param)); return returnType.isVoid() ? Void.TYPE : result; } else { Object result = operation.repository.save(param); @@ -184,6 +186,17 @@ public Object invoke(Operation operation) { } }; + private static List getArray(Object param) { + List entities = new ArrayList<>(); + int length = Array.getLength(param); + for (int index = 0; index < length; index++) { + Object element = Array.get(param, index); + entities.add(element); + } + + return entities; + } + private static void checkParameterNumber(Operation operation) { if (operation.params.length != 1) { throw new UnsupportedOperationException("The method operation requires one parameter, please check the method: " diff --git a/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperationTest.java b/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperationTest.java index 501efbb14..be88fc3ae 100644 --- a/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperationTest.java +++ b/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperationTest.java @@ -47,6 +47,7 @@ void shouldReturnInvalidParameter() throws Throwable { Assertions.assertThatThrownBy(() -> UPDATE.invoke(new AnnotationOperation.Operation(method, new Object[]{person, person}, repository))) .isInstanceOf(UnsupportedOperationException.class); } + @Test void shouldInsertSingleParameter() throws Throwable { Method method = PersonRepository.class.getDeclaredMethod("same", Person.class); @@ -69,7 +70,7 @@ void shouldInsertIterableParameter() throws Throwable { @Test - void shouldInsertArrayParameter() throws Throwable { + void shouldInsertArrayObjectParameter() throws Throwable { Method method = PersonRepository.class.getDeclaredMethod("array", Person[].class); Person person = Person.builder().build(); Mockito.when(repository.insertAll(List.of(person))).thenReturn(List.of(person)); @@ -79,6 +80,7 @@ void shouldInsertArrayParameter() throws Throwable { Assertions.assertThat(List.of(person)).isEqualTo(invoked); } + @Test void shouldUpdateSingleParameter() throws Throwable { Method method = PersonRepository.class.getDeclaredMethod("same", Person.class); diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java new file mode 100644 index 000000000..1441b5ce0 --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java @@ -0,0 +1,96 @@ +/* + * 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: + * + * Otavio Santana + */ +package org.eclipse.jnosql.mapping.semistructured.query; + + +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.core.query.AbstractRepository; +import org.eclipse.jnosql.mapping.core.query.AnnotationOperation; +import org.eclipse.jnosql.mapping.core.query.RepositoryType; +import org.eclipse.jnosql.mapping.core.repository.ThrowingSupplier; +import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; +import org.eclipse.jnosql.mapping.semistructured.SemiStructuredTemplate; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Logger; + +import static org.eclipse.jnosql.mapping.core.query.AnnotationOperation.DELETE; +import static org.eclipse.jnosql.mapping.core.query.AnnotationOperation.INSERT; +import static org.eclipse.jnosql.mapping.core.query.AnnotationOperation.SAVE; +import static org.eclipse.jnosql.mapping.core.query.AnnotationOperation.UPDATE; + +/** + * This class is the engine of a custom repository from Jakarta Data specification. + * The implementation is based on {@link InvocationHandler} and it's used to create a custom repository. + + */ +public class CustomRepository implements InvocationHandler { + + private static final Logger LOGGER = Logger.getLogger(CustomRepository.class.getName()); + + private final EntitiesMetadata entitiesMetadata; + + private final SemiStructuredTemplate template; + + private final Class customRepositoryType; + + private final Converters converters; + + CustomRepository(EntitiesMetadata entitiesMetadata, SemiStructuredTemplate template, + Class customRepositoryType, + Converters converters) { + this.entitiesMetadata = entitiesMetadata; + this.template = template; + this.customRepositoryType = customRepositoryType; + this.converters = converters; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { + LOGGER.info("Executing the method: " + method); + RepositoryType type = RepositoryType.of(method, customRepositoryType); + switch (type) { + case SAVE -> { + return unwrapInvocationTargetException(() -> SAVE.invoke(new AnnotationOperation.Operation(method, params, repository(method)))); + } + case INSERT -> { + return unwrapInvocationTargetException(() -> INSERT.invoke(new AnnotationOperation.Operation(method, params, repository(method)))); + } + case DELETE -> { + return unwrapInvocationTargetException(() -> DELETE.invoke(new AnnotationOperation.Operation(method, params, repository(method)))); + } + case UPDATE -> { + return unwrapInvocationTargetException(() -> UPDATE.invoke(new AnnotationOperation.Operation(method, params, repository(method)))); + } + default -> { + return Void.class; + } + } + } + + private AbstractRepository repository(Method method) { + return null; + } + + protected Object unwrapInvocationTargetException(ThrowingSupplier supplier) throws Throwable { + try { + return supplier.get(); + } catch (InvocationTargetException ex) { + throw ex.getCause(); + } + } +} diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java new file mode 100644 index 000000000..b8320730e --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java @@ -0,0 +1,61 @@ +/* + * 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: + * + * Otavio Santana + */ +package org.eclipse.jnosql.mapping.semistructured.query; + +import jakarta.inject.Inject; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.core.spi.EntityMetadataExtension; +import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; +import org.eclipse.jnosql.mapping.reflection.Reflections; +import org.eclipse.jnosql.mapping.semistructured.EntityConverter; +import org.eclipse.jnosql.mapping.semistructured.MockProducer; +import org.eclipse.jnosql.mapping.semistructured.SemiStructuredTemplate; +import org.jboss.weld.junit5.auto.AddExtensions; +import org.jboss.weld.junit5.auto.AddPackages; +import org.jboss.weld.junit5.auto.EnableAutoWeld; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Proxy; + +import static org.junit.jupiter.api.Assertions.*; + +@EnableAutoWeld +@AddPackages(value = {Converters.class, EntityConverter.class}) +@AddPackages(MockProducer.class) +@AddPackages(Reflections.class) +@AddExtensions({EntityMetadataExtension.class}) +class CustomRepositoryTest { + + @Inject + private EntitiesMetadata entitiesMetadata; + + @Inject + private SemiStructuredTemplate template; + + @Inject + private Converters converters; + + private People people; + + @Test + void setUp(){ + + CustomRepository customRepository = new CustomRepository(entitiesMetadata, template, People.class, converters); + people = (People) Proxy.newProxyInstance(People.class.getClassLoader(), new Class[]{People.class}, + personHandler); + } + + +} \ No newline at end of file diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java new file mode 100644 index 000000000..983b31d1c --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java @@ -0,0 +1,2 @@ +package org.eclipse.jnosql.mapping.semistructured.query;public interface People { +} From aee4683488ebd1eeb41a9dedc96551914e57d90f Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 30 May 2024 06:39:09 +0100 Subject: [PATCH 09/35] feat: define array convertion Signed-off-by: Otavio Santana --- .../mapping/core/query/AnnotationOperation.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperation.java b/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperation.java index 8f4f3e91c..88e59a8fb 100644 --- a/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperation.java +++ b/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperation.java @@ -44,7 +44,8 @@ public Object invoke(Operation operation) { return returnInsert(returnType, result); } else if (param.getClass().isArray()) { Iterable result = operation.repository.insertAll(getArray(param)); - return returnInsert(returnType, result); + + return returnInsert(returnType, iterableToArray(param, result)); } else { var result = operation.repository.insert(param); return returnInsert(returnType, result); @@ -186,6 +187,15 @@ public Object invoke(Operation operation) { } }; + private static Object iterableToArray(Object param, Iterable result) { + List elements = new ArrayList<>(); + for (Object o : result) { + elements.add(o); + } + Object newArray = Array.newInstance(param.getClass().getComponentType(), elements.size()); + return elements.toArray((Object[]) newArray); + } + private static List getArray(Object param) { List entities = new ArrayList<>(); int length = Array.getLength(param); From 5b5450bda8f17a27f6c23cc4702b92b249c085d9 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 30 May 2024 06:41:39 +0100 Subject: [PATCH 10/35] test: update test at annotation operation Signed-off-by: Otavio Santana --- .../jnosql/mapping/core/query/AnnotationOperationTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperationTest.java b/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperationTest.java index be88fc3ae..ccd36d043 100644 --- a/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperationTest.java +++ b/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperationTest.java @@ -68,16 +68,15 @@ void shouldInsertIterableParameter() throws Throwable { Assertions.assertThat(List.of(person)).isEqualTo(invoked); } - @Test void shouldInsertArrayObjectParameter() throws Throwable { Method method = PersonRepository.class.getDeclaredMethod("array", Person[].class); - Person person = Person.builder().build(); + Person person = Person.builder().withName("Ada").withAge(8).build(); Mockito.when(repository.insertAll(List.of(person))).thenReturn(List.of(person)); Object invoked = INSERT.invoke(new AnnotationOperation.Operation(method, new Object[]{new Person[]{person}}, repository)); Mockito.verify(repository).insertAll(List.of(person)); - Assertions.assertThat(List.of(person)).isEqualTo(invoked); + Assertions.assertThat(new Person[]{person}).isEqualTo(invoked); } From 55cf9142987ba18816977d7f023440280e9eeaf8 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 30 May 2024 06:44:18 +0100 Subject: [PATCH 11/35] feat: create custom repository to insert Signed-off-by: Otavio Santana --- .../SemiStructuredTemplate.java | 2 - .../query/CustomRepositoryHandler.java | 18 +++++-- .../query/CustomRepositoryHandlerTest.java | 52 ++++++++++++++++--- .../mapping/semistructured/query/People.java | 32 +++++++++++- 4 files changed, 89 insertions(+), 15 deletions(-) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/SemiStructuredTemplate.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/SemiStructuredTemplate.java index b5fa28514..571e8c8af 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/SemiStructuredTemplate.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/SemiStructuredTemplate.java @@ -29,8 +29,6 @@ */ public interface SemiStructuredTemplate extends Template { - - /** * Returns the number of elements in a specified column family. * diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java index 1441b5ce0..9c55a2265 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java @@ -21,11 +21,14 @@ import org.eclipse.jnosql.mapping.core.query.RepositoryType; import org.eclipse.jnosql.mapping.core.repository.ThrowingSupplier; import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; +import org.eclipse.jnosql.mapping.metadata.EntityMetadata; import org.eclipse.jnosql.mapping.semistructured.SemiStructuredTemplate; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.util.Optional; import java.util.logging.Logger; import static org.eclipse.jnosql.mapping.core.query.AnnotationOperation.DELETE; @@ -38,9 +41,9 @@ * The implementation is based on {@link InvocationHandler} and it's used to create a custom repository. */ -public class CustomRepository implements InvocationHandler { +public class CustomRepositoryHandler implements InvocationHandler { - private static final Logger LOGGER = Logger.getLogger(CustomRepository.class.getName()); + private static final Logger LOGGER = Logger.getLogger(CustomRepositoryHandler.class.getName()); private final EntitiesMetadata entitiesMetadata; @@ -50,7 +53,7 @@ public class CustomRepository implements InvocationHandler { private final Converters converters; - CustomRepository(EntitiesMetadata entitiesMetadata, SemiStructuredTemplate template, + CustomRepositoryHandler(EntitiesMetadata entitiesMetadata, SemiStructuredTemplate template, Class customRepositoryType, Converters converters) { this.entitiesMetadata = entitiesMetadata; @@ -83,7 +86,14 @@ public Object invoke(Object proxy, Method method, Object[] params) throws Throwa } private AbstractRepository repository(Method method) { - return null; + Class typeClass = (Class) method.getReturnType(); + if (typeClass.isArray()) { + typeClass = typeClass.getComponentType(); + } else if(Iterable.class.isAssignableFrom(typeClass)) { + typeClass = (Class) ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0]; + } + Optional entity = entitiesMetadata.findByClassName(typeClass.getName()); + return entity.map(entityMetadata -> new SemiStructuredRepositoryProxy.SemiStructuredRepository<>(template, entityMetadata)).orElse(null); } protected Object unwrapInvocationTargetException(ThrowingSupplier supplier) throws Throwable { diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java index b8320730e..86ded87d7 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java @@ -15,6 +15,7 @@ package org.eclipse.jnosql.mapping.semistructured.query; import jakarta.inject.Inject; +import org.assertj.core.api.Assertions; import org.eclipse.jnosql.mapping.core.Converters; import org.eclipse.jnosql.mapping.core.spi.EntityMetadataExtension; import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; @@ -22,26 +23,27 @@ import org.eclipse.jnosql.mapping.semistructured.EntityConverter; import org.eclipse.jnosql.mapping.semistructured.MockProducer; import org.eclipse.jnosql.mapping.semistructured.SemiStructuredTemplate; +import org.eclipse.jnosql.mapping.semistructured.entities.Person; import org.jboss.weld.junit5.auto.AddExtensions; import org.jboss.weld.junit5.auto.AddPackages; import org.jboss.weld.junit5.auto.EnableAutoWeld; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import java.lang.reflect.Proxy; - -import static org.junit.jupiter.api.Assertions.*; +import java.util.List; @EnableAutoWeld @AddPackages(value = {Converters.class, EntityConverter.class}) @AddPackages(MockProducer.class) @AddPackages(Reflections.class) @AddExtensions({EntityMetadataExtension.class}) -class CustomRepositoryTest { +class CustomRepositoryHandlerTest { @Inject private EntitiesMetadata entitiesMetadata; - @Inject private SemiStructuredTemplate template; @Inject @@ -49,12 +51,46 @@ class CustomRepositoryTest { private People people; + @BeforeEach + void setUp() { + template = Mockito.mock(SemiStructuredTemplate.class); + CustomRepositoryHandler customRepositoryHandler = new CustomRepositoryHandler(entitiesMetadata, template, People.class, converters); + people = (People) Proxy.newProxyInstance(People.class.getClassLoader(), new Class[]{People.class}, + customRepositoryHandler); + } + @Test - void setUp(){ + void shouldInsertEntity() { + Person person = Person.builder().withAge(26).withName("Ada").build(); + Mockito.when(template.insert(person)).thenReturn(person); + Person result = people.insert(person); - CustomRepository customRepository = new CustomRepository(entitiesMetadata, template, People.class, converters); - people = (People) Proxy.newProxyInstance(People.class.getClassLoader(), new Class[]{People.class}, - personHandler); + Mockito.verify(template).insert(person); + Mockito.verifyNoMoreInteractions(template); + Assertions.assertThat(result).isEqualTo(person); + } + + @Test + void shouldInsertListEntity() { + var persons = List.of(Person.builder().withAge(26).withName("Ada").build()); + Mockito.when(template.insert(persons)).thenReturn(persons); + List result = people.insert(persons); + + Mockito.verify(template).insert(persons); + Mockito.verifyNoMoreInteractions(template); + Assertions.assertThat(result).isEqualTo(persons); + } + + @Test + void shouldInsertArrayEntity() { + Person ada = Person.builder().withAge(26).withName("Ada").build(); + var persons = new Person[]{ada}; + Mockito.when(template.insert(Mockito.any())).thenReturn(List.of(ada)); + Person[] result = people.insert(persons); + + Mockito.verify(template).insert(List.of(ada)); + Mockito.verifyNoMoreInteractions(template); + Assertions.assertThat(result).isEqualTo(persons); } diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java index 983b31d1c..c03d37899 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java @@ -1,2 +1,32 @@ -package org.eclipse.jnosql.mapping.semistructured.query;public interface People { +/* + * 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: + * + * Otavio Santana + */ +package org.eclipse.jnosql.mapping.semistructured.query; + +import jakarta.data.repository.Insert; +import org.eclipse.jnosql.mapping.semistructured.entities.Person; + +import java.util.List; + +public interface People { + + @Insert + List insert(List people); + + @Insert + Person insert(Person person); + + @Insert + Person[] insert(Person[] person); } From 6df9035a32abca44adb4142c19a4ff0a5b1e812c Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 30 May 2024 21:16:49 +0100 Subject: [PATCH 12/35] feat: create update test scenrios Signed-off-by: Otavio Santana --- .../query/CustomRepositoryHandlerTest.java | 34 +++++++++++++++++++ .../mapping/semistructured/query/People.java | 11 ++++++ 2 files changed, 45 insertions(+) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java index 86ded87d7..7629ce577 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java @@ -94,4 +94,38 @@ void shouldInsertArrayEntity() { } + @Test + void shouldUpdateEntity() { + Person person = Person.builder().withAge(26).withName("Ada").build(); + Mockito.when(template.update(person)).thenReturn(person); + Person result = people.update(person); + + Mockito.verify(template).update(person); + Mockito.verifyNoMoreInteractions(template); + Assertions.assertThat(result).isEqualTo(person); + } + + @Test + void shouldUpdateListEntity() { + var persons = List.of(Person.builder().withAge(26).withName("Ada").build()); + Mockito.when(template.update(persons)).thenReturn(persons); + List result = people.update(persons); + + Mockito.verify(template).update(persons); + Mockito.verifyNoMoreInteractions(template); + Assertions.assertThat(result).isEqualTo(persons); + } + + @Test + void shouldUpdateArrayEntity() { + Person ada = Person.builder().withAge(26).withName("Ada").build(); + var persons = new Person[]{ada}; + Mockito.when(template.update(Mockito.any())).thenReturn(List.of(ada)); + Person[] result = people.update(persons); + + Mockito.verify(template).update(List.of(ada)); + Mockito.verifyNoMoreInteractions(template); + Assertions.assertThat(result).isEqualTo(persons); + } + } \ No newline at end of file diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java index c03d37899..ee2e223ca 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java @@ -15,6 +15,7 @@ package org.eclipse.jnosql.mapping.semistructured.query; import jakarta.data.repository.Insert; +import jakarta.data.repository.Update; import org.eclipse.jnosql.mapping.semistructured.entities.Person; import java.util.List; @@ -29,4 +30,14 @@ public interface People { @Insert Person[] insert(Person[] person); + + + @Update + List update(List people); + + @Update + Person update(Person person); + + @Update + Person[] update(Person[] person); } From ba25cf2bb17cd25410f570fc060fe5e18447e640 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 30 May 2024 21:20:30 +0100 Subject: [PATCH 13/35] feat: update annotation operation at Save to work with array Signed-off-by: Otavio Santana --- .../jnosql/mapping/core/query/AnnotationOperation.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperation.java b/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperation.java index 88e59a8fb..d2818be04 100644 --- a/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperation.java +++ b/jnosql-mapping/jnosql-mapping-core/src/main/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperation.java @@ -96,7 +96,7 @@ private static Object executeIterable(Operation operation, Iterable entities, Re } else if (returnType.isLong()) { return (long) result.size(); } else if (isArray) { - return result.toArray(); + return iterableToArray(param, result); } else { return entities; } @@ -179,7 +179,7 @@ public Object invoke(Operation operation) { return returnType.isVoid() ? Void.TYPE : result; } else if (param.getClass().isArray()) { Iterable result = operation.repository.saveAll(getArray(param)); - return returnType.isVoid() ? Void.TYPE : result; + return returnType.isVoid() ? Void.TYPE : iterableToArray(param, result); } else { Object result = operation.repository.save(param); return returnType.isVoid() ? Void.TYPE : result; From 693ea312244f91a0192a8692ae9d95af7c70ca2d Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 30 May 2024 21:26:08 +0100 Subject: [PATCH 14/35] test: update test scenarios with the operation changes Signed-off-by: Otavio Santana --- .../mapping/core/query/AnnotationOperationTest.java | 6 +++--- .../core/repository/RepositoryReflectionUtilsTest.java | 10 +++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperationTest.java b/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperationTest.java index ccd36d043..30b76b36f 100644 --- a/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperationTest.java +++ b/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/query/AnnotationOperationTest.java @@ -403,12 +403,12 @@ void shouldSaveIterableParameter() throws Throwable { @Test void shouldSaveArrayParameter() throws Throwable { Method method = PersonRepository.class.getDeclaredMethod("array", Person[].class); - Person person = Person.builder().build(); + Person person = Person.builder().withName("Ada").withAge(12).build(); Mockito.when(repository.saveAll(List.of(person))).thenReturn(List.of(person)); - Object invoked = SAVE.invoke(new AnnotationOperation.Operation(method, new Object[]{new Person[]{person}}, + Person[] invoked = (Person[]) SAVE.invoke(new AnnotationOperation.Operation(method, new Object[]{new Person[]{person}}, repository)); Mockito.verify(repository).saveAll(List.of(person)); - Assertions.assertThat(List.of(person)).isEqualTo(invoked); + Assertions.assertThat(invoked).contains(person); } @Test diff --git a/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/repository/RepositoryReflectionUtilsTest.java b/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/repository/RepositoryReflectionUtilsTest.java index d0c932a73..302d12b56 100644 --- a/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/repository/RepositoryReflectionUtilsTest.java +++ b/jnosql-mapping/jnosql-mapping-core/src/test/java/org/eclipse/jnosql/mapping/core/repository/RepositoryReflectionUtilsTest.java @@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Stream; @@ -34,7 +35,8 @@ class RepositoryReflectionUtilsTest { @Test void shouldGetParams(){ - Method method = PersonRepository.class.getDeclaredMethods()[0]; + Method method = Arrays.stream(PersonRepository.class.getDeclaredMethods()).filter(m -> m.getName().equals("query")) + .findFirst().orElseThrow(); Map params = RepositoryReflectionUtils.INSTANCE.getParams(method, new Object[]{"Ada"}); assertThat(params) .hasSize(1) @@ -44,14 +46,16 @@ void shouldGetParams(){ @Test void shouldQuery(){ - Method method = PersonRepository.class.getDeclaredMethods()[0]; + Method method = Arrays.stream(PersonRepository.class.getDeclaredMethods()).filter(m -> m.getName().equals("query")) + .findFirst().orElseThrow(); String query = RepositoryReflectionUtils.INSTANCE.getQuery(method); assertEquals("FROM Person WHERE name = :name", query); } @Test void shouldBy(){ - Method method = PersonRepository.class.getDeclaredMethods()[0]; + Method method = Arrays.stream(PersonRepository.class.getDeclaredMethods()).filter(m -> m.getName().equals("query")) + .findFirst().orElseThrow(); Map params = RepositoryReflectionUtils.INSTANCE.getBy(method, new Object[]{"Ada"}); assertThat(params) .hasSize(1) From 0bffb8a70dccfe98cbbaadfd4919542f952d495c Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 30 May 2024 21:43:41 +0100 Subject: [PATCH 15/35] feat: operates with NoSQL dastabase using annotations operations Signed-off-by: Otavio Santana --- .../query/CustomRepositoryHandler.java | 17 +++++++++-- .../query/CustomRepositoryHandlerTest.java | 28 +++++++++++++++++++ .../mapping/semistructured/query/People.java | 11 ++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java index 9c55a2265..632db15b2 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java @@ -28,6 +28,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; +import java.lang.reflect.TypeVariable; import java.util.Optional; import java.util.logging.Logger; @@ -74,7 +75,7 @@ public Object invoke(Object proxy, Method method, Object[] params) throws Throwa return unwrapInvocationTargetException(() -> INSERT.invoke(new AnnotationOperation.Operation(method, params, repository(method)))); } case DELETE -> { - return unwrapInvocationTargetException(() -> DELETE.invoke(new AnnotationOperation.Operation(method, params, repository(method)))); + return unwrapInvocationTargetException(() -> DELETE.invoke(new AnnotationOperation.Operation(method, params, repository(params)))); } case UPDATE -> { return unwrapInvocationTargetException(() -> UPDATE.invoke(new AnnotationOperation.Operation(method, params, repository(method)))); @@ -86,7 +87,7 @@ public Object invoke(Object proxy, Method method, Object[] params) throws Throwa } private AbstractRepository repository(Method method) { - Class typeClass = (Class) method.getReturnType(); + Class typeClass = method.getReturnType(); if (typeClass.isArray()) { typeClass = typeClass.getComponentType(); } else if(Iterable.class.isAssignableFrom(typeClass)) { @@ -96,6 +97,18 @@ private AbstractRepository repository(Method method) { return entity.map(entityMetadata -> new SemiStructuredRepositoryProxy.SemiStructuredRepository<>(template, entityMetadata)).orElse(null); } + private AbstractRepository repository(Object[] params) { + Class typeClass = params[0].getClass(); + if (typeClass.isArray()) { + typeClass = typeClass.getComponentType(); + } else if(Iterable.class.isAssignableFrom(typeClass)) { + var entity = ((Iterable) params[0]).iterator().next(); + typeClass = entity.getClass(); + } + Optional entity = entitiesMetadata.findByClassName(typeClass.getName()); + return entity.map(entityMetadata -> new SemiStructuredRepositoryProxy.SemiStructuredRepository<>(template, entityMetadata)).orElse(null); + } + protected Object unwrapInvocationTargetException(ThrowingSupplier supplier) throws Throwable { try { return supplier.get(); diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java index 7629ce577..56754423f 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java @@ -128,4 +128,32 @@ void shouldUpdateArrayEntity() { Assertions.assertThat(result).isEqualTo(persons); } + @Test + void shouldDeleteEntity() { + Person person = Person.builder().withId(1).withAge(26).withName("Ada").build(); + people.delete(person); + + Mockito.verify(template).delete(Person.class, 1L); + Mockito.verifyNoMoreInteractions(template); + } + + @Test + void shouldDeleteListEntity() { + var persons = List.of(Person.builder().withId(12L).withAge(26).withName("Ada").build()); + people.delete(persons); + + Mockito.verify(template).delete(Person.class, 12L); + Mockito.verifyNoMoreInteractions(template); + } + + @Test + void shouldDeleteArrayEntity() { + Person ada = Person.builder().withId(2L).withAge(26).withName("Ada").build(); + var persons = new Person[]{ada}; + people.delete(persons); + + Mockito.verify(template).delete(Person.class, 2L); + Mockito.verifyNoMoreInteractions(template); + } + } \ No newline at end of file diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java index ee2e223ca..ec7b44600 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java @@ -14,6 +14,7 @@ */ package org.eclipse.jnosql.mapping.semistructured.query; +import jakarta.data.repository.Delete; import jakarta.data.repository.Insert; import jakarta.data.repository.Update; import org.eclipse.jnosql.mapping.semistructured.entities.Person; @@ -40,4 +41,14 @@ public interface People { @Update Person[] update(Person[] person); + + + @Delete + void delete(List people); + + @Delete + void delete(Person person); + + @Delete + void delete(Person[] person); } From 3871e7d910d36faf976c34dd3c08b80f3e69b6ff Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Thu, 30 May 2024 21:44:14 +0100 Subject: [PATCH 16/35] style: remove unsed imports Signed-off-by: Otavio Santana --- .../mapping/semistructured/query/CustomRepositoryHandler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java index 632db15b2..38b8e40cb 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java @@ -28,7 +28,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; -import java.lang.reflect.TypeVariable; import java.util.Optional; import java.util.logging.Logger; From 8c0b12d336ab6239e0b085858dc5c3a5ce6c1430 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 31 May 2024 08:47:34 +0100 Subject: [PATCH 17/35] feat: update params condition Signed-off-by: Otavio Santana --- .../semistructured/query/CustomRepositoryHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java index 38b8e40cb..cb94ea3f9 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java @@ -68,16 +68,16 @@ public Object invoke(Object proxy, Method method, Object[] params) throws Throwa RepositoryType type = RepositoryType.of(method, customRepositoryType); switch (type) { case SAVE -> { - return unwrapInvocationTargetException(() -> SAVE.invoke(new AnnotationOperation.Operation(method, params, repository(method)))); + return unwrapInvocationTargetException(() -> SAVE.invoke(new AnnotationOperation.Operation(method, params, repository(params)))); } case INSERT -> { - return unwrapInvocationTargetException(() -> INSERT.invoke(new AnnotationOperation.Operation(method, params, repository(method)))); + return unwrapInvocationTargetException(() -> INSERT.invoke(new AnnotationOperation.Operation(method, params, repository(params)))); } case DELETE -> { return unwrapInvocationTargetException(() -> DELETE.invoke(new AnnotationOperation.Operation(method, params, repository(params)))); } case UPDATE -> { - return unwrapInvocationTargetException(() -> UPDATE.invoke(new AnnotationOperation.Operation(method, params, repository(method)))); + return unwrapInvocationTargetException(() -> UPDATE.invoke(new AnnotationOperation.Operation(method, params, repository(params)))); } default -> { return Void.class; From 7e819abd857915c9b9f8a1db9f2c4acf65e31b82 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Fri, 31 May 2024 08:48:37 +0100 Subject: [PATCH 18/35] feat: update custom repository in log Signed-off-by: Otavio Santana --- .../semistructured/query/CustomRepositoryHandler.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java index cb94ea3f9..efd28f9f7 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java @@ -28,6 +28,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; +import java.util.Arrays; import java.util.Optional; import java.util.logging.Logger; @@ -64,8 +65,10 @@ public class CustomRepositoryHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { - LOGGER.info("Executing the method: " + method); + RepositoryType type = RepositoryType.of(method, customRepositoryType); + LOGGER.info("Executing the method " + method + " with the parameters " + Arrays.toString(params) + " and the type " + type); + switch (type) { case SAVE -> { return unwrapInvocationTargetException(() -> SAVE.invoke(new AnnotationOperation.Operation(method, params, repository(params)))); From d39ccfc2d4cc8e7eb09ce2755bc1fd0ba40d2f1d Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 06:34:45 +0100 Subject: [PATCH 19/35] feat: create structure to execuctions Signed-off-by: Otavio Santana --- .../query/CustomRepositoryHandler.java | 35 ++++++++++++++----- .../query/SemiStructuredRepositoryProxy.java | 10 ++++++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java index efd28f9f7..8825d693d 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java @@ -15,6 +15,7 @@ package org.eclipse.jnosql.mapping.semistructured.query; +import jakarta.enterprise.inject.spi.CDI; import org.eclipse.jnosql.mapping.core.Converters; import org.eclipse.jnosql.mapping.core.query.AbstractRepository; import org.eclipse.jnosql.mapping.core.query.AnnotationOperation; @@ -64,23 +65,36 @@ public class CustomRepositoryHandler implements InvocationHandler { } @Override - public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { + public Object invoke(Object instance, Method method, Object[] params) throws Throwable { RepositoryType type = RepositoryType.of(method, customRepositoryType); LOGGER.info("Executing the method " + method + " with the parameters " + Arrays.toString(params) + " and the type " + type); switch (type) { case SAVE -> { - return unwrapInvocationTargetException(() -> SAVE.invoke(new AnnotationOperation.Operation(method, params, repository(params)))); + return unwrapInvocationTargetException(() -> SAVE.invoke(new AnnotationOperation.Operation(method, params, repository(params, method)))); } case INSERT -> { - return unwrapInvocationTargetException(() -> INSERT.invoke(new AnnotationOperation.Operation(method, params, repository(params)))); + return unwrapInvocationTargetException(() -> INSERT.invoke(new AnnotationOperation.Operation(method, params, repository(params, method)))); } case DELETE -> { - return unwrapInvocationTargetException(() -> DELETE.invoke(new AnnotationOperation.Operation(method, params, repository(params)))); + return unwrapInvocationTargetException(() -> DELETE.invoke(new AnnotationOperation.Operation(method, params, repository(params, method)))); } case UPDATE -> { - return unwrapInvocationTargetException(() -> UPDATE.invoke(new AnnotationOperation.Operation(method, params, repository(params)))); + return unwrapInvocationTargetException(() -> UPDATE.invoke(new AnnotationOperation.Operation(method, params, repository(params, method)))); + } + case DEFAULT -> { + return unwrapInvocationTargetException(() -> InvocationHandler.invokeDefault(instance, method, params)); + } + case OBJECT_METHOD -> { + return unwrapInvocationTargetException(() -> unwrapInvocationTargetException(() -> method.invoke(this, params))); + } + case FIND_ALL, FIND_BY, PARAMETER_BASED -> { + return unwrapInvocationTargetException(() -> repository(method)); + } + case CUSTOM_REPOSITORY -> { + Object customRepository = CDI.current().select(method.getDeclaringClass()).get(); + return unwrapInvocationTargetException(() -> method.invoke(customRepository, params)); } default -> { return Void.class; @@ -88,7 +102,7 @@ public Object invoke(Object proxy, Method method, Object[] params) throws Throwa } } - private AbstractRepository repository(Method method) { + private SemiStructuredRepositoryProxy repository(Method method) { Class typeClass = method.getReturnType(); if (typeClass.isArray()) { typeClass = typeClass.getComponentType(); @@ -96,10 +110,12 @@ private AbstractRepository repository(Method method) { typeClass = (Class) ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0]; } Optional entity = entitiesMetadata.findByClassName(typeClass.getName()); - return entity.map(entityMetadata -> new SemiStructuredRepositoryProxy.SemiStructuredRepository<>(template, entityMetadata)).orElse(null); + Class entityType = typeClass; + return entity.map(entityMetadata -> new SemiStructuredRepositoryProxy<>(template, entityMetadata, entityType, converters)) + .orElseThrow(() -> new UnsupportedOperationException("The repository does not support the method " + method)); } - private AbstractRepository repository(Object[] params) { + private AbstractRepository repository(Object[] params,Method method) { Class typeClass = params[0].getClass(); if (typeClass.isArray()) { typeClass = typeClass.getComponentType(); @@ -108,7 +124,8 @@ private AbstractRepository repository(Object[] params) { typeClass = entity.getClass(); } Optional entity = entitiesMetadata.findByClassName(typeClass.getName()); - return entity.map(entityMetadata -> new SemiStructuredRepositoryProxy.SemiStructuredRepository<>(template, entityMetadata)).orElse(null); + return entity.map(entityMetadata -> new SemiStructuredRepositoryProxy.SemiStructuredRepository<>(template, entityMetadata)) + .orElseThrow(() -> new UnsupportedOperationException("The repository does not support the method: " + method)); } protected Object unwrapInvocationTargetException(ThrowingSupplier supplier) throws Throwable { diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredRepositoryProxy.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredRepositoryProxy.java index 4505d25ef..245d275c5 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredRepositoryProxy.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredRepositoryProxy.java @@ -65,6 +65,16 @@ public SemiStructuredRepositoryProxy(SemiStructuredTemplate template, this.repositoryType = repositoryType; } + SemiStructuredRepositoryProxy(SemiStructuredTemplate template, + EntityMetadata metadata, Class typeClass, + Converters converters) { + this.template = template; + this.entityMetadata = metadata; + this.repository = new SemiStructuredRepository<>(template, entityMetadata); + this.converters = converters; + this.repositoryType = null; + } + @Override protected AbstractRepository repository() { return repository; From 0b9042d268c3b672dedd18891deac251685fae66 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 09:09:25 +0100 Subject: [PATCH 20/35] test: create repository scenarios to custom repository Signed-off-by: Otavio Santana --- .../query/CustomRepositoryHandler.java | 27 +++- .../query/SemiStructuredRepositoryProxy.java | 2 +- .../query/CustomRepositoryHandlerTest.java | 123 ++++++++++++++++++ .../mapping/semistructured/query/People.java | 22 ++++ 4 files changed, 166 insertions(+), 8 deletions(-) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java index 8825d693d..ff423234a 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java @@ -15,6 +15,8 @@ package org.eclipse.jnosql.mapping.semistructured.query; +import jakarta.data.page.CursoredPage; +import jakarta.data.page.Page; import jakarta.enterprise.inject.spi.CDI; import org.eclipse.jnosql.mapping.core.Converters; import org.eclipse.jnosql.mapping.core.query.AbstractRepository; @@ -31,7 +33,9 @@ import java.lang.reflect.ParameterizedType; import java.util.Arrays; import java.util.Optional; +import java.util.function.Predicate; import java.util.logging.Logger; +import java.util.stream.Stream; import static org.eclipse.jnosql.mapping.core.query.AnnotationOperation.DELETE; import static org.eclipse.jnosql.mapping.core.query.AnnotationOperation.INSERT; @@ -47,6 +51,13 @@ public class CustomRepositoryHandler implements InvocationHandler { private static final Logger LOGGER = Logger.getLogger(CustomRepositoryHandler.class.getName()); + private static final Predicate> IS_ITERABLE = Iterable.class::isAssignableFrom; + private static final Predicate> IS_STREAM = Stream.class::isAssignableFrom; + private static final Predicate> IS_OPTIONAL = Optional.class::isAssignableFrom; + private static final Predicate> IS_PAGE = Page.class::isAssignableFrom; + private static final Predicate> IS_CURSOR_PAGE = CursoredPage.class::isAssignableFrom; + private static final Predicate> IS_GENERIC_SUPPORTED_TYPE = IS_ITERABLE.or(IS_STREAM).or(IS_OPTIONAL).or(IS_PAGE).or(IS_CURSOR_PAGE); + private final EntitiesMetadata entitiesMetadata; private final SemiStructuredTemplate template; @@ -83,14 +94,14 @@ public Object invoke(Object instance, Method method, Object[] params) throws Thr case UPDATE -> { return unwrapInvocationTargetException(() -> UPDATE.invoke(new AnnotationOperation.Operation(method, params, repository(params, method)))); } - case DEFAULT -> { + case DEFAULT_METHOD -> { return unwrapInvocationTargetException(() -> InvocationHandler.invokeDefault(instance, method, params)); } case OBJECT_METHOD -> { return unwrapInvocationTargetException(() -> unwrapInvocationTargetException(() -> method.invoke(this, params))); } - case FIND_ALL, FIND_BY, PARAMETER_BASED -> { - return unwrapInvocationTargetException(() -> repository(method)); + case FIND_ALL, FIND_BY, PARAMETER_BASED, CURSOR_PAGINATION -> { + return unwrapInvocationTargetException(() -> repository(method).invoke(instance, method, params)); } case CUSTOM_REPOSITORY -> { Object customRepository = CDI.current().select(method.getDeclaringClass()).get(); @@ -103,10 +114,12 @@ public Object invoke(Object instance, Method method, Object[] params) throws Thr } private SemiStructuredRepositoryProxy repository(Method method) { + + Class typeClass = method.getReturnType(); if (typeClass.isArray()) { typeClass = typeClass.getComponentType(); - } else if(Iterable.class.isAssignableFrom(typeClass)) { + } else if(Iterable.class.isAssignableFrom(typeClass) || Stream.class.isAssignableFrom(typeClass) || Optional.class.isAssignableFrom(typeClass)) { typeClass = (Class) ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0]; } Optional entity = entitiesMetadata.findByClassName(typeClass.getName()); @@ -115,11 +128,11 @@ private SemiStructuredRepositoryProxy repository(Method method) { .orElseThrow(() -> new UnsupportedOperationException("The repository does not support the method " + method)); } - private AbstractRepository repository(Object[] params,Method method) { - Class typeClass = params[0].getClass(); + private AbstractRepository repository(Object[] params, Method method) { + Class typeClass = params[0].getClass(); if (typeClass.isArray()) { typeClass = typeClass.getComponentType(); - } else if(Iterable.class.isAssignableFrom(typeClass)) { + } else if (IS_GENERIC_SUPPORTED_TYPE.test(typeClass)) { var entity = ((Iterable) params[0]).iterator().next(); typeClass = entity.getClass(); } diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredRepositoryProxy.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredRepositoryProxy.java index 245d275c5..c10d07c40 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredRepositoryProxy.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/SemiStructuredRepositoryProxy.java @@ -72,7 +72,7 @@ public SemiStructuredRepositoryProxy(SemiStructuredTemplate template, this.entityMetadata = metadata; this.repository = new SemiStructuredRepository<>(template, entityMetadata); this.converters = converters; - this.repositoryType = null; + this.repositoryType = typeClass; } @Override diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java index 56754423f..b647d73e6 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java @@ -14,8 +14,13 @@ */ package org.eclipse.jnosql.mapping.semistructured.query; +import jakarta.data.page.CursoredPage; +import jakarta.data.page.Page; +import jakarta.data.page.PageRequest; import jakarta.inject.Inject; import org.assertj.core.api.Assertions; +import org.assertj.core.api.SoftAssertions; +import org.eclipse.jnosql.communication.semistructured.SelectQuery; import org.eclipse.jnosql.mapping.core.Converters; import org.eclipse.jnosql.mapping.core.spi.EntityMetadataExtension; import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; @@ -29,10 +34,13 @@ import org.jboss.weld.junit5.auto.EnableAutoWeld; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import java.lang.reflect.Proxy; import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; @EnableAutoWeld @AddPackages(value = {Converters.class, EntityConverter.class}) @@ -156,4 +164,119 @@ void shouldDeleteArrayEntity() { Mockito.verifyNoMoreInteractions(template); } + @Test + void shouldExecuteObjectMethods(){ + Assertions.assertThat(people.toString()).isNotNull(); + Assertions.assertThat(people.hashCode()).isNotEqualTo(0); + } + + @Test + void shouldExecuteDefaultMethod(){ + Assertions.assertThat(people.defaultMethod()).isEqualTo("default"); + } + + @Test + void shouldExecuteFindByAge() { + Mockito.when(template.select(Mockito.any(SelectQuery.class))) + .thenReturn(Stream.of(Person.builder().withAge(26).withName("Ada").build())); + var result = people.findByAge(26); + + Assertions.assertThat(result).hasSize(1).isNotNull().isInstanceOf(List.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(SelectQuery.class); + Mockito.verify(template).select(captor.capture()); + Mockito.verifyNoMoreInteractions(template); + SelectQuery query = captor.getValue(); + + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(query.sorts()).isEmpty(); + soft.assertThat(query.name()).isEqualTo("Person"); + soft.assertThat(query.condition()).isPresent(); + }); + } + + @Test + void shouldExecuteFindById() { + + Mockito.when(template.singleResult(Mockito.any(SelectQuery.class))) + .thenReturn(Optional.of(Person.builder().withAge(26).withName("Ada").build())); + + var result = people.findById(26L); + + Assertions.assertThat(result).isNotNull().isInstanceOf(Person.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(SelectQuery.class); + Mockito.verify(template).singleResult(captor.capture()); + Mockito.verifyNoMoreInteractions(template); + SelectQuery query = captor.getValue(); + + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(query.sorts()).isEmpty(); + soft.assertThat(query.name()).isEqualTo("Person"); + soft.assertThat(query.condition()).isPresent(); + }); + } + + @Test + void shouldExecuteFindByIdAndName() { + + Mockito.when(template.singleResult(Mockito.any(SelectQuery.class))) + .thenReturn(Optional.of(Person.builder().withAge(26).withName("Ada").build())); + + var result = people.findByIdAndName(26L, "Ada"); + + Assertions.assertThat(result).isNotNull().isPresent().isInstanceOf(Optional.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(SelectQuery.class); + Mockito.verify(template).singleResult(captor.capture()); + Mockito.verifyNoMoreInteractions(template); + SelectQuery query = captor.getValue(); + + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(query.sorts()).isEmpty(); + soft.assertThat(query.name()).isEqualTo("Person"); + soft.assertThat(query.condition()).isPresent(); + }); + } + + @Test + void shouldExecuteFindPagination() { + + Mockito.when(template.select(Mockito.any(SelectQuery.class))) + .thenReturn(Stream.of(Person.builder().withAge(26).withName("Ada").build())); + + var result = people.findByAge(26, PageRequest.ofSize(2)); + + Assertions.assertThat(result).isNotNull().isInstanceOf(Page.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(SelectQuery.class); + Mockito.verify(template).select(captor.capture()); + Mockito.verifyNoMoreInteractions(template); + SelectQuery query = captor.getValue(); + + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(query.sorts()).isEmpty(); + soft.assertThat(query.name()).isEqualTo("Person"); + soft.assertThat(query.condition()).isPresent(); + }); + } + + @Test + void shouldExecuteFindCursorPagination() { + + var mock = Mockito.mock(CursoredPage.class); + Mockito.when(template.selectCursor(Mockito.any(SelectQuery.class), Mockito.any(PageRequest.class))) + .thenReturn(mock); + + var result = people.findByName("Ada", PageRequest.ofSize(2)); + + Assertions.assertThat(result).isNotNull().isInstanceOf(CursoredPage.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(SelectQuery.class); + Mockito.verify(template).selectCursor(captor.capture(), Mockito.any(PageRequest.class)); + Mockito.verifyNoMoreInteractions(template); + SelectQuery query = captor.getValue(); + + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(query.sorts()).isEmpty(); + soft.assertThat(query.name()).isEqualTo("Person"); + soft.assertThat(query.condition()).isPresent(); + }); + } + } \ No newline at end of file diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java index ec7b44600..c954632d0 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java @@ -14,12 +14,17 @@ */ package org.eclipse.jnosql.mapping.semistructured.query; +import jakarta.data.page.CursoredPage; +import jakarta.data.page.Page; +import jakarta.data.page.PageRequest; import jakarta.data.repository.Delete; +import jakarta.data.repository.Find; import jakarta.data.repository.Insert; import jakarta.data.repository.Update; import org.eclipse.jnosql.mapping.semistructured.entities.Person; import java.util.List; +import java.util.Optional; public interface People { @@ -51,4 +56,21 @@ public interface People { @Delete void delete(Person[] person); + + List findByAge(int age); + + Person findById(Long id); + + Page findByAge(int age, PageRequest pageRequest); + + CursoredPage findByName(String name, PageRequest pageRequest); + + Optional findByIdAndName(Long id, String name); + + @Find + Person name(String name); + + default String defaultMethod() { + return "default"; + } } From 3eb067e5335a98e7e7819d607c3c251da8c0ab82 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 09:20:51 +0100 Subject: [PATCH 21/35] test; create custom repository handler Signed-off-by: Otavio Santana --- .../query/CustomRepositoryHandlerTest.java | 20 +++++++++++++++++++ .../mapping/semistructured/query/People.java | 3 ++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java index b647d73e6..7c852e2dd 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java @@ -279,4 +279,24 @@ void shouldExecuteFindCursorPagination() { }); } + @Test + void shouldExecutePathParameter() { + + Mockito.when(template.select(Mockito.any(SelectQuery.class))) + .thenReturn(Stream.of(Person.builder().withAge(26).withName("Ada").build())); + + var result = people.name("Ada"); + + Assertions.assertThat(result).isNotNull().isInstanceOf(List.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(SelectQuery.class); + Mockito.verify(template).select(captor.capture()); + Mockito.verifyNoMoreInteractions(template); + SelectQuery query = captor.getValue(); + + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(query.sorts()).isEmpty(); + soft.assertThat(query.name()).isEqualTo("Person"); + soft.assertThat(query.condition()).isNotEmpty(); + }); + } } \ No newline at end of file diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java index c954632d0..c38bae932 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java @@ -17,6 +17,7 @@ import jakarta.data.page.CursoredPage; import jakarta.data.page.Page; import jakarta.data.page.PageRequest; +import jakarta.data.repository.By; import jakarta.data.repository.Delete; import jakarta.data.repository.Find; import jakarta.data.repository.Insert; @@ -68,7 +69,7 @@ public interface People { Optional findByIdAndName(Long id, String name); @Find - Person name(String name); + List name(@By("name") String name); default String defaultMethod() { return "default"; From 44625a18529fe568040902b42c54a1a4376b0676 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 09:23:59 +0100 Subject: [PATCH 22/35] test: create query scenarios Signed-off-by: Otavio Santana --- .../jnosql/mapping/semistructured/query/People.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java index c38bae932..b09b0dadf 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java @@ -21,6 +21,8 @@ import jakarta.data.repository.Delete; import jakarta.data.repository.Find; import jakarta.data.repository.Insert; +import jakarta.data.repository.Param; +import jakarta.data.repository.Query; import jakarta.data.repository.Update; import org.eclipse.jnosql.mapping.semistructured.entities.Person; @@ -71,6 +73,12 @@ public interface People { @Find List name(@By("name") String name); + @Query("from Person where name = :name") + List queryName(@Param("name") String name); + + @Query("delete from Person where name = :name") + void deleteByName(@Param("name") String name); + default String defaultMethod() { return "default"; } From 910cca4c29e66e69551b1069c902bdac95abaefe Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 16:51:30 +0100 Subject: [PATCH 23/35] test: increase test coverry at prepare statement Signed-off-by: Otavio Santana --- .../query/CustomRepositoryHandler.java | 50 ++++++++-- .../semistructured/PreparedStatementTest.java | 91 +++++++++++++++++++ .../query/CustomRepositoryHandlerTest.java | 40 ++++++++ 3 files changed, 171 insertions(+), 10 deletions(-) create mode 100644 jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/PreparedStatementTest.java diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java index ff423234a..f62272579 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java @@ -17,11 +17,14 @@ import jakarta.data.page.CursoredPage; import jakarta.data.page.Page; +import jakarta.data.repository.Query; import jakarta.enterprise.inject.spi.CDI; +import org.eclipse.jnosql.mapping.PreparedStatement; import org.eclipse.jnosql.mapping.core.Converters; import org.eclipse.jnosql.mapping.core.query.AbstractRepository; import org.eclipse.jnosql.mapping.core.query.AnnotationOperation; import org.eclipse.jnosql.mapping.core.query.RepositoryType; +import org.eclipse.jnosql.mapping.core.repository.RepositoryReflectionUtils; import org.eclipse.jnosql.mapping.core.repository.ThrowingSupplier; import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; import org.eclipse.jnosql.mapping.metadata.EntityMetadata; @@ -32,6 +35,7 @@ import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.util.Arrays; +import java.util.Map; import java.util.Optional; import java.util.function.Predicate; import java.util.logging.Logger; @@ -45,7 +49,6 @@ /** * This class is the engine of a custom repository from Jakarta Data specification. * The implementation is based on {@link InvocationHandler} and it's used to create a custom repository. - */ public class CustomRepositoryHandler implements InvocationHandler { @@ -67,8 +70,8 @@ public class CustomRepositoryHandler implements InvocationHandler { private final Converters converters; CustomRepositoryHandler(EntitiesMetadata entitiesMetadata, SemiStructuredTemplate template, - Class customRepositoryType, - Converters converters) { + Class customRepositoryType, + Converters converters) { this.entitiesMetadata = entitiesMetadata; this.template = template; this.customRepositoryType = customRepositoryType; @@ -107,25 +110,52 @@ public Object invoke(Object instance, Method method, Object[] params) throws Thr Object customRepository = CDI.current().select(method.getDeclaringClass()).get(); return unwrapInvocationTargetException(() -> method.invoke(customRepository, params)); } + case QUERY -> { + var repositoryMetadata = repositoryMetadata(method); + if (repositoryMetadata.metadata().isEmpty()) { + var query = method.getAnnotation(Query.class); + Map parameters = RepositoryReflectionUtils.INSTANCE.getParams(method, params); + var prepare = template.prepare(query.value()); + parameters.forEach(prepare::bind); + if (prepare.isCount()) { + return prepare.count(); + } + Stream entities = prepare.result(); + if (method.getReturnType().equals(long.class) || method.getReturnType().equals(Long.class)) { + return entities.count(); + } + return Void.class; + } + return unwrapInvocationTargetException(() -> repository(method).invoke(instance, method, params)); + + } + case DELETE_BY, COUNT_BY, EXISTS_BY -> + throw new UnsupportedOperationException("The custom repository does not support the method " + method); default -> { return Void.class; } } } - private SemiStructuredRepositoryProxy repository(Method method) { - + private SemiStructuredRepositoryProxy repository(Method method) { + RepositoryMetadata result = repositoryMetadata(method); + Class entityType = result.typeClass(); + return result.metadata().map(entityMetadata -> new SemiStructuredRepositoryProxy<>(template, entityMetadata, entityType, converters)) + .orElseThrow(() -> new UnsupportedOperationException("The repository does not support the method " + method)); + } + private RepositoryMetadata repositoryMetadata(Method method) { Class typeClass = method.getReturnType(); if (typeClass.isArray()) { typeClass = typeClass.getComponentType(); - } else if(Iterable.class.isAssignableFrom(typeClass) || Stream.class.isAssignableFrom(typeClass) || Optional.class.isAssignableFrom(typeClass)) { + } else if (Iterable.class.isAssignableFrom(typeClass) || Stream.class.isAssignableFrom(typeClass) || Optional.class.isAssignableFrom(typeClass)) { typeClass = (Class) ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0]; } - Optional entity = entitiesMetadata.findByClassName(typeClass.getName()); - Class entityType = typeClass; - return entity.map(entityMetadata -> new SemiStructuredRepositoryProxy<>(template, entityMetadata, entityType, converters)) - .orElseThrow(() -> new UnsupportedOperationException("The repository does not support the method " + method)); + Optional metadata = entitiesMetadata.findByClassName(typeClass.getName()); + return new RepositoryMetadata(typeClass, metadata); + } + + private record RepositoryMetadata(Class typeClass, Optional metadata) { } private AbstractRepository repository(Object[] params, Method method) { diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/PreparedStatementTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/PreparedStatementTest.java new file mode 100644 index 000000000..31dbcdbfe --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/PreparedStatementTest.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: + * + * Otavio Santana + */ +package org.eclipse.jnosql.mapping.semistructured; + +import jakarta.inject.Inject; +import org.assertj.core.api.Assertions; +import org.eclipse.jnosql.communication.semistructured.CommunicationEntity; +import org.eclipse.jnosql.communication.semistructured.SelectQuery; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.core.spi.EntityMetadataExtension; +import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; +import org.eclipse.jnosql.mapping.reflection.Reflections; +import org.eclipse.jnosql.mapping.semistructured.entities.Person; +import org.jboss.weld.junit5.auto.AddExtensions; +import org.jboss.weld.junit5.auto.AddPackages; +import org.jboss.weld.junit5.auto.EnableAutoWeld; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.Optional; + +@EnableAutoWeld +@AddPackages(value = {Converters.class, EntityConverter.class}) +@AddPackages(MockProducer.class) +@AddPackages(Reflections.class) +@AddExtensions({EntityMetadataExtension.class}) +class PreparedStatementTest { + + + @Inject + private EntitiesMetadata entitiesMetadata; + + @Inject + private EntityConverter converter; + + @Test + void shouldReturnCount(){ + var communicationPreparedStatement = Mockito.mock(org.eclipse.jnosql.communication.semistructured.CommunicationPreparedStatement.class); + Mockito.when(communicationPreparedStatement.count()).thenReturn(10L); + var preparedStatement = new PreparedStatement(communicationPreparedStatement, converter); + Assertions.assertThat(preparedStatement.count()).isEqualTo(10L); + } + + @Test + void shouldReturnFalseWhenQueryIsEmpty(){ + var communicationPreparedStatement = Mockito.mock(org.eclipse.jnosql.communication.semistructured.CommunicationPreparedStatement.class); + Mockito.when(communicationPreparedStatement.select()).thenReturn(Optional.empty()); + var preparedStatement = new PreparedStatement(communicationPreparedStatement, converter); + Assertions.assertThat(preparedStatement.isCount()).isFalse(); + } + + @Test + void shouldReturnCheckIsCountBaseOnQuery(){ + var communicationPreparedStatement = Mockito.mock(org.eclipse.jnosql.communication.semistructured.CommunicationPreparedStatement.class); + var query = Mockito.mock(SelectQuery.class); + Mockito.when(query.isCount()).thenReturn(true); + Mockito.when(communicationPreparedStatement.select()).thenReturn(Optional.of(query)); + var preparedStatement = new PreparedStatement(communicationPreparedStatement, converter); + Assertions.assertThat(preparedStatement.isCount()).isTrue(); + } + + @Test + void shouldReturnSingleResult(){ + var communicationPreparedStatement = Mockito.mock(org.eclipse.jnosql.communication.semistructured.CommunicationPreparedStatement.class); + CommunicationEntity entity = CommunicationEntity.of("Person"); + entity.add("name", "Ada"); + entity.add("age", 20); + entity.add("_id", 20); + + Mockito.when(communicationPreparedStatement.singleResult()).thenReturn(Optional.of(entity)); + + var preparedStatement = new PreparedStatement(communicationPreparedStatement, converter); + Optional person = preparedStatement.singleResult(); + + Assertions.assertThat(person).isPresent(); + + } + +} \ No newline at end of file diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java index 7c852e2dd..a4a103c2e 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java @@ -21,6 +21,7 @@ import org.assertj.core.api.Assertions; import org.assertj.core.api.SoftAssertions; import org.eclipse.jnosql.communication.semistructured.SelectQuery; +import org.eclipse.jnosql.mapping.PreparedStatement; import org.eclipse.jnosql.mapping.core.Converters; import org.eclipse.jnosql.mapping.core.spi.EntityMetadataExtension; import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; @@ -299,4 +300,43 @@ void shouldExecutePathParameter() { soft.assertThat(query.condition()).isNotEmpty(); }); } + + + @Test + void shouldExecuteQuery(){ + + var preparedStatement = Mockito.mock(PreparedStatement.class); + Mockito.when(template.prepare(Mockito.anyString(), Mockito.anyString())) + .thenReturn(preparedStatement); + Mockito.when(template.query(Mockito.anyString())) + .thenReturn(Stream.of(Person.builder().withAge(26).withName("Ada").build())); + + var result = people.queryName("Ada"); + + Assertions.assertThat(result).isNotNull().isInstanceOf(List.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + Mockito.verify(template).prepare(captor.capture(), Mockito.eq("Person")); + Mockito.verifyNoMoreInteractions(template); + var query = captor.getValue(); + + Assertions.assertThat(query).isEqualTo("from Person where name = :name"); + } + + @Test + void shouldExecuteQueryWithVoid(){ + + var preparedStatement = Mockito.mock(PreparedStatement.class); + Mockito.when(template.prepare(Mockito.anyString())).thenReturn(preparedStatement); + Mockito.when(template.query(Mockito.anyString())) + .thenReturn(Stream.of(Person.builder().withAge(26).withName("Ada").build())); + + people.deleteByName("Ada"); + + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + Mockito.verify(template).prepare(captor.capture()); + Mockito.verifyNoMoreInteractions(template); + var query = captor.getValue(); + + Assertions.assertThat(query).isEqualTo("delete from Person where name = :name"); + } } \ No newline at end of file From d995ff06493dca3e37ec9d1e17c0f90b99c726c5 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 17:01:39 +0100 Subject: [PATCH 24/35] style: remove unecessary import at custom repository handler Signed-off-by: Otavio Santana --- .../mapping/semistructured/query/CustomRepositoryHandler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java index f62272579..912ac0755 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java @@ -19,7 +19,6 @@ import jakarta.data.page.Page; import jakarta.data.repository.Query; import jakarta.enterprise.inject.spi.CDI; -import org.eclipse.jnosql.mapping.PreparedStatement; import org.eclipse.jnosql.mapping.core.Converters; import org.eclipse.jnosql.mapping.core.query.AbstractRepository; import org.eclipse.jnosql.mapping.core.query.AnnotationOperation; From 0d2a80a4c9a3df215604ed55fc0cd2a7ae465c11 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 20:58:50 +0100 Subject: [PATCH 25/35] test: create custom repository save scenarios Signed-off-by: Otavio Santana --- .../query/CustomRepositoryHandlerTest.java | 39 +++++++++++++++++++ .../mapping/semistructured/query/People.java | 10 +++++ 2 files changed, 49 insertions(+) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java index a4a103c2e..46650af3d 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java @@ -165,6 +165,45 @@ void shouldDeleteArrayEntity() { Mockito.verifyNoMoreInteractions(template); } + @Test + void shouldSaveEntity() { + Person person = Person.builder().withAge(26).withName("Ada").build(); + Mockito.when(template.insert(person)).thenReturn(person); + Person result = people.save(person); + + Mockito.verify(template).insert(person); + Mockito.verify(template).find(Person.class, 0L); + Assertions.assertThat(result).isEqualTo(person); + } + + @Test + void shouldSaveListEntity() { + Person ada = Person.builder().withAge(26).withName("Ada").build(); + var persons = List.of(ada); + Mockito.when(template.insert(persons)).thenReturn(persons); + Mockito.when(template.insert(ada)).thenReturn(ada); + List result = people.save(persons); + + Mockito.verify(template).insert(ada); + Mockito.verify(template).find(Person.class, 0L); + Assertions.assertThat(result).isEqualTo(persons); + } + + @Test + void shouldSaveArrayEntity() { + Person ada = Person.builder().withAge(26).withName("Ada").build(); + var persons = new Person[]{ada}; + Mockito.when(template.insert(Mockito.any())).thenReturn(List.of(ada)); + Mockito.when(template.insert(ada)).thenReturn(ada); + Person[] result = people.save(persons); + + Mockito.verify(template).insert(ada); + Mockito.verify(template).find(Person.class, 0L); + Assertions.assertThat(result).isEqualTo(persons); + } + + + @Test void shouldExecuteObjectMethods(){ Assertions.assertThat(people.toString()).isNotNull(); diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java index b09b0dadf..342e28d78 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/People.java @@ -23,6 +23,7 @@ import jakarta.data.repository.Insert; import jakarta.data.repository.Param; import jakarta.data.repository.Query; +import jakarta.data.repository.Save; import jakarta.data.repository.Update; import org.eclipse.jnosql.mapping.semistructured.entities.Person; @@ -50,6 +51,15 @@ public interface People { @Update Person[] update(Person[] person); + @Save + List save(List people); + + @Save + Person save(Person person); + + @Save + Person[] save(Person[] person); + @Delete void delete(List people); From d6b4217abbf155d9eea496d47b4b2d17261260fa Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 21:04:03 +0100 Subject: [PATCH 26/35] feat: create custom repository handler builder Signed-off-by: Otavio Santana --- .../query/CustomRepositoryHandler.java | 9 ++ .../query/CustomRepositoryHandlerBuilder.java | 97 +++++++++++++++++++ .../query/CustomRepositoryHandlerTest.java | 2 +- 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerBuilder.java diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java index 912ac0755..eaef8cb25 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandler.java @@ -177,4 +177,13 @@ protected Object unwrapInvocationTargetException(ThrowingSupplier suppli throw ex.getCause(); } } + + /** + * Creates a new {@link CustomRepositoryHandlerBuilder} instance. + * + * @return a {@link CustomRepositoryHandlerBuilder} instance + */ + public static CustomRepositoryHandlerBuilder builder() { + return new CustomRepositoryHandlerBuilder(); + } } diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerBuilder.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerBuilder.java new file mode 100644 index 000000000..8efef9ecf --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerBuilder.java @@ -0,0 +1,97 @@ +/* + * 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: + * + * Otavio Santana + */ +package org.eclipse.jnosql.mapping.semistructured.query; + +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; +import org.eclipse.jnosql.mapping.semistructured.SemiStructuredTemplate; + +import java.util.Objects; + + +/** + * Builder class for constructing instances of {@link CustomRepositoryHandler}. + * This builder facilitates the configuration of various components required + * to instantiate a custom repository handler. + */ +public class CustomRepositoryHandlerBuilder { + + private EntitiesMetadata entitiesMetadata; + + private SemiStructuredTemplate template; + + private Class customRepositoryType; + + private Converters converters; + + + /** + * Sets the entities metadata for the custom repository handler. + * + * @param entitiesMetadata the {@link EntitiesMetadata} instance + * @return the current instance of {@link CustomRepositoryHandlerBuilder} + * @throws NullPointerException if the entitiesMetadata is null + */ + public CustomRepositoryHandlerBuilder entitiesMetadata(EntitiesMetadata entitiesMetadata) { + this.entitiesMetadata = Objects.requireNonNull(entitiesMetadata, "entitiesMetadata is required"); + return this; + } + + /** + * Sets the template for the custom repository handler. + * + * @param template the {@link SemiStructuredTemplate} instance + * @return the current instance of {@link CustomRepositoryHandlerBuilder} + * @throws NullPointerException if the template is null + */ + public CustomRepositoryHandlerBuilder template(SemiStructuredTemplate template) { + this.template = Objects.requireNonNull(template, "template is required"); + return this; + } + + /** + * Sets the custom repository type for the custom repository handler. + * + * @param customRepositoryType the {@link Class} type of the custom repository + * @return the current instance of {@link CustomRepositoryHandlerBuilder} + * @throws NullPointerException if the customRepositoryType is null + */ + public CustomRepositoryHandlerBuilder customRepositoryType(Class customRepositoryType) { + this.customRepositoryType = Objects.requireNonNull(customRepositoryType, "customRepositoryType is required"); + return this; + } + + /** + * Sets the converters for the custom repository handler. + * + * @param converters the {@link Converters} instance + * @return the current instance of {@link CustomRepositoryHandlerBuilder} + */ + public CustomRepositoryHandlerBuilder converters(Converters converters) { + this.converters = Objects.requireNonNull(converters, "converters is required");; + return this; + } + + /** + * Builds and returns a {@link CustomRepositoryHandler} instance configured + * with the provided components. + * + * @return a new instance of {@link CustomRepositoryHandler} + * @throws IllegalStateException if the entitiesMetadata, template, customRepositoryType, or converters are null + */ + public CustomRepositoryHandler build() { + return new CustomRepositoryHandler(entitiesMetadata, template, customRepositoryType, converters); + } +} \ No newline at end of file diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java index 46650af3d..7a0b73ac0 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java @@ -63,7 +63,7 @@ class CustomRepositoryHandlerTest { @BeforeEach void setUp() { template = Mockito.mock(SemiStructuredTemplate.class); - CustomRepositoryHandler customRepositoryHandler = new CustomRepositoryHandler(entitiesMetadata, template, People.class, converters); + CustomRepositoryHandler customRepositoryHandler = new CustomRepositoryHandlerBuilder().entitiesMetadata(entitiesMetadata).template(template).customRepositoryType(People.class).converters(converters).build(); people = (People) Proxy.newProxyInstance(People.class.getClassLoader(), new Class[]{People.class}, customRepositoryHandler); } From 0714f59aa21a20c3fd9dd780aa713ae3d522cdea Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 21:04:51 +0100 Subject: [PATCH 27/35] test: update custom repository handler to use custom repository! Signed-off-by: Otavio Santana --- .../semistructured/query/CustomRepositoryHandlerTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java index 7a0b73ac0..8a118db8d 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerTest.java @@ -63,7 +63,10 @@ class CustomRepositoryHandlerTest { @BeforeEach void setUp() { template = Mockito.mock(SemiStructuredTemplate.class); - CustomRepositoryHandler customRepositoryHandler = new CustomRepositoryHandlerBuilder().entitiesMetadata(entitiesMetadata).template(template).customRepositoryType(People.class).converters(converters).build(); + CustomRepositoryHandler customRepositoryHandler = CustomRepositoryHandler.builder() + .entitiesMetadata(entitiesMetadata) + .template(template).customRepositoryType(People.class) + .converters(converters).build(); people = (People) Proxy.newProxyInstance(People.class.getClassLoader(), new Class[]{People.class}, customRepositoryHandler); } From 456b3944aaeb9c328cb49961693b28434b009851 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 21:17:24 +0100 Subject: [PATCH 28/35] test: create test scenaio to abstracture semistructure Signed-off-by: Otavio Santana --- .../AbstractSemiStructuredTemplate.java | 19 +++----- .../query/CustomRepositoryHandlerBuilder.java | 3 +- ...=> DefaultSemiStructuredTemplateTest.java} | 46 ++++++++++++++++++- 3 files changed, 53 insertions(+), 15 deletions(-) rename jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/{DefaultColumnTemplateTest.java => DefaultSemiStructuredTemplateTest.java} (91%) diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/AbstractSemiStructuredTemplate.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/AbstractSemiStructuredTemplate.java index 83525bb53..804d8a469 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/AbstractSemiStructuredTemplate.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/AbstractSemiStructuredTemplate.java @@ -236,22 +236,17 @@ public Stream query(String query, String entity) { @Override public Optional singleResult(String query) { - Stream entities = query(query); - final Iterator iterator = entities.iterator(); - - if (!iterator.hasNext()) { - return Optional.empty(); - } - final T entity = iterator.next(); - if (!iterator.hasNext()) { - return Optional.of(entity); - } - throw new NonUniqueResultException("No unique result found to the query: " + query); + return singleResult(query, null); } @Override public Optional singleResult(String query, String entityName) { - Stream entities = query(query, entityName); + Stream entities; + if(entityName == null){ + entities = query(query); + } else { + entities = query(query, entityName); + } final Iterator iterator = entities.iterator(); if (!iterator.hasNext()) { diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerBuilder.java b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerBuilder.java index 8efef9ecf..03e47c18e 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerBuilder.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/main/java/org/eclipse/jnosql/mapping/semistructured/query/CustomRepositoryHandlerBuilder.java @@ -36,7 +36,6 @@ public class CustomRepositoryHandlerBuilder { private Converters converters; - /** * Sets the entities metadata for the custom repository handler. * @@ -80,7 +79,7 @@ public CustomRepositoryHandlerBuilder customRepositoryType(Class customReposi * @return the current instance of {@link CustomRepositoryHandlerBuilder} */ public CustomRepositoryHandlerBuilder converters(Converters converters) { - this.converters = Objects.requireNonNull(converters, "converters is required");; + this.converters = Objects.requireNonNull(converters, "converters is required"); return this; } diff --git a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/DefaultColumnTemplateTest.java b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/DefaultSemiStructuredTemplateTest.java similarity index 91% rename from jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/DefaultColumnTemplateTest.java rename to jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/DefaultSemiStructuredTemplateTest.java index 4a1a835ee..9b60e932a 100644 --- a/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/DefaultColumnTemplateTest.java +++ b/jnosql-mapping/jnosql-mapping-semistructured/src/test/java/org/eclipse/jnosql/mapping/semistructured/DefaultSemiStructuredTemplateTest.java @@ -64,7 +64,7 @@ @AddPackages(MockProducer.class) @AddPackages(Reflections.class) @AddExtensions({EntityMetadataExtension.class}) -class DefaultColumnTemplateTest { +class DefaultSemiStructuredTemplateTest { private final Person person = Person.builder(). withAge(). @@ -302,6 +302,29 @@ void shouldReturnSingleResultIsEmpty() { assertFalse(result.isPresent()); } + @Test + void shouldReturnSingleResultQuery() { + CommunicationEntity columnEntity = CommunicationEntity.of("Person"); + columnEntity.addAll(Stream.of(columns).collect(Collectors.toList())); + + Mockito.when(managerMock + .select(any(SelectQuery.class))) + .thenReturn(Stream.of(columnEntity)); + + Optional result = template.singleResult("from Person"); + assertTrue(result.isPresent()); + } + + @Test + void shouldReturnSingleResultQueryIsEmpty() { + Mockito.when(managerMock + .select(any(SelectQuery.class))) + .thenReturn(Stream.empty()); + + Optional result = template.singleResult("from Person"); + assertFalse(result.isPresent()); + } + @Test void shouldReturnErrorWhenThereMoreThanASingleResult() { Assertions.assertThrows(NonUniqueResultException.class, () -> { @@ -369,6 +392,16 @@ void shouldExecuteQuery() { assertEquals("Person", query.name()); } + @Test + void shouldExecuteQueryEntity() { + template.query("FROM Person", "Person"); + ArgumentCaptor queryCaptor = ArgumentCaptor.forClass(SelectQuery.class); + verify(managerMock).select(queryCaptor.capture()); + SelectQuery query = queryCaptor.getValue(); + assertEquals("Person", query.name()); + } + + @Test void shouldConvertEntity() { template.query("FROM Movie"); @@ -415,6 +448,17 @@ void shouldPreparedStatement() { assertEquals("Person", query.name()); } + @Test + void shouldPreparedStatementEntity() { + PreparedStatement preparedStatement = template.prepare("FROM Person WHERE name = :name", "Person"); + preparedStatement.bind("name", "Ada"); + preparedStatement.result(); + ArgumentCaptor queryCaptor = ArgumentCaptor.forClass(SelectQuery.class); + verify(managerMock).select(queryCaptor.capture()); + SelectQuery query = queryCaptor.getValue(); + assertEquals("Person", query.name()); + } + @Test void shouldCount() { template.count("Person"); From 2af7b0caa7f780897110dd8dff254246f218ae70 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 21:22:07 +0100 Subject: [PATCH 29/35] test: create scenario people Signed-off-by: Otavio Santana --- .../mapping/document/entities/People.java | 27 ++++++++ .../spi/DocumentCustomExtensionTest.java | 69 +++++++++++++++++++ .../document/spi/DocumentExtensionTest.java | 1 - 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/entities/People.java create mode 100644 jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/spi/DocumentCustomExtensionTest.java diff --git a/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/entities/People.java b/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/entities/People.java new file mode 100644 index 000000000..896f18417 --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/entities/People.java @@ -0,0 +1,27 @@ +/* + * 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.mapping.document.entities; + +import jakarta.data.repository.Insert; +import jakarta.data.repository.Repository; + +import java.util.List; + +@Repository +public interface People { + + @Insert + List insert(List people); +} diff --git a/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/spi/DocumentCustomExtensionTest.java b/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/spi/DocumentCustomExtensionTest.java new file mode 100644 index 000000000..b942ad67c --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/spi/DocumentCustomExtensionTest.java @@ -0,0 +1,69 @@ +/* + * 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.mapping.document.spi; + +import jakarta.inject.Inject; +import org.eclipse.jnosql.mapping.Database; +import org.eclipse.jnosql.mapping.DatabaseType; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.core.spi.EntityMetadataExtension; +import org.eclipse.jnosql.mapping.document.DocumentTemplate; +import org.eclipse.jnosql.mapping.document.MockProducer; +import org.eclipse.jnosql.mapping.document.entities.People; +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.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + + +@EnableAutoWeld +@AddPackages(value = {Converters.class, EntityConverter.class, DocumentTemplate.class}) +@AddPackages(MockProducer.class) +@AddPackages(Reflections.class) +@AddExtensions({EntityMetadataExtension.class, DocumentExtension.class}) +class DocumentCustomExtensionTest { + + @Inject + @Database(value = DatabaseType.DOCUMENT) + private People people; + + @Inject + @Database(value = DatabaseType.DOCUMENT, provider = "documentRepositoryMock") + private People pepoleMock; + + @Inject + private People repository; + + + @Test + void shouldInitiate() { + assertNotNull(people); + } + + @Test + void shouldUseMock(){ + assertNotNull(pepoleMock); + } + + @Test + void shouldUseDefault(){ + assertNotNull(repository); + } +} diff --git a/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/spi/DocumentExtensionTest.java b/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/spi/DocumentExtensionTest.java index 4ca678ebc..b2f209b3b 100644 --- a/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/spi/DocumentExtensionTest.java +++ b/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/spi/DocumentExtensionTest.java @@ -57,7 +57,6 @@ class DocumentExtensionTest { @Inject private DocumentTemplate template; - @Test void shouldInitiate() { assertNotNull(repository); From 40ec7443e39b3be11bc0d0abe378be38325eb1a0 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 21:33:40 +0100 Subject: [PATCH 30/35] feat: include document validation to person Signed-off-by: Otavio Santana --- .../query/CustomRepositoryDocumentBean.java | 119 ++++++++++++++++++ .../document/spi/DocumentExtension.java | 15 ++- .../mapping/document/entities/People.java | 3 +- .../spi/DocumentCustomExtensionTest.java | 19 +++ 4 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 jnosql-mapping/jnosql-mapping-document/src/main/java/org/eclipse/jnosql/mapping/document/query/CustomRepositoryDocumentBean.java diff --git a/jnosql-mapping/jnosql-mapping-document/src/main/java/org/eclipse/jnosql/mapping/document/query/CustomRepositoryDocumentBean.java b/jnosql-mapping/jnosql-mapping-document/src/main/java/org/eclipse/jnosql/mapping/document/query/CustomRepositoryDocumentBean.java new file mode 100644 index 000000000..a9a0075d6 --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-document/src/main/java/org/eclipse/jnosql/mapping/document/query/CustomRepositoryDocumentBean.java @@ -0,0 +1,119 @@ +/* + * 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.mapping.document.query; + +import jakarta.enterprise.context.spi.CreationalContext; +import org.eclipse.jnosql.mapping.DatabaseQualifier; +import org.eclipse.jnosql.mapping.DatabaseType; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.core.spi.AbstractBean; +import org.eclipse.jnosql.mapping.core.util.AnnotationLiteralUtil; +import org.eclipse.jnosql.mapping.document.DocumentTemplate; +import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; +import org.eclipse.jnosql.mapping.semistructured.query.CustomRepositoryHandler; + +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; + + +/** + * This class serves as a JNoSQL discovery bean for CDI extension, responsible for registering Custom Repository instances. + * 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 CustomRepositoryDocumentBean 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 CustomRepositoryDocumentBean(Class type, String provider) { + this.type = (Class) type; + this.types = Collections.singleton(type); + this.provider = provider; + if (provider.isEmpty()) { + this.qualifiers = new HashSet<>(); + qualifiers.add(DatabaseQualifier.ofDocument()); + qualifiers.add(AnnotationLiteralUtil.DEFAULT_ANNOTATION); + qualifiers.add(AnnotationLiteralUtil.ANY_ANNOTATION); + } else { + this.qualifiers = Collections.singleton(DatabaseQualifier.ofDocument(provider)); + } + } + + @Override + public Class getBeanClass() { + return type; + } + + @SuppressWarnings("unchecked") + @Override + public T create(CreationalContext context) { + var entities = getInstance(EntitiesMetadata.class); + var template = provider.isEmpty() ? getInstance(DocumentTemplate.class) : + getInstance(DocumentTemplate.class, DatabaseQualifier.ofDocument(provider)); + + var converters = getInstance(Converters.class); + + var handler = CustomRepositoryHandler.builder() + .entitiesMetadata(entities) + .template(template) + .customRepositoryType(type) + .converters(converters) + .build(); + + 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-mapping/jnosql-mapping-document/src/main/java/org/eclipse/jnosql/mapping/document/spi/DocumentExtension.java b/jnosql-mapping/jnosql-mapping-document/src/main/java/org/eclipse/jnosql/mapping/document/spi/DocumentExtension.java index fcf1857e5..8f4681bfc 100644 --- a/jnosql-mapping/jnosql-mapping-document/src/main/java/org/eclipse/jnosql/mapping/document/spi/DocumentExtension.java +++ b/jnosql-mapping/jnosql-mapping-document/src/main/java/org/eclipse/jnosql/mapping/document/spi/DocumentExtension.java @@ -23,6 +23,7 @@ import org.eclipse.jnosql.mapping.DatabaseMetadata; import org.eclipse.jnosql.mapping.DatabaseType; import org.eclipse.jnosql.mapping.Databases; +import org.eclipse.jnosql.mapping.document.query.CustomRepositoryDocumentBean; import org.eclipse.jnosql.mapping.document.query.RepositoryDocumentBean; import org.eclipse.jnosql.mapping.metadata.ClassScanner; @@ -56,8 +57,10 @@ void onAfterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery) Set> crudTypes = scanner.repositoriesStandard(); - LOGGER.info(String.format("Processing Document extension: %d databases crud %d found", - databases.size(), crudTypes.size())); + Set> customRepositories = scanner.customRepositories(); + + LOGGER.info(String.format("Processing Document extension: %d databases crud %d found, custom repositories: %d", + databases.size(), crudTypes.size(), customRepositories.size())); LOGGER.info("Processing repositories as a Document implementation: " + crudTypes); databases.forEach(type -> { @@ -76,6 +79,14 @@ void onAfterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery) afterBeanDiscovery.addBean(new RepositoryDocumentBean<>(type, database.getProvider()))); }); + customRepositories.forEach(type -> { + if (!databases.contains(DatabaseMetadata.DEFAULT_DOCUMENT)) { + afterBeanDiscovery.addBean(new CustomRepositoryDocumentBean<>(type, "")); + } + databases.forEach(database -> + afterBeanDiscovery.addBean(new CustomRepositoryDocumentBean<>(type, database.getProvider()))); + }); + } } diff --git a/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/entities/People.java b/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/entities/People.java index 896f18417..5039e38ec 100644 --- a/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/entities/People.java +++ b/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/entities/People.java @@ -17,11 +17,10 @@ import jakarta.data.repository.Insert; import jakarta.data.repository.Repository; -import java.util.List; @Repository public interface People { @Insert - List insert(List people); + Person insert(Person person); } diff --git a/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/spi/DocumentCustomExtensionTest.java b/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/spi/DocumentCustomExtensionTest.java index b942ad67c..3c2bde33b 100644 --- a/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/spi/DocumentCustomExtensionTest.java +++ b/jnosql-mapping/jnosql-mapping-document/src/test/java/org/eclipse/jnosql/mapping/document/spi/DocumentCustomExtensionTest.java @@ -15,6 +15,7 @@ package org.eclipse.jnosql.mapping.document.spi; import jakarta.inject.Inject; +import org.assertj.core.api.SoftAssertions; import org.eclipse.jnosql.mapping.Database; import org.eclipse.jnosql.mapping.DatabaseType; import org.eclipse.jnosql.mapping.core.Converters; @@ -22,6 +23,7 @@ import org.eclipse.jnosql.mapping.document.DocumentTemplate; import org.eclipse.jnosql.mapping.document.MockProducer; import org.eclipse.jnosql.mapping.document.entities.People; +import org.eclipse.jnosql.mapping.document.entities.Person; import org.eclipse.jnosql.mapping.reflection.Reflections; import org.eclipse.jnosql.mapping.semistructured.EntityConverter; import org.jboss.weld.junit5.auto.AddExtensions; @@ -55,15 +57,32 @@ class DocumentCustomExtensionTest { @Test void shouldInitiate() { assertNotNull(people); + Person person = people.insert(Person.builder().build()); + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(person).isNotNull(); + soft.assertThat(person.getName()).isEqualTo("Default"); + }); } @Test void shouldUseMock(){ assertNotNull(pepoleMock); + + Person person = pepoleMock.insert(Person.builder().build()); + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(person).isNotNull(); + soft.assertThat(person.getName()).isEqualTo("documentRepositoryMock"); + }); } @Test void shouldUseDefault(){ assertNotNull(repository); + + Person person = repository.insert(Person.builder().build()); + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(person).isNotNull(); + soft.assertThat(person.getName()).isEqualTo("Default"); + }); } } From 34c1f73a7d4a4aeb79e442e205f8bf69035f9c77 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 21:55:04 +0100 Subject: [PATCH 31/35] feat: include integreation with column bean Signed-off-by: Otavio Santana --- .../query/CustomRepositoryColumnBean.java | 119 ++++++++++++++++++ .../mapping/column/spi/ColumnExtension.java | 16 ++- .../mapping/column/entities/People.java | 26 ++++ .../column/spi/ColumnCustomExtensionTest.java | 87 +++++++++++++ 4 files changed, 246 insertions(+), 2 deletions(-) create mode 100644 jnosql-mapping/jnosql-mapping-column/src/main/java/org/eclipse/jnosql/mapping/column/query/CustomRepositoryColumnBean.java create mode 100644 jnosql-mapping/jnosql-mapping-column/src/test/java/org/eclipse/jnosql/mapping/column/entities/People.java create mode 100644 jnosql-mapping/jnosql-mapping-column/src/test/java/org/eclipse/jnosql/mapping/column/spi/ColumnCustomExtensionTest.java diff --git a/jnosql-mapping/jnosql-mapping-column/src/main/java/org/eclipse/jnosql/mapping/column/query/CustomRepositoryColumnBean.java b/jnosql-mapping/jnosql-mapping-column/src/main/java/org/eclipse/jnosql/mapping/column/query/CustomRepositoryColumnBean.java new file mode 100644 index 000000000..69b0fafcf --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-column/src/main/java/org/eclipse/jnosql/mapping/column/query/CustomRepositoryColumnBean.java @@ -0,0 +1,119 @@ +/* + * 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.mapping.column.query; + +import jakarta.enterprise.context.spi.CreationalContext; +import org.eclipse.jnosql.mapping.DatabaseQualifier; +import org.eclipse.jnosql.mapping.DatabaseType; +import org.eclipse.jnosql.mapping.column.ColumnTemplate; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.core.spi.AbstractBean; +import org.eclipse.jnosql.mapping.core.util.AnnotationLiteralUtil; +import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; +import org.eclipse.jnosql.mapping.semistructured.query.CustomRepositoryHandler; + +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; + + +/** + * This class serves as a JNoSQL discovery bean for CDI extension, responsible for registering Custom Repository instances. + * 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 CustomRepositoryColumnBean 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 CustomRepositoryColumnBean(Class type, String provider) { + this.type = (Class) type; + this.types = Collections.singleton(type); + this.provider = provider; + if (provider.isEmpty()) { + this.qualifiers = new HashSet<>(); + qualifiers.add(DatabaseQualifier.ofColumn()); + qualifiers.add(AnnotationLiteralUtil.DEFAULT_ANNOTATION); + qualifiers.add(AnnotationLiteralUtil.ANY_ANNOTATION); + } else { + this.qualifiers = Collections.singleton(DatabaseQualifier.ofColumn(provider)); + } + } + + @Override + public Class getBeanClass() { + return type; + } + + @SuppressWarnings("unchecked") + @Override + public T create(CreationalContext context) { + var entities = getInstance(EntitiesMetadata.class); + var template = provider.isEmpty() ? getInstance(ColumnTemplate.class) : + getInstance(ColumnTemplate.class, DatabaseQualifier.ofColumn(provider)); + + var converters = getInstance(Converters.class); + + var handler = CustomRepositoryHandler.builder() + .entitiesMetadata(entities) + .template(template) + .customRepositoryType(type) + .converters(converters) + .build(); + + 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.COLUMN + "-" + provider; + } + +} \ No newline at end of file diff --git a/jnosql-mapping/jnosql-mapping-column/src/main/java/org/eclipse/jnosql/mapping/column/spi/ColumnExtension.java b/jnosql-mapping/jnosql-mapping-column/src/main/java/org/eclipse/jnosql/mapping/column/spi/ColumnExtension.java index db630f203..272480556 100644 --- a/jnosql-mapping/jnosql-mapping-column/src/main/java/org/eclipse/jnosql/mapping/column/spi/ColumnExtension.java +++ b/jnosql-mapping/jnosql-mapping-column/src/main/java/org/eclipse/jnosql/mapping/column/spi/ColumnExtension.java @@ -22,6 +22,7 @@ import org.eclipse.jnosql.communication.semistructured.DatabaseManager; import org.eclipse.jnosql.mapping.DatabaseMetadata; import org.eclipse.jnosql.mapping.Databases; +import org.eclipse.jnosql.mapping.column.query.CustomRepositoryColumnBean; import org.eclipse.jnosql.mapping.column.query.RepositoryColumnBean; import org.eclipse.jnosql.mapping.metadata.ClassScanner; @@ -51,8 +52,10 @@ void onAfterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery) ClassScanner scanner = ClassScanner.load(); Set> crudTypes = scanner.repositoriesStandard(); - LOGGER.info(String.format("Processing Column extension: %d databases crud %d found", - databases.size(), crudTypes.size())); + Set> customRepositories = scanner.customRepositories(); + + LOGGER.info(String.format("Processing Document extension: %d databases crud %d found, custom repositories: %d", + databases.size(), crudTypes.size(), customRepositories.size())); LOGGER.info("Processing repositories as a Column implementation: " + crudTypes); databases.forEach(type -> { @@ -70,6 +73,15 @@ void onAfterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery) .addBean(new RepositoryColumnBean<>(type, database.getProvider()))); }); + + customRepositories.forEach(type -> { + if (!databases.contains(DatabaseMetadata.DEFAULT_COLUMN)) { + afterBeanDiscovery.addBean(new CustomRepositoryColumnBean<>(type, "")); + } + databases.forEach(database -> + afterBeanDiscovery.addBean(new CustomRepositoryColumnBean<>(type, database.getProvider()))); + }); + } } diff --git a/jnosql-mapping/jnosql-mapping-column/src/test/java/org/eclipse/jnosql/mapping/column/entities/People.java b/jnosql-mapping/jnosql-mapping-column/src/test/java/org/eclipse/jnosql/mapping/column/entities/People.java new file mode 100644 index 000000000..a903fb577 --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-column/src/test/java/org/eclipse/jnosql/mapping/column/entities/People.java @@ -0,0 +1,26 @@ +/* + * 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.mapping.column.entities; + +import jakarta.data.repository.Insert; +import jakarta.data.repository.Repository; + + +@Repository +public interface People { + + @Insert + Person insert(Person person); +} diff --git a/jnosql-mapping/jnosql-mapping-column/src/test/java/org/eclipse/jnosql/mapping/column/spi/ColumnCustomExtensionTest.java b/jnosql-mapping/jnosql-mapping-column/src/test/java/org/eclipse/jnosql/mapping/column/spi/ColumnCustomExtensionTest.java new file mode 100644 index 000000000..aff602169 --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-column/src/test/java/org/eclipse/jnosql/mapping/column/spi/ColumnCustomExtensionTest.java @@ -0,0 +1,87 @@ +/* + * 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.mapping.column.spi; + +import jakarta.inject.Inject; +import org.assertj.core.api.SoftAssertions; +import org.eclipse.jnosql.mapping.Database; +import org.eclipse.jnosql.mapping.DatabaseType; +import org.eclipse.jnosql.mapping.column.ColumnTemplate; +import org.eclipse.jnosql.mapping.column.MockProducer; +import org.eclipse.jnosql.mapping.column.entities.People; +import org.eclipse.jnosql.mapping.column.entities.Person; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.core.spi.EntityMetadataExtension; +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.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + + +@EnableAutoWeld +@AddPackages(value = {Converters.class, EntityConverter.class, ColumnTemplate.class}) +@AddPackages(MockProducer.class) +@AddPackages(Reflections.class) +@AddExtensions({EntityMetadataExtension.class, ColumnExtension.class}) +class ColumnCustomExtensionTest { + + @Inject + @Database(value = DatabaseType.COLUMN) + private People people; + + @Inject + @Database(value = DatabaseType.COLUMN, provider = "columnRepositoryMock") + private People pepoleMock; + + @Inject + private People repository; + + + @Test + void shouldInitiate() { + assertNotNull(people); + Person person = people.insert(Person.builder().build()); + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(person).isNotNull(); + soft.assertThat(person.getName()).isEqualTo("Default"); + }); + } + + @Test + void shouldUseMock(){ + assertNotNull(pepoleMock); + + Person person = pepoleMock.insert(Person.builder().build()); + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(person).isNotNull(); + soft.assertThat(person.getName()).isEqualTo("columnRepositoryMock"); + }); + } + + @Test + void shouldUseDefault(){ + assertNotNull(repository); + + Person person = repository.insert(Person.builder().build()); + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(person).isNotNull(); + soft.assertThat(person.getName()).isEqualTo("Default"); + }); + } +} From 5635de7508fb0cebe721a32846bdabe57949f567 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 21:56:27 +0100 Subject: [PATCH 32/35] style: remove extra line at document extension Signed-off-by: Otavio Santana --- .../eclipse/jnosql/mapping/document/spi/DocumentExtension.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jnosql-mapping/jnosql-mapping-document/src/main/java/org/eclipse/jnosql/mapping/document/spi/DocumentExtension.java b/jnosql-mapping/jnosql-mapping-document/src/main/java/org/eclipse/jnosql/mapping/document/spi/DocumentExtension.java index 8f4681bfc..92a4e4b22 100644 --- a/jnosql-mapping/jnosql-mapping-document/src/main/java/org/eclipse/jnosql/mapping/document/spi/DocumentExtension.java +++ b/jnosql-mapping/jnosql-mapping-document/src/main/java/org/eclipse/jnosql/mapping/document/spi/DocumentExtension.java @@ -70,7 +70,6 @@ void onAfterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery) } }); - crudTypes.forEach(type -> { if (!databases.contains(DatabaseMetadata.DEFAULT_DOCUMENT)) { afterBeanDiscovery.addBean(new RepositoryDocumentBean<>(type, "")); From c9aba4f31ac446097278646873c4d706e11fd5d1 Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 22:07:04 +0100 Subject: [PATCH 33/35] feat: enhnace log for column Signed-off-by: Otavio Santana --- .../mapping/column/spi/ColumnExtension.java | 2 +- .../graph/spi/CustomRepositoryGraphBean.java | 119 ++++++++++++++++++ .../mapping/graph/spi/GraphExtension.java | 8 +- 3 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 jnosql-mapping/jnosql-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/spi/CustomRepositoryGraphBean.java diff --git a/jnosql-mapping/jnosql-mapping-column/src/main/java/org/eclipse/jnosql/mapping/column/spi/ColumnExtension.java b/jnosql-mapping/jnosql-mapping-column/src/main/java/org/eclipse/jnosql/mapping/column/spi/ColumnExtension.java index 272480556..8902c0286 100644 --- a/jnosql-mapping/jnosql-mapping-column/src/main/java/org/eclipse/jnosql/mapping/column/spi/ColumnExtension.java +++ b/jnosql-mapping/jnosql-mapping-column/src/main/java/org/eclipse/jnosql/mapping/column/spi/ColumnExtension.java @@ -54,7 +54,7 @@ void onAfterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery) Set> crudTypes = scanner.repositoriesStandard(); Set> customRepositories = scanner.customRepositories(); - LOGGER.info(String.format("Processing Document extension: %d databases crud %d found, custom repositories: %d", + LOGGER.info(String.format("Processing Column extension: %d databases crud %d found, custom repositories: %d", databases.size(), crudTypes.size(), customRepositories.size())); LOGGER.info("Processing repositories as a Column implementation: " + crudTypes); diff --git a/jnosql-mapping/jnosql-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/spi/CustomRepositoryGraphBean.java b/jnosql-mapping/jnosql-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/spi/CustomRepositoryGraphBean.java new file mode 100644 index 000000000..59f89d70e --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/spi/CustomRepositoryGraphBean.java @@ -0,0 +1,119 @@ +/* + * 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.mapping.graph.spi; + +import jakarta.enterprise.context.spi.CreationalContext; +import org.eclipse.jnosql.mapping.DatabaseQualifier; +import org.eclipse.jnosql.mapping.DatabaseType; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.core.spi.AbstractBean; +import org.eclipse.jnosql.mapping.core.util.AnnotationLiteralUtil; +import org.eclipse.jnosql.mapping.graph.GraphTemplate; +import org.eclipse.jnosql.mapping.metadata.EntitiesMetadata; +import org.eclipse.jnosql.mapping.semistructured.query.CustomRepositoryHandler; + +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; + + +/** + * This class serves as a JNoSQL discovery bean for CDI extension, responsible for registering Custom Repository instances. + * 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 CustomRepositoryGraphBean 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 CustomRepositoryGraphBean(Class type, String provider) { + this.type = (Class) type; + this.types = Collections.singleton(type); + this.provider = provider; + if (provider.isEmpty()) { + this.qualifiers = new HashSet<>(); + qualifiers.add(DatabaseQualifier.ofGraph()); + qualifiers.add(AnnotationLiteralUtil.DEFAULT_ANNOTATION); + qualifiers.add(AnnotationLiteralUtil.ANY_ANNOTATION); + } else { + this.qualifiers = Collections.singleton(DatabaseQualifier.ofGraph(provider)); + } + } + + @Override + public Class getBeanClass() { + return type; + } + + @SuppressWarnings("unchecked") + @Override + public T create(CreationalContext context) { + var entities = getInstance(EntitiesMetadata.class); + var template = provider.isEmpty() ? getInstance(GraphTemplate.class) : + getInstance(GraphTemplate.class, DatabaseQualifier.ofGraph(provider)); + + var converters = getInstance(Converters.class); + + var handler = CustomRepositoryHandler.builder() + .entitiesMetadata(entities) + .template(template) + .customRepositoryType(type) + .converters(converters) + .build(); + + 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.GRAPH + "-" + provider; + } + +} \ No newline at end of file diff --git a/jnosql-mapping/jnosql-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/spi/GraphExtension.java b/jnosql-mapping/jnosql-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/spi/GraphExtension.java index a59a77d5a..0979a3b74 100644 --- a/jnosql-mapping/jnosql-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/spi/GraphExtension.java +++ b/jnosql-mapping/jnosql-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/spi/GraphExtension.java @@ -49,8 +49,12 @@ void onAfterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery) ClassScanner scanner = ClassScanner.load(); Set> crudTypes = scanner.repositoriesStandard(); - LOGGER.info(String.format("Processing graph extension: %d databases crud %d found", - databases.size(), crudTypes.size())); + + Set> customRepositories = scanner.customRepositories(); + + LOGGER.info(String.format("Processing graph extension: %d databases crud %d found, custom repositories: %d", + databases.size(), crudTypes.size(), customRepositories.size())); + LOGGER.info("Processing repositories as a Graph implementation: " + crudTypes); databases.forEach(type -> { if (!type.getProvider().isBlank()) { From c55868e2356c5113138b8d4ee167946d452263fc Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 22:15:29 +0100 Subject: [PATCH 34/35] feat: include extension to graph database! Signed-off-by: Otavio Santana --- .../mapping/graph/spi/GraphExtension.java | 8 ++ .../jnosql/mapping/graph/entities/People.java | 26 ++++++ .../graph/spi/GraphCustomExtensionTest.java | 83 +++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 jnosql-mapping/jnosql-mapping-graph/src/test/java/org/eclipse/jnosql/mapping/graph/entities/People.java create mode 100644 jnosql-mapping/jnosql-mapping-graph/src/test/java/org/eclipse/jnosql/mapping/graph/spi/GraphCustomExtensionTest.java diff --git a/jnosql-mapping/jnosql-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/spi/GraphExtension.java b/jnosql-mapping/jnosql-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/spi/GraphExtension.java index 0979a3b74..88dc3e6cf 100644 --- a/jnosql-mapping/jnosql-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/spi/GraphExtension.java +++ b/jnosql-mapping/jnosql-mapping-graph/src/main/java/org/eclipse/jnosql/mapping/graph/spi/GraphExtension.java @@ -71,5 +71,13 @@ void onAfterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery) databases.forEach(database -> afterBeanDiscovery .addBean(new RepositoryGraphBean<>(type, database.getProvider()))); }); + + customRepositories.forEach(type -> { + if (!databases.contains(DatabaseMetadata.DEFAULT_DOCUMENT)) { + afterBeanDiscovery.addBean(new CustomRepositoryGraphBean<>(type, "")); + } + databases.forEach(database -> + afterBeanDiscovery.addBean(new CustomRepositoryGraphBean<>(type, database.getProvider()))); + }); } } diff --git a/jnosql-mapping/jnosql-mapping-graph/src/test/java/org/eclipse/jnosql/mapping/graph/entities/People.java b/jnosql-mapping/jnosql-mapping-graph/src/test/java/org/eclipse/jnosql/mapping/graph/entities/People.java new file mode 100644 index 000000000..56e35d37d --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-graph/src/test/java/org/eclipse/jnosql/mapping/graph/entities/People.java @@ -0,0 +1,26 @@ +/* + * 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.mapping.graph.entities; + +import jakarta.data.repository.Insert; +import jakarta.data.repository.Repository; + + +@Repository +public interface People { + + @Insert + Person insert(Person person); +} diff --git a/jnosql-mapping/jnosql-mapping-graph/src/test/java/org/eclipse/jnosql/mapping/graph/spi/GraphCustomExtensionTest.java b/jnosql-mapping/jnosql-mapping-graph/src/test/java/org/eclipse/jnosql/mapping/graph/spi/GraphCustomExtensionTest.java new file mode 100644 index 000000000..abdd3c1cb --- /dev/null +++ b/jnosql-mapping/jnosql-mapping-graph/src/test/java/org/eclipse/jnosql/mapping/graph/spi/GraphCustomExtensionTest.java @@ -0,0 +1,83 @@ +/* + * 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.mapping.graph.spi; + +import jakarta.inject.Inject; +import org.assertj.core.api.SoftAssertions; +import org.eclipse.jnosql.mapping.Database; +import org.eclipse.jnosql.mapping.DatabaseType; +import org.eclipse.jnosql.mapping.core.Converters; +import org.eclipse.jnosql.mapping.core.spi.EntityMetadataExtension; +import org.eclipse.jnosql.mapping.graph.GraphProducer; +import org.eclipse.jnosql.mapping.graph.GraphTemplate; +import org.eclipse.jnosql.mapping.graph.entities.People; +import org.eclipse.jnosql.mapping.graph.entities.Person; +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.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + + +@EnableAutoWeld +@AddPackages(value = {Converters.class, EntityConverter.class, GraphTemplate.class}) +@AddPackages(GraphProducer.class) +@AddPackages(Reflections.class) +@AddExtensions({EntityMetadataExtension.class, GraphExtension.class}) +class GraphCustomExtensionTest { + + @Inject + @Database(value = DatabaseType.GRAPH) + private People people; + + @Inject + @Database(value = DatabaseType.GRAPH, provider = "graphRepositoryMock") + private People pepoleMock; + + @Inject + private People repository; + + @Test + void shouldInitiate() { + assertNotNull(people); + Person person = people.insert(Person.builder().build()); + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(person).isNotNull(); + }); + } + + @Test + void shouldUseMock(){ + assertNotNull(pepoleMock); + + Person person = pepoleMock.insert(Person.builder().build()); + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(person).isNotNull(); + }); + } + + @Test + void shouldUseDefault(){ + assertNotNull(repository); + + Person person = repository.insert(Person.builder().build()); + SoftAssertions.assertSoftly(soft -> { + soft.assertThat(person).isNotNull(); + }); + } +} From 28f3f618259cf1a2b590a06916797a95ebeb223c Mon Sep 17 00:00:00 2001 From: Otavio Santana Date: Sat, 1 Jun 2024 22:16:57 +0100 Subject: [PATCH 35/35] feat: include looging to key-value database Signed-off-by: Otavio Santana --- .../jnosql/mapping/keyvalue/spi/KeyValueExtension.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jnosql-mapping/jnosql-mapping-key-value/src/main/java/org/eclipse/jnosql/mapping/keyvalue/spi/KeyValueExtension.java b/jnosql-mapping/jnosql-mapping-key-value/src/main/java/org/eclipse/jnosql/mapping/keyvalue/spi/KeyValueExtension.java index b52610b07..321269ca7 100644 --- a/jnosql-mapping/jnosql-mapping-key-value/src/main/java/org/eclipse/jnosql/mapping/keyvalue/spi/KeyValueExtension.java +++ b/jnosql-mapping/jnosql-mapping-key-value/src/main/java/org/eclipse/jnosql/mapping/keyvalue/spi/KeyValueExtension.java @@ -47,10 +47,14 @@ void onAfterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery) ClassScanner scanner = ClassScanner.load(); Set> crudTypes = scanner.repositoriesStandard(); + Set> customRepositories = scanner.customRepositories(); + LOGGER.info(String.format("Processing Key-Value extension: %d databases crud %d found", databases.size(), crudTypes.size())); LOGGER.info("Processing repositories as a Key-Value implementation: " + crudTypes); + LOGGER.info("Ignoring custom repositories as a Key-Value implementation: " + customRepositories); + databases.forEach(type -> { final TemplateBean bean = new TemplateBean(type.getProvider()); afterBeanDiscovery.addBean(bean);