From 84db42511424c650802072a38bf05c6b5b2eb365 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Mon, 26 Apr 2021 15:24:46 +0200 Subject: [PATCH] repo-sqale: update contexts moved to sub-package, javadoc/refactoring Still WIP, nested and table container contexts are not used yet, but contracts are now much clearer. TableRelationResolver is still WIP. *TableMapping#*mapper() factory methods have now flexible schema type parameter, because it's different for top-level and nested mappings. --- .../repo/sqale/SqaleRepositoryService.java | 1 + .../repo/sqale/SqaleUpdateContext.java | 71 ----------- .../midpoint/repo/sqale/SqaleUtils.java | 6 + .../delta/DelegatingItemDeltaProcessor.java | 14 ++- .../sqale/delta/ItemDeltaValueProcessor.java | 2 +- .../item/ContainerTableDeltaProcessor.java | 2 +- .../item/EmbeddedContainerDeltaProcessor.java | 2 +- .../delta/item/EnumItemDeltaProcessor.java | 2 +- .../item/ItemDeltaSingleValueProcessor.java | 2 +- .../item/PolyStringItemDeltaProcessor.java | 2 +- .../delta/item/RefItemDeltaProcessor.java | 2 +- .../item/RefTableItemDeltaProcessor.java | 2 +- .../delta/item/SimpleItemDeltaProcessor.java | 2 +- .../item/SinglePathItemDeltaProcessor.java | 2 +- .../item/TimestampItemDeltaProcessor.java | 2 +- .../delta/item/UriItemDeltaProcessor.java | 2 +- .../sqale/mapping/NestedMappingResolver.java | 20 +-- .../mapping/SqaleItemRelationResolver.java | 8 +- .../sqale/mapping/SqaleItemSqlMapper.java | 2 +- .../sqale/mapping/TableRelationResolver.java | 32 +++-- .../repo/sqale/qmodel/SqaleMappingMixin.java | 6 +- .../repo/sqale/qmodel/SqaleNestedMapping.java | 2 +- .../repo/sqale/qmodel/SqaleTableMapping.java | 73 ++++++++--- .../repo/sqale/qmodel/common/QContainer.java | 8 +- .../sqale/qmodel/ref/QOwnedByMapping.java | 5 + .../repo/sqale/qmodel/ref/QReference.java | 2 +- .../{ => update}/ContainerUpdateContext.java | 13 +- .../update/NestedContainerUpdateContext.java | 40 ++++++ .../sqale/{ => update}/RootUpdateContext.java | 15 +-- .../repo/sqale/update/SqaleUpdateContext.java | 114 ++++++++++++++++++ .../filtering/ValueFilterProcessor.java | 3 + .../sqlbase/mapping/ItemRelationResolver.java | 8 +- .../sqlbase/mapping/QueryModelMapping.java | 10 +- .../sqlbase/mapping/QueryTableMapping.java | 56 +++++++-- 34 files changed, 359 insertions(+), 174 deletions(-) delete mode 100644 repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/SqaleUpdateContext.java rename repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/{ => update}/ContainerUpdateContext.java (81%) create mode 100644 repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/NestedContainerUpdateContext.java rename repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/{ => update}/RootUpdateContext.java (92%) create mode 100644 repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/SqaleUpdateContext.java diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/SqaleRepositoryService.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/SqaleRepositoryService.java index 4d66eafd4a2..aed444e32c3 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/SqaleRepositoryService.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/SqaleRepositoryService.java @@ -36,6 +36,7 @@ import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObjectType; import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; +import com.evolveum.midpoint.repo.sqale.update.RootUpdateContext; import com.evolveum.midpoint.repo.sqlbase.*; import com.evolveum.midpoint.repo.sqlbase.mapping.QueryTableMapping; import com.evolveum.midpoint.repo.sqlbase.perfmon.SqlPerformanceMonitorImpl; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/SqaleUpdateContext.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/SqaleUpdateContext.java deleted file mode 100644 index efa0eb167bd..00000000000 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/SqaleUpdateContext.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2010-2021 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.repo.sqale; - -import javax.xml.namespace.QName; - -import com.querydsl.core.types.Path; - -import com.evolveum.midpoint.repo.sqale.qmodel.ref.QOwnedByMapping; -import com.evolveum.midpoint.repo.sqale.qmodel.ref.TransformerForOwnedBy; -import com.evolveum.midpoint.repo.sqlbase.JdbcSession; -import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; - -public abstract class SqaleUpdateContext, R> { - - protected final Trace logger = TraceManager.getTrace(getClass()); - - protected final SqaleTransformerSupport transformerSupport; - protected final JdbcSession jdbcSession; - protected final S object; - protected final R row; - - public SqaleUpdateContext(SqaleTransformerSupport sqlTransformerSupport, - JdbcSession jdbcSession, S object, R row) { - this.transformerSupport = sqlTransformerSupport; - this.jdbcSession = jdbcSession; - this.object = object; - this.row = row; - } - - public SqaleTransformerSupport transformerSupport() { - return transformerSupport; - } - - public Integer processCacheableRelation(QName relation) { - return transformerSupport.processCacheableRelation(relation); - } - - public Integer processCacheableUri(String uri) { - return transformerSupport.processCacheableUri(uri); - } - - public JdbcSession jdbcSession() { - return jdbcSession; - } - - public S schemaObject() { - return object; - } - - public R row() { - return row; - } - - public abstract Q path(); - - public abstract

