Skip to content

Commit

Permalink
sqale: Added support for orderBy extension item
Browse files Browse the repository at this point in the history
  • Loading branch information
tonydamage committed Aug 11, 2021
1 parent 5e26545 commit 3a7ab28
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 34 deletions.
Expand Up @@ -6,13 +6,19 @@
*/
package com.evolveum.midpoint.repo.sqale.mapping;

import static com.querydsl.core.types.dsl.Expressions.stringTemplate;

import java.util.function.Function;

import com.querydsl.core.types.Path;
import com.querydsl.core.types.Expression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.query.ValueFilter;
import com.evolveum.midpoint.repo.sqale.ExtensionProcessor;
import com.evolveum.midpoint.repo.sqale.ExtensionProcessor.ExtItemInfo;
import com.evolveum.midpoint.repo.sqale.SqaleRepoContext;
import com.evolveum.midpoint.repo.sqale.delta.ItemDeltaProcessor;
import com.evolveum.midpoint.repo.sqale.delta.item.ExtensionItemDeltaProcessor;
import com.evolveum.midpoint.repo.sqale.filtering.ExtensionItemFilterProcessor;
Expand All @@ -38,24 +44,27 @@ public class ExtensionItemSqlMapper<Q extends FlexibleRelationalPathBase<R>, R>

private final Function<Q, JsonbPath> rootToExtensionPath;
private final MExtItemHolderType holderType;
private @NotNull SqaleRepoContext repositoryContext;

public ExtensionItemSqlMapper(
@NotNull Function<Q, JsonbPath> rootToExtensionPath,
@NotNull MExtItemHolderType holderType) {
@NotNull MExtItemHolderType holderType,
@NotNull SqaleRepoContext context) {
this.rootToExtensionPath = rootToExtensionPath;
this.holderType = holderType;
this.repositoryContext = context;
}

@Override
public @Nullable Path<?> itemPrimaryPath(Q entityPath) {
// TODO this currently does NOT work because:
// - sorting by ext does not make sense, we want to sort by ext->something (or ->>)
// - that also means that we don't want to return Path but Expression instead
// - but sorting by ext/something is not yet supported in SqlQueryContext.processOrdering
// In short, we will not even get here
return rootToExtensionPath.apply(entityPath);
public @Nullable Expression<?> itemOrdering(Q entityPath, ItemDefinition<?> definition) {

JsonbPath path = rootToExtensionPath.apply(entityPath);
ExtItemInfo info = new ExtensionProcessor(repositoryContext).findExtensionItem(definition, holderType);
// TODO: Is polystring ordered by normalized or original form?
return stringTemplate("{0}->'{1s}'", path, info.getId());
}


@Override
public @Nullable <T extends ValueFilter<?, ?>> ItemValueFilterProcessor<T> createFilterProcessor(
SqlQueryContext<?, ?, ?> sqlQueryContext) {
Expand Down
Expand Up @@ -13,6 +13,7 @@
import org.jetbrains.annotations.Nullable;

import com.evolveum.midpoint.prism.Containerable;
import com.evolveum.midpoint.repo.sqale.SqaleRepoContext;
import com.evolveum.midpoint.repo.sqale.jsonb.JsonbPath;
import com.evolveum.midpoint.repo.sqale.qmodel.ext.MExtItemHolderType;
import com.evolveum.midpoint.repo.sqlbase.mapping.ItemSqlMapper;
Expand All @@ -38,11 +39,12 @@ public class ExtensionMapping<Q extends FlexibleRelationalPathBase<R>, R>
protected ExtensionMapping(
@NotNull MExtItemHolderType holderType,
@NotNull Class<Q> queryType,
@NotNull Function<Q, JsonbPath> rootToExtensionPath) {
@NotNull Function<Q, JsonbPath> rootToExtensionPath,
SqaleRepoContext context) {
super(Containerable.class, queryType);

this.holderType = holderType;
this.itemMapper = new ExtensionItemSqlMapper<>(rootToExtensionPath, holderType);
this.itemMapper = new ExtensionItemSqlMapper<>(rootToExtensionPath, holderType, context);
}

@Override
Expand Down
Expand Up @@ -106,6 +106,7 @@ protected SqaleTableMapping(
@NotNull Class<Q> queryType,
@NotNull SqaleRepoContext repositoryContext) {
super(tableName, defaultAliasName, schemaType, queryType, repositoryContext);

}

@Override
Expand Down Expand Up @@ -238,7 +239,7 @@ protected ItemSqlMapper<Q, R> multiUriMapper(
ctx, rootToQueryItem, "INTEGER", Integer.class,
((SqaleRepoContext) ctx.repositoryContext())::searchCachedUriId),
ctx -> new ArrayItemDeltaProcessor<>(ctx, rootToQueryItem, Integer.class,
((SqaleRepoContext) ctx.repositoryContext())::processCacheableUri));
ctx.repositoryContext()::processCacheableUri));
}

