use of com.evolveum.midpoint.prism.query.builder.S_ConditionEntry in project midpoint by Evolveum.
the class SqaleAuditService method iterativeSearchCondition.
/**
* Similar to {@link SqaleRepositoryService#lastOidCondition}.
*
* TODO, lots of possible improvements:
*
* * Just like in repo iterative search this is added to the original filter with `AND`.
* However, if `timestamp` is used in the original filter, it could be replaced by stricter
* `timestamp` condition based on the `lastProcessedObject` - this is not implemented yet.
* ** TODO: If provided, do we want to add another timestamp condition?
* Would it help with partitions?
* Probably, with ID condition + ordering, it's not a big deal to leave it out.
*
* * Support for multiple order specifications from the client is not supported.
* Perhaps some short-term stateful filter/order object would be better to construct this,
* especially if it could be used in both repo and audit (with strict order attribute
* provided in constructor for example).
*
* [NOTE]
* ====
* Both `timestamp` and `repoId` is used for iterative search condition, but *only `repoId`*
* is used for additional ordering to assure strict reliable ordering.
* This can be further complicated by the fact that both `repoId` and `timestamp`
* can be part of custom ordering from client (this is different from repository, where `oid`
* is not valid for filter and ordering on the model level, even when it's usable for repository).
* If used on the top-level `AND` group, they can be be replaced by next iteration condition,
* which is likely more selective.
*
* As for the ordering, if multiple ordering is used (*not supported yet*) if `repoId` is used,
* anything after it can be omitted as irrelevant.
* ====
*
* TODO: Currently, single path ordering is supported. Finish multi-path too.
* TODO: What about nullable columns?
*/
@Nullable
private ObjectFilter iterativeSearchCondition(@Nullable AuditEventRecordType lastProcessedObject, List<? extends ObjectOrdering> providedOrdering) {
if (lastProcessedObject == null) {
return null;
}
// TODO inspect originalFilter to detect timestamp/repoId conditions.
// Only top level AND filter should be checked, anything else is irrelevant
// for the decision whether to skip additional timestamp condition.
// BTW: We CANNOT skip repoId condition, that one is CRITICAL for proper iterating.
Long lastProcessedId = lastProcessedObject.getRepoId();
XMLGregorianCalendar lastProcessedTimestamp = lastProcessedObject.getTimestamp();
if (providedOrdering == null || providedOrdering.isEmpty()) {
return prismContext().queryFor(AuditEventRecordType.class).item(AuditEventRecordType.F_REPO_ID).gt(lastProcessedId).and().item(AuditEventRecordType.F_TIMESTAMP).ge(lastProcessedTimestamp).buildFilter();
}
if (providedOrdering.size() == 1) {
ObjectOrdering objectOrdering = providedOrdering.get(0);
ItemPath orderByPath = objectOrdering.getOrderBy();
boolean asc = objectOrdering.getDirection() == OrderDirection.ASCENDING;
S_ConditionEntry filter = prismContext().queryFor(AuditEventRecordType.class).item(orderByPath);
@SuppressWarnings("unchecked") Item<PrismValue, ItemDefinition<?>> item = lastProcessedObject.asPrismContainerValue().findItem(orderByPath);
if (item.size() > 1) {
throw new IllegalArgumentException("Multi-value property for ordering is forbidden - item: " + item);
} else if (item.isEmpty()) {
// TODO what if it's nullable? is it null-first or last?
// See: https://www.postgresql.org/docs/13/queries-order.html
// "By default, null values sort as if larger than any non-null value; that is,
// NULLS FIRST is the default for DESC order, and NULLS LAST otherwise."
} else {
S_MatchingRuleEntry matchingRuleEntry = asc ? filter.gt(item.getRealValue()) : filter.lt(item.getRealValue());
filter = matchingRuleEntry.or().block().item(orderByPath).eq(item.getRealValue()).and().item(AuditEventRecordType.F_REPO_ID);
return (asc ? filter.gt(lastProcessedId) : filter.lt(lastProcessedId)).endBlock().buildFilter();
}
}
throw new IllegalArgumentException("Shouldn't get here with check in executeSearchObjectsIterative()");
}
use of com.evolveum.midpoint.prism.query.builder.S_ConditionEntry in project midpoint by Evolveum.
the class ValueSearchFilterItem method buildFilter.
public ObjectFilter buildFilter(PrismContext prismContext, Class<O> type) {
S_ConditionEntry conditionEntry = prismContext.queryFor(type).item(propertyPath);
ObjectFilter builtFilter = null;
if (FilterName.EQUAL.equals(filterTypeName)) {
builtFilter = conditionEntry.eq(value).buildFilter();
} else if (FilterName.GREATER.equals(filterTypeName)) {
builtFilter = conditionEntry.gt(value).buildFilter();
} else if (FilterName.GREATER_OR_EQUAL.equals(filterTypeName)) {
builtFilter = conditionEntry.ge(value).buildFilter();
} else if (FilterName.LESS.equals(filterTypeName)) {
builtFilter = conditionEntry.lt(value).buildFilter();
} else if (FilterName.LESS_OR_EQUAL.equals(filterTypeName)) {
builtFilter = conditionEntry.le(value).buildFilter();
} else if (FilterName.REF.equals(filterTypeName)) {
if (value != null) {
PrismReferenceValue refVal = null;
if (value instanceof PrismReferenceValue) {
refVal = (PrismReferenceValue) value;
} else if (value instanceof ObjectReferenceType) {
refVal = ((ObjectReferenceType) value).asReferenceValue();
}
if (refVal.isEmpty() && expression != null) {
builtFilter = conditionEntry.ref(expression).buildFilter();
} else if (refVal.getParent() instanceof RefFilter) {
builtFilter = (RefFilter) refVal.getParent();
} else {
builtFilter = conditionEntry.ref(refVal).buildFilter();
}
} else {
builtFilter = conditionEntry.ref(Collections.emptyList()).buildFilter();
}
} else if (FilterName.SUBSTRING.equals(filterTypeName)) {
builtFilter = conditionEntry.contains(value).buildFilter();
} else if (FilterName.SUBSTRING_ANCHOR_START.equals(filterTypeName)) {
builtFilter = conditionEntry.startsWith(value).buildFilter();
} else if (FilterName.SUBSTRING_ANCHOR_END.equals(filterTypeName)) {
builtFilter = conditionEntry.endsWith(value).buildFilter();
}
if (builtFilter instanceof ValueFilter && matchingRule != null) {
((ValueFilter) builtFilter).setMatchingRule(matchingRule.getMatchingRuleName());
}
if (builtFilter instanceof ValueFilter && expression != null) {
((ValueFilter) builtFilter).setExpression(expression);
}
if (isApplyNegation()) {
builtFilter = prismContext.queryFactory().createNot(builtFilter);
}
return builtFilter != null ? builtFilter : prismContext.queryFor(type).buildFilter();
}
use of com.evolveum.midpoint.prism.query.builder.S_ConditionEntry in project midpoint by Evolveum.
the class SqlAuditServiceImpl method iterativeSearchCondition.
/**
* See {@code SqaleRepositoryService.iterativeSearchCondition()} for more info.
* This is unsupported version only for Ninja usage.
*/
@Nullable
private ObjectFilter iterativeSearchCondition(@Nullable AuditEventRecordType lastProcessedObject, List<? extends ObjectOrdering> providedOrdering) {
if (lastProcessedObject == null) {
return null;
}
Long lastProcessedId = lastProcessedObject.getRepoId();
XMLGregorianCalendar lastProcessedTimestamp = lastProcessedObject.getTimestamp();
if (providedOrdering == null || providedOrdering.isEmpty()) {
return schemaService.prismContext().queryFor(AuditEventRecordType.class).item(AuditEventRecordType.F_REPO_ID).gt(lastProcessedId).and().item(AuditEventRecordType.F_TIMESTAMP).ge(lastProcessedTimestamp).buildFilter();
}
if (providedOrdering.size() == 1) {
ObjectOrdering objectOrdering = providedOrdering.get(0);
ItemPath orderByPath = objectOrdering.getOrderBy();
boolean asc = objectOrdering.getDirection() == OrderDirection.ASCENDING;
S_ConditionEntry filter = schemaService.prismContext().queryFor(AuditEventRecordType.class).item(orderByPath);
@SuppressWarnings("unchecked") Item<PrismValue, ItemDefinition<?>> item = lastProcessedObject.asPrismContainerValue().findItem(orderByPath);
if (item.size() > 1) {
throw new IllegalArgumentException("Multi-value property for ordering is forbidden - item: " + item);
} else if (item.isEmpty()) {
// TODO what if it's nullable? is it null-first or last?
// See: https://www.postgresql.org/docs/13/queries-order.html
// "By default, null values sort as if larger than any non-null value; that is,
// NULLS FIRST is the default for DESC order, and NULLS LAST otherwise."
} else {
S_MatchingRuleEntry matchingRuleEntry = asc ? filter.gt(item.getRealValue()) : filter.lt(item.getRealValue());
filter = matchingRuleEntry.or().block().item(orderByPath).eq(item.getRealValue()).and().item(AuditEventRecordType.F_REPO_ID);
return (asc ? filter.gt(lastProcessedId) : filter.lt(lastProcessedId)).endBlock().buildFilter();
}
}
throw new IllegalArgumentException("Shouldn't get here with check in executeSearchObjectsIterative()");
}
use of com.evolveum.midpoint.prism.query.builder.S_ConditionEntry in project midpoint by Evolveum.
the class SqaleRepositoryService method lastOidCondition.
/**
* Without requested ordering, this is easy: `WHERE oid > lastOid`
*
* But with outside ordering we need to respect it and for ordering by X, Y, Z use
* (`original conditions AND` is taken care of outside of this method):
*
* ----
* ... WHERE original conditions AND (
* X > last.X
* OR (X = last.X AND Y > last.Y)
* OR (X = last.X AND Y = last.Y AND Z > last.Z)
* OR (X = last.X AND Y = last.Y ...if all equal AND OID > last.OID)
* ----
*
* This is suddenly much more fun, isn't it?
* Of course the condition `>` or `<` depends on `ASC` vs `DESC`.
*
* TODO: Currently, single path ordering is supported. Finish multi-path too.
* TODO: What about nullable columns?
*/
@Nullable
private <T extends ObjectType> ObjectFilter lastOidCondition(PrismObject<T> lastProcessedObject, List<? extends ObjectOrdering> providedOrdering) {
if (lastProcessedObject == null) {
return null;
}
String lastProcessedOid = lastProcessedObject.getOid();
if (providedOrdering == null || providedOrdering.isEmpty()) {
return prismContext().queryFor(lastProcessedObject.getCompileTimeClass()).item(OID_PATH).gt(lastProcessedOid).buildFilter();
}
if (providedOrdering.size() == 1) {
ObjectOrdering objectOrdering = providedOrdering.get(0);
ItemPath orderByPath = objectOrdering.getOrderBy();
boolean asc = objectOrdering.getDirection() == OrderDirection.ASCENDING;
S_ConditionEntry filter = prismContext().queryFor(lastProcessedObject.getCompileTimeClass()).item(orderByPath);
// noinspection rawtypes
Item<PrismValue, ItemDefinition<Item>> item = lastProcessedObject.findItem(orderByPath);
if (item.size() > 1) {
throw new IllegalArgumentException("Multi-value property for ordering is forbidden - item: " + item);
} else if (item.isEmpty()) {
// TODO what if it's nullable? is it null-first or last?
// See: https://www.postgresql.org/docs/13/queries-order.html
// "By default, null values sort as if larger than any non-null value; that is,
// NULLS FIRST is the default for DESC order, and NULLS LAST otherwise."
} else {
S_MatchingRuleEntry matchingRuleEntry = asc ? filter.gt(item.getRealValue()) : filter.lt(item.getRealValue());
filter = matchingRuleEntry.or().block().item(orderByPath).eq(item.getRealValue()).and().item(OID_PATH);
return (asc ? filter.gt(lastProcessedOid) : filter.lt(lastProcessedOid)).endBlock().buildFilter();
}
}
throw new IllegalArgumentException("Shouldn't get here with check in executeSearchObjectsIterative()");
/*
TODO: Unfinished - this is painful with fluent API. Should I call
prismContext().queryFor(lastProcessedObject.getCompileTimeClass()) for each component
and then use ObjectQueryUtil.filterAnd/Or?
// we need to handle the complicated case with externally provided ordering
S_FilterEntryOrEmpty orBlock = prismContext()
.queryFor(lastProcessedObject.getCompileTimeClass()).block();
orLoop:
for (ObjectOrdering orMasterOrdering : providedOrdering) {
Iterator<? extends ObjectOrdering> iterator = providedOrdering.iterator();
while (iterator.hasNext()) {
S_FilterEntryOrEmpty andBlock = orBlock.block();
ObjectOrdering ordering = iterator.next();
if (ordering.equals(orMasterOrdering)) {
// ...
continue orLoop;
}
orBlock = andBlock.endBlock();
}
}
return orBlock.endBlock().buildFilter();
*/
}
Aggregations