Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ public String getType() {
return getService().getModelClass().getSimpleName();
}

@GetMapping()
protected ExtendedRequest<T> newExtendedRequest() {
return new ExtendedRequest<>(extendedParameters, r2dbcDialect, getService().getModelClass());
}

@GetMapping
public Flux<T> findAll(ServerHttpResponse response, ServerHttpRequest request) {
ExtendedRequest<T> extendedRequest = new ExtendedRequest<>(extendedParameters, r2dbcDialect, getService().getModelClass());
ExtendedRequest<T> extendedRequest = newExtendedRequest();
try {
extendedRequest.parseParameter(request.getQueryParams());
} catch (GetException getException) {
Expand Down
126 changes: 42 additions & 84 deletions src/main/java/org/dcsa/core/extendedrequest/ExtendedRequest.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,27 @@
package org.dcsa.core.extendedrequest;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.r2dbc.spi.Row;
import io.r2dbc.spi.RowMetadata;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.dcsa.core.exception.GetException;
import org.dcsa.core.query.DBEntityAnalysis;
import org.dcsa.core.query.impl.AbstractQueryFactory;
import org.dcsa.core.query.impl.PreparedQuery;
import org.springframework.data.r2dbc.dialect.R2dbcDialect;
import org.springframework.data.relational.core.dialect.RenderContextFactory;
import org.springframework.data.relational.core.sql.*;
import org.springframework.data.relational.core.sql.render.RenderContext;
import org.springframework.data.relational.core.sql.render.SqlRenderer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.r2dbc.core.PreparedOperation;
import org.springframework.r2dbc.core.binding.BindTarget;
import org.springframework.r2dbc.core.binding.Bindings;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.Key;
Expand All @@ -51,7 +45,7 @@
* * object.
*/
@RequiredArgsConstructor
public class ExtendedRequest<T> {
public class ExtendedRequest<T> extends AbstractQueryFactory<T> {

public static final String PARAMETER_SPLIT = "&";
public static final String CURSOR_SPLIT = "=";
Expand Down Expand Up @@ -124,6 +118,20 @@ public void parseParameter(Map<String, List<String>> params, boolean fromCursor)
finishedParsingParameters();
}

protected CursorBackedFilterCondition getFilterCondition() {
return filterCondition;
}

@Override
protected Set<String> getJoinAliasInUse() {
return joinAliasInUse;
}

@Override
protected SelectBuilder.SelectFromAndJoin applyLimitOffset(SelectBuilder.SelectFromAndJoin t) {
return getPagination().applyLimitOffset(t);
}

// For sub-classes to hook into this
protected void finishedParsingParameters() {
filterCondition = getQueryParameterParser().build();
Expand Down Expand Up @@ -213,66 +221,37 @@ private static Map<String, List<String>> convertToQueryStringToHashMap(String so
return data;
}

public DatabaseClient.GenericExecuteSpec getCount(DatabaseClient databaseClient) {
return databaseClient.sql(this.getCountQuery());
}

public DatabaseClient.GenericExecuteSpec getFindAll(DatabaseClient databaseClient) {
return databaseClient.sql(this.getQuery());
}

public Select getSelectQuery() {
List<Expression> expressions = dbEntityAnalysis.getAllSelectableFields().stream().map(queryField -> {
markQueryFieldInUse(queryField);
return queryField.getSelectColumn();
}).collect(Collectors.toList());
Sort<T> sort = getSort();

return generateBaseQuery(Select.builder().select(expressions))
.orderBy(sort.getOrderByFields()).build();
}

public Select getSelectCountQuery() {
return generateBaseQuery(Select.builder().select(
Functions.count(Expressions.asterisk()).as("count")
)).build();
protected SelectBuilder.BuildSelect applyOrder(SelectBuilder.SelectOrdered builder) {
return builder.orderBy(getSort().getOrderByFields());
}

@Override
protected SelectBuilder.SelectOrdered generateBaseQuery(SelectBuilder.SelectAndFrom selectBuilder) {
if (filterCondition == null) {
finishedParsingParameters();
}
Pagination<T> pagination = getPagination();
if (selectDistinct) {
selectBuilder = selectBuilder.distinct();
}
SelectBuilder.SelectWhere selectWhere = applyJoins(pagination.applyLimitOffset(selectBuilder.from(
dbEntityAnalysis.getTableAndJoins().getPrimaryTable()
)));
Condition con = filterCondition.computeCondition(r2dbcDialect);
if (TrueCondition.INSTANCE.equals(con)) {
return selectWhere;
}
return selectWhere.where(con);
return super.generateBaseQuery(selectBuilder);
}

public void setQueryCount(Integer count) {
getPagination().setTotal(count);
@Override
protected Condition generateCondition() {
return getFilterCondition().computeCondition(r2dbcDialect);
}

protected SelectBuilder.SelectWhere applyJoins(SelectBuilder.SelectFromAndJoin selectBuilder) {
if (!joinAliasInUse.isEmpty()) {
return dbEntityAnalysis.getTableAndJoins().applyJoins(selectBuilder, joinAliasInUse);
}
return selectBuilder;
public void setQueryCount(Integer count) {
getPagination().setTotal(count);
}

public PreparedOperation<Select> getCountQuery() {
public PreparedOperation<Select> generateCountQuery() {
if (filterCondition == null) {
finishedParsingParameters();
}
return super.generateCountQuery();
}

protected PreparedQuery createPreparedOperation(Select select) {
RenderContextFactory factory = new RenderContextFactory(r2dbcDialect);
return PreparedQuery.of(getSelectCountQuery(), factory.createRenderContext(), filterCondition.getBindings());
return PreparedQuery.of(select, factory.createRenderContext(), filterCondition.getBindings());
}

/**
Expand Down Expand Up @@ -319,29 +298,27 @@ protected DBEntityAnalysis.DBEntityAnalysisBuilder<T> prepareDBEntityAnalysis()
return DBEntityAnalysis.builder(this.modelClass).loadFieldsAndJoinsFromModel();
}

public PreparedOperation<Select> getQuery() {
public PreparedOperation<Select> generateSelectQuery() {
List<Expression> expressions = dbEntityAnalysis.getAllSelectableFields().stream().map(queryField -> {
markQueryFieldInUse(queryField);
return queryField.getSelectColumn();
}).collect(Collectors.toList());
return this.generateSelectQuery(expressions);
}

protected PreparedOperation<Select> generateSelectQuery(List<Expression> expressions) {
if (filterCondition == null) {
finishedParsingParameters();
assert filterCondition != null;
}
RenderContextFactory factory = new RenderContextFactory(r2dbcDialect);
return PreparedQuery.of(getSelectQuery(), factory.createRenderContext(), filterCondition.getBindings());
return super.generateSelectQuery(expressions);
}

public boolean ignoreUnknownProperties() {
JsonIgnoreProperties jsonIgnoreProperties = modelClass.getAnnotation(JsonIgnoreProperties.class);
return jsonIgnoreProperties != null && jsonIgnoreProperties.ignoreUnknown();
}

public T getModelClassInstance(Row row, RowMetadata meta) {
try {
Constructor<T> constructor = modelClass.getDeclaredConstructor();
return constructor.newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new GetException("Error when creating a new instance of: " + modelClass.getSimpleName());
}
}

/*
* DO NOT USE THIS CIPHER FOR ANYTHING IMPORTANT (we are not in asseco-reactive-api-code)
* -> Reason: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_(ECB)
Expand Down Expand Up @@ -454,23 +431,4 @@ private String getHeaderPageCursor(Pagination.PageRequest page) {
return getExtendedParameters().getPaginationCursorName() + CURSOR_SPLIT + Base64.getUrlEncoder().encodeToString(parameters);
}

@RequiredArgsConstructor(staticName = "of")
private static class PreparedQuery implements PreparedOperation<Select> {

@Getter
private final Select source;
private final RenderContext renderContext;
private final Bindings bindings;

@Override
public void bindTo(BindTarget target) {
bindings.apply(target);
}

@Override
public String toQuery() {
SqlRenderer sqlRenderer = SqlRenderer.create(this.renderContext);
return sqlRenderer.render(source);
}
}
}
13 changes: 13 additions & 0 deletions src/main/java/org/dcsa/core/extendedrequest/QueryField.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.dcsa.core.extendedrequest;

import org.springframework.data.domain.Sort;
import org.springframework.data.relational.core.sql.Column;
import org.springframework.data.relational.core.sql.OrderByField;

import java.lang.reflect.Field;

Expand All @@ -19,7 +21,18 @@ default boolean isSelectable() {
default String getDatePattern() {
return null;
}
default String getFieldPath() {
return null;
}
default Field getCombinedModelField() {
return null;
}

default OrderByField asOrderByField(Sort.Direction direction) {
Column column = getSelectColumn();
if (column == null) {
column = getInternalQueryColumn();
}
return OrderByField.from(column, direction);
}
}
5 changes: 5 additions & 0 deletions src/main/java/org/dcsa/core/extendedrequest/QueryFields.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public static QueryField queryFieldFromFieldWithSelectPrefix(Class<?> combinedMo
selectColumn = internalColumn.as(SqlIdentifier.quoted(namePrefix + selectName));
}
return FieldBackedQueryField.of(
namePrefix + combinedModelField.getName(),
combinedModelField,
internalColumn,
selectColumn,
Expand Down Expand Up @@ -84,6 +85,10 @@ public Column getSelectColumn() {
@Data(staticConstructor = "of")
private static class FieldBackedQueryField implements QueryField {

@NonNull
@Getter
private final String fieldPath;

@NonNull
@Getter
private final Field combinedModelField;
Expand Down
Loading