Skip to content

Commit

Permalink
MID-6319: little progress with condition mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
virgo47 committed Jun 30, 2020
1 parent b2757e9 commit 247213e
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 31 deletions.
Expand Up @@ -7,11 +7,14 @@

package com.evolveum.midpoint.repo.sql;

import static org.assertj.core.api.Assertions.assertThat;

import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.testng.annotations.Test;

import com.evolveum.midpoint.audit.api.AuditEventRecord;
import com.evolveum.midpoint.audit.api.AuditEventType;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.schema.SearchResultList;
import com.evolveum.midpoint.task.api.test.NullTaskImpl;
Expand All @@ -26,11 +29,31 @@
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class AuditSearchTest extends BaseSQLRepoTest {

public static final long TIMESTAMP_1 = 1577836800000L; // 2020-01-01
public static final long TIMESTAMP_2 = 1580515200000L; // 2020-02-01
public static final long TIMESTAMP_3 = 1583020800000L; // 2020-03-01

@Override
public void initSystem() throws Exception {
AuditEventRecord record = new AuditEventRecord();
record.addPropertyValue("prop", "val");
auditService.audit(record, NullTaskImpl.INSTANCE);
AuditEventRecord record1 = new AuditEventRecord();
record1.addPropertyValue("prop", "val1");
record1.setTimestamp(TIMESTAMP_1);
record1.setEventType(AuditEventType.ADD_OBJECT);
auditService.audit(record1, NullTaskImpl.INSTANCE);

AuditEventRecord record2 = new AuditEventRecord();
record2.addPropertyValue("prop", "val2");
record2.setTimestamp(TIMESTAMP_2);
record2.setEventType(AuditEventType.MODIFY_OBJECT);
auditService.audit(record2, NullTaskImpl.INSTANCE);

AuditEventRecord record3 = new AuditEventRecord();
record3.addPropertyValue("prop", "val3-1");
record3.addPropertyValue("prop", "val3-2");
record3.addPropertyValue("prop", "val3-3");
record3.setTimestamp(TIMESTAMP_3);
record3.setEventType(AuditEventType.MODIFY_OBJECT);
auditService.audit(record3, NullTaskImpl.INSTANCE);

// TODO add some sample audits here
}
Expand All @@ -39,11 +62,12 @@ public void initSystem() throws Exception {
public void test100SearchAllAuditEvents() throws SchemaException {
when("Searching audit with query without any conditions");
ObjectQuery query = prismContext.queryFor(AuditEventRecordType.class).build();
SearchResultList<AuditEventRecordType> prismObjects =
SearchResultList<AuditEventRecordType> result =
auditService.searchObjects(query, null, null);

then("All audit events are returned");
System.out.println("prismObjects = " + prismObjects);
assertThat(result).hasSize(3);
System.out.println("result = " + result);
// TODO
}

Expand All @@ -53,11 +77,12 @@ public void test110SearchAllAuditEventsOfSomeType() throws SchemaException {
ObjectQuery query = prismContext.queryFor(AuditEventRecordType.class)
.item(AuditEventRecordType.F_EVENT_TYPE).eq(AuditEventTypeType.ADD_OBJECT)
.build();
SearchResultList<AuditEventRecordType> prismObjects =
SearchResultList<AuditEventRecordType> result =
auditService.searchObjects(query, null, null);

then("only audit events of a particular type are returned");
System.out.println("prismObjects = " + prismObjects);
assertThat(result).hasSize(1);
System.out.println("result = " + result);
// TODO
}
}
Expand Down
Expand Up @@ -48,6 +48,7 @@
import com.evolveum.midpoint.repo.sql.helpers.BaseHelper;
import com.evolveum.midpoint.repo.sql.perf.SqlPerformanceMonitorImpl;
import com.evolveum.midpoint.repo.sql.pure.SqlQueryExecutor;
import com.evolveum.midpoint.repo.sql.query.QueryException;
import com.evolveum.midpoint.repo.sql.util.DtoTranslationException;
import com.evolveum.midpoint.repo.sql.util.GetObjectResult;
import com.evolveum.midpoint.repo.sql.util.RUtil;
Expand Down Expand Up @@ -918,14 +919,14 @@ public long countObjects(ObjectQuery query,
@NotNull
public SearchResultList<AuditEventRecordType> searchObjects(
ObjectQuery query,
Collection<SelectorOptions<GetOperationOptions>> options, OperationResult parentResult) {
Collection<SelectorOptions<GetOperationOptions>> options,
OperationResult parentResult) {
// TODO MID-6319
// support for options, skipped for now
// do something with the OperationResult... skipped for now

try {
return sqlQueryExecutor.list(AuditEventRecordType.class, query);
} catch (SQLException e) {
return sqlQueryExecutor.list(AuditEventRecordType.class, query, options);
} catch (QueryException e) {
// TODO
throw new RuntimeException(e);
}
Expand Down
@@ -0,0 +1,29 @@
package com.evolveum.midpoint.repo.sql.pure;

import com.evolveum.midpoint.repo.sql.pure.mapping.QueryModelMapping;

/**
* SQL path context with mapping information.
*/
public class SqlPathContext {

private final FlexibleRelationalPathBase<?> path;
private final QueryModelMapping<?, ?> mapping;

public SqlPathContext(FlexibleRelationalPathBase<?> path, QueryModelMapping<?, ?> mapping) {
this.path = path;
this.mapping = mapping;
}

public FlexibleRelationalPathBase<?> path() {
return path;
}

public <T extends FlexibleRelationalPathBase<?>> T path(Class<T> pathType) {
return pathType.cast(path);
}

public QueryModelMapping<?, ?> mapping() {
return mapping;
}
}
@@ -0,0 +1,42 @@
package com.evolveum.midpoint.repo.sql.pure;

import static com.evolveum.midpoint.repo.sql.pure.SqlQueryExecutor.QUERYDSL_CONFIGURATION;

import java.sql.Connection;

import com.querydsl.core.types.Predicate;
import com.querydsl.sql.SQLQuery;

import com.evolveum.midpoint.repo.sql.pure.mapping.QueryModelMapping;

/**
* Context information about SQL query.
* Works as a kind of accumulator where information are added as the object query is interpreted.
*/
public class SqlQueryContext extends SqlPathContext {

private final SQLQuery<?> query;

public SqlQueryContext(
FlexibleRelationalPathBase<?> root,
QueryModelMapping<?, ?> rootMapping) {
super(root, rootMapping);
query = new SQLQuery<>(QUERYDSL_CONFIGURATION).from(root);
}

public FlexibleRelationalPathBase<?> root() {
return path();
}

public <T extends FlexibleRelationalPathBase<?>> T root(Class<T> rootType) {
return path(rootType);
}

public SQLQuery<?> query(Connection connection) {
return query.clone(connection);
}

public void addPredicate(Predicate predicate) {
query.where(predicate);
}
}
Expand Up @@ -2,7 +2,11 @@

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;

import com.querydsl.core.Tuple;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.sql.Configuration;
import com.querydsl.sql.SQLQuery;
import com.querydsl.sql.SQLTemplates;
Expand All @@ -11,12 +15,21 @@
import org.springframework.stereotype.Component;

import com.evolveum.midpoint.prism.Containerable;
import com.evolveum.midpoint.prism.query.EqualFilter;
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.query.PropertyValueFilter;
import com.evolveum.midpoint.repo.sql.DataSourceFactory;
import com.evolveum.midpoint.repo.sql.pure.mapping.QueryModelMapping;
import com.evolveum.midpoint.repo.sql.pure.mapping.QueryModelMappingConfig;
import com.evolveum.midpoint.repo.sql.pure.querymodel.QAuditEventRecord;
import com.evolveum.midpoint.repo.sql.query.QueryException;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.SearchResultList;
import com.evolveum.midpoint.schema.SearchResultMetadata;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.xml.ns._public.common.audit_3.AuditEventRecordType;
import com.evolveum.midpoint.xml.ns._public.common.audit_3.AuditEventTypeType;

/**
* Component just under the service that orchestrates query transformation and execution.
Expand All @@ -32,49 +45,97 @@ public class SqlQueryExecutor {
private DataSourceFactory dataSourceFactory;

public <T extends Containerable> SearchResultList<T> list(
Class<T> prismType, // ignored for the moment
ObjectQuery query) throws SQLException {
@NotNull Class<T> prismType, // ignored for the moment
ObjectQuery query, Collection<SelectorOptions<GetOperationOptions>> options) throws QueryException {

// TODO use?
boolean distinctRequested = GetOperationOptions.isDistinct(SelectorOptions.findRootOptions(options));

QueryModelMapping<?, ?> rootMapping = QueryModelMappingConfig.getByModelType(prismType);
FlexibleRelationalPathBase<?> root = rootMapping.defaultAlias();
SqlQueryContext context = new SqlQueryContext(root, rootMapping);

// add conditions (with exists clauses as necessary)
ObjectFilter filter = query != null ? query.getFilter() : null;
if (filter != null) {
processFilter(context, filter);
}

// TODO: what if we declare AuditEventRecordType, but we want transformed result?
// some mapping function as an argument?
// some builder to construct the whole definition that will be an argument?

PageOf<MAuditEventRecord> result = executeQuery();
PageOf<Tuple> result = executeQuery(context);

PageOf<AuditEventRecordType> map = result
.map(t -> (MAuditEventRecord) t.get(root))
.map(AuditEventRecordSqlTransformer::toAuditEventRecordType);
//noinspection unchecked
return (SearchResultList<T>) createSearchResultList(map);
}

@NotNull
public <T extends Containerable> SearchResultList<T> createSearchResultList(PageOf<T> result) {
SearchResultMetadata metadata = new SearchResultMetadata();
metadata.setApproxNumberOfAllResults((int) result.totalCount());
return new SearchResultList<>(result.content(), metadata);
private void processFilter(SqlQueryContext context, ObjectFilter filter) throws QueryException {
if (filter instanceof PropertyValueFilter) {
PropertyValueFilter<?> propertyValueFilter = (PropertyValueFilter<?>) filter;
System.out.println("filter = " + propertyValueFilter);
Object path = propertyValueFilter.getFullPath().first();
System.out.println("path = " + path);
FlexibleRelationalPathBase<?> pathWithCondition = context.path();
if (propertyValueFilter instanceof EqualFilter<?>) {
// hardcoded condition from test110SearchAllAuditEventsOfSomeType - TODO: now just do it magically
QAuditEventRecord root = context.root(QAuditEventRecord.class);
BooleanExpression predicate = root.eventtype.eq(AuditEventTypeType.ADD_OBJECT.ordinal());
context.addPredicate(predicate);
// ExpressionUtils.eq(context.mapping().)
// context.mapping()
} else {
throw new QueryException("Unsupported filter " + filter);
}
/*
EQUAL: eventType,PPV(AuditEventTypeType:ADD_OBJECT)
how to resolve eventType to actual PathName?
PropertyValueFilter valFilter = (PropertyValueFilter) filter;
ItemPath path = valFilter.getFullPath();
ItemDefinition definition = valFilter.getDefinition();
ProperDataSearchResult propDefRes = resolver.findProperDataDefinition(baseEntityDefinition, path, definition, JpaPropertyDefinition.class,
context.getPrismContext());
if (propDefRes == null) {
throw new QueryException("Couldn't find a proper data item to query, given base entity " + baseEntityDefinition + " and this filter: " + valFilter.debugDump());
}
return new PropertyRestriction(context, valFilter, propDefRes.getEntityDefinition(), parent, propDefRes.getLinkDefinition());
*/
} else {
throw new QueryException("Unsupported filter " + filter);
}
}

public PageOf<MAuditEventRecord> executeQuery() throws SQLException {
public PageOf<Tuple> executeQuery(SqlQueryContext context) throws QueryException {
try (Connection connection = getConnection()) {
QAuditEventRecord aer = new QAuditEventRecord();
SQLQuery<MAuditEventRecord> query = newQuery(connection)
.select(aer)
.from(aer)
FlexibleRelationalPathBase<?> root = context.root();
SQLQuery<Tuple> query = context.query(connection)
.select(Projections.tuple(root))
// TODO add paging
// .offset(2)
// .limit(2)
;
long count = query.fetchCount();

return new PageOf<>(query.fetch(), PageOf.PAGE_NO_PAGINATION, 0, count);
} catch (SQLException e) {
throw new QueryException(e.toString(), e);
}
}

private Connection getConnection() throws SQLException {
return dataSourceFactory.getDataSource().getConnection();
@NotNull
public <T extends Containerable> SearchResultList<T> createSearchResultList(PageOf<T> result) {
SearchResultMetadata metadata = new SearchResultMetadata();
metadata.setApproxNumberOfAllResults((int) result.totalCount());
return new SearchResultList<>(result.content(), metadata);
}

@NotNull
public SQLQuery<Object> newQuery(Connection connection) {
return new SQLQuery<>(connection, QUERYDSL_CONFIGURATION);
private Connection getConnection() throws SQLException {
return dataSourceFactory.getDataSource().getConnection();
}
}
Expand Up @@ -2,6 +2,10 @@

import static com.evolveum.midpoint.repo.sql.pure.querymodel.QAuditEventRecord.*;

import java.util.function.Function;

import com.querydsl.core.types.Expression;

import com.evolveum.midpoint.repo.sql.pure.querymodel.QAuditEventRecord;
import com.evolveum.midpoint.xml.ns._public.common.audit_3.AuditEventRecordType;

Expand All @@ -12,11 +16,13 @@ public class QAuditEventRecordMapping
extends QueryModelMapping<AuditEventRecordType, QAuditEventRecord> {

public static final String TABLE_NAME = "M_AUDIT_EVENT";
public static final String DEFAULT_ALIAS_NAME = "aer";

public static final QAuditEventRecordMapping INSTANCE = new QAuditEventRecordMapping();

private QAuditEventRecordMapping() {
super(TABLE_NAME, AuditEventRecordType.class, QAuditEventRecord.class,
super(TABLE_NAME, DEFAULT_ALIAS_NAME,
AuditEventRecordType.class, QAuditEventRecord.class,
ID, CHANNEL, ATTORNEY_NAME, ATTORNEY_OID,
EVENT_IDENTIFIER, EVENT_STAGE, EVENT_TYPE,
HOST_IDENTIFIER, INITIATOR_NAME, INITIATOR_OID, INITIATOR_TYPE,
Expand All @@ -25,5 +31,10 @@ private QAuditEventRecordMapping() {
TARGET_NAME, TARGET_OID, TARGET_TYPE,
TARGET_OWNER_NAME, TARGET_OWNER_OID, TARGET_OWNER_TYPE,
TASK_IDENTIFIER, TASK_OID, TIMESTAMP_VALUE);

Function<QAuditEventRecord, Expression> x = q -> q.eventtype;
// TODO how to represent this? for what kind of filters?
// addPathProcessor(AuditEventRecordType.F_EVENT_TYPE, EVENT_TYPE, x);
}

}

0 comments on commit 247213e

Please sign in to comment.