/**
Expand Down Expand Up @@ -404,7 +405,7 @@ public void addExtensionMapping(
@NotNull MExtItemHolderType holderType,
@NotNull Function<Q, JsonbPath> rootToPath) {
ExtensionMapping<Q, R> mapping =
new ExtensionMapping<>(holderType, queryType(), rootToPath);
new ExtensionMapping<>(holderType, queryType(), rootToPath, repositoryContext());
addRelationResolver(itemName, new ExtensionMappingResolver<>(mapping, rootToPath));
addItemMapping(itemName, new SqaleItemSqlMapper<>(
ctx -> new ExtensionContainerDeltaProcessor<>(ctx, mapping, rootToPath)));
Expand Down
Expand Up @@ -996,7 +996,7 @@ public void test502SearchObjectWithoutExtensionStringItem() throws SchemaExcepti
creatorOid, modifierOid, user3Oid, user4Oid);
}

@Test(enabled = false) // TODO missing feature order by complex paths, see SqlQueryContext.processOrdering
@Test() // TODO missing feature order by complex paths, see SqlQueryContext.processOrdering
public void test503SearchObjectWithAnyValueForExtensionItemOrderedByIt() throws SchemaException {
searchUsersTest("with extension string item with any value ordered by that item",
f -> f.not()
Expand Down
Expand Up @@ -21,8 +21,12 @@
import com.querydsl.sql.SQLQuery;
import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.PrismConstants;
import com.evolveum.midpoint.prism.PrismContainerDefinition;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.path.CanonicalItemPath;
import com.evolveum.midpoint.prism.path.ItemName;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.*;
import com.evolveum.midpoint.repo.sqlbase.filtering.FilterProcessor;
Expand Down Expand Up @@ -205,35 +209,45 @@ private void processOrdering(List<? extends ObjectOrdering> orderings)
throws RepositoryException {
for (ObjectOrdering ordering : orderings) {
ItemPath orderByItemPath = ordering.getOrderBy();
Path<?> path = orderingPath(orderByItemPath);
if (!(path instanceof ComparableExpressionBase)) {
Expression<?> expression = orderingPath(orderByItemPath);
if (!(expression instanceof ComparableExpressionBase)) {
throw new QueryException(
"ORDER BY is not possible for non-comparable path: " + orderByItemPath);
}

if (ordering.getDirection() == OrderDirection.DESCENDING) {
sqlQuery.orderBy(((ComparableExpressionBase<?>) path).desc());
sqlQuery.orderBy(((ComparableExpressionBase<?>) expression).desc());
} else {
sqlQuery.orderBy(((ComparableExpressionBase<?>) path).asc());
sqlQuery.orderBy(((ComparableExpressionBase<?>) expression).asc());
}
}
}

private Path<?> orderingPath(ItemPath orderByItemPath) throws RepositoryException {
private Expression<?> orderingPath(ItemPath orderByItemPath) throws RepositoryException {
ItemPath path = orderByItemPath;
QueryModelMapping<?, ?, ?> current = entityPathMapping;
PrismContainerDefinition<?> container = (PrismContainerDefinition<?>) entityPathMapping.itemDefinition();
// TODO to support ordering by ext/something we need to implement correctly itemPrimaryPath in ExtensionMapping
// That may not even require cache for JOIN because it should be allowed only for
// single-value containers embedded in the object.
while (path.size() > 1) {
ItemRelationResolver resolver = current.relationResolver(path);
ItemRelationResolver resolver = current.relationResolver(path); // Resolves only first element
ItemRelationResolver.ResolutionResult<?, ?> resolution = resolver.resolve(this);
current = resolution.mapping;
container = container.findLocalItemDefinition(path.firstToName(), PrismContainerDefinition.class, false);
// TODO: Throw when subquery true?
path = path.rest();
}
ItemSqlMapper mapper = current.itemMapper(path.firstToName());
return mapper.itemPrimaryPath(entityPath);

ItemName itemName = path.firstToName();
final ItemDefinition<?> definition;
if (PrismConstants.T_ID.equals(itemName)) {
definition = null;
} else {
definition = container.findItemDefinition(itemName);
}
ItemSqlMapper mapper = current.itemMapper(itemName);
return mapper.itemOrdering(entityPath, definition);
}

/**
Expand Down
Expand Up @@ -13,6 +13,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.query.ValueFilter;
import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext;
import com.evolveum.midpoint.repo.sqlbase.filtering.FilterProcessor;
Expand Down Expand Up @@ -61,7 +62,8 @@ public DefaultItemSqlMapper(
this(filterProcessorFactory, null);
}

public @Nullable Path<?> itemPrimaryPath(Q root) {
@Override
public @Nullable Path<?> itemOrdering(Q root, ItemDefinition<?> itemName) {
return primaryItemMapping != null ? primaryItemMapping.apply(root) : null;
}

Expand All @@ -78,10 +80,11 @@ public DefaultItemSqlMapper(
* This may return null if the subclass supports other type of mapping for this item,
* but not filtering for queries.
*/
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public @Nullable <T extends ValueFilter<?, ?>> ItemValueFilterProcessor<T> createFilterProcessor(
SqlQueryContext<?, ?, ?> sqlQueryContext) {
return (ItemValueFilterProcessor<T>) filterProcessorFactory
return filterProcessorFactory
.apply((SqlQueryContext) sqlQueryContext);
}
}
Expand Up @@ -6,9 +6,11 @@
*/
package com.evolveum.midpoint.repo.sqlbase.mapping;

