Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,119 +2,17 @@

import static java.util.stream.Collectors.toMap;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import lombok.Value;
import org.hypertrace.core.grpcutils.context.RequestContext;
import org.hypertrace.entity.attribute.translator.EntityAttributeMapping;
import org.hypertrace.entity.data.service.v1.AttributeFilter;
import lombok.NoArgsConstructor;
import org.hypertrace.entity.data.service.v1.AttributeValue;
import org.hypertrace.entity.data.service.v1.AttributeValueList;
import org.hypertrace.entity.data.service.v1.AttributeValueMap;
import org.hypertrace.entity.data.service.v1.Operator;
import org.hypertrace.entity.data.service.v1.Query;
import org.hypertrace.entity.query.service.v1.EntityQueryRequest;
import org.hypertrace.entity.query.service.v1.Expression;
import org.hypertrace.entity.query.service.v1.Filter;
import org.hypertrace.entity.query.service.v1.LiteralConstant;
import org.hypertrace.entity.query.service.v1.OrderByExpression;
import org.hypertrace.entity.query.service.v1.SortOrder;
import org.hypertrace.entity.query.service.v1.ValueType;
import org.hypertrace.entity.service.constants.EntityServiceConstants;

@NoArgsConstructor
class EntityQueryConverter {

private final EntityAttributeMapping attributeMapping;

EntityQueryConverter(EntityAttributeMapping attributeMapping) {
this.attributeMapping = attributeMapping;
}

@Deprecated(forRemoval = true)
public Query convertToEDSQuery(RequestContext requestContext, EntityQueryRequest queryRequest) {
Query.Builder queryBuilder = Query.newBuilder().setEntityType(queryRequest.getEntityType());

AttributeFilter attributeFilter =
convertToAttributeFilter(requestContext, queryBuilder, queryRequest.getFilter());
if (attributeFilter != null) {
queryBuilder.setFilter(attributeFilter);
}

queryBuilder.addAllOrderBy(convertOrderBy(requestContext, queryRequest.getOrderByList()));
queryBuilder.setLimit(queryRequest.getLimit());
queryBuilder.setOffset(queryRequest.getOffset());

return queryBuilder.build();
}

private AttributeFilter convertToAttributeFilter(
RequestContext requestContext, Query.Builder queryBuilder, Filter filter) {
if (filter == null || filter.equals(Filter.getDefaultInstance())) {
return null;
}
AttributeFilter.Builder builder = null;
if (filter.getChildFilterCount() == 0) {
// Copy the lhs and rhs from the filter.
AttributeColumnInformation attributeData =
getAttributeColumnInfo(requestContext, filter.getLhs());
String edsColumnName = attributeData.getColumnName();
org.hypertrace.entity.query.service.v1.Value rhsValue =
filter.getRhs().getLiteral().getValue();
if (edsColumnName.equals(EntityServiceConstants.ENTITY_ID)) {
if (rhsValue.getValueType() == ValueType.STRING) {
queryBuilder.addEntityId(rhsValue.getString());
} else if (rhsValue.getValueType() == ValueType.STRING_ARRAY) {
queryBuilder.addAllEntityId(rhsValue.getStringArrayList());
}
} else if (edsColumnName.equals(EntityServiceConstants.ENTITY_NAME)) {
queryBuilder.setEntityName(rhsValue.getString());
} else {
builder = AttributeFilter.newBuilder();
builder.setOperator(convertOperator(filter.getOperator()));
builder.setName(edsColumnName);
builder.setIsMultiValued(attributeData.isMultiValued());
builder.setAttributeValue(convertToAttributeValue(filter.getRhs()));
}
} else {
builder = AttributeFilter.newBuilder();
builder.setOperator(convertOperator(filter.getOperator()));
for (Filter child : filter.getChildFilterList()) {
AttributeFilter attributeFilter =
convertToAttributeFilter(requestContext, queryBuilder, child);
if (null != attributeFilter) {
builder.addChildFilter(attributeFilter);
}
}
}
return (null != builder) ? builder.build() : null;
}

private static org.hypertrace.entity.data.service.v1.Operator convertOperator(
org.hypertrace.entity.query.service.v1.Operator operator) {
// Might not handle all cases but this is a starter.
return Operator.valueOf(operator.name());
}

private static AttributeValue.Builder convertToAttributeValue(Expression expression) {
switch (expression.getValueCase()) {
case LITERAL:
return convertToAttributeValue(expression.getLiteral());
case COLUMNIDENTIFIER:
throw new IllegalArgumentException("Column Identifier should be LHS");
case FUNCTION:
throw new UnsupportedOperationException(
"Filtering on functional expressions not supported in EDS");
case ORDERBY:
throw new IllegalArgumentException("Filter cant have a Order By clause");
case VALUE_NOT_SET:
default:
return AttributeValue.newBuilder();
}
}

public static AttributeValue.Builder convertToAttributeValue(LiteralConstant literal) {
AttributeValue.Builder builder = AttributeValue.newBuilder();
org.hypertrace.entity.query.service.v1.Value value = literal.getValue();
Expand Down Expand Up @@ -237,76 +135,4 @@ public static AttributeValue.Builder convertToAttributeValue(LiteralConstant lit
}
return builder;
}

private AttributeColumnInformation getAttributeColumnInfo(
RequestContext requestContext, Expression expression) {
switch (expression.getValueCase()) {
case LITERAL:
throw new IllegalArgumentException("LHS should be a Attribute key");
case COLUMNIDENTIFIER:
String attributeId = expression.getColumnIdentifier().getColumnName();
String attributeName =
this.attributeMapping
.getDocStorePathByAttributeId(requestContext, attributeId)
.orElseThrow(
() ->
new IllegalArgumentException(
String.format(
"Unrecognized attribute: %s does not match any known entity attribute",
attributeId)));
final boolean isArray = this.attributeMapping.isArray(requestContext, attributeId);
return new AttributeColumnInformation(attributeName, isArray);
case FUNCTION:
throw new UnsupportedOperationException(
"Filtering on functional expressions not supported in EDS");
case ORDERBY:
throw new IllegalArgumentException("Filter cant have a Order By clause");
case VALUE_NOT_SET:
default:
throw new IllegalArgumentException(
String.format("Attribute Key for expression:%s not found", expression));
}
}

private List<org.hypertrace.entity.data.service.v1.OrderByExpression> convertOrderBy(
RequestContext requestContext, List<OrderByExpression> orderByExpressions) {
if (orderByExpressions.isEmpty()) {
return Collections.emptyList();
}

List<org.hypertrace.entity.data.service.v1.OrderByExpression> result = new ArrayList<>();
for (OrderByExpression orderByExpression : orderByExpressions)
if (orderByExpression.hasExpression()) {
if (orderByExpression.getExpression().hasColumnIdentifier()) {
String edsColumnName =
getAttributeColumnInfo(requestContext, orderByExpression.getExpression())
.getColumnName();
org.hypertrace.entity.data.service.v1.OrderByExpression convertedExpression =
org.hypertrace.entity.data.service.v1.OrderByExpression.newBuilder()
.setName(edsColumnName)
.setOrder(convertSortOrder(orderByExpression.getOrder()))
.build();
result.add(convertedExpression);
} else {
// entity data service and doc store only support field order by. There's no
// aggregate order by yet
throw new UnsupportedOperationException(
"OrderByExpression only support Column Identifier Expression");
}
}
return result;
}

private static org.hypertrace.entity.data.service.v1.SortOrder convertSortOrder(
SortOrder sortOrder) {
return SortOrder.DESC == sortOrder
? org.hypertrace.entity.data.service.v1.SortOrder.DESC
: org.hypertrace.entity.data.service.v1.SortOrder.ASC;
}

@Value
private static class AttributeColumnInformation {
String columnName;
boolean multiValued;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
import org.hypertrace.entity.data.service.v1.AttributeValue;
import org.hypertrace.entity.data.service.v1.AttributeValueList;
import org.hypertrace.entity.data.service.v1.Entity;
import org.hypertrace.entity.data.service.v1.Query;
import org.hypertrace.entity.fetcher.EntityFetcher;
import org.hypertrace.entity.metric.EntityCounterMetricSender;
import org.hypertrace.entity.query.service.converter.AliasProvider;
Expand Down Expand Up @@ -131,7 +130,6 @@ public class EntityQueryServiceImpl extends EntityQueryServiceImplBase {
.collect(joining("."));

private final Collection entitiesCollection;
private final EntityQueryConverter entityQueryConverter;
private final EntityAttributeMapping entityAttributeMapping;
private final int CHUNK_SIZE;
private final Injector injector;
Expand Down Expand Up @@ -208,7 +206,6 @@ public EntityQueryServiceImpl(
int maxStringLengthForUpdate) {
this.entitiesCollection = entitiesCollection;
this.entityAttributeMapping = entityAttributeMapping;
this.entityQueryConverter = new EntityQueryConverter(entityAttributeMapping);
this.CHUNK_SIZE = chunkSize;
this.injector = Guice.createInjector(new ConverterModule(entityAttributeMapping));
this.maxEntitiesToDelete = maxEntitiesToDelete;
Expand Down Expand Up @@ -667,11 +664,17 @@ public void total(
.build();

// converting entity query request to entity data service query
Query query = entityQueryConverter.convertToEDSQuery(requestContext, entityQueryRequest);
org.hypertrace.core.documentstore.query.Query query;
try {
final Converter<EntityQueryRequest, org.hypertrace.core.documentstore.query.Query>
queryConverter = getQueryConverter();
query = queryConverter.convert(entityQueryRequest, requestContext);
} catch (Exception ex) {
responseObserver.onError(new ServiceException("Unable to parse query."));
return;
}

// TODO: Replace to use the new org.hypertrace.core.documentstore.query.Query DTO
long total =
entitiesCollection.total(DocStoreConverter.transform(tenantId.get(), query, emptyList()));
long total = entitiesCollection.count(query);
responseObserver.onNext(TotalEntitiesResponse.newBuilder().setTotal(total).build());
responseObserver.onCompleted();
}
Expand Down
Loading