From d509976322e0bdc44bb57ef8ef719150c30522c2 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Thu, 3 Jun 2021 10:27:00 +0200 Subject: [PATCH 1/6] Remove now unused code Signed-off-by: Niels Thykier --- .../core/extendedrequest/TableAndJoins.java | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/src/main/java/org/dcsa/core/extendedrequest/TableAndJoins.java b/src/main/java/org/dcsa/core/extendedrequest/TableAndJoins.java index 7e495ec..77828a9 100644 --- a/src/main/java/org/dcsa/core/extendedrequest/TableAndJoins.java +++ b/src/main/java/org/dcsa/core/extendedrequest/TableAndJoins.java @@ -41,41 +41,6 @@ public JoinDescriptor getJoinDescriptor(String aliasId) { return joins.get(aliasId); } - private static void applyJoinToStringBuilder(StringBuilder sb, JoinDescriptor descriptor) { - Column lhs = descriptor.getLHSColumn(); - Column rhs = descriptor.getRHSColumn(); - Table table = descriptor.getRHSTable(); - String joinLine = table.toString() + " ON " + lhs.toString() + "=" + rhs.toString(); - switch (descriptor.getJoinType()) { - case JOIN: - sb.append(" JOIN "); - break; - case LEFT_OUTER_JOIN: - sb.append(" LEFT JOIN "); - break; - case RIGHT_OUTER_JOIN: - throw new UnsupportedOperationException("Rewrite to use LEFT JOIN instead"); - default: - throw new UnsupportedOperationException("Unsupported join type: " + descriptor.getJoinType()); - } - sb.append(joinLine); - } - - protected void generateFromAndJoins(StringBuilder sb, Set selectedJoinAliases) { - int selectedJoins = 0; - sb.append(" FROM "); - sb.append(primaryTable.toString()); - for (JoinDescriptor joinDescriptor : joins.values()) { - if (selectedJoinAliases.contains(joinDescriptor.getJoinAliasId())) { - applyJoinToStringBuilder(sb, joinDescriptor); - selectedJoins++; - } - } - if (selectedJoinAliases.size() != selectedJoins) { - throw new IllegalArgumentException("selectedJoinAliases contained an unknown alias"); - } - } - public boolean hasJoins() { return !joins.isEmpty(); } From 59b10da7526479292c54f5c7d7add18aca5ca607 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Thu, 3 Jun 2021 10:22:25 +0200 Subject: [PATCH 2/6] Refactor ExtendedRequest initialization Signed-off-by: Niels Thykier --- .../org/dcsa/core/controller/ExtendedBaseController.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/dcsa/core/controller/ExtendedBaseController.java b/src/main/java/org/dcsa/core/controller/ExtendedBaseController.java index 7969bc3..c646e4b 100644 --- a/src/main/java/org/dcsa/core/controller/ExtendedBaseController.java +++ b/src/main/java/org/dcsa/core/controller/ExtendedBaseController.java @@ -24,9 +24,13 @@ public String getType() { return getService().getModelClass().getSimpleName(); } - @GetMapping() + protected ExtendedRequest newExtendedRequest() { + return new ExtendedRequest<>(extendedParameters, r2dbcDialect, getService().getModelClass()); + } + + @GetMapping public Flux findAll(ServerHttpResponse response, ServerHttpRequest request) { - ExtendedRequest extendedRequest = new ExtendedRequest<>(extendedParameters, r2dbcDialect, getService().getModelClass()); + ExtendedRequest extendedRequest = newExtendedRequest(); try { extendedRequest.parseParameter(request.getQueryParams()); } catch (GetException getException) { From a51c0c60a974887d943c16f91329511a36d7fc96 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Tue, 1 Jun 2021 12:19:22 +0200 Subject: [PATCH 3/6] Refactor query generation Signed-off-by: Niels Thykier --- .../core/extendedrequest/ExtendedRequest.java | 122 +++++++----------- .../core/extendedrequest/TableAndJoins.java | 8 ++ .../org/dcsa/core/query/DBEntityAnalysis.java | 1 + .../core/query/impl/AbstractQueryFactory.java | 66 ++++++++++ .../query/impl/DefaultDBEntityAnalysis.java | 2 + .../impl/DefaultDBEntityAnalysisBuilder.java | 1 + .../org/dcsa/core/ExtendedRequestTest.java | 2 +- 7 files changed, 123 insertions(+), 79 deletions(-) create mode 100644 src/main/java/org/dcsa/core/query/impl/AbstractQueryFactory.java diff --git a/src/main/java/org/dcsa/core/extendedrequest/ExtendedRequest.java b/src/main/java/org/dcsa/core/extendedrequest/ExtendedRequest.java index a4aefc5..ae10320 100644 --- a/src/main/java/org/dcsa/core/extendedrequest/ExtendedRequest.java +++ b/src/main/java/org/dcsa/core/extendedrequest/ExtendedRequest.java @@ -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; @@ -51,7 +45,7 @@ * * object. */ @RequiredArgsConstructor -public class ExtendedRequest { +public class ExtendedRequest extends AbstractQueryFactory { public static final String PARAMETER_SPLIT = "&"; public static final String CURSOR_SPLIT = "="; @@ -124,6 +118,20 @@ public void parseParameter(Map> params, boolean fromCursor) finishedParsingParameters(); } + protected CursorBackedFilterCondition getFilterCondition() { + return filterCondition; + } + + @Override + protected Set 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(); @@ -214,65 +222,44 @@ private static Map> convertToQueryStringToHashMap(String so } public DatabaseClient.GenericExecuteSpec getCount(DatabaseClient databaseClient) { - return databaseClient.sql(this.getCountQuery()); + return databaseClient.sql(this.generateCountQuery()); } public DatabaseClient.GenericExecuteSpec getFindAll(DatabaseClient databaseClient) { - return databaseClient.sql(this.getQuery()); - } - - public Select getSelectQuery() { - List expressions = dbEntityAnalysis.getAllSelectableFields().stream().map(queryField -> { - markQueryFieldInUse(queryField); - return queryField.getSelectColumn(); - }).collect(Collectors.toList()); - Sort sort = getSort(); - - return generateBaseQuery(Select.builder().select(expressions)) - .orderBy(sort.getOrderByFields()).build(); + return databaseClient.sql(this.generateSelectQuery()); } - 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 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 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()); } /** @@ -319,13 +306,20 @@ protected DBEntityAnalysis.DBEntityAnalysisBuilder prepareDBEntityAnalysis() return DBEntityAnalysis.builder(this.modelClass).loadFieldsAndJoinsFromModel(); } - public PreparedOperation generateSelectQuery() { + List expressions = dbEntityAnalysis.getAllSelectableFields().stream().map(queryField -> { + markQueryFieldInUse(queryField); + return queryField.getSelectColumn(); + }).collect(Collectors.toList()); + return this.generateSelectQuery(expressions); + } + + protected PreparedOperation { - - @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); - } - } } diff --git a/src/main/java/org/dcsa/core/extendedrequest/TableAndJoins.java b/src/main/java/org/dcsa/core/extendedrequest/TableAndJoins.java index 77828a9..80250bf 100644 --- a/src/main/java/org/dcsa/core/extendedrequest/TableAndJoins.java +++ b/src/main/java/org/dcsa/core/extendedrequest/TableAndJoins.java @@ -7,6 +7,7 @@ import org.springframework.data.relational.core.sql.SelectBuilder; import org.springframework.data.relational.core.sql.Table; +import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Set; @@ -45,6 +46,13 @@ public boolean hasJoins() { return !joins.isEmpty(); } + public Set getAvailableJoinAliases(boolean includePrimary) { + if (includePrimary) { + return Collections.unmodifiableSet(knownAliases); + } + return Collections.unmodifiableSet(joins.keySet()); + } + public SelectBuilder.SelectFromAndJoinCondition applyJoins(SelectBuilder.SelectFromAndJoin selectFromAndJoin, Set selectedJoinAliases) { SelectBuilder.SelectJoin current = selectFromAndJoin; int selectedJoins = 0; diff --git a/src/main/java/org/dcsa/core/query/DBEntityAnalysis.java b/src/main/java/org/dcsa/core/query/DBEntityAnalysis.java index 969cdfe..c254305 100644 --- a/src/main/java/org/dcsa/core/query/DBEntityAnalysis.java +++ b/src/main/java/org/dcsa/core/query/DBEntityAnalysis.java @@ -18,6 +18,7 @@ public interface DBEntityAnalysis { QueryField getQueryFieldFromSelectName(String selectColumnName) throws IllegalArgumentException; List getAllSelectableFields(); TableAndJoins getTableAndJoins(); + Class getEntityType(); static DBEntityAnalysisBuilder builder(Class entityType) { return new DefaultDBEntityAnalysisBuilder<>(entityType); diff --git a/src/main/java/org/dcsa/core/query/impl/AbstractQueryFactory.java b/src/main/java/org/dcsa/core/query/impl/AbstractQueryFactory.java new file mode 100644 index 0000000..2fedc04 --- /dev/null +++ b/src/main/java/org/dcsa/core/query/impl/AbstractQueryFactory.java @@ -0,0 +1,66 @@ +package org.dcsa.core.query.impl; + +import lombok.RequiredArgsConstructor; +import org.dcsa.core.extendedrequest.TableAndJoins; +import org.dcsa.core.query.DBEntityAnalysis; +import org.springframework.data.relational.core.sql.*; +import org.springframework.r2dbc.core.PreparedOperation; + +import java.util.List; +import java.util.Set; + +@RequiredArgsConstructor +public abstract class AbstractQueryFactory { + + public abstract DBEntityAnalysis getDbEntityAnalysis(); + + protected abstract Set getJoinAliasInUse(); + + protected abstract boolean isSelectDistinct(); + + protected abstract SelectBuilder.SelectFromAndJoin applyLimitOffset(SelectBuilder.SelectFromAndJoin t); + + protected SelectBuilder.SelectOrdered generateBaseQuery(SelectBuilder.SelectAndFrom selectBuilder) { + DBEntityAnalysis dbEntityAnalysis = getDbEntityAnalysis(); + TableAndJoins tableAndJoins = dbEntityAnalysis.getTableAndJoins(); + // Run this before the call to applyJoins(...) as it can affect which joins will be used. + Condition con = generateCondition(); + + if (isSelectDistinct()) { + selectBuilder = selectBuilder.distinct(); + } + SelectBuilder.SelectWhere selectWhere = applyJoins(tableAndJoins, applyLimitOffset(selectBuilder.from( + tableAndJoins.getPrimaryTable() + ))); + if (con == null || TrueCondition.INSTANCE.equals(con)) { + return selectWhere; + } + return selectWhere.where(con); + } + + protected abstract Condition generateCondition(); + + protected abstract SelectBuilder.BuildSelect applyOrder(SelectBuilder.SelectOrdered builder); + + public abstract PreparedOperation generateSelectQuery(List expressions) { + return createPreparedOperation(applyOrder(generateBaseQuery(Select.builder().select(expressions))).build()); + } + + public PreparedOperation createPreparedOperation(Select select); + + private SelectBuilder.SelectWhere applyJoins(TableAndJoins tableAndJoins, SelectBuilder.SelectFromAndJoin selectBuilder) { + Set joinAliasInUse = getJoinAliasInUse(); + if (!joinAliasInUse.isEmpty()) { + return tableAndJoins.applyJoins(selectBuilder, joinAliasInUse); + } + return selectBuilder; + } +} diff --git a/src/main/java/org/dcsa/core/query/impl/DefaultDBEntityAnalysis.java b/src/main/java/org/dcsa/core/query/impl/DefaultDBEntityAnalysis.java index dac3a59..40b6866 100644 --- a/src/main/java/org/dcsa/core/query/impl/DefaultDBEntityAnalysis.java +++ b/src/main/java/org/dcsa/core/query/impl/DefaultDBEntityAnalysis.java @@ -13,6 +13,8 @@ @RequiredArgsConstructor public class DefaultDBEntityAnalysis implements DBEntityAnalysis { + @Getter + private final Class entityType; private final Map jsonName2QueryField; private final Map selectName2QueryField; private final Set declaredButNotSelectable; diff --git a/src/main/java/org/dcsa/core/query/impl/DefaultDBEntityAnalysisBuilder.java b/src/main/java/org/dcsa/core/query/impl/DefaultDBEntityAnalysisBuilder.java index 135748c..6007561 100644 --- a/src/main/java/org/dcsa/core/query/impl/DefaultDBEntityAnalysisBuilder.java +++ b/src/main/java/org/dcsa/core/query/impl/DefaultDBEntityAnalysisBuilder.java @@ -569,6 +569,7 @@ public DBEntityAnalysis build() { this.verifyFieldsAndJoins(); used = true; return new DefaultDBEntityAnalysis<>( + entityType, Collections.unmodifiableMap(jsonName2DbField), Collections.unmodifiableMap(selectName2DbField), Collections.unmodifiableSet(declaredButNotSelectable), diff --git a/src/test/java/org/dcsa/core/ExtendedRequestTest.java b/src/test/java/org/dcsa/core/ExtendedRequestTest.java index 6365349..b8fb4f6 100644 --- a/src/test/java/org/dcsa/core/ExtendedRequestTest.java +++ b/src/test/java/org/dcsa/core/ExtendedRequestTest.java @@ -206,7 +206,7 @@ public void verify(String query, Consumer> requestMutator) { if (requestMutator != null) { requestMutator.accept(request); } - generated = request.getQuery().toQuery(); + generated = request.generateSelectQuery().toQuery(); Assertions.assertEquals(prettifyQuery(query), prettifyQuery(generated)); } From d77e24fe7afc4951076a8c29c18f812f859f203f Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Thu, 3 Jun 2021 13:42:26 +0200 Subject: [PATCH 4/6] Joins: Forgive primary table being present in apply joins Signed-off-by: Niels Thykier --- .../java/org/dcsa/core/extendedrequest/TableAndJoins.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/dcsa/core/extendedrequest/TableAndJoins.java b/src/main/java/org/dcsa/core/extendedrequest/TableAndJoins.java index 80250bf..25830a9 100644 --- a/src/main/java/org/dcsa/core/extendedrequest/TableAndJoins.java +++ b/src/main/java/org/dcsa/core/extendedrequest/TableAndJoins.java @@ -21,10 +21,12 @@ public class TableAndJoins { private final Table primaryTable; private final Set knownAliases = new HashSet<>(); private final LinkedHashMap joins = new LinkedHashMap<>(); + private final String primaryTableAlias; public TableAndJoins(Table primaryTable) { this.primaryTable = primaryTable; - knownAliases.add(ReflectUtility.getAliasId(primaryTable)); + primaryTableAlias = ReflectUtility.getAliasId(primaryTable); + knownAliases.add(primaryTableAlias); } public void addJoinDescriptor(JoinDescriptor joinDescriptor) { @@ -65,6 +67,10 @@ public SelectBuilder.SelectFromAndJoinCondition applyJoins(SelectBuilder.SelectF selectedJoins++; } } + // "Forgive" if the primary table is included as well. + if (selectedJoinAliases.contains(primaryTableAlias)) { + selectedJoins++; + } if (selectedJoinAliases.size() != selectedJoins) { throw new IllegalArgumentException("selectedJoinAliases contained an unknown alias"); } From 96815db3b8f0b1e1ba4cd3e229ab7466c2662ce0 Mon Sep 17 00:00:00 2001 From: Niels Thykier Date: Thu, 3 Jun 2021 14:09:35 +0200 Subject: [PATCH 5/6] Alternative method to create custom queries Signed-off-by: Niels Thykier --- .../core/extendedrequest/ExtendedRequest.java | 8 -- .../dcsa/core/query/QueryFactoryBuilder.java | 23 ++++ .../core/query/impl/GenericQueryFactory.java | 68 +++++++++++ .../dcsa/core/query/impl/PreparedQuery.java | 30 +++++ .../query/impl/QueryFactoryBuilderImpl.java | 108 ++++++++++++++++++ .../core/repository/ExtendedRepository.java | 4 + .../repository/ExtendedRepositoryImpl.java | 27 ++++- 7 files changed, 255 insertions(+), 13 deletions(-) create mode 100644 src/main/java/org/dcsa/core/query/QueryFactoryBuilder.java create mode 100644 src/main/java/org/dcsa/core/query/impl/GenericQueryFactory.java create mode 100644 src/main/java/org/dcsa/core/query/impl/PreparedQuery.java create mode 100644 src/main/java/org/dcsa/core/query/impl/QueryFactoryBuilderImpl.java diff --git a/src/main/java/org/dcsa/core/extendedrequest/ExtendedRequest.java b/src/main/java/org/dcsa/core/extendedrequest/ExtendedRequest.java index ae10320..000535d 100644 --- a/src/main/java/org/dcsa/core/extendedrequest/ExtendedRequest.java +++ b/src/main/java/org/dcsa/core/extendedrequest/ExtendedRequest.java @@ -221,14 +221,6 @@ private static Map> convertToQueryStringToHashMap(String so return data; } - public DatabaseClient.GenericExecuteSpec getCount(DatabaseClient databaseClient) { - return databaseClient.sql(this.generateCountQuery()); - } - - public DatabaseClient.GenericExecuteSpec getFindAll(DatabaseClient databaseClient) { - return databaseClient.sql(this.generateSelectQuery()); - } - protected SelectBuilder.BuildSelect applyOrder(SelectBuilder.SelectOrdered builder) { return builder.orderBy(getSort().getOrderByFields()); } diff --git a/src/main/java/org/dcsa/core/query/QueryFactoryBuilder.java b/src/main/java/org/dcsa/core/query/QueryFactoryBuilder.java new file mode 100644 index 0000000..ee25e0c --- /dev/null +++ b/src/main/java/org/dcsa/core/query/QueryFactoryBuilder.java @@ -0,0 +1,23 @@ +package org.dcsa.core.query; + +import org.dcsa.core.extendedrequest.CursorBackedFilterCondition; +import org.dcsa.core.query.impl.AbstractQueryFactory; +import org.dcsa.core.query.impl.QueryFactoryBuilderImpl; +import org.springframework.data.r2dbc.dialect.R2dbcDialect; +import org.springframework.data.relational.core.sql.SelectBuilder; + +import java.util.function.Function; + +public interface QueryFactoryBuilder { + + QueryFactoryBuilder distinct(); + QueryFactoryBuilder limitOffset(Function limitOffsetFunction); + QueryFactoryBuilder order(Function orderFunction); + QueryFactoryBuilder r2dbcDialect(R2dbcDialect r2dbcDialect); + QueryFactoryBuilder copyBuilder(); + AbstractQueryFactory build(CursorBackedFilterCondition filterCondition); + + static QueryFactoryBuilder builder(DBEntityAnalysis dbEntityAnalysis) { + return QueryFactoryBuilderImpl.of(dbEntityAnalysis, false, null, null, null); + } +} diff --git a/src/main/java/org/dcsa/core/query/impl/GenericQueryFactory.java b/src/main/java/org/dcsa/core/query/impl/GenericQueryFactory.java new file mode 100644 index 0000000..f6941b4 --- /dev/null +++ b/src/main/java/org/dcsa/core/query/impl/GenericQueryFactory.java @@ -0,0 +1,68 @@ +package org.dcsa.core.query.impl; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.dcsa.core.query.DBEntityAnalysis; +import org.springframework.data.relational.core.dialect.RenderContextFactory; +import org.springframework.data.relational.core.sql.Condition; +import org.springframework.data.relational.core.sql.Expression; +import org.springframework.data.relational.core.sql.Select; +import org.springframework.data.relational.core.sql.SelectBuilder; +import org.springframework.r2dbc.core.PreparedOperation; +import org.springframework.r2dbc.core.binding.Bindings; + +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +@RequiredArgsConstructor(staticName = "of") +class GenericQueryFactory extends AbstractQueryFactory { + + @Getter + private final DBEntityAnalysis dbEntityAnalysis; + + @Getter + private final boolean selectDistinct; + + private final Function limitOffsets; + private final Function order; + @Getter + private final Set joinAliasInUse; + private final Condition conditions; + private final List selectExpressions; + + private final RenderContextFactory renderContextFactory; + private final Bindings bindings; + + + @Override + public PreparedOperation createPreparedOperation(Select select) { + return PreparedQuery.of(select, renderContextFactory.createRenderContext(), bindings); + } + + @Override + protected Condition generateCondition() { + return conditions; + } + + @Override + protected SelectBuilder.SelectFromAndJoin applyLimitOffset(SelectBuilder.SelectFromAndJoin builder) { + if (limitOffsets != null) { + return limitOffsets.apply(builder); + } + return builder; + } + + @Override + protected SelectBuilder.BuildSelect applyOrder(SelectBuilder.SelectOrdered builder) { + if (order != null) { + return order.apply(builder); + } + return builder; + } +} diff --git a/src/main/java/org/dcsa/core/query/impl/PreparedQuery.java b/src/main/java/org/dcsa/core/query/impl/PreparedQuery.java new file mode 100644 index 0000000..865f042 --- /dev/null +++ b/src/main/java/org/dcsa/core/query/impl/PreparedQuery.java @@ -0,0 +1,30 @@ +package org.dcsa.core.query.impl; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.data.relational.core.sql.Select; +import org.springframework.data.relational.core.sql.render.RenderContext; +import org.springframework.data.relational.core.sql.render.SqlRenderer; +import org.springframework.r2dbc.core.PreparedOperation; +import org.springframework.r2dbc.core.binding.BindTarget; +import org.springframework.r2dbc.core.binding.Bindings; + +@RequiredArgsConstructor(staticName = "of") +public class PreparedQuery implements PreparedOperation