Skip to content

Commit

Permalink
Merge pull request #529 from eclipse/update-cursor-query
Browse files Browse the repository at this point in the history
Update cursor query and update NoSQLPage to return true instead of exception
  • Loading branch information
otaviojava authored Jul 9, 2024
2 parents b70173b + c3fb28d commit 491e704
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

Expand All @@ -28,6 +29,8 @@
*/
public final class CommunicationPreparedStatement {

private static final UnaryOperator<SelectQuery> SELECT_MAPPER_DEFAULT = s -> s;

private final SelectQuery selectQuery;

private final DeleteQuery deleteQuery;
Expand All @@ -44,6 +47,8 @@ public final class CommunicationPreparedStatement {

private final DatabaseManager manager;

private UnaryOperator<SelectQuery> selectMapper = SELECT_MAPPER_DEFAULT;

private CommunicationPreparedStatement(SelectQuery selectQuery,
DeleteQuery deleteQuery,
UpdateQuery updateQuery,
Expand Down Expand Up @@ -111,7 +116,7 @@ public CommunicationPreparedStatement bind(int index, Object value) {
*
* @return the select query
*/
public Optional<SelectQuery> select(){
public Optional<SelectQuery> select() {
return Optional.ofNullable(selectQuery);
}

Expand All @@ -127,7 +132,7 @@ public Stream<CommunicationEntity> result() {
}
switch (type) {
case SELECT -> {
return manager.select(selectQuery);
return manager.select(operator().apply(selectQuery));
}
case DELETE -> {
manager.delete(deleteQuery);
Expand All @@ -140,6 +145,25 @@ public Stream<CommunicationEntity> result() {
}
}

/**
* Returns the operator to be used in the query.
*
* @return the operator
*/
public UnaryOperator<SelectQuery> operator() {
return this.selectMapper;
}

/**
* Sets the operator to be used in the query.
*
* @param selectMapper the operator
*/
public void setSelectMapper(UnaryOperator<SelectQuery> selectMapper) {
Objects.requireNonNull(selectMapper, "selectMapper is required");
this.selectMapper = selectMapper;
}

/**
* Returns the number of elements in the result.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,5 @@ public interface PreparedStatement {
* @return {@code true} if the operation is a count operation, otherwise {@code false}
*/
boolean isCount();

}
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ public int numberOfElements() {

@Override
public boolean hasNext() {
throw new UnsupportedOperationException("Eclipse JNoSQL has no support for this feature hasNext");
return true;
}

@Override
public boolean hasPrevious() {
throw new UnsupportedOperationException("Eclipse JNoSQL has no support for this feature hasPrevious");
return true;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,26 @@ void shouldReturnUnsupportedOperation() {
PageRequest.ofPage(2));

assertThrows(UnsupportedOperationException.class, page::totalPages);

assertThrows(UnsupportedOperationException.class, page::totalElements);
assertThrows(UnsupportedOperationException.class, page::hasNext);
assertThrows(UnsupportedOperationException.class, page::hasPrevious);
assertThrows(UnsupportedOperationException.class, page::hasTotals);
}

@Test
void shouldReturnTrueHasNext(){
Page<Person> page = NoSQLPage.of(Collections.singletonList(Person.builder().withName("Otavio").build()),
PageRequest.ofPage(2));

org.assertj.core.api.Assertions.assertThat(page.hasNext()).isTrue();
}

@Test
void shouldReturnTrueHasPrevious(){
Page<Person> page = NoSQLPage.of(Collections.singletonList(Person.builder().withName("Otavio").build()),
PageRequest.ofPage(2));

org.assertj.core.api.Assertions.assertThat(page.hasPrevious()).isTrue();
}

@Test
void shouldReturnHasContent() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
import org.eclipse.jnosql.communication.semistructured.CommunicationEntity;
import org.eclipse.jnosql.communication.semistructured.SelectQuery;

import java.util.Objects;
import java.util.Optional;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;

/**
Expand Down Expand Up @@ -77,4 +79,16 @@ public boolean isCount() {
public Optional<SelectQuery> selectQuery(){
return preparedStatement.select();
}

/**
* Sets the operator to be used in the query.
*
* @param selectMapper the operator
*/
public void setSelectMapper(UnaryOperator<SelectQuery> selectMapper) {
Objects.requireNonNull(selectMapper, "selectMapper is required");
this.preparedStatement.setSelectMapper(selectMapper);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@
package org.eclipse.jnosql.mapping.semistructured.query;

import jakarta.data.Sort;
import jakarta.data.page.PageRequest;
import jakarta.data.repository.Find;
import jakarta.data.repository.OrderBy;
import jakarta.data.repository.Query;
import org.eclipse.jnosql.communication.semistructured.DeleteQuery;
import org.eclipse.jnosql.mapping.core.repository.DynamicQueryMethodReturn;
import org.eclipse.jnosql.mapping.core.repository.DynamicReturn;
import org.eclipse.jnosql.mapping.core.repository.RepositoryReflectionUtils;
import org.eclipse.jnosql.mapping.core.repository.SpecialParameters;
import org.eclipse.jnosql.mapping.metadata.EntityMetadata;

import java.lang.reflect.Method;
Expand All @@ -47,24 +46,41 @@ protected Object executeQuery(Object instance, Method method, Object[] params) {
.withArgs(params)
.withMethod(method)
.withTypeClass(type)
.withPrepareConverter(q -> template().prepare(q, entity))
.withPrepareConverter(textQuery -> {
var prepare = (org.eclipse.jnosql.mapping.semistructured.PreparedStatement)template().prepare(textQuery, entity);
prepare.setSelectMapper(query -> updateQueryDynamically(params, query));
return prepare;
})
.build();
return methodReturn.execute();
}

@Override
protected Object executeCursorPagination(Object instance, Method method, Object[] params) {
if (method.getAnnotation(Find.class) == null) {

if (method.getAnnotation(Query.class) != null) {
var entity = entityMetadata().name();
var textQuery = method.getAnnotation(Query.class).value();
var prepare = (org.eclipse.jnosql.mapping.semistructured.PreparedStatement)template().prepare(textQuery, entity);
var argsParams = RepositoryReflectionUtils.INSTANCE.getParams(method, params);
argsParams.forEach(prepare::bind);
var selectQuery = updateQueryDynamically(params, prepare.selectQuery().orElseThrow());
var special = DynamicReturn.findSpecialParameters(params, sortParser());
var pageRequest = special.pageRequest()
.orElseThrow(() -> new IllegalArgumentException("Pageable is required in the method signature as parameter at " + method));

return this.template().selectCursor(selectQuery, pageRequest);
} else if (method.getAnnotation(Find.class) == null) {
var query = query(method, params);
SpecialParameters special = DynamicReturn.findSpecialParameters(params, sortParser());
PageRequest pageRequest = special.pageRequest()
var special = DynamicReturn.findSpecialParameters(params, sortParser());
var pageRequest = special.pageRequest()
.orElseThrow(() -> new IllegalArgumentException("Pageable is required in the method signature as parameter at " + method));
return this.template().selectCursor(query, pageRequest);
} else {
Map<String, Object> parameters = RepositoryReflectionUtils.INSTANCE.getBy(method, params);
var parameters = RepositoryReflectionUtils.INSTANCE.getBy(method, params);
var query = SemiStructuredParameterBasedQuery.INSTANCE.toQuery(parameters, getSorts(method, entityMetadata()), entityMetadata());
SpecialParameters special = DynamicReturn.findSpecialParameters(params, sortParser());
PageRequest pageRequest = special.pageRequest()
var special = DynamicReturn.findSpecialParameters(params, sortParser());
var pageRequest = special.pageRequest()
.orElseThrow(() -> new IllegalArgumentException("Pageable is required in the method signature as parameter at " + method));
return this.template().selectCursor(query, pageRequest);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,12 @@
import jakarta.data.page.Page;
import jakarta.data.page.PageRequest;
import org.eclipse.jnosql.communication.Params;
import org.eclipse.jnosql.communication.query.SelectQuery;
import org.eclipse.jnosql.communication.query.method.DeleteMethodProvider;
import org.eclipse.jnosql.communication.query.method.SelectMethodProvider;
import org.eclipse.jnosql.communication.semistructured.CommunicationObserverParser;
import org.eclipse.jnosql.communication.semistructured.CriteriaCondition;
import org.eclipse.jnosql.communication.semistructured.DeleteQueryParser;
import org.eclipse.jnosql.communication.semistructured.Element;
import org.eclipse.jnosql.communication.semistructured.QueryParams;
import org.eclipse.jnosql.communication.semistructured.SelectQueryParser;
import org.eclipse.jnosql.mapping.core.Converters;
import org.eclipse.jnosql.mapping.core.NoSQLPage;
Expand Down Expand Up @@ -89,11 +87,11 @@ public abstract class BaseSemiStructuredRepository<T, K> extends AbstractReposit


protected org.eclipse.jnosql.communication.semistructured.SelectQuery query(Method method, Object[] args) {
SelectMethodProvider provider = SelectMethodProvider.INSTANCE;
SelectQuery selectQuery = provider.apply(method, entityMetadata().name());
QueryParams queryParams = SELECT_PARSER.apply(selectQuery, parser());
var provider = SelectMethodProvider.INSTANCE;
var selectQuery = provider.apply(method, entityMetadata().name());
var queryParams = SELECT_PARSER.apply(selectQuery, parser());
var query = queryParams.query();
Params params = queryParams.params();
var params = queryParams.params();
paramsBinder().bind(params, args(args), method);
return updateQueryDynamically(args(args), query);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -606,23 +606,23 @@ void shouldConvertFieldToTheType() {

@Test
void shouldExecuteJNoSQLQuery() {
PreparedStatement statement = Mockito.mock(PreparedStatement.class);
PreparedStatement statement = Mockito.mock(org.eclipse.jnosql.mapping.semistructured.PreparedStatement.class);
when(template.prepare(Mockito.anyString(), Mockito.anyString())).thenReturn(statement);
personRepository.findByQuery();
verify(template).prepare("FROM Person", "Person");
}

@Test
void shouldExecuteJNoSQLPrepare() {
PreparedStatement statement = Mockito.mock(PreparedStatement.class);
PreparedStatement statement = Mockito.mock(org.eclipse.jnosql.mapping.semistructured.PreparedStatement.class);
when(template.prepare(Mockito.anyString(), Mockito.anyString())).thenReturn(statement);
personRepository.findByQuery("Ada");
verify(statement).bind("id", "Ada");
}

@Test
void shouldExecuteJNoSQLPrepareIndex() {
PreparedStatement statement = Mockito.mock(PreparedStatement.class);
PreparedStatement statement = Mockito.mock(org.eclipse.jnosql.mapping.semistructured.PreparedStatement.class);
when(template.prepare(Mockito.anyString(), Mockito.anyString())).thenReturn(statement);
personRepository.findByQuery(10);
verify(statement).bind("?1", 10);
Expand Down Expand Up @@ -732,7 +732,7 @@ void shouldFindByAgeNotGreaterThan() {
@Test
void shouldCount() {

PreparedStatement statement = Mockito.mock(PreparedStatement.class);
PreparedStatement statement = Mockito.mock(org.eclipse.jnosql.mapping.semistructured.PreparedStatement.class);
when(template.prepare(Mockito.anyString(), Mockito.anyString())).thenReturn(statement);

when(statement.isCount()).thenReturn(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ void shouldExecutePathParameter() {
@Test
void shouldExecuteQuery(){

var preparedStatement = Mockito.mock(PreparedStatement.class);
var preparedStatement = Mockito.mock(org.eclipse.jnosql.mapping.semistructured.PreparedStatement.class);
Mockito.when(template.prepare(Mockito.anyString(), Mockito.anyString()))
.thenReturn(preparedStatement);
Mockito.when(template.query(Mockito.anyString()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import jakarta.data.Sort;
import jakarta.data.repository.By;
import jakarta.data.repository.Find;
import jakarta.data.repository.Param;
import jakarta.data.repository.Query;
import jakarta.inject.Inject;
import org.assertj.core.api.SoftAssertions;
import org.eclipse.jnosql.communication.Condition;
Expand Down Expand Up @@ -684,6 +686,37 @@ public void shouldParameterMatch() {
});
}

@Test
public void shouldParameterQuery() {
CursoredPage<Person> mock = Mockito.mock(CursoredPage.class);
var prepare = Mockito.mock(org.eclipse.jnosql.mapping.semistructured.PreparedStatement.class);

when(prepare.selectQuery()).thenReturn(Optional.of(SelectQuery.select().from("Person").where("name").eq("ada").build()));
when(template.<Person>selectCursor(any(SelectQuery.class),
any(PageRequest.class))).thenReturn(mock);

when(template.<Person>prepare(any(String.class),
any(String.class))).thenReturn(prepare);

CursoredPage<Person> page = personRepository.cursorJQDL("name",
PageRequest.afterCursor(PageRequest.Cursor.forKey("Ada"), 1, 10, false));

SoftAssertions.assertSoftly(s -> s.assertThat(page).isEqualTo(mock));

ArgumentCaptor<SelectQuery> captor = ArgumentCaptor.forClass(SelectQuery.class);
verify(template).selectCursor(captor.capture(), Mockito.any());
var query = captor.getValue();

SoftAssertions.assertSoftly(soft ->{
soft.assertThat(query.name()).isEqualTo("Person");
soft.assertThat(query.skip()).isEqualTo(0);
soft.assertThat(query.condition().isPresent()).isTrue();
soft.assertThat(query.sorts()).hasSize(0);
CriteriaCondition condition = query.condition().orElseThrow();
soft.assertThat(condition.condition()).isEqualTo(EQUALS);
});
}



private PageRequest getPageRequest() {
Expand All @@ -702,6 +735,9 @@ interface PersonRepository extends BasicRepository<Person, Long> {
@Find
CursoredPage<Person> findPageParameter(@By("name") String name, PageRequest pageRequest);

@Query("select * from Person where name = :name")
CursoredPage<Person> cursorJQDL(@Param("name") String name, PageRequest pageRequest);

List<Person> findByName(String name, Sort<Person> sort);

List<Person> findByName(String name, Limit limit, Sort<Person> sort);
Expand Down
Loading

0 comments on commit 491e704

Please sign in to comment.