Skip to content

Commit

Permalink
repo-sqale: finished assignment ref insertion + test
Browse files Browse the repository at this point in the history
This required another refactoring and another generics battle:
- Ref mapping is aware of Q-type for the owner now as well.
- Context in filter processors and mapping in transformers was stored
all the way up in the hierarchy, this is not flexible, we will store
it at the level where the type is most specific (this is started, WIP).
- QAssignmentReference constructor now takes table name as it should.
- Ref mapping instances for "abstract" tables are accessed via methods
that fix their parametrized types to conform to the current instance.
  • Loading branch information
virgo47 committed Apr 20, 2021
1 parent f5fe678 commit 14b8515
Show file tree
Hide file tree
Showing 20 changed files with 227 additions and 90 deletions.
Expand Up @@ -15,14 +15,16 @@
import com.evolveum.midpoint.repo.sqale.qmodel.ref.QReference;
import com.evolveum.midpoint.repo.sqale.qmodel.ref.QReferenceMapping;
import com.evolveum.midpoint.repo.sqale.qmodel.ref.ReferenceSqlTransformer;
import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase;

public class RefTableItemDeltaProcessor<Q extends QReference<?>, OR> extends ItemDeltaValueProcessor<Referencable> {
public class RefTableItemDeltaProcessor<Q extends QReference<?>, OQ extends FlexibleRelationalPathBase<OR>, OR>
extends ItemDeltaValueProcessor<Referencable> {

private final QReferenceMapping<Q, ?, OR> refTableMapping;
private final QReferenceMapping<Q, ?, OQ, OR> refTableMapping;

public RefTableItemDeltaProcessor(
SqaleUpdateContext<?, ?, ?> context, // TODO OR as last here as well
QReferenceMapping<Q, ?, OR> refTableMapping) {
QReferenceMapping<Q, ?, OQ, OR> refTableMapping) {
super(context);
this.refTableMapping = refTableMapping;
}
Expand Down
Expand Up @@ -9,36 +9,35 @@
import com.querydsl.core.types.Predicate;

import com.evolveum.midpoint.prism.query.RefFilter;
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.sqale.qmodel.ref.QReferenceMapping;
import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext;
import com.evolveum.midpoint.repo.sqlbase.filtering.item.ItemFilterProcessor;
import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase;

/**
* Filter processor for reference item paths resolved via {@link QReference} tables.
* This just joins the reference table and then delegates to {@link RefItemFilterProcessor}.
*/
public class RefTableItemFilterProcessor
public class RefTableItemFilterProcessor<Q extends QReference<R>, R extends MReference,
OQ extends FlexibleRelationalPathBase<OR>, OR>
extends ItemFilterProcessor<RefFilter> {

private final QObjectReferenceMapping qObjectReferenceMapping;
private final SqlQueryContext<?, OQ, OR> context;
private final QReferenceMapping<Q, R, OQ, OR> referenceMapping;

public RefTableItemFilterProcessor(
SqlQueryContext<?, ?, ?> context, QObjectReferenceMapping qObjectReferenceMapping) {
SqlQueryContext<?, OQ, OR> context, QReferenceMapping<Q, R, OQ, OR> referenceMapping) {
super(context);
this.qObjectReferenceMapping = qObjectReferenceMapping;
this.context = context;
this.referenceMapping = referenceMapping;
}

@Override
public Predicate process(RefFilter filter) {
// the cast is NOT redundant really (IDEA thinks so), it's needed for "o" in lambda
@SuppressWarnings({ "RedundantCast", "unchecked" })
SqlQueryContext<?, QObjectReference, MReference> refContext =
((SqlQueryContext<?, QObject<?>, ?>) context)
.leftJoin(qObjectReferenceMapping, (o, r) -> o.oid.eq(r.ownerOid));
SqlQueryContext<?, Q, R> refContext =
context.leftJoin(referenceMapping, referenceMapping.joinOnPredicate());
QReference<?> ref = refContext.path();

return new RefItemFilterProcessor(context, ref.targetOid, ref.targetType, ref.relationId)
Expand Down
Expand Up @@ -18,9 +18,12 @@
public class ObjectTemplateSqlTransformer
extends ObjectSqlTransformer<ObjectTemplateType, QObjectTemplate, MObject> {

private final QObjectTemplateMapping mapping;

public ObjectTemplateSqlTransformer(
SqlTransformerSupport transformerSupport, QObjectTemplateMapping mapping) {
super(transformerSupport, mapping);
this.mapping = mapping;
}

@Override
Expand Down
Expand Up @@ -18,7 +18,8 @@
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.qmodel.ref.QObjectReferenceMapping;
import com.evolveum.midpoint.repo.sqale.qmodel.ref.QReferenceMapping;
import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext;
import com.evolveum.midpoint.repo.sqlbase.mapping.ItemRelationResolver;
import com.evolveum.midpoint.repo.sqlbase.mapping.ItemSqlMapper;
import com.evolveum.midpoint.repo.sqlbase.mapping.QueryModelMapping;
Expand Down Expand Up @@ -61,12 +62,20 @@ default <N extends Containerable> SqaleNestedMapping<N, Q, R> addNestedMapping(
return nestedMapping;
}

/** Defines reference mapping for both query and modifications. */
/**
* Defines reference mapping for both query and modifications.
* Reference mapping is assumed to be `QReferenceMapping<?, ?, Q, R>` really, but because
* the instances of reference mapping are not typed flexibly enough, wildcard is used for
* parameter for client code convenience.
*/
default SqaleMappingMixin<S, Q, R> addRefMapping(
@NotNull QName itemName, @NotNull QObjectReferenceMapping qReferenceMapping) {
@NotNull QName itemName, @NotNull QReferenceMapping<?, ?, Q, R> referenceMapping) {
//noinspection unchecked
addItemMapping(itemName, new SqaleItemSqlMapper(
ctx -> new RefTableItemFilterProcessor(ctx, qReferenceMapping),
ctx -> new RefTableItemDeltaProcessor(ctx, qReferenceMapping)));
ctx -> new RefTableItemFilterProcessor<>(
(SqlQueryContext<?, Q, R>) ctx, referenceMapping),
ctx -> new RefTableItemDeltaProcessor<>(ctx, referenceMapping)));

// TODO add relation mapping too for reaching to the reference target
return this;
}
Expand Down
Expand Up @@ -7,25 +7,21 @@
package com.evolveum.midpoint.repo.sqale.qmodel;

import java.util.function.Function;
import javax.xml.namespace.QName;

import com.querydsl.core.types.EntityPath;
import com.querydsl.core.types.dsl.*;
import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.repo.sqale.delta.item.*;
import com.evolveum.midpoint.repo.sqale.filtering.RefItemFilterProcessor;
import com.evolveum.midpoint.repo.sqale.filtering.RefTableItemFilterProcessor;
import com.evolveum.midpoint.repo.sqale.filtering.UriItemFilterProcessor;
import com.evolveum.midpoint.repo.sqale.mapping.SqaleItemSqlMapper;
import com.evolveum.midpoint.repo.sqale.qmodel.object.MObjectType;
import com.evolveum.midpoint.repo.sqale.qmodel.object.QObject;
import com.evolveum.midpoint.repo.sqale.qmodel.ref.QObjectReferenceMapping;
import com.evolveum.midpoint.repo.sqlbase.filtering.item.EnumItemFilterProcessor;
import com.evolveum.midpoint.repo.sqlbase.filtering.item.PolyStringItemFilterProcessor;
import com.evolveum.midpoint.repo.sqlbase.filtering.item.SimpleItemFilterProcessor;
import com.evolveum.midpoint.repo.sqlbase.filtering.item.TimestampItemFilterProcessor;
import com.evolveum.midpoint.repo.sqlbase.mapping.QueryModelMapping;
import com.evolveum.midpoint.repo.sqlbase.mapping.QueryTableMapping;
import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase;
import com.evolveum.midpoint.repo.sqlbase.querydsl.UuidPath;
Expand Down
Expand Up @@ -60,6 +60,10 @@ protected SqaleTransformerBase(
this.mapping = mapping;
}

public QueryTableMapping<S, Q, R> mapping() {
return mapping;
}

@Override
public S toSchemaObject(R row) {
throw new UnsupportedOperationException("Use toSchemaObject(Tuple,...)");
Expand Down Expand Up @@ -191,9 +195,9 @@ protected void setReference(ObjectReferenceType ref, JdbcSession jdbcSession,
}
}

protected <REF extends MReference, OR> void storeRefs(
protected <REF extends MReference, OQ extends FlexibleRelationalPathBase<OR>, OR> void storeRefs(
@NotNull OR ownerRow, @NotNull List<ObjectReferenceType> refs,
@NotNull QReferenceMapping<?, REF, OR> mapping, @NotNull JdbcSession jdbcSession) {
@NotNull QReferenceMapping<?, REF, OQ, OR> mapping, @NotNull JdbcSession jdbcSession) {
if (!refs.isEmpty()) {
ReferenceSqlTransformer<?, REF, OR> transformer =
mapping.createTransformer(transformerSupport);
Expand All @@ -210,7 +214,7 @@ protected String[] arrayFor(List<String> strings) {

/** Convenient insert shortcut when the row is fully populated. */
protected void insert(R row, JdbcSession jdbcSession) {
jdbcSession.newInsert(mapping.defaultAlias())
jdbcSession.newInsert(mapping().defaultAlias())
.populate(row)
.execute();
}
Expand Down
Expand Up @@ -29,8 +29,8 @@ public class QAssignmentReference extends QReference<MAssignmentReference> {
public final PrimaryKey<MAssignmentReference> pk =
createPrimaryKey(ownerOid, assignmentCid, referenceType, relationId, targetOid);

public QAssignmentReference(String variable) {
this(variable, DEFAULT_SCHEMA_NAME, TABLE_NAME);
public QAssignmentReference(String variable, String tableName) {
this(variable, DEFAULT_SCHEMA_NAME, tableName);
}

public QAssignmentReference(String variable, String schema, String table) {
Expand Down
Expand Up @@ -15,7 +15,7 @@
* The mapping is the same for all subtypes, see different `INSTANCE_*` constants below.
*/
public class QAssignmentReferenceMapping
extends QReferenceMapping<QAssignmentReference, MAssignmentReference, MAssignment> {
extends QReferenceMapping<QAssignmentReference, MAssignmentReference, QAssignment, MAssignment> {

public static final QAssignmentReferenceMapping INSTANCE_ASSIGNMENT_CREATE_APPROVER =
new QAssignmentReferenceMapping("m_assignment_ref_create_approver", "arefca");
Expand All @@ -30,7 +30,7 @@ private QAssignmentReferenceMapping(String tableName, String defaultAliasName) {

@Override
protected QAssignmentReference newAliasInstance(String alias) {
return new QAssignmentReference(alias);
return new QAssignmentReference(alias, tableName());
}

@Override
Expand Down
Expand Up @@ -9,7 +9,6 @@
import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.repo.sqale.qmodel.object.ObjectSqlTransformer;
import com.evolveum.midpoint.repo.sqale.qmodel.ref.QObjectReferenceMapping;
import com.evolveum.midpoint.repo.sqlbase.JdbcSession;
import com.evolveum.midpoint.repo.sqlbase.SqlTransformerSupport;
import com.evolveum.midpoint.util.MiscUtil;
Expand All @@ -18,9 +17,12 @@
public class FocusSqlTransformer<S extends FocusType, Q extends QFocus<R>, R extends MFocus>
extends ObjectSqlTransformer<S, Q, R> {

private final QFocusMapping<S, Q, R> mapping;

public FocusSqlTransformer(
SqlTransformerSupport transformerSupport, QFocusMapping<S, Q, R> mapping) {
super(transformerSupport, mapping);
this.mapping = mapping;
}

@SuppressWarnings("DuplicatedCode") // activation code duplicated with assignment
Expand Down Expand Up @@ -77,8 +79,8 @@ public void storeRelatedEntities(
super.storeRelatedEntities(row, schemaObject, jdbcSession);

storeRefs(row, schemaObject.getLinkRef(),
QObjectReferenceMapping.INSTANCE_PROJECTION, jdbcSession);
mapping.projectionReferenceMapping(), jdbcSession);
storeRefs(row, schemaObject.getPersonaRef(),
QObjectReferenceMapping.INSTANCE_PERSONA, jdbcSession);
mapping.personaReferenceMapping(), jdbcSession);
}
}
Expand Up @@ -80,9 +80,20 @@ protected QFocusMapping(
.addItemMapping(ActivationType.F_LOCKOUT_STATUS,
enumMapper(path(q -> q.lockoutStatus)));

addRefMapping(F_DELEGATED_REF, QObjectReferenceMapping.INSTANCE_DELEGATED);
addRefMapping(F_PERSONA_REF, QObjectReferenceMapping.INSTANCE_PERSONA);
addRefMapping(F_LINK_REF, QObjectReferenceMapping.INSTANCE_PROJECTION);
addRefMapping(F_PERSONA_REF, personaReferenceMapping());
addRefMapping(F_LINK_REF, projectionReferenceMapping());
}

/** Fixes rigid parametric types of static mapping instance to this instance. */
public @NotNull QObjectReferenceMapping<Q, R> personaReferenceMapping() {
//noinspection unchecked
return (QObjectReferenceMapping<Q, R>) QObjectReferenceMapping.INSTANCE_PERSONA;
}

/** Fixes rigid parametric types of static mapping instance to this instance. */
public @NotNull QObjectReferenceMapping<Q, R> projectionReferenceMapping() {
//noinspection unchecked
return (QObjectReferenceMapping<Q, R>) QObjectReferenceMapping.INSTANCE_PROJECTION;
}

@Override
Expand Down
Expand Up @@ -19,9 +19,12 @@ public class ContainerSqlTransformer
<S extends Containerable, Q extends QContainer<R>, R extends MContainer>
extends SqaleTransformerBase<S, Q, R> {

private final QContainerMapping<S, Q, R> mapping;

public ContainerSqlTransformer(
SqlTransformerSupport transformerSupport, QContainerMapping<S, Q, R> mapping) {
super(transformerSupport, mapping);
this.mapping = mapping;
}

/**
Expand Down
Expand Up @@ -23,7 +23,6 @@
import com.evolveum.midpoint.repo.sqale.qmodel.assignment.AssignmentSqlTransformer;
import com.evolveum.midpoint.repo.sqale.qmodel.assignment.QAssignmentMapping;
import com.evolveum.midpoint.repo.sqale.qmodel.common.QUri;
import com.evolveum.midpoint.repo.sqale.qmodel.ref.QObjectReferenceMapping;
import com.evolveum.midpoint.repo.sqlbase.JdbcSession;
import com.evolveum.midpoint.repo.sqlbase.SqlTransformerSupport;
import com.evolveum.midpoint.schema.GetOperationOptions;
Expand All @@ -36,10 +35,13 @@
public class ObjectSqlTransformer<S extends ObjectType, Q extends QObject<R>, R extends MObject>
extends SqaleTransformerBase<S, Q, R> {

private final QObjectMapping<S, Q, R> mapping;

public ObjectSqlTransformer(
SqlTransformerSupport transformerSupport,
QObjectMapping<S, Q, R> mapping) {
super(transformerSupport, mapping);
this.mapping = mapping;
}

@Override
Expand All @@ -64,7 +66,7 @@ public S toSchemaObject(Tuple row, Q entityPath,
// This is a serious thing. We have corrupted XML in the repo. This may happen even
// during system init. We want really loud and detailed error here.
logger.error("Couldn't parse object {} {}: {}: {}\n{}",
mapping.schemaType().getSimpleName(), row.get(entityPath.oid),
mapping().schemaType().getSimpleName(), row.get(entityPath.oid),
e.getClass().getName(), e.getMessage(), serializedForm, e);
throw e;
}
Expand All @@ -86,7 +88,7 @@ public S toSchemaObject(Tuple row, Q entityPath,
@SuppressWarnings("DuplicatedCode") // see comment for metadata lower
@NotNull
public R toRowObjectWithoutFullObject(S schemaObject, JdbcSession jdbcSession) {
R row = mapping.newRowObject();
R row = mapping().newRowObject();

row.oid = oidToUUid(schemaObject.getOid());
// objectType MUST be left NULL, it's determined by PG
Expand Down Expand Up @@ -146,9 +148,9 @@ public void storeRelatedEntities(
MetadataType metadata = schemaObject.getMetadata();
if (metadata != null) {
storeRefs(row, metadata.getCreateApproverRef(),
QObjectReferenceMapping.INSTANCE_OBJECT_CREATE_APPROVER, jdbcSession);
mapping.objectCreateApproverReferenceMapping(), jdbcSession);
storeRefs(row, metadata.getModifyApproverRef(),
QObjectReferenceMapping.INSTANCE_OBJECT_MODIFY_APPROVER, jdbcSession);
mapping.objectModifyApproverReferenceMapping(), jdbcSession);
}

List<TriggerType> triggers = schemaObject.getTrigger();
Expand All @@ -165,7 +167,8 @@ public void storeRelatedEntities(
operationExecutions.forEach(oe -> transformer.insert(oe, row, jdbcSession));
}

// schemaObject.getParentOrgRef() TODO
storeRefs(row, schemaObject.getParentOrgRef(),
mapping.objectParentOrgReferenceMapping(), jdbcSession);

if (schemaObject instanceof AssignmentHolderType) {
storeAssignmentHolderEntities(row, (AssignmentHolderType) schemaObject, jdbcSession);
Expand All @@ -179,7 +182,7 @@ public void storeRelatedEntities(
}

private void storeAssignmentHolderEntities(
MObject row, AssignmentHolderType schemaObject, JdbcSession jdbcSession) {
R row, AssignmentHolderType schemaObject, JdbcSession jdbcSession) {
List<AssignmentType> assignments = schemaObject.getAssignment();
if (!assignments.isEmpty()) {
AssignmentSqlTransformer transformer =
Expand All @@ -188,12 +191,12 @@ private void storeAssignmentHolderEntities(
transformer.insert(assignment, row, jdbcSession));
}

storeRefs(row, schemaObject.getRoleMembershipRef(),
QObjectReferenceMapping.INSTANCE_ROLE_MEMBERSHIP, jdbcSession);
storeRefs(row, schemaObject.getDelegatedRef(),
QObjectReferenceMapping.INSTANCE_DELEGATED, jdbcSession);
storeRefs(row, schemaObject.getArchetypeRef(),
QObjectReferenceMapping.INSTANCE_ARCHETYPE, jdbcSession);
mapping.archetypeReferenceMapping(), jdbcSession);
storeRefs(row, schemaObject.getDelegatedRef(),
mapping.delegatedReferenceMapping(), jdbcSession);
storeRefs(row, schemaObject.getRoleMembershipRef(),
mapping.roleMembershipReferenceMapping(), jdbcSession);
}

/**
Expand Down

0 comments on commit 14b8515

Please sign in to comment.