Skip to content

Commit

Permalink
repo-sqale: first success in applying deltas to nested mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
virgo47 committed Apr 13, 2021
1 parent 6529425 commit 5becd33
Show file tree
Hide file tree
Showing 26 changed files with 242 additions and 92 deletions.
Expand Up @@ -9,7 +9,7 @@
import com.querydsl.sql.SQLQuery;

import com.evolveum.midpoint.prism.query.InOidFilter;
import com.evolveum.midpoint.repo.sqale.mapping.InOidFilterProcessor;
import com.evolveum.midpoint.repo.sqale.filtering.InOidFilterProcessor;
import com.evolveum.midpoint.repo.sqale.qmodel.SqaleTableMapping;
import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext;
import com.evolveum.midpoint.repo.sqlbase.SqlRepoContext;
Expand Down
Expand Up @@ -16,14 +16,13 @@

import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.repo.sqale.mapping.delta.SqaleItemSqlMapper;
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;
import com.evolveum.midpoint.repo.sqlbase.JdbcSession;
import com.evolveum.midpoint.repo.sqlbase.RepositoryException;
import com.evolveum.midpoint.repo.sqlbase.mapping.ItemSqlMapper;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;

Expand Down Expand Up @@ -69,23 +68,8 @@ public Q path() {
}

public void processModification(ItemDelta<?, ?> modification) throws RepositoryException {
QName itemPath = modification.getPath().asSingleName();
if (itemPath == null) {
return; // TODO no action now, we don't want NPE
}

// TODO later resolution of complex paths just like for filters
ItemSqlMapper itemSqlMapper = mapping.getItemMapper(itemPath);
if (itemSqlMapper instanceof SqaleItemSqlMapper) {
((SqaleItemSqlMapper) itemSqlMapper)
.createItemDeltaProcessor(this)
.process(modification);
} else if (itemSqlMapper != null) {
throw new IllegalArgumentException("No delta processor available for " + itemPath
+ " in mapping " + mapping + "! (Only query mapping is available.)");
}

// if the mapper null it is not indexed ("externalized") attribute, no action
new DelegatingItemDeltaProcessor(this, mapping)
.process(modification);
}

/**
Expand Down
@@ -0,0 +1,91 @@
/*
* 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.delta;

import javax.xml.namespace.QName;

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.sqlbase.RepositoryException;
import com.evolveum.midpoint.repo.sqlbase.mapping.ItemRelationResolver;
import com.evolveum.midpoint.repo.sqlbase.mapping.ItemSqlMapper;
import com.evolveum.midpoint.repo.sqlbase.mapping.QueryModelMapping;

/**
* This is default item delta processor that decides what to do with the modification.
* If the modification has multi-part name then it resolves it to the last component first.
*
* *Implementation note:*
* This is a separate component used by {@link SqaleUpdateContext} but while the context is
* one for all modifications this is instantiated for each modification (or even path resolution
* step) which allows for state changes that don't affect processing of another modification.
*/
public class DelegatingItemDeltaProcessor implements ItemDeltaProcessor {

/** Query context and mapping is not final as it can change during complex path resolution. */
private SqaleUpdateContext<?, ?, ?> context;
private QueryModelMapping<?, ?, ?> mapping;

public DelegatingItemDeltaProcessor(
SqaleUpdateContext<?, ?, ?> context, QueryModelMapping<?, ?, ?> mapping) {
this.context = context;
this.mapping = mapping;
}

@Override
public void process(ItemDelta<?, ?> modification) throws RepositoryException {
// TODO will we need various types of SqaleUpdateContext too?
// E.g. AccessCertificationWorkItemType is container inside container and to add/delete
// it we need to anchor the context in its parent, not in absolute root of update context.
// Similar situation is adding multi-value references to containers like assignments.

QName itemName = resolvePath(modification.getPath());
if (itemName == null) {
// This may indicate forgotten mapping, but normally it means that the item is simply
// not externalized and there is nothing to, update is only in fullObject.
return;
}

ItemSqlMapper itemSqlMapper = mapping.getItemMapper(itemName);
if (itemSqlMapper instanceof SqaleItemSqlMapper) {
((SqaleItemSqlMapper) itemSqlMapper)
.createItemDeltaProcessor(context)
.process(modification);
} else if (itemSqlMapper != null) {
// This should not happen, all the Sqale mappings should use SqaleItemSqlMapper.
throw new IllegalArgumentException("No delta processor available for " + itemName
+ " in mapping " + mapping + "! (Only query mapping is available.)");
}

// If the mapper is null, the item is not indexed ("externalized") attribute, no action.
// It's a similar case like the fast return after resolving the path.
}

private QName resolvePath(ItemPath path) throws QueryException {
while (!path.isSingleName()) {
ItemName firstName = path.firstName();
path = path.rest();

ItemRelationResolver relationResolver = mapping.relationResolver(firstName);
if (!(relationResolver instanceof SqaleItemRelationResolver)) {
// Again, programmers fault.
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);
context = resolution.context;
mapping = resolution.mapping;
}
return path.asSingleName();
}
}
@@ -0,0 +1,15 @@
/*
* 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.delta;

import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.repo.sqlbase.RepositoryException;

public interface ItemDeltaProcessor {

void process(ItemDelta<?, ?> modification) throws RepositoryException;
}
Expand Up @@ -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.mapping.delta;
package com.evolveum.midpoint.repo.sqale.delta.item;

import java.util.function.Function;

Expand Down
Expand Up @@ -4,30 +4,30 @@
* 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.mapping.delta;
package com.evolveum.midpoint.repo.sqale.delta.item;

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.sqlbase.RepositoryException;
import com.evolveum.midpoint.repo.sqale.delta.ItemDeltaProcessor;

/**
* Processes delta modification and arranges necessary SQL changes using update context.
* Applies item delta values to an item and arranges necessary SQL changes using update context.
* This typically means adding set clauses to the update but can also mean adding rows
* for containers, etc.
* This kind of item delta processor does not resolve multi-part item paths, see other
* subclasses of {@link ItemDeltaProcessor} for that.
*
* @param <T> expected type of the real value for the modification (after optional conversion)
*/
public abstract class ItemDeltaProcessor<T> {
public abstract class ItemDeltaValueProcessor<T> implements ItemDeltaProcessor {

protected final SqaleUpdateContext<?, ?, ?> context;

protected ItemDeltaProcessor(SqaleUpdateContext<?, ?, ?> context) {
protected ItemDeltaValueProcessor(SqaleUpdateContext<?, ?, ?> context) {
this.context = context;
}

public abstract void process(ItemDelta<?, ?> modification) throws RepositoryException;

/**
* Often the single real value is necessary, optionally transformed using
* {@link #transformRealValue(Object)} to get expected type.
Expand Down
Expand Up @@ -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.mapping.delta;
package com.evolveum.midpoint.repo.sqale.delta.item;

import java.util.function.Function;

Expand All @@ -16,7 +16,7 @@
import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext;
import com.evolveum.midpoint.repo.sqlbase.RepositoryException;

public class PolyStringItemDeltaProcessor extends ItemDeltaProcessor<PolyString> {
public class PolyStringItemDeltaProcessor extends ItemDeltaValueProcessor<PolyString> {

private final StringPath origPath;
private final StringPath normPath;
Expand Down
Expand Up @@ -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.mapping.delta;
package com.evolveum.midpoint.repo.sqale.delta.item;

import java.util.UUID;
import java.util.function.Function;
Expand All @@ -20,7 +20,7 @@
import com.evolveum.midpoint.repo.sqlbase.querydsl.UuidPath;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;

public class RefItemDeltaProcessor extends ItemDeltaProcessor<ObjectReferenceType> {
public class RefItemDeltaProcessor extends ItemDeltaValueProcessor<ObjectReferenceType> {

// only oidPath is strictly not-null, but then the filter better not ask for type or relation
private final UuidPath oidPath;
Expand Down
Expand Up @@ -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.mapping.delta;
package com.evolveum.midpoint.repo.sqale.delta.item;

import java.util.function.Function;

Expand Down
Expand Up @@ -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.mapping.delta;
package com.evolveum.midpoint.repo.sqale.delta.item;

import java.util.function.Function;

Expand All @@ -20,7 +20,8 @@
* to match the column (attribute) type in the row bean (M-type)
* @param <P> type of the corresponding path in the Q-type
*/
public class SinglePathItemDeltaProcessor<T, P extends Path<T>> extends ItemDeltaProcessor<T> {
public class SinglePathItemDeltaProcessor<T, P extends Path<T>>
extends ItemDeltaValueProcessor<T> {

protected final P path;

Expand Down
Expand Up @@ -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.mapping.delta;
package com.evolveum.midpoint.repo.sqale.delta.item;

import java.util.function.Function;

Expand Down
Expand Up @@ -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.mapping.delta;
package com.evolveum.midpoint.repo.sqale.delta.item;

import java.util.function.Function;

Expand Down
Expand Up @@ -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.mapping;
package com.evolveum.midpoint.repo.sqale.filtering;

import java.util.Collection;
import java.util.UUID;
Expand Down
Expand Up @@ -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.mapping;
package com.evolveum.midpoint.repo.sqale.filtering;

import com.querydsl.core.types.Predicate;

Expand Down
Expand Up @@ -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.mapping;
package com.evolveum.midpoint.repo.sqale.filtering;

import java.util.List;
import java.util.UUID;
Expand Down
Expand Up @@ -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.mapping;
package com.evolveum.midpoint.repo.sqale.filtering;

import java.util.function.Function;

Expand Down
Expand Up @@ -4,10 +4,10 @@
* 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.mapping.item;
package com.evolveum.midpoint.repo.sqale.mapping;

import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext;
import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext;
import com.evolveum.midpoint.repo.sqlbase.mapping.ItemRelationResolver;
import com.evolveum.midpoint.repo.sqlbase.mapping.QueryModelMapping;
import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase;

Expand All @@ -17,7 +17,7 @@
* @param <Q> type of source entity path
*/
public class NestedMappingResolver<Q extends FlexibleRelationalPathBase<?>>
implements ItemRelationResolver {
implements SqaleItemRelationResolver {

private final QueryModelMapping<?, Q, ?> mapping;

Expand All @@ -30,4 +30,9 @@ public NestedMappingResolver(QueryModelMapping<?, Q, ?> mapping) {
public ResolutionResult resolve(SqlQueryContext<?, ?, ?> context) {
return new ResolutionResult(context, mapping);
}

@Override
public UpdateResolutionResult resolve(SqaleUpdateContext<?, ?, ?> context) {
return new UpdateResolutionResult(context, mapping);
}
}
@@ -0,0 +1,37 @@
/*
* 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.mapping;

import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext;
import com.evolveum.midpoint.repo.sqlbase.mapping.ItemRelationResolver;
import com.evolveum.midpoint.repo.sqlbase.mapping.QueryModelMapping;

/**
* 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 {

/**
* 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);

class UpdateResolutionResult {
public final SqaleUpdateContext<?, ?, ?> context; // something update related
public final QueryModelMapping<?, ?, ?> mapping;

public UpdateResolutionResult(
SqaleUpdateContext<?, ?, ?> context, QueryModelMapping<?, ?, ?> mapping) {
this.context = context;
this.mapping = mapping;
}
}
}

0 comments on commit 5becd33

Please sign in to comment.