, T> void set(P path, T value); - - @SuppressWarnings("UnusedReturnValue") - public TR insertOwnedRow(QOwnedByMapping mapping, TS schemaObject) { - TransformerForOwnedBy transformer = - mapping.createTransformer(transformerSupport()); - return transformer.insert(schemaObject, row, jdbcSession); - } -} diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/SqaleUtils.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/SqaleUtils.java index 3c1b306b834..ddf123dd60f 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/SqaleUtils.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/SqaleUtils.java @@ -38,4 +38,10 @@ public static int objectVersionAsInt(PrismObject prismObject) { throw new IllegalArgumentException("Version must be a number: " + version); } } + + /** Parametrized type friendly version of {@link Object#getClass()}. */ + public static Class getClass(S object) { + //noinspection unchecked + return (Class) object.getClass(); + } } diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/DelegatingItemDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/DelegatingItemDeltaProcessor.java index e90982dd4ed..c4e461f1403 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/DelegatingItemDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/DelegatingItemDeltaProcessor.java @@ -11,10 +11,9 @@ import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.path.ItemName; import com.evolveum.midpoint.prism.path.ItemPath; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqale.mapping.SqaleItemRelationResolver; import com.evolveum.midpoint.repo.sqale.mapping.SqaleItemSqlMapper; -import com.evolveum.midpoint.repo.sqlbase.QueryException; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.RepositoryException; import com.evolveum.midpoint.repo.sqlbase.filtering.ValueFilterProcessor; import com.evolveum.midpoint.repo.sqlbase.mapping.ItemRelationResolver; @@ -68,12 +67,12 @@ public void process(ItemDelta modification) throws RepositoryException { // It's a similar case like the fast return after resolving the path. } - private QName resolvePath(ItemPath path) throws QueryException { + private QName resolvePath(ItemPath path) { while (!path.isSingleName()) { ItemName firstName = path.firstName(); path = path.rest(); - ItemRelationResolver relationResolver = mapping.getRelationResolver(firstName); + ItemRelationResolver relationResolver = mapping.getRelationResolver(firstName); if (relationResolver == null) { return null; // unmapped, not persisted, nothing to do } @@ -83,8 +82,11 @@ private QName resolvePath(ItemPath path) throws QueryException { throw new IllegalArgumentException("Relation resolver for " + firstName + " in mapping " + mapping + " does not support delta modifications!"); } - SqaleItemRelationResolver resolver = (SqaleItemRelationResolver) relationResolver; - SqaleItemRelationResolver.UpdateResolutionResult resolution = resolver.resolve(context); + + // we know nothing about context and resolver types, so we have to ignore it + @SuppressWarnings({ "rawtypes", "unchecked" }) + SqaleItemRelationResolver.UpdateResolutionResult resolution = + ((SqaleItemRelationResolver) relationResolver).resolve(context); context = resolution.context; mapping = resolution.mapping; } diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaValueProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaValueProcessor.java index d59d36668e4..5d8620599e6 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaValueProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/ItemDeltaValueProcessor.java @@ -13,7 +13,7 @@ import org.jetbrains.annotations.Nullable; import com.evolveum.midpoint.prism.delta.ItemDelta; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.RepositoryException; /** diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ContainerTableDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ContainerTableDeltaProcessor.java index 0d23b072942..12b373847ee 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ContainerTableDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ContainerTableDeltaProcessor.java @@ -11,11 +11,11 @@ import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.prism.Containerable; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqale.delta.ItemDeltaValueProcessor; import com.evolveum.midpoint.repo.sqale.qmodel.common.MContainer; import com.evolveum.midpoint.repo.sqale.qmodel.common.QContainer; import com.evolveum.midpoint.repo.sqale.qmodel.common.QContainerMapping; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; /** diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/EmbeddedContainerDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/EmbeddedContainerDeltaProcessor.java index 1fc392bd70c..79051f9e9a1 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/EmbeddedContainerDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/EmbeddedContainerDeltaProcessor.java @@ -12,10 +12,10 @@ import com.evolveum.midpoint.prism.Containerable; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismContainerValue; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqale.delta.ItemDeltaValueProcessor; import com.evolveum.midpoint.repo.sqale.mapping.SqaleItemSqlMapper; import com.evolveum.midpoint.repo.sqale.qmodel.SqaleNestedMapping; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.mapping.ItemSqlMapper; import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/EnumItemDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/EnumItemDeltaProcessor.java index 39b1d4097b7..3630d99c289 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/EnumItemDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/EnumItemDeltaProcessor.java @@ -10,7 +10,7 @@ import com.querydsl.core.types.dsl.EnumPath; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; /** diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ItemDeltaSingleValueProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ItemDeltaSingleValueProcessor.java index 435840994da..520f9d22923 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ItemDeltaSingleValueProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/ItemDeltaSingleValueProcessor.java @@ -10,8 +10,8 @@ import com.evolveum.midpoint.prism.PrismValue; import com.evolveum.midpoint.prism.delta.ItemDelta; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqale.delta.ItemDeltaValueProcessor; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.RepositoryException; /** diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/PolyStringItemDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/PolyStringItemDeltaProcessor.java index de4ff86e0b5..b6d46638882 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/PolyStringItemDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/PolyStringItemDeltaProcessor.java @@ -11,7 +11,7 @@ import com.querydsl.core.types.dsl.StringPath; import com.evolveum.midpoint.prism.polystring.PolyString; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; public class PolyStringItemDeltaProcessor extends ItemDeltaSingleValueProcessor { diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/RefItemDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/RefItemDeltaProcessor.java index a0675b9e36a..c31601cc86c 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/RefItemDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/RefItemDeltaProcessor.java @@ -13,8 +13,8 @@ import com.querydsl.core.types.dsl.NumberPath; import com.evolveum.midpoint.prism.Referencable; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObjectType; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; import com.evolveum.midpoint.repo.sqlbase.querydsl.UuidPath; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/RefTableItemDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/RefTableItemDeltaProcessor.java index 093b3157056..011dbb6b2d3 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/RefTableItemDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/RefTableItemDeltaProcessor.java @@ -10,10 +10,10 @@ import java.util.UUID; import com.evolveum.midpoint.prism.Referencable; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqale.delta.ItemDeltaValueProcessor; import com.evolveum.midpoint.repo.sqale.qmodel.ref.QReference; import com.evolveum.midpoint.repo.sqale.qmodel.ref.QReferenceMapping; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; /** diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/SimpleItemDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/SimpleItemDeltaProcessor.java index 240f1277833..9f24e3c2e72 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/SimpleItemDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/SimpleItemDeltaProcessor.java @@ -10,7 +10,7 @@ import com.querydsl.core.types.Path; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; /** diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/SinglePathItemDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/SinglePathItemDeltaProcessor.java index 755c7aa3280..c5fbe97c07a 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/SinglePathItemDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/SinglePathItemDeltaProcessor.java @@ -10,7 +10,7 @@ import com.querydsl.core.types.Path; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; /** diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/TimestampItemDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/TimestampItemDeltaProcessor.java index 402c77e9d45..25ff95b9442 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/TimestampItemDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/TimestampItemDeltaProcessor.java @@ -11,7 +11,7 @@ import com.querydsl.core.types.dsl.DateTimePath; import org.jetbrains.annotations.Nullable; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; import com.evolveum.midpoint.repo.sqlbase.querydsl.QuerydslUtils; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/UriItemDeltaProcessor.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/UriItemDeltaProcessor.java index 402ec726278..c1acaf69af4 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/UriItemDeltaProcessor.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/delta/item/UriItemDeltaProcessor.java @@ -11,7 +11,7 @@ import com.querydsl.core.types.dsl.NumberPath; import org.jetbrains.annotations.Nullable; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; public class UriItemDeltaProcessor diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/NestedMappingResolver.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/NestedMappingResolver.java index 5e1190be382..34d3f019725 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/NestedMappingResolver.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/NestedMappingResolver.java @@ -6,7 +6,7 @@ */ package com.evolveum.midpoint.repo.sqale.mapping; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext; import com.evolveum.midpoint.repo.sqlbase.mapping.QueryModelMapping; import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; @@ -14,25 +14,29 @@ /** * Resolver that maps the nested items (next component of the path) to the same query type columns. * - * @param type of source entity path + * @param query type of source entity (where the mapping is declared) + * @param row type of {@link Q} */ -public class NestedMappingResolver> - implements SqaleItemRelationResolver { +public class NestedMappingResolver, R> + implements SqaleItemRelationResolver { - private final QueryModelMapping mapping; + private final QueryModelMapping mapping; - public NestedMappingResolver(QueryModelMapping mapping) { + public NestedMappingResolver(QueryModelMapping mapping) { this.mapping = mapping; } /** Returns the same context and nested mapping. */ @Override - public ResolutionResult resolve(SqlQueryContext context) { + public ResolutionResult resolve(SqlQueryContext context) { return new ResolutionResult(context, mapping); } @Override - public UpdateResolutionResult resolve(SqaleUpdateContext context) { + public UpdateResolutionResult resolve(SqaleUpdateContext context) { + // TODO this is OK unless we need to capture new schema object, e.g. nested metadata, + // in the context (SqaleUpdateContext#object). Row stays still the same, update clause + // doesn't change either, that's OK. Currently we're just losing type information. return new UpdateResolutionResult(context, mapping); } } diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/SqaleItemRelationResolver.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/SqaleItemRelationResolver.java index 22c81162d30..8e007dec805 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/SqaleItemRelationResolver.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/SqaleItemRelationResolver.java @@ -6,23 +6,25 @@ */ package com.evolveum.midpoint.repo.sqale.mapping; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.mapping.ItemRelationResolver; import com.evolveum.midpoint.repo.sqlbase.mapping.QueryModelMapping; +import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; /** * Extension of {@link ItemRelationResolver}, this is a common contract for resolver * that helps with navigating over complex (non-single) item paths for both query * and application of delta modification. */ -public interface SqaleItemRelationResolver extends ItemRelationResolver { +public interface SqaleItemRelationResolver, R> + extends ItemRelationResolver { /** * Resolves current query context to {@link ResolutionResult} with new context and mapping. * The information about the resolved item is captured in the instance resolver already * in a manner that is specific for various types of resolution (JOIN or nested mapping). */ - UpdateResolutionResult resolve(SqaleUpdateContext context); + UpdateResolutionResult resolve(SqaleUpdateContext context); class UpdateResolutionResult { public final SqaleUpdateContext context; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/SqaleItemSqlMapper.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/SqaleItemSqlMapper.java index 229bf52eaa4..00d4db0a1f2 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/SqaleItemSqlMapper.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/SqaleItemSqlMapper.java @@ -13,9 +13,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqale.delta.ItemDeltaProcessor; import com.evolveum.midpoint.repo.sqale.delta.ItemDeltaValueProcessor; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext; import com.evolveum.midpoint.repo.sqlbase.filtering.item.ItemFilterProcessor; import com.evolveum.midpoint.repo.sqlbase.mapping.ItemRelationResolver; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/TableRelationResolver.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/TableRelationResolver.java index b636bbcf62c..cea860e86fc 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/TableRelationResolver.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/mapping/TableRelationResolver.java @@ -11,7 +11,9 @@ import com.querydsl.core.types.Predicate; import org.jetbrains.annotations.NotNull; -import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext; +import com.evolveum.midpoint.repo.sqale.qmodel.QOwnedBy; +import com.evolveum.midpoint.repo.sqale.qmodel.SqaleTableMapping; +import com.evolveum.midpoint.repo.sqale.update.SqaleUpdateContext; import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext; import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; @@ -19,22 +21,27 @@ * Resolver that knows how to add {@code JOIN} for the specified target query type. * * @param type of source entity path + * @param row type for {@link Q}, this is the owner of the target table + * @param schema type for the target entity * @param type of target entity path * @param row type related to the target entity path {@link TQ} */ // TODO: Can we have just this one time for both container and references? // If not (probably because of modify), subclass it. public class TableRelationResolver< - Q extends FlexibleRelationalPathBase, TQ extends FlexibleRelationalPathBase, TR> - implements SqaleItemRelationResolver { + Q extends FlexibleRelationalPathBase, R, + TS, TQ extends FlexibleRelationalPathBase & QOwnedBy, TR> + // TODO how to add & QOwnedByMapping without clashing on transformer? perhaps it will not be necessary to capture here +// M extends SqaleTableMapping> // without & the M is not necessary + implements SqaleItemRelationResolver { - private final Class targetQueryType; + private final SqaleTableMapping targetMapping; private final BiFunction joinPredicate; public TableRelationResolver( - @NotNull Class targetQueryType, + @NotNull SqaleTableMapping targetMapping, @NotNull BiFunction joinPredicate) { - this.targetQueryType = targetQueryType; + this.targetMapping = targetMapping; this.joinPredicate = joinPredicate; } @@ -46,20 +53,21 @@ public TableRelationResolver( * @return result with context for JOINed entity path and its mapping */ @Override - public ResolutionResult resolve(SqlQueryContext context) { - //noinspection unchecked - SqlQueryContext joinContext = - ((SqlQueryContext) context).leftJoin(targetQueryType, joinPredicate); + public ResolutionResult resolve(SqlQueryContext context) { + SqlQueryContext joinContext = + context.leftJoin(targetMapping.queryType(), joinPredicate); return new ResolutionResult(joinContext, joinContext.mapping()); } @Override - public UpdateResolutionResult resolve(SqaleUpdateContext context) { + public UpdateResolutionResult resolve(SqaleUpdateContext context) { // TODO for query above we can hop to another table with join, still using SqlQueryContext // (just a new instance), but right now SqaleUpdateContext is not built for that. // Options - superclass? Common interface? Parametrized to Flexible... instead of QObject? - return null; // TODO: now fails outside with NPE +// return null; // TODO: now fails outside with NPE +// new ContainerTableDeltaProcessor<> + return new UpdateResolutionResult(context, targetMapping); } } diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleMappingMixin.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleMappingMixin.java index 9fefa0bed7c..0d67e362a96 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleMappingMixin.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleMappingMixin.java @@ -8,9 +8,9 @@ import com.evolveum.midpoint.prism.Containerable; import com.evolveum.midpoint.prism.path.ItemName; +import com.evolveum.midpoint.repo.sqale.delta.item.ContainerTableDeltaProcessor; import com.evolveum.midpoint.repo.sqale.delta.item.EmbeddedContainerDeltaProcessor; import com.evolveum.midpoint.repo.sqale.delta.item.RefTableItemDeltaProcessor; -import com.evolveum.midpoint.repo.sqale.delta.item.ContainerTableDeltaProcessor; import com.evolveum.midpoint.repo.sqale.filtering.RefTableItemFilterProcessor; import com.evolveum.midpoint.repo.sqale.mapping.NestedMappingResolver; import com.evolveum.midpoint.repo.sqale.mapping.SqaleItemSqlMapper; @@ -41,7 +41,7 @@ public interface SqaleMappingMixin, R @SuppressWarnings("UnusedReturnValue") QueryModelMapping addRelationResolver( @NotNull ItemName itemName, - @NotNull ItemRelationResolver itemRelationResolver); + @NotNull ItemRelationResolver itemRelationResolver); QueryModelMapping addItemMapping( @NotNull QName itemName, @NotNull ItemSqlMapper itemMapper); @@ -91,7 +91,7 @@ SqaleMappingMixin addContainerTableMapping( // of course the join would be implemented in QOwnedBy // BTW: adding OQ on refs is messy, we already have AOR and we would need AOQ for QAssignmentReferenceMapping too. addRelationResolver(itemName, - new TableRelationResolver<>(containerMapping.queryType(), joinPredicate)); + new TableRelationResolver<>(containerMapping, joinPredicate)); addItemMapping(itemName, new SqaleItemSqlMapper<>( ctx -> new ContainerTableDeltaProcessor<>(ctx, containerMapping))); diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleNestedMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleNestedMapping.java index 0fa5cbbc758..60b81ee10af 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleNestedMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleNestedMapping.java @@ -38,7 +38,7 @@ protected SqaleNestedMapping(@NotNull Class schemaType, @NotNull Class que @Override public SqaleNestedMapping addItemMapping( - @NotNull QName itemName, @NotNull ItemSqlMapper itemMapper) { + @NotNull QName itemName, @NotNull ItemSqlMapper itemMapper) { super.addItemMapping(itemName, itemMapper); return this; } diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleTableMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleTableMapping.java index d7065146118..81b5cbdb34b 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleTableMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/SqaleTableMapping.java @@ -27,6 +27,7 @@ /** * Mapping superclass with common functions for {@link QObject} and non-objects (e.g. containers). + * See javadoc in {@link QueryTableMapping} for more. * * @param schema type * @param type of entity path @@ -45,9 +46,13 @@ protected SqaleTableMapping( super(tableName, defaultAliasName, schemaType, queryType); } - /** Returns the mapper creating the string filter/delta processors from context. */ + /** + * Returns the mapper creating the string filter/delta processors from context. + * + * @param mapped schema type, see javadoc in {@link QueryTableMapping} + */ @Override - protected SqaleItemSqlMapper stringMapper( + protected SqaleItemSqlMapper stringMapper( Function rootToQueryItem) { return new SqaleItemSqlMapper<>( ctx -> new SimpleItemFilterProcessor<>(ctx, rootToQueryItem), @@ -55,9 +60,13 @@ protected SqaleItemSqlMapper stringMapper( rootToQueryItem); } - /** Returns the mapper creating the integer filter/delta processors from context. */ + /** + * Returns the mapper creating the integer filter/delta processors from context. + * + * @param mapped schema type, see javadoc in {@link QueryTableMapping} + */ @Override - public SqaleItemSqlMapper integerMapper( + public SqaleItemSqlMapper integerMapper( Function> rootToQueryItem) { return new SqaleItemSqlMapper<>( ctx -> new SimpleItemFilterProcessor<>(ctx, rootToQueryItem), @@ -65,27 +74,39 @@ public SqaleItemSqlMapper integerMapper( rootToQueryItem); } - /** Returns the mapper creating the boolean filter/delta processors from context. */ + /** + * Returns the mapper creating the boolean filter/delta processors from context. + * + * @param mapped schema type, see javadoc in {@link QueryTableMapping} + */ @Override - protected SqaleItemSqlMapper booleanMapper(Function rootToQueryItem) { + protected SqaleItemSqlMapper booleanMapper(Function rootToQueryItem) { return new SqaleItemSqlMapper<>( ctx -> new SimpleItemFilterProcessor<>(ctx, rootToQueryItem), ctx -> new SimpleItemDeltaProcessor<>(ctx, rootToQueryItem), rootToQueryItem); } - /** Returns the mapper creating the UUID filter/delta processors from context. */ + /** + * Returns the mapper creating the UUID filter/delta processors from context. + * + * @param mapped schema type, see javadoc in {@link QueryTableMapping} + */ @Override - protected SqaleItemSqlMapper uuidMapper(Function rootToQueryItem) { + protected SqaleItemSqlMapper uuidMapper(Function rootToQueryItem) { return new SqaleItemSqlMapper<>( ctx -> new SimpleItemFilterProcessor<>(ctx, rootToQueryItem), ctx -> new SimpleItemDeltaProcessor<>(ctx, rootToQueryItem), rootToQueryItem); } - /** Returns the mapper creating the timestamp filter/delta processors from context. */ + /** + * Returns the mapper creating the timestamp filter/delta processors from context. + * + * @param mapped schema type, see javadoc in {@link QueryTableMapping} + */ @Override - protected > SqaleItemSqlMapper timestampMapper( + protected > SqaleItemSqlMapper timestampMapper( Function> rootToQueryItem) { return new SqaleItemSqlMapper<>( ctx -> new TimestampItemFilterProcessor<>(ctx, rootToQueryItem), @@ -93,9 +114,13 @@ protected > SqaleItemSqlMapper timestampMapper( rootToQueryItem); } - /** Returns the mapper creating the polystring filter/delta processors from context. */ + /** + * Returns the mapper creating the polystring filter/delta processors from context. + * + * @param mapped schema type, see javadoc in {@link QueryTableMapping} + */ @Override - protected SqaleItemSqlMapper polyStringMapper( + protected SqaleItemSqlMapper polyStringMapper( @NotNull Function origMapping, @NotNull Function normMapping) { return new SqaleItemSqlMapper<>( @@ -104,8 +129,12 @@ protected SqaleItemSqlMapper polyStringMapper( origMapping); } - /** Returns the mapper creating the reference filter/delta processors from context. */ - protected SqaleItemSqlMapper refMapper( + /** + * Returns the mapper creating the reference filter/delta processors from context. + * + * @param mapped schema type, see javadoc in {@link QueryTableMapping} + */ + protected SqaleItemSqlMapper refMapper( Function rootToOidPath, Function> rootToTypePath, Function> rootToRelationIdPath) { @@ -116,16 +145,24 @@ protected SqaleItemSqlMapper refMapper( rootToOidPath, rootToTypePath, rootToRelationIdPath)); } - /** Returns the mapper creating the cached URI filter/delta processors from context. */ - protected SqaleItemSqlMapper uriMapper( + /** + * Returns the mapper creating the cached URI filter/delta processors from context. + * + * @param mapped schema type, see javadoc in {@link QueryTableMapping} + */ + protected SqaleItemSqlMapper uriMapper( Function> rootToPath) { return new SqaleItemSqlMapper<>( ctx -> new UriItemFilterProcessor(ctx, rootToPath), ctx -> new UriItemDeltaProcessor(ctx, rootToPath)); } - /** Returns the mapper creating the enum filter/delta processors from context. */ - public > SqaleItemSqlMapper enumMapper( + /** + * Returns the mapper creating the enum filter/delta processors from context. + * + * @param mapped schema type, see javadoc in {@link QueryTableMapping} + */ + public > SqaleItemSqlMapper enumMapper( @NotNull Function> rootToQueryItem) { return new SqaleItemSqlMapper<>( ctx -> new EnumItemFilterProcessor<>(ctx, rootToQueryItem), diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/common/QContainer.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/common/QContainer.java index 5a7326a0787..99b13891be1 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/common/QContainer.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/common/QContainer.java @@ -24,7 +24,7 @@ * Querydsl query type for {@value #TABLE_NAME} table. */ @SuppressWarnings("unused") -public class QContainer extends FlexibleRelationalPathBase +public class QContainer extends FlexibleRelationalPathBase implements QOwnedBy { private static final long serialVersionUID = 1033484385814003347L; @@ -48,16 +48,16 @@ public class QContainer extends FlexibleRelationalPath public final EnumPath containerType = createEnum("containerType", MContainerType.class, CONTAINER_TYPE); - public final PrimaryKey pk = createPrimaryKey(ownerOid, cid); + public final PrimaryKey pk = createPrimaryKey(ownerOid, cid); public final ForeignKey> objectOidIdFk = createForeignKey(ownerOid, QObject.OID.getName()); - public QContainer(Class type, String variable) { + public QContainer(Class type, String variable) { this(type, variable, DEFAULT_SCHEMA_NAME, TABLE_NAME); } - public QContainer(Class type, String variable, String schema, String table) { + public QContainer(Class type, String variable, String schema, String table) { super(type, variable, schema, table); } diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/ref/QOwnedByMapping.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/ref/QOwnedByMapping.java index 7823a7db9bf..b1448ffb6bb 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/ref/QOwnedByMapping.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/ref/QOwnedByMapping.java @@ -11,6 +11,11 @@ /** * Marks mappings for {@link QOwnedBy} entities. + * + * @param schema type or the mapped object, typically a container owned by + * either an object or another container + * @param row type of the mapped object + * @param row type of the owner object */ public interface QOwnedByMapping { diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/ref/QReference.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/ref/QReference.java index ee359d05cd5..5f7d30752e1 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/ref/QReference.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/qmodel/ref/QReference.java @@ -27,7 +27,7 @@ * @param type of the owner row */ public class QReference extends FlexibleRelationalPathBase - implements QOwnedBy { + implements QOwnedBy { private static final long serialVersionUID = -466419569179455042L; diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/ContainerUpdateContext.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/ContainerUpdateContext.java similarity index 81% rename from repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/ContainerUpdateContext.java rename to repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/ContainerUpdateContext.java index 66203d1fda4..d1102624626 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/ContainerUpdateContext.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/ContainerUpdateContext.java @@ -4,13 +4,12 @@ * This work is dual-licensed under the Apache License 2.0 * and European Union Public License. See LICENSE file for details. */ -package com.evolveum.midpoint.repo.sqale; +package com.evolveum.midpoint.repo.sqale.update; import com.querydsl.core.types.Path; import com.querydsl.sql.dml.SQLUpdateClause; import com.evolveum.midpoint.prism.Containerable; -import com.evolveum.midpoint.repo.sqale.qmodel.SqaleTableMapping; import com.evolveum.midpoint.repo.sqale.qmodel.common.MContainer; import com.evolveum.midpoint.repo.sqale.qmodel.common.QContainer; import com.evolveum.midpoint.repo.sqlbase.JdbcSession; @@ -25,21 +24,19 @@ * @param schema type of the object stored in the owned (child) table * @param type of entity path for the owned (child) table * @param row type related to the {@link Q} + * TODO: other params */ +// TODO rename to ContainerTableUpdateContext public class ContainerUpdateContext, R extends MContainer, OR> extends SqaleUpdateContext { - private final SqaleTableMapping mapping; private final Q path; private final SQLUpdateClause update; public ContainerUpdateContext(SqaleUpdateContext parentContext, - JdbcSession jdbcSession, S object, R rootRow) { - super(parentContext.transformerSupport, parentContext.jdbcSession, object, rootRow); + JdbcSession jdbcSession, S object, R row) { + super(parentContext, object, row); - //noinspection unchecked - mapping = transformerSupport.sqlRepoContext() - .getMappingBySchemaType((Class) object.getClass()); path = mapping.defaultAlias(); // we create the update, but only use it if set methods are used update = jdbcSession.newUpdate(path) diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/NestedContainerUpdateContext.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/NestedContainerUpdateContext.java new file mode 100644 index 00000000000..8bb395da618 --- /dev/null +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/NestedContainerUpdateContext.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010-2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.repo.sqale.update; + +import com.querydsl.core.types.Path; + +import com.evolveum.midpoint.prism.Containerable; +import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; + +/** + * Update context for nested containers stored in the same table used by the parent context. + * + * @param schema type of the object mapped by nested mapping + * @param entity query type that holds the data for the mapped attributes + * @param row type related to the {@link Q} + */ +public class NestedContainerUpdateContext, R> + extends SqaleUpdateContext { + + public NestedContainerUpdateContext( + SqaleUpdateContext parentContext, S object, R rootRow) { + super(parentContext, object, rootRow); + + // TODO + } + + @Override + public Q path() { + return null; // TODO + } + + @Override + public

, T> void set(P path, T value) { + // TODO delegate to parent + } +} diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/RootUpdateContext.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/RootUpdateContext.java similarity index 92% rename from repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/RootUpdateContext.java rename to repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/RootUpdateContext.java index 9eb2ef7bbdd..d72392b4939 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/RootUpdateContext.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/RootUpdateContext.java @@ -4,7 +4,7 @@ * This work is dual-licensed under the Apache License 2.0 * and European Union Public License. See LICENSE file for details. */ -package com.evolveum.midpoint.repo.sqale; +package com.evolveum.midpoint.repo.sqale.update; import static com.evolveum.midpoint.repo.sqale.SqaleUtils.objectVersionAsInt; @@ -17,8 +17,10 @@ import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.equivalence.EquivalenceStrategy; +import com.evolveum.midpoint.repo.sqale.ContainerValueIdGenerator; +import com.evolveum.midpoint.repo.sqale.SqaleTransformerSupport; +import com.evolveum.midpoint.repo.sqale.SqaleUtils; import com.evolveum.midpoint.repo.sqale.delta.DelegatingItemDeltaProcessor; -import com.evolveum.midpoint.repo.sqale.qmodel.SqaleTableMapping; import com.evolveum.midpoint.repo.sqale.qmodel.object.MObject; import com.evolveum.midpoint.repo.sqale.qmodel.object.ObjectSqlTransformer; import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject; @@ -39,7 +41,6 @@ public class RootUpdateContext, R extends MObject> extends SqaleUpdateContext { - private final SqaleTableMapping mapping; private final Q rootPath; private final SQLUpdateClause update; private final int objectVersion; @@ -48,11 +49,11 @@ public class RootUpdateContext, R ext public RootUpdateContext(SqaleTransformerSupport transformerSupport, JdbcSession jdbcSession, S object, R rootRow) { - super(transformerSupport, jdbcSession, object, rootRow); + super(transformerSupport, + transformerSupport.sqlRepoContext() + .getMappingBySchemaType(SqaleUtils.getClass(object)), + jdbcSession, object, rootRow); - //noinspection unchecked - mapping = this.transformerSupport.sqlRepoContext() - .getMappingBySchemaType((Class) object.getClass()); rootPath = mapping.defaultAlias(); objectVersion = objectVersionAsInt(object); // root context always updates, at least version and full object, so we can create it early diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/SqaleUpdateContext.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/SqaleUpdateContext.java new file mode 100644 index 00000000000..b3845226052 --- /dev/null +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/SqaleUpdateContext.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2010-2021 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.repo.sqale.update; + +import javax.xml.namespace.QName; + +import com.querydsl.core.types.Path; + +import com.evolveum.midpoint.repo.sqale.SqaleTransformerSupport; +import com.evolveum.midpoint.repo.sqale.SqaleUtils; +import com.evolveum.midpoint.repo.sqale.delta.ItemDeltaValueProcessor; +import com.evolveum.midpoint.repo.sqale.delta.item.UriItemDeltaProcessor; +import com.evolveum.midpoint.repo.sqale.qmodel.SqaleTableMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.ref.QOwnedByMapping; +import com.evolveum.midpoint.repo.sqale.qmodel.ref.TransformerForOwnedBy; +import com.evolveum.midpoint.repo.sqlbase.JdbcSession; +import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; + +/** + * Update context manages state information related to the currently executed modify operation. + * Contexts can be nested for any non-trivial updates where each instance matches the changed item + * and its mapping. + * {@link RootUpdateContext} is the top level parent context that holds the main object. + * + * For example, given a path `assignment/1/metadata/channel`: + * + * * {@link RootUpdateContext} is created for the object, imagine it at the root of the path. + * * {@link ContainerUpdateContext} is created for `assignment/1` part under the root context. + * * {@link NestedContainerUpdateContext} is created for `metadata` part. + * * One of {@link ItemDeltaValueProcessor} is then created for `channel` based on the type of + * the property (in this case {@link UriItemDeltaProcessor}) which processes actual values and + * uses the context above to do so. + * + * In this example channel is single-valued property and will be changed adding a `SET` clause + * to the `UPDATE` held by the container table update context. + * This `UPDATE` will use proper `WHERE` clause negotiated between this context and its parent, + * which in this case is the root context, using also the container ID provided in the item path. + * Nested container context merely "focuses" from assignment container to its metadata, but the + * table is still the same. + * + * @param schema type of the mapped object (potentially in nested mapping) + * @param query entity type + * @param row type related to the {@link Q} + */ +public abstract class SqaleUpdateContext, R> { + + protected final Trace logger = TraceManager.getTrace(getClass()); + + protected final SqaleTransformerSupport transformerSupport; + protected final SqaleTableMapping mapping; + protected final JdbcSession jdbcSession; + protected final S object; + protected final R row; + + public SqaleUpdateContext(SqaleTransformerSupport sqlTransformerSupport, + SqaleTableMapping mapping, + JdbcSession jdbcSession, S object, R row) { + this.transformerSupport = sqlTransformerSupport; + this.mapping = mapping; + this.jdbcSession = jdbcSession; + this.object = object; + this.row = row; + } + + public SqaleUpdateContext(SqaleUpdateContext parentContext, S object, R row) { + this.transformerSupport = parentContext.transformerSupport; + this.mapping = transformerSupport.sqlRepoContext() + .getMappingBySchemaType(SqaleUtils.getClass(object)); + this.jdbcSession = parentContext.jdbcSession(); + this.object = object; + this.row = row; + } + + public SqaleTransformerSupport transformerSupport() { + return transformerSupport; + } + + public Integer processCacheableRelation(QName relation) { + return transformerSupport.processCacheableRelation(relation); + } + + public Integer processCacheableUri(String uri) { + return transformerSupport.processCacheableUri(uri); + } + + public JdbcSession jdbcSession() { + return jdbcSession; + } + + public S schemaObject() { + return object; + } + + public R row() { + return row; + } + + public abstract Q path(); + + public abstract

, T> void set(P path, T value); + + @SuppressWarnings("UnusedReturnValue") + public TR insertOwnedRow(QOwnedByMapping mapping, TS schemaObject) { + TransformerForOwnedBy transformer = + mapping.createTransformer(transformerSupport()); + return transformer.insert(schemaObject, row, jdbcSession); + } +} diff --git a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/ValueFilterProcessor.java b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/ValueFilterProcessor.java index 9ba3426e179..4af7e16fa2b 100644 --- a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/ValueFilterProcessor.java +++ b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/filtering/ValueFilterProcessor.java @@ -80,7 +80,10 @@ private QName resolvePath(ItemPath path) throws QueryException { ItemName firstName = path.firstName(); path = path.rest(); + // we know nothing about context and resolver types, so we have to ignore it + //noinspection rawtypes ItemRelationResolver resolver = mapping.relationResolver(firstName); + //noinspection unchecked ItemRelationResolver.ResolutionResult resolution = resolver.resolve(context); context = resolution.context; mapping = resolution.mapping; diff --git a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/ItemRelationResolver.java b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/ItemRelationResolver.java index e30f21e9e39..5173e16e89a 100644 --- a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/ItemRelationResolver.java +++ b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/ItemRelationResolver.java @@ -7,19 +7,23 @@ package com.evolveum.midpoint.repo.sqlbase.mapping; import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext; +import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase; /** * Common contract for resolver that helps with navigating over complex (non-single) item paths * for query purposes. + * + * @param query type with the mapping + * @param row type related to {@link Q} */ -public interface ItemRelationResolver { +public interface ItemRelationResolver, R> { /** * Resolves a query context to {@link ResolutionResult} with new context and mapping. * The information about the resolved item is captured in the instance resolver already * in a manner that is specific for various types of resolution (JOIN or nested mapping). */ - ResolutionResult resolve(SqlQueryContext context); + ResolutionResult resolve(SqlQueryContext context); class ResolutionResult { public final SqlQueryContext context; diff --git a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/QueryModelMapping.java b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/QueryModelMapping.java index cd2f2f9ae14..edaa59726b5 100644 --- a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/QueryModelMapping.java +++ b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/QueryModelMapping.java @@ -43,7 +43,7 @@ public class QueryModelMapping, R> { private final Class queryType; private final Map> itemMappings = new LinkedHashMap<>(); - private final Map itemRelationResolvers = new HashMap<>(); + private final Map> itemRelationResolvers = new HashMap<>(); public QueryModelMapping( @NotNull Class schemaType, @@ -102,7 +102,7 @@ public QueryModelMapping addItemMapping( // TODO add "to-many" option so the interpreter can use WHERE EXISTS instead of JOIN public QueryModelMapping addRelationResolver( @NotNull ItemName itemName, - @NotNull ItemRelationResolver itemRelationResolver) { + @NotNull ItemRelationResolver itemRelationResolver) { itemRelationResolvers.put(itemName, itemRelationResolver); return this; } @@ -135,9 +135,9 @@ public QueryModelMapping addRelationResolver( * * @throws QueryException if the resolver for the item is not found */ - public final @NotNull ItemRelationResolver relationResolver(ItemName itemName) + public final @NotNull ItemRelationResolver relationResolver(ItemName itemName) throws QueryException { - ItemRelationResolver resolver = getRelationResolver(itemName); + ItemRelationResolver resolver = getRelationResolver(itemName); if (resolver == null) { throw new QueryException("Missing relation resolver for " + itemName + " in mapping " + getClass().getSimpleName()); @@ -148,7 +148,7 @@ public QueryModelMapping addRelationResolver( /** * Returns {@link ItemRelationResolver} for provided {@link ItemName} or `null`. */ - public final @Nullable ItemRelationResolver getRelationResolver(ItemName itemName) { + public final @Nullable ItemRelationResolver getRelationResolver(ItemName itemName) { return QNameUtil.getByQName(itemRelationResolvers, itemName); } diff --git a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/QueryTableMapping.java b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/QueryTableMapping.java index a0f6236ab5c..64567a5b031 100644 --- a/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/QueryTableMapping.java +++ b/repo/repo-sqlbase/src/main/java/com/evolveum/midpoint/repo/sqlbase/mapping/QueryTableMapping.java @@ -52,6 +52,13 @@ * * It allows creating "aliases" (entity path instances) {@link #newAlias(String)}. * * It knows how to traverse to other related entities, defined by {@link #addRelationResolver} * + * Mapper factory methods like {@link #stringMapper} return mappers that may or may not be bound + * to the same schema type because of the nested mappings. + * E.g. attribute `name` is part of the `S` object, but `metadata/createChannel` is based on nested + * mapping for `metadata` for which `S` is `MetadataType`. + * That's why these methods have flexible schema type parameter. + * Because such nested mapping still uses the same table, types `Q` and `R` remain the same. + * * @param schema type * @param type of entity path * @param row type related to the {@link Q} @@ -91,44 +98,69 @@ protected QueryTableMapping( this.defaultAliasName = defaultAliasName; } - /** Returns the mapper creating the string filter processor from context. */ - protected ItemSqlMapper stringMapper( + /** + * Returns the mapper creating the string filter processor from context. + * + * @param mapped schema type, see javadoc for the class + */ + protected ItemSqlMapper stringMapper( Function rootToQueryItem) { return new ItemSqlMapper<>( ctx -> new SimpleItemFilterProcessor<>(ctx, rootToQueryItem), rootToQueryItem); } - /** Returns the mapper creating the integer filter processor from context. */ - public ItemSqlMapper integerMapper( + /** + * Returns the mapper creating the integer filter processor from context. + * + * @param mapped schema type, see javadoc for the class + */ + public ItemSqlMapper integerMapper( Function> rootToQueryItem) { return new ItemSqlMapper<>(ctx -> new SimpleItemFilterProcessor<>(ctx, rootToQueryItem), rootToQueryItem); } - /** Returns the mapper creating the boolean filter processor from context. */ - protected ItemSqlMapper booleanMapper( + /** + * Returns the mapper creating the boolean filter processor from context. + * + * @param mapped schema type, see javadoc for the class + */ + protected ItemSqlMapper booleanMapper( Function rootToQueryItem) { return new ItemSqlMapper<>(ctx -> new SimpleItemFilterProcessor<>(ctx, rootToQueryItem), rootToQueryItem); } - /** Returns the mapper creating the OID (UUID) filter processor from context. */ - protected ItemSqlMapper uuidMapper( + /** + * Returns the mapper creating the OID (UUID) filter processor from context. + * + * @param mapped schema type, see javadoc for the class + */ + protected ItemSqlMapper uuidMapper( Function rootToQueryItem) { return new ItemSqlMapper<>(ctx -> new SimpleItemFilterProcessor<>(ctx, rootToQueryItem), rootToQueryItem); } - /** Returns the mapper function creating the timestamp filter processor from context. */ - protected > ItemSqlMapper timestampMapper( + /** + * Returns the mapper function creating the timestamp filter processor from context. + * + * @param mapped schema type, see javadoc for the class + * @param actual data type of the query path storing the timestamp + */ + protected > ItemSqlMapper timestampMapper( Function> rootToQueryItem) { return new ItemSqlMapper<>(context -> new TimestampItemFilterProcessor<>(context, rootToQueryItem), rootToQueryItem); } - /** Returns the mapper creating the string filter processor from context. */ - protected ItemSqlMapper polyStringMapper( + /** + * Returns the mapper creating the string filter processor from context. + * + * @param mapped schema type, see javadoc for the class + */ + protected ItemSqlMapper polyStringMapper( Function origMapping, Function normMapping) { return new ItemSqlMapper<>(ctx ->