Skip to content

Commit

Permalink
repo-sqale: replacing whole embedded container, still WIP/tests needed
Browse files Browse the repository at this point in the history
EmbeddedContainerDeltaProcessor was added which is now added as part of
nexted mapping. ItemDeltaValueProcessor capabilities were extended from
mere process to setValue+delete to support it.
  • Loading branch information
virgo47 committed Apr 13, 2021
1 parent 5becd33 commit 30d4497
Show file tree
Hide file tree
Showing 24 changed files with 328 additions and 70 deletions.
Expand Up @@ -132,6 +132,9 @@ public SqaleRepositoryService(
// subResult, () -> objectRetriever.getObjectAttempt(type, oid, options, operationResult));
// object = objectLocal;
invokeConflictWatchers((w) -> w.afterGetObject(object));

// TODO both update and get need this?
ObjectTypeUtil.normalizeAllRelations(object, schemaService.relationRegistry());
return object;
} catch (RuntimeException e) { // TODO what else to catch?
throw handledGeneralException(e, operationResult);
Expand Down Expand Up @@ -411,22 +414,20 @@ public <T extends ObjectType> ModifyObjectResult<T> modifyObject(
SqaleUpdateContext<S, Q, R> updateContext = new SqaleUpdateContext<>(
transformerSupport, jdbcSession, prismObject);

// region updatePrismObject: can be extracted as updatePrismObject (not done before CID generation is cleared up)
ItemDeltaCollectionsUtil.applyTo(modifications, prismObject);
ObjectTypeUtil.normalizeAllRelations(prismObject, schemaService.relationRegistry());
// TODO generate missing container IDs, see also old repo PrismIdentifierGenerator
// BWT: it's not enough to do it in prism object, we need it for deltas adding containers too
// endregion

// TODO APPLY modifications HERE (generate update/set clauses)
for (ItemDelta<?, ?> modification : modifications) {
try {
// TODO generate missing container IDs, see also old repo PrismIdentifierGenerator
// BWT: it's not enough to do it in prism object, we need it for deltas adding containers too
modification.applyTo(prismObject);

updateContext.processModification(modification);
} catch (IllegalArgumentException e) {
LOGGER.warn("Modification failed/not implemented yet: {}", e.toString());
}
}

ObjectTypeUtil.normalizeAllRelations(prismObject, schemaService.relationRegistry());
updateContext.execute();
return modifications;
}
Expand Down
Expand Up @@ -43,4 +43,15 @@ protected T transformRealValue(Object realValue) {
//noinspection unchecked
return (T) realValue;
}

/** Sets the database columns to reflect the provided real value. */
public void setRealValue(Object realValue) {
setValue(transformRealValue(realValue));
}

/** Sets the database columns to reflect the provided value (must be transformed if needed). */
public abstract void setValue(T value);

/** Resets the database columns, exposed for the needs of container processing. */
public abstract void delete();
}
Expand Up @@ -35,11 +35,21 @@ public void process(ItemDelta<?, ?> modification) throws RepositoryException {
// See implementation comments in SinglePathItemDeltaProcessor#process for logic details.
PolyString polyString = getAnyValue(modification);
if (modification.isDelete() || polyString == null) {
context.set(origPath, null);
context.set(normPath, null);
delete();
} else {
context.set(origPath, polyString.getOrig());
context.set(normPath, polyString.getNorm());
setValue(polyString);
}
}

@Override
public void setValue(PolyString value) {
context.set(origPath, value.getOrig());
context.set(normPath, value.getNorm());
}

@Override
public void delete() {
context.set(origPath, null);
context.set(normPath, null);
}
}
Expand Up @@ -13,14 +13,14 @@
import com.querydsl.core.types.dsl.EnumPath;
import com.querydsl.core.types.dsl.NumberPath;

import com.evolveum.midpoint.prism.Referencable;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext;
import com.evolveum.midpoint.repo.sqale.qmodel.object.MObjectType;
import com.evolveum.midpoint.repo.sqlbase.RepositoryException;
import com.evolveum.midpoint.repo.sqlbase.querydsl.UuidPath;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;

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

// 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 @@ -49,17 +49,27 @@ public RefItemDeltaProcessor(

@Override
public void process(ItemDelta<?, ?> modification) throws RepositoryException {
ObjectReferenceType ref = getAnyValue(modification);
Referencable ref = getAnyValue(modification);

// See implementation comments in SinglePathItemDeltaProcessor#process for logic details.
if (modification.isDelete() || ref == null) {
context.set(oidPath, null);
context.set(typePath, null);
context.set(relationIdPath, null);
delete();
} else {
context.set(oidPath, UUID.fromString(ref.getOid()));
context.set(typePath, MObjectType.fromTypeQName(ref.getType()));
context.set(relationIdPath, context.processCacheableRelation(ref.getRelation()));
setValue(ref);
}
}

@Override
public void setValue(Referencable value) {
context.set(oidPath, UUID.fromString(value.getOid()));
context.set(typePath, MObjectType.fromTypeQName(value.getType()));
context.set(relationIdPath, context.processCacheableRelation(value.getRelation()));
}

@Override
public void delete() {
context.set(oidPath, null);
context.set(typePath, null);
context.set(relationIdPath, null);
}
}
Expand Up @@ -33,13 +33,25 @@ public SinglePathItemDeltaProcessor(

@Override
public void process(ItemDelta<?, ?> modification) throws RepositoryException {
if (modification.isDelete()) {
T value = getAnyValue(modification);

if (modification.isDelete() || value == null) {
// Repo does not check deleted value for single-value properties.
// This should be handled already by narrowing the modifications.
context.set(path, null);
delete();
} else {
// We treat add and replace the same way for single-value properties.
context.set(path, getAnyValue(modification));
setValue(value);
}
}

@Override
public void setValue(T value) {
context.set(path, value);
}

@Override
public void delete() {
context.set(path, null);
}
}
Expand Up @@ -9,14 +9,14 @@
import com.querydsl.core.types.Predicate;

import com.evolveum.midpoint.prism.query.RefFilter;
import com.evolveum.midpoint.repo.sqale.mapping.SqaleItemSqlMapper;
import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject;
import com.evolveum.midpoint.repo.sqale.qmodel.ref.MReference;
import com.evolveum.midpoint.repo.sqale.qmodel.ref.QObjectReference;
import com.evolveum.midpoint.repo.sqale.qmodel.ref.QObjectReferenceMapping;
import com.evolveum.midpoint.repo.sqale.qmodel.ref.QReference;
import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext;
import com.evolveum.midpoint.repo.sqlbase.filtering.item.ItemFilterProcessor;
import com.evolveum.midpoint.repo.sqlbase.mapping.ItemSqlMapper;

/**
* Filter processor for reference item paths resolved via {@link QReference} tables.
Expand All @@ -26,9 +26,12 @@ public class ObjectRefTableItemFilterProcessor
extends ItemFilterProcessor<RefFilter> {

/** Returns the mapper function creating the ref-filter processor from query context. */
public static ItemSqlMapper mapper(
public static SqaleItemSqlMapper mapper(
QObjectReferenceMapping qReferenceMapping) {
return new ItemSqlMapper(ctx -> new ObjectRefTableItemFilterProcessor(ctx, qReferenceMapping));
return new SqaleItemSqlMapper(
ctx -> new ObjectRefTableItemFilterProcessor(ctx, qReferenceMapping),
ctx -> null // TODO add delta processor
);
}

private final QObjectReferenceMapping qObjectReferenceMapping;
Expand Down
Expand Up @@ -15,6 +15,7 @@
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.item.ItemDeltaValueProcessor;
import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext;
import com.evolveum.midpoint.repo.sqlbase.filtering.item.ItemFilterProcessor;
Expand Down Expand Up @@ -45,7 +46,7 @@ public SqaleItemSqlMapper(
}

/**
* Creates {@link ItemDeltaValueProcessor} based on this mapping.
* Creates {@link ItemDeltaProcessor} based on this mapping.
* Provided {@link SqaleUpdateContext} is used to figure out the query paths when this is
* executed (as the entity path instance is not yet available when the mapping is configured
* in a declarative manner).
Expand Down
@@ -0,0 +1,98 @@
/*
* 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.qmodel;

import java.util.Map;
import javax.xml.namespace.QName;

import com.evolveum.midpoint.prism.Containerable;
import com.evolveum.midpoint.prism.Item;
import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.repo.sqale.SqaleUpdateContext;
import com.evolveum.midpoint.repo.sqale.delta.item.ItemDeltaValueProcessor;
import com.evolveum.midpoint.repo.sqale.mapping.SqaleItemSqlMapper;
import com.evolveum.midpoint.repo.sqlbase.RepositoryException;
import com.evolveum.midpoint.repo.sqlbase.mapping.ItemSqlMapper;

/**
* Processor for embedded containers.
* Due to stateful nature of processing call either {@link #process(ItemDelta)}
* or {@link #delete()} and call it only once - *do not reuse this processor instance*.
*/
public class EmbeddedContainerDeltaProcessor<T extends Containerable>
extends ItemDeltaValueProcessor<T> {

private final SqaleNestedMapping<?, ?, ?> mapping;
private final Map<QName, ItemSqlMapper> mappers; // iterated in a stateful manner

public EmbeddedContainerDeltaProcessor(
SqaleUpdateContext<?, ?, ?> context, SqaleNestedMapping<?, ?, ?> nestedMapping) {
super(context);
this.mapping = nestedMapping;
mappers = mapping.getItemMappings();
}

@Override
public void process(ItemDelta<?, ?> modification) throws RepositoryException {
if (!modification.isDelete()) {
setValue(getAnyValue(modification));
}

// we want to delete values for all mapper unused until now
delete();
}

/**
* Sets the values for items in the PCV that are mapped to database columns.
* Removes entries for used items from the {@link #mappers}.
*/
public void setValue(T value) {
PrismContainerValue<T> pcv = Containerable.asPrismContainerValue(value);
for (Item<?, ?> item : pcv.getItems()) {
ItemSqlMapper mapper = mappers.remove(item.getElementName());
if (mapper == null) {
continue; // ok, not mapped to database
}

if (!(mapper instanceof SqaleItemSqlMapper)) {
throw new IllegalArgumentException("No delta processor available for " + mapper
+ " in mapping " + mapping + "! (Only query mapping is available.)");
}
SqaleItemSqlMapper sqaleMapper = (SqaleItemSqlMapper) mapper;
ItemDeltaValueProcessor<?> processor = sqaleMapper.createItemDeltaProcessor(context);
if (processor == null) {
// TODO this should not happen when all mapper types are covered (e.g. ref tables)
System.out.println("PROCESSOR NULL for: " + sqaleMapper);
return;
}
processor.setRealValue(item.getAnyValue().getRealValue());
}
}

@Override
public void delete() {
for (ItemSqlMapper mapper : mappers.values()) {
deleteUsing(mapper);
}
}

private void deleteUsing(ItemSqlMapper mapper) {
if (!(mapper instanceof SqaleItemSqlMapper)) {
throw new IllegalArgumentException("No delta processor available for " + mapper
+ " in mapping " + mapping + "! (Only query mapping is available.)");
}
SqaleItemSqlMapper sqaleMapper = (SqaleItemSqlMapper) mapper;
ItemDeltaValueProcessor<?> processor = sqaleMapper.createItemDeltaProcessor(context);
if (processor == null) {
// TODO this should not happen when all mapper types are covered (e.g. ref tables)
System.out.println("PROCESSOR NULL for: " + sqaleMapper);
return;
}
processor.delete();
}
}
Expand Up @@ -39,6 +39,7 @@ public SqaleNestedMapping<S, Q, R> addItemMapping(
}

// TODO will the version for RefItemFilterProcessor be useful too? Yes, if it needs relation mapping too!

public final SqaleNestedMapping<S, Q, R> addRefMapping(
@NotNull QName itemName, @NotNull QObjectReferenceMapping qReferenceMapping) {
((QueryModelMapping<?, ?, ?>) this).addItemMapping(itemName,
Expand Down

0 comments on commit 30d4497

Please sign in to comment.