From f8860f027f2cc2832c78f745e23dc1e259654cc8 Mon Sep 17 00:00:00 2001 From: Sergei Galiamichev <69846379+g-sg-v@users.noreply.github.com> Date: Wed, 27 Nov 2024 16:12:45 +0100 Subject: [PATCH] Query multiple tables using one entity (Refactoring) (#96) --- .../ydb/statement/CountAllStatement.java | 60 ++++++++ .../ydb/statement/DeleteAllStatement.java | 30 ++++ .../ydb/statement/DeleteByIdStatement.java | 4 + .../ydb/statement/FindInStatement.java | 29 +++- .../ydb/statement/FindRangeStatement.java | 6 +- .../ydb/statement/FindStatement.java | 52 +++++++ .../ydb/statement/FindYqlStatement.java | 67 +++++++++ .../ydb/statement/InsertYqlStatement.java | 4 + .../ydb/statement/PredicateStatement.java | 12 +- .../ydb/statement/UpdateByIdStatement.java | 9 +- .../ydb/statement/UpdateInStatement.java | 11 +- .../ydb/statement/YqlStatement.java | 135 ++---------------- 12 files changed, 292 insertions(+), 127 deletions(-) create mode 100644 repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/CountAllStatement.java create mode 100644 repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/DeleteAllStatement.java create mode 100644 repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindStatement.java create mode 100644 repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindYqlStatement.java diff --git a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/CountAllStatement.java b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/CountAllStatement.java new file mode 100644 index 00000000..1fdb8236 --- /dev/null +++ b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/CountAllStatement.java @@ -0,0 +1,60 @@ +package tech.ydb.yoj.repository.ydb.statement; + +import tech.ydb.yoj.databind.schema.Schema; +import tech.ydb.yoj.repository.db.Entity; +import tech.ydb.yoj.repository.db.EntitySchema; +import tech.ydb.yoj.repository.ydb.yql.YqlPredicate; +import tech.ydb.yoj.repository.ydb.yql.YqlStatementPart; + +import java.util.Collection; +import java.util.function.Function; + +import static java.util.Comparator.comparing; +import static java.util.stream.Collectors.joining; + +class CountAllStatement> extends PredicateStatement>, ENTITY, Count> { + private final Collection> parts; + + public CountAllStatement( + EntitySchema schema, + Schema resultSchema, + Collection> parts, + Function>, YqlPredicate> predicateFrom + ) { + super(schema, resultSchema, parts, predicateFrom); + this.parts = parts; + } + + public CountAllStatement( + EntitySchema schema, + Schema resultSchema, + Collection> parts, + Function>, YqlPredicate> predicateFrom, + String tableName + ) { + super(schema, resultSchema, parts, predicateFrom, tableName); + this.parts = parts; + } + + @Override + public String getQuery(String tablespace) { + return declarations() + + "SELECT COUNT(*) AS count" + + " FROM " + table(tablespace) + + " " + mergeParts(parts.stream()) + .sorted(comparing(YqlStatementPart::getPriority)) + .map(sp -> sp.toFullYql(schema)) + .map(this::resolveParamNames) + .collect(joining(" ")); + } + + @Override + public QueryType getQueryType() { + return QueryType.SELECT; + } + + @Override + public String toDebugString(Collection> yqlStatementParts) { + return "count(" + parts + ")"; + } +} diff --git a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/DeleteAllStatement.java b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/DeleteAllStatement.java new file mode 100644 index 00000000..1a3f57ed --- /dev/null +++ b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/DeleteAllStatement.java @@ -0,0 +1,30 @@ +package tech.ydb.yoj.repository.ydb.statement; + +import lombok.NonNull; +import tech.ydb.yoj.repository.db.Entity; +import tech.ydb.yoj.repository.db.EntitySchema; + +class DeleteAllStatement> extends YqlStatement { + public DeleteAllStatement(@NonNull Class type) { + super(EntitySchema.of(type), EntitySchema.of(type)); + } + + public DeleteAllStatement(@NonNull EntitySchema schema, String tableName) { + super(schema, schema, tableName); + } + + @Override + public String getQuery(String tablespace) { + return "DELETE FROM " + table(tablespace); + } + + @Override + public QueryType getQueryType() { + return QueryType.DELETE_ALL; + } + + @Override + public String toDebugString(PARAMS params) { + return "deleteAll(" + schema.getName() + ")"; + } +} diff --git a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/DeleteByIdStatement.java b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/DeleteByIdStatement.java index b8e5bb51..9e5b6772 100644 --- a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/DeleteByIdStatement.java +++ b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/DeleteByIdStatement.java @@ -10,6 +10,10 @@ public class DeleteByIdStatement> extends MultipleVarsYq super(type); } + DeleteByIdStatement(Class type, String tableName) { + super(type, tableName); + } + @Override public QueryType getQueryType() { return QueryType.DELETE; diff --git a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindInStatement.java b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindInStatement.java index b4fe27df..cefde5fa 100644 --- a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindInStatement.java +++ b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindInStatement.java @@ -135,7 +135,19 @@ protected FindInStatement( @Nullable OrderExpression orderBy, @Nullable Integer limit ) { - super(schema, resultSchema); + this(schema, resultSchema, ids, filter, orderBy, limit, schema.getName()); + } + + protected FindInStatement( + EntitySchema schema, + Schema resultSchema, + Iterable> ids, + @Nullable FilterExpression filter, + @Nullable OrderExpression orderBy, + @Nullable Integer limit, + String tableName + ) { + super(schema, resultSchema, tableName); this.orderBy = orderBy; this.limit = limit; @@ -160,7 +172,20 @@ protected FindInStatement( @Nullable OrderExpression orderBy, @Nullable Integer limit ) { - super(schema, resultSchema); + this(schema, resultSchema, indexName, keys, filter, orderBy, limit, schema.getName()); + } + + protected FindInStatement( + EntitySchema schema, + Schema resultSchema, + String indexName, + Iterable keys, + @Nullable FilterExpression filter, + @Nullable OrderExpression orderBy, + @Nullable Integer limit, + String tableName + ) { + super(schema, resultSchema, tableName); this.indexName = indexName; this.orderBy = orderBy; diff --git a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindRangeStatement.java b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindRangeStatement.java index a187bad1..f05dc623 100644 --- a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindRangeStatement.java +++ b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindRangeStatement.java @@ -24,7 +24,11 @@ public class FindRangeStatement, ID extends Entity private final List params; public FindRangeStatement(EntitySchema schema, Schema outSchema, Range range) { - super(schema, outSchema); + this(schema, outSchema, range, schema.getName()); + } + + public FindRangeStatement(EntitySchema schema, Schema outSchema, Range range, String tableName) { + super(schema, outSchema, tableName); this.params = Stream.of(RangeBound.values()) .flatMap(b -> toParams(b.map(range).keySet(), b)) .collect(toList()); diff --git a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindStatement.java b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindStatement.java new file mode 100644 index 00000000..bf0e71bd --- /dev/null +++ b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindStatement.java @@ -0,0 +1,52 @@ +package tech.ydb.yoj.repository.ydb.statement; + +import lombok.NonNull; +import tech.ydb.yoj.databind.schema.Schema; +import tech.ydb.yoj.repository.db.Entity; +import tech.ydb.yoj.repository.db.EntitySchema; +import tech.ydb.yoj.repository.ydb.yql.YqlPredicate; +import tech.ydb.yoj.repository.ydb.yql.YqlStatementPart; + +import java.util.Collection; +import java.util.function.Function; + +import static java.util.Comparator.comparing; +import static java.util.stream.Collectors.joining; + +public class FindStatement, RESULT> extends PredicateStatement>, ENTITY, RESULT> { + private final boolean distinct; + private final Collection> parts; + + public FindStatement( + @NonNull EntitySchema schema, + @NonNull Schema outSchema, + @NonNull Collection> parts, + @NonNull Function>, YqlPredicate> predicateFrom, + boolean distinct, + String tableName) { + super(schema, outSchema, parts, predicateFrom, tableName); + this.distinct = distinct; + this.parts = parts; + } + + public String getQuery(String tablespace) { + return declarations() + + "SELECT " + (distinct ? "DISTINCT " : "") + outNames() + + " FROM " + table(tablespace) + + " " + mergeParts(parts.stream()) + .sorted(comparing(YqlStatementPart::getPriority)) + .map(sp -> sp.toFullYql(schema)) + .map(this::resolveParamNames) + .collect(joining(" ")); + } + + @Override + public Statement.QueryType getQueryType() { + return Statement.QueryType.SELECT; + } + + @Override + public String toDebugString(Collection> yqlStatementParts) { + return "find(" + yqlStatementParts + ")"; + } +} diff --git a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindYqlStatement.java b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindYqlStatement.java new file mode 100644 index 00000000..6b93189b --- /dev/null +++ b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/FindYqlStatement.java @@ -0,0 +1,67 @@ +package tech.ydb.yoj.repository.ydb.statement; + +import lombok.NonNull; +import tech.ydb.yoj.databind.schema.Schema; +import tech.ydb.yoj.repository.db.Entity; +import tech.ydb.yoj.repository.db.EntitySchema; +import tech.ydb.yoj.repository.db.cache.RepositoryCache; +import tech.ydb.yoj.repository.ydb.yql.YqlType; + +import java.util.Collections; +import java.util.List; + +import static java.util.stream.Collectors.toList; + +public class FindYqlStatement, RESULT> extends YqlStatement { + public FindYqlStatement(@NonNull EntitySchema schema, @NonNull Schema resultSchema) { + super(schema, resultSchema); + } + + public FindYqlStatement(@NonNull EntitySchema schema, @NonNull Schema resultSchema, String tableName) { + super(schema, resultSchema, tableName); + } + + @Override + public List getParams() { + return schema.flattenId().stream() + .map(c -> YqlStatementParam.required(YqlType.of(c), c.getName())) + .collect(toList()); + } + + @Override + public String getQuery(String tablespace) { + return declarations() + + "SELECT " + outNames() + + " FROM " + table(tablespace) + + " WHERE " + nameEqVars(); + } + + @Override + public List readFromCache(PARAMS params, RepositoryCache cache) { + RepositoryCache.Key key = new RepositoryCache.Key(resultSchema.getType(), params); + if (!cache.contains(key)) { + return null; + } + + //noinspection unchecked + return cache.get(key) + .map(o -> Collections.singletonList((RESULT) o)) + .orElse(Collections.emptyList()); + } + + @Override + public void storeToCache(PARAMS params, List result, RepositoryCache cache) { + RepositoryCache.Key key = new RepositoryCache.Key(resultSchema.getType(), params); + cache.put(key, result.stream().findFirst().orElse(null)); + } + + @Override + public QueryType getQueryType() { + return QueryType.SELECT; + } + + @Override + public String toDebugString(PARAMS params) { + return "find(" + params + ")"; + } +} diff --git a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/InsertYqlStatement.java b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/InsertYqlStatement.java index ea37a587..c3907e7b 100644 --- a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/InsertYqlStatement.java +++ b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/InsertYqlStatement.java @@ -10,6 +10,10 @@ public InsertYqlStatement(Class type) { super(type); } + public InsertYqlStatement(Class type, String tableName) { + super(type, tableName); + } + @Override public QueryType getQueryType() { return QueryType.INSERT; diff --git a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/PredicateStatement.java b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/PredicateStatement.java index b5573cb5..8f4709fb 100644 --- a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/PredicateStatement.java +++ b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/PredicateStatement.java @@ -39,7 +39,17 @@ public PredicateStatement( @NonNull PARAMS params, @NonNull Function getPredicate ) { - super(schema, outSchema); + this(schema, outSchema, params, getPredicate, schema.getName()); + } + + public PredicateStatement( + @NonNull EntitySchema schema, + @NonNull Schema outSchema, + @NonNull PARAMS params, + @NonNull Function getPredicate, + String tableName + ) { + super(schema, outSchema, tableName); this.getPredicate = getPredicate; YqlPredicate pred = getPredicate.apply(params); diff --git a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/UpdateByIdStatement.java b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/UpdateByIdStatement.java index f7924113..ba318e7e 100644 --- a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/UpdateByIdStatement.java +++ b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/UpdateByIdStatement.java @@ -2,6 +2,7 @@ import tech.ydb.proto.ValueProtos; import tech.ydb.yoj.repository.db.Entity; +import tech.ydb.yoj.repository.db.EntitySchema; import tech.ydb.yoj.repository.ydb.yql.YqlType; import java.util.Collection; @@ -18,13 +19,17 @@ import static java.util.stream.Stream.concat; public final class UpdateByIdStatement, ID extends Entity.Id> - extends YqlStatement.Simple, ENTITY> { + extends YqlStatement, ENTITY, ENTITY> { private final Map setParams; private final Set idParams; public UpdateByIdStatement(Class type, UpdateModel.ById model) { - super(type); + this(type, model, EntitySchema.of(type).getName()); + } + + public UpdateByIdStatement(Class type, UpdateModel.ById model, String tableName) { + super(EntitySchema.of(type), EntitySchema.of(type), tableName); this.idParams = schema.flattenId().stream() .map(c -> YqlStatementParam.required(YqlType.of(c), c.getName())) .collect(toUnmodifiableSet()); diff --git a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/UpdateInStatement.java b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/UpdateInStatement.java index 15a07f58..9248fa46 100644 --- a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/UpdateInStatement.java +++ b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/UpdateInStatement.java @@ -37,7 +37,16 @@ public UpdateInStatement( Schema resultSchema, UpdateInStatementInput in ) { - super(schema, resultSchema); + this(schema, resultSchema, in, schema.getName()); + } + + public UpdateInStatement( + EntitySchema schema, + Schema resultSchema, + UpdateInStatementInput in, + String tableName + ) { + super(schema, resultSchema, tableName); this.keyFields = collectKeyFields(in.ids); this.values = new HashMap<>(in.values.size()); diff --git a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/YqlStatement.java b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/YqlStatement.java index bb402cf1..d5b69840 100644 --- a/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/YqlStatement.java +++ b/repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/statement/YqlStatement.java @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Spliterator; @@ -31,10 +30,8 @@ import static java.lang.String.format; import static java.util.Collections.emptyList; -import static java.util.Comparator.comparing; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; @SuppressWarnings({"FieldCanBeLocal", "WeakerAccess"}) @@ -97,51 +94,7 @@ public static , VIEW extends View> Stateme private static , RESULT> Statement find( EntitySchema schema, Schema resultSchema) { - return new YqlStatement<>(schema, resultSchema) { - @Override - public List getParams() { - return schema.flattenId().stream() - .map(c -> YqlStatementParam.required(YqlType.of(c), c.getName())) - .collect(toList()); - } - - @Override - public String getQuery(String tablespace) { - return declarations() - + "SELECT " + outNames() - + " FROM " + table(tablespace) - + " WHERE " + nameEqVars(); - } - - @Override - public List readFromCache(PARAMS params, RepositoryCache cache) { - RepositoryCache.Key key = new RepositoryCache.Key(resultSchema.getType(), params); - if (!cache.contains(key)) { - return null; - } - - //noinspection unchecked - return cache.get(key) - .map(o -> Collections.singletonList((RESULT) o)) - .orElse(Collections.emptyList()); - } - - @Override - public void storeToCache(PARAMS params, List result, RepositoryCache cache) { - RepositoryCache.Key key = new RepositoryCache.Key(resultSchema.getType(), params); - cache.put(key, result.stream().findFirst().orElse(null)); - } - - @Override - public QueryType getQueryType() { - return QueryType.SELECT; - } - - @Override - public String toDebugString(PARAMS params) { - return "find(" + params + ")"; - } - }; + return new FindYqlStatement<>(schema, resultSchema); } public static , ID extends Entity.Id> Statement, ENTITY> findRange( @@ -299,6 +252,16 @@ private static , RESULT> Statement resultSchema, boolean distinct, Collection> parts + ) { + return find(schema, resultSchema, distinct, parts, schema.getName()); + } + + static , RESULT> Statement>, RESULT> find( + EntitySchema schema, + Schema resultSchema, + boolean distinct, + Collection> parts, + String tableName ) { List> partList = new ArrayList<>(parts); if (!distinct) { @@ -306,29 +269,7 @@ private static , RESULT> Statement(schema, resultSchema, parts, YqlStatement::predicateFrom) { - @Override - public String getQuery(String tablespace) { - return declarations() - + "SELECT " + (distinct ? "DISTINCT " : "") + outNames() - + " FROM " + table(tablespace) - + " " + mergeParts(partList.stream()) - .sorted(comparing(YqlStatementPart::getPriority)) - .map(sp -> sp.toFullYql(schema)) - .map(this::resolveParamNames) - .collect(joining(" ")); - } - - @Override - public QueryType getQueryType() { - return QueryType.SELECT; - } - - @Override - public String toDebugString(Collection> yqlStatementParts) { - return "find(" + yqlStatementParts + ")"; - } - }; + return new FindStatement<>(schema, resultSchema, parts, YqlStatement::predicateFrom, distinct, tableName); } public static > Statement>, Count> count( @@ -342,30 +283,7 @@ private static > Statement schema, Collection> parts ) { - return new PredicateStatement<>(schema, ObjectSchema.of(Count.class), parts, YqlStatement::predicateFrom) { - - @Override - public String getQuery(String tablespace) { - return declarations() - + "SELECT COUNT(*) AS count" - + " FROM " + table(tablespace) - + " " + mergeParts(parts.stream()) - .sorted(comparing(YqlStatementPart::getPriority)) - .map(sp -> sp.toFullYql(schema)) - .map(this::resolveParamNames) - .collect(joining(" ")); - } - - @Override - public QueryType getQueryType() { - return QueryType.SELECT; - } - - @Override - public String toDebugString(Collection> yqlStatementParts) { - return "count(" + parts + ")"; - } - }; + return new CountAllStatement<>(schema, ObjectSchema.of(Count.class), parts, YqlStatement::predicateFrom); } protected static YqlPredicate predicateFrom(Collection> parts) { @@ -392,23 +310,7 @@ private static List> combine(List> Statement deleteAll(Class type) { - return new YqlStatement.Simple<>(type) { - - @Override - public String getQuery(String tablespace) { - return "DELETE FROM " + table(tablespace); - } - - @Override - public QueryType getQueryType() { - return QueryType.DELETE_ALL; - } - - @Override - public String toDebugString(PARAMS params) { - return "deleteAll(" + schema.getName() + ")"; - } - }; + return new DeleteAllStatement<>(type); } public static > Statement delete(Class type) { @@ -438,7 +340,6 @@ protected ValueProtos.TypedValue createTQueryParameter(YqlType type, Object o, b protected ValueProtos.Type.Builder getYqlType(YqlType yqlType, boolean optional) { ValueProtos.Type.Builder ttype = yqlType.getYqlTypeBuilder(); return !optional ? ttype : ValueProtos.Type.newBuilder().setOptionalType(ValueProtos.OptionalType.newBuilder().setItem(ttype)); - } protected ValueProtos.Value.Builder getYqlValue(YqlType type, Object value) { @@ -509,6 +410,7 @@ protected String escape(String value) { * {@code {entity.java.field}} placeholders to DB field names. * * @param yql YQL with parameter and field name placeholders ({@code ?} and {@code {field.name}}, respectively) + * * @return YQL with real parameter names */ protected String resolveParamNames(String yql) { @@ -568,11 +470,4 @@ protected String resolveParamNames(String yql) { return newYql.toString(); } - - protected static abstract class Simple> - extends YqlStatement { - public Simple(@NonNull Class type) { - super(EntitySchema.of(type), EntitySchema.of(type)); - } - } }