import com.querydsl.core.types.Path;
import com.querydsl.core.types.Expression;

import org.jetbrains.annotations.Nullable;

import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.query.ValueFilter;
import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext;
import com.evolveum.midpoint.repo.sqlbase.filtering.item.ItemValueFilterProcessor;
Expand All @@ -24,7 +26,7 @@
public interface ItemSqlMapper<Q extends FlexibleRelationalPathBase<R>, R> {

/** Returns primary path for provided entity path - usable for ordering. */
@Nullable Path<?> itemPrimaryPath(Q entityPath);
@Nullable Expression<?> itemOrdering(Q entityPath, ItemDefinition<?> definition);

/**
* Creates {@link ItemValueFilterProcessor} based on this mapping.
Expand Down
Expand Up @@ -21,12 +21,11 @@
import com.querydsl.core.types.dsl.StringPath;
import com.querydsl.sql.ColumnMetadata;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.path.ItemName;
import com.evolveum.midpoint.repo.sqlbase.QueryException;
import com.evolveum.midpoint.repo.sqlbase.RepositoryException;
import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext;
import com.evolveum.midpoint.repo.sqlbase.SqlRepoContext;
import com.evolveum.midpoint.repo.sqlbase.filtering.item.PolyStringItemFilterProcessor;
Expand Down Expand Up @@ -78,6 +77,7 @@ public abstract class QueryTableMapping<S, Q extends FlexibleRelationalPathBase<

/** Instantiated lazily as needed, see {@link #defaultAlias()}. */
private Q defaultAlias;
private ItemDefinition<?> itemDefinition;

/**
* Creates metamodel for the table described by designated type (Q-class) related to schema type.
Expand All @@ -98,6 +98,7 @@ protected QueryTableMapping(
this.tableName = tableName;
this.defaultAliasName = defaultAliasName;
this.repositoryContext = repositoryContext;
this.itemDefinition = repositoryContext.prismContext().getSchemaRegistry().findItemDefinitionByCompileTimeClass(schemaType, ItemDefinition.class);
}

/**
Expand Down Expand Up @@ -194,12 +195,6 @@ protected <TQ extends FlexibleRelationalPathBase<TR>, TR> BiFunction<Q, TQ, Pred
return joinOnPredicateFunction;
}

public final @Nullable Path<?> primarySqlPath(
QName itemName, SqlQueryContext<S, Q, R> context)
throws RepositoryException {
return itemMapper(itemName).itemPrimaryPath(context.path());
}

public String tableName() {
return tableName;
}
Expand Down Expand Up @@ -349,4 +344,8 @@ public String toString() {
", queryType=" + queryType() +
'}';
}

public Object itemDefinition() {
return itemDefinition;
}
}

0 comments on commit 3a7ab28

Please sign in to comment.