Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for BQPrimaryWithCriteriaFilterTranslator.mergeTranslator #1155

Merged
merged 9 commits into from
Feb 4, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,60 @@ public Optional<ApiFilterTranslator> mergedTranslatorAttributeFilter(
this, attributeFilters, logicalOperator, attributeSwapFields);
}

@Override
public Optional<ApiFilterTranslator> mergedTranslatorHierarchyHasAncestorFilter(
List<HierarchyHasAncestorFilter> hierarchyHasAncestorFilters,
LogicalOperator logicalOperator,
Map<Attribute, SqlField> attributeSwapFields) {
return BQHierarchyHasAncestorFilterTranslator.mergedTranslator(
this, hierarchyHasAncestorFilters, logicalOperator, attributeSwapFields);
}

@Override
public Optional<ApiFilterTranslator> mergedTranslatorHierarchyHasParentFilter(
List<HierarchyHasParentFilter> hierarchyHasParentFilters,
LogicalOperator logicalOperator,
Map<Attribute, SqlField> attributeSwapFields) {
return BQHierarchyHasParentFilterTranslator.mergedTranslator(
this, hierarchyHasParentFilters, logicalOperator, attributeSwapFields);
}

@Override
public Optional<ApiFilterTranslator> mergedTranslatorHierarchyIsLeafFilter(
List<HierarchyIsLeafFilter> hierarchyIsLeafFilters,
LogicalOperator logicalOperator,
Map<Attribute, SqlField> attributeSwapFields) {
return BQHierarchyIsLeafFilterTranslator.mergedTranslator(
this, hierarchyIsLeafFilters, logicalOperator, attributeSwapFields);
}

@Override
public Optional<ApiFilterTranslator> mergedTranslatorHierarchyIsMemberFilter(
List<HierarchyIsMemberFilter> hierarchyIsMemberFilters,
LogicalOperator logicalOperator,
Map<Attribute, SqlField> attributeSwapFields) {
return BQHierarchyIsMemberFilterTranslator.mergedTranslator(
this, hierarchyIsMemberFilters, logicalOperator, attributeSwapFields);
}

@Override
public Optional<ApiFilterTranslator> mergedTranslatorHierarchyRootFilter(
List<HierarchyIsRootFilter> hierarchyIsRootFilters,
LogicalOperator logicalOperator,
Map<Attribute, SqlField> attributeSwapFields) {
return BQHierarchyIsRootFilterTranslator.mergedTranslator(
this, hierarchyIsRootFilters, logicalOperator, attributeSwapFields);
}

@Override
public Optional<ApiFilterTranslator> mergedTranslatorPrimaryWithCriteriaFilter(
List<PrimaryWithCriteriaFilter> primaryWithCriteriaFilters,
LogicalOperator logicalOperator,
Map<Attribute, SqlField> attributeSwapFields) {
return BQPrimaryWithCriteriaFilterTranslator.mergedTranslator(
this, primaryWithCriteriaFilters, logicalOperator, attributeSwapFields);
}

@Override
public String naryFilterOnRepeatedFieldSql(
SqlField field,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package bio.terra.tanagra.query.bigquery.translator.filter;

import bio.terra.tanagra.api.filter.BooleanAndOrFilter.LogicalOperator;
import bio.terra.tanagra.api.filter.HierarchyHasAncestorFilter;
import bio.terra.tanagra.api.shared.BinaryOperator;
import bio.terra.tanagra.api.shared.Literal;
Expand All @@ -10,53 +11,70 @@
import bio.terra.tanagra.query.sql.translator.ApiTranslator;
import bio.terra.tanagra.underlay.entitymodel.Attribute;
import bio.terra.tanagra.underlay.indextable.ITHierarchyAncestorDescendant;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class BQHierarchyHasAncestorFilterTranslator extends ApiFilterTranslator {
private final HierarchyHasAncestorFilter hierarchyHasAncestorFilter;
private final List<HierarchyHasAncestorFilter> hierarchyHasAncestorFilters;

public BQHierarchyHasAncestorFilterTranslator(
ApiTranslator apiTranslator,
HierarchyHasAncestorFilter hierarchyHasAncestorFilter,
Map<Attribute, SqlField> attributeSwapFields) {
super(apiTranslator, attributeSwapFields);
this.hierarchyHasAncestorFilter = hierarchyHasAncestorFilter;
this.hierarchyHasAncestorFilters = List.of(hierarchyHasAncestorFilter);
}

public BQHierarchyHasAncestorFilterTranslator(
ApiTranslator apiTranslator,
List<HierarchyHasAncestorFilter> hierarchyHasAncestorFilters,
Map<Attribute, SqlField> attributeSwapFields) {
super(apiTranslator, attributeSwapFields);
this.hierarchyHasAncestorFilters = hierarchyHasAncestorFilters;
}

@Override
public String buildSql(SqlParams sqlParams, String tableAlias) {
// entity.id IN (SELECT ancestorId UNION ALL SELECT descendant FROM ancestorDescendantTable
// FILTER ON ancestorId)

// List is used only when they are mergeable (private constructor). See mergedTranslator
HierarchyHasAncestorFilter singleFilter = hierarchyHasAncestorFilters.get(0);
List<Literal> ancestorIds =
hierarchyHasAncestorFilters.stream()
.flatMap(filter -> filter.getAncestorIds().stream())
.toList();

ITHierarchyAncestorDescendant ancestorDescendantTable =
hierarchyHasAncestorFilter
singleFilter
.getUnderlay()
.getIndexSchema()
.getHierarchyAncestorDescendant(
hierarchyHasAncestorFilter.getEntity().getName(),
hierarchyHasAncestorFilter.getHierarchy().getName());
Attribute idAttribute = hierarchyHasAncestorFilter.getEntity().getIdAttribute();
singleFilter.getEntity().getName(), singleFilter.getHierarchy().getName());
Attribute idAttribute = singleFilter.getEntity().getIdAttribute();
SqlField idField =
attributeSwapFields.containsKey(idAttribute)
? attributeSwapFields.get(idAttribute)
: hierarchyHasAncestorFilter
: singleFilter
.getUnderlay()
.getIndexSchema()
.getEntityMain(hierarchyHasAncestorFilter.getEntity().getName())
.getEntityMain(singleFilter.getEntity().getName())
.getAttributeValueField(idAttribute.getName());

// FILTER ON ancestorId = [WHERE ancestor IN (ancestorIds)] or [WHERE ancestor = ancestorId]
String ancestorIdFilterSql =
hierarchyHasAncestorFilter.getAncestorIds().size() > 1
ancestorIds.size() > 1
? apiTranslator.naryFilterSql(
ancestorDescendantTable.getAncestorField(),
NaryOperator.IN,
hierarchyHasAncestorFilter.getAncestorIds(),
ancestorIds,
null,
sqlParams)
: apiTranslator.binaryFilterSql(
ancestorDescendantTable.getAncestorField(),
BinaryOperator.EQUALS,
hierarchyHasAncestorFilter.getAncestorIds().get(0),
ancestorIds.get(0),
null,
sqlParams);

Expand All @@ -69,11 +87,33 @@ public String buildSql(SqlParams sqlParams, String tableAlias) {
null,
false,
sqlParams,
hierarchyHasAncestorFilter.getAncestorIds().toArray(new Literal[0]));
ancestorIds.toArray(new Literal[0]));
}

@Override
public boolean isFilterOnAttribute(Attribute attribute) {
return attribute.isId();
}

public static Optional<ApiFilterTranslator> mergedTranslator(
ApiTranslator apiTranslator,
List<HierarchyHasAncestorFilter> hierarchyHasAncestorFilters,
LogicalOperator logicalOperator,
Map<Attribute, SqlField> attributeSwapFields) {
// LogicalOperator.AND is not supported for hierarchy filters
if (logicalOperator == LogicalOperator.AND) {
return Optional.empty();
}

// hierarchy must be the same
return hierarchyHasAncestorFilters.stream()
.map(HierarchyHasAncestorFilter::getHierarchy)
.distinct()
.count()
== 1
? Optional.of(
new BQHierarchyHasAncestorFilterTranslator(
apiTranslator, hierarchyHasAncestorFilters, attributeSwapFields))
: Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -1,60 +1,75 @@
package bio.terra.tanagra.query.bigquery.translator.filter;

import bio.terra.tanagra.api.filter.BooleanAndOrFilter.LogicalOperator;
import bio.terra.tanagra.api.filter.HierarchyHasParentFilter;
import bio.terra.tanagra.api.shared.BinaryOperator;
import bio.terra.tanagra.api.shared.Literal;
import bio.terra.tanagra.api.shared.NaryOperator;
import bio.terra.tanagra.query.sql.SqlField;
import bio.terra.tanagra.query.sql.SqlParams;
import bio.terra.tanagra.query.sql.translator.ApiFilterTranslator;
import bio.terra.tanagra.query.sql.translator.ApiTranslator;
import bio.terra.tanagra.underlay.entitymodel.Attribute;
import bio.terra.tanagra.underlay.indextable.ITHierarchyChildParent;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class BQHierarchyHasParentFilterTranslator extends ApiFilterTranslator {
private final HierarchyHasParentFilter hierarchyHasParentFilter;
private final List<HierarchyHasParentFilter> hierarchyHasParentFilters;

public BQHierarchyHasParentFilterTranslator(
ApiTranslator apiTranslator,
HierarchyHasParentFilter hierarchyHasParentFilter,
Map<Attribute, SqlField> attributeSwapFields) {
super(apiTranslator, attributeSwapFields);
this.hierarchyHasParentFilter = hierarchyHasParentFilter;
this.hierarchyHasParentFilters = List.of(hierarchyHasParentFilter);
}

public BQHierarchyHasParentFilterTranslator(
ApiTranslator apiTranslator,
List<HierarchyHasParentFilter> hierarchyHasParentFilters,
Map<Attribute, SqlField> attributeSwapFields) {
super(apiTranslator, attributeSwapFields);
this.hierarchyHasParentFilters = hierarchyHasParentFilters;
}

@Override
public String buildSql(SqlParams sqlParams, String tableAlias) {
// entity.id IN (SELECT child FROM childParentTable FILTER ON parentId)

// List is used only when they are mergeable (private constructor). See mergedTranslator
HierarchyHasParentFilter singleFilter = hierarchyHasParentFilters.get(0);
List<Literal> parentIds =
hierarchyHasParentFilters.stream()
.flatMap(filter -> filter.getParentIds().stream())
.toList();

ITHierarchyChildParent childParentIndexTable =
hierarchyHasParentFilter
singleFilter
.getUnderlay()
.getIndexSchema()
.getHierarchyChildParent(
hierarchyHasParentFilter.getEntity().getName(),
hierarchyHasParentFilter.getHierarchy().getName());
Attribute idAttribute = hierarchyHasParentFilter.getEntity().getIdAttribute();
singleFilter.getEntity().getName(), singleFilter.getHierarchy().getName());
Attribute idAttribute = singleFilter.getEntity().getIdAttribute();
SqlField idField =
attributeSwapFields.containsKey(idAttribute)
? attributeSwapFields.get(idAttribute)
: hierarchyHasParentFilter
: singleFilter
.getUnderlay()
.getIndexSchema()
.getEntityMain(hierarchyHasParentFilter.getEntity().getName())
.getEntityMain(singleFilter.getEntity().getName())
.getAttributeValueField(idAttribute.getName());

// FILTER ON parentId = [WHERE parent IN (parentIds)] or [WHERE parent = parentId]
String parentIdFilterSql =
hierarchyHasParentFilter.getParentIds().size() > 1
parentIds.size() > 1
? apiTranslator.naryFilterSql(
childParentIndexTable.getParentField(),
NaryOperator.IN,
hierarchyHasParentFilter.getParentIds(),
null,
sqlParams)
childParentIndexTable.getParentField(), NaryOperator.IN, parentIds, null, sqlParams)
: apiTranslator.binaryFilterSql(
childParentIndexTable.getParentField(),
BinaryOperator.EQUALS,
hierarchyHasParentFilter.getParentIds().get(0),
parentIds.get(0),
null,
sqlParams);

Expand All @@ -66,11 +81,34 @@ public String buildSql(SqlParams sqlParams, String tableAlias) {
parentIdFilterSql,
null,
false,
sqlParams);
sqlParams,
parentIds.toArray(new Literal[0]));
}

@Override
public boolean isFilterOnAttribute(Attribute attribute) {
return attribute.isId();
}

public static Optional<ApiFilterTranslator> mergedTranslator(
ApiTranslator apiTranslator,
List<HierarchyHasParentFilter> hierarchyHasParentFilters,
LogicalOperator logicalOperator,
Map<Attribute, SqlField> attributeSwapFields) {
// LogicalOperator.AND is not supported for hierarchy filters
if (logicalOperator == LogicalOperator.AND) {
return Optional.empty();
}

// hierarchy must be the same
return hierarchyHasParentFilters.stream()
.map(HierarchyHasParentFilter::getHierarchy)
.distinct()
.count()
== 1
? Optional.of(
new BQHierarchyHasParentFilterTranslator(
apiTranslator, hierarchyHasParentFilters, attributeSwapFields))
: Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package bio.terra.tanagra.query.bigquery.translator.filter;

import bio.terra.tanagra.api.filter.BooleanAndOrFilter.LogicalOperator;
import bio.terra.tanagra.api.filter.HierarchyIsLeafFilter;
import bio.terra.tanagra.api.shared.BinaryOperator;
import bio.terra.tanagra.api.shared.Literal;
Expand All @@ -9,7 +10,9 @@
import bio.terra.tanagra.query.sql.translator.ApiTranslator;
import bio.terra.tanagra.underlay.entitymodel.Attribute;
import bio.terra.tanagra.underlay.indextable.ITEntityMain;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class BQHierarchyIsLeafFilterTranslator extends ApiFilterTranslator {
private final HierarchyIsLeafFilter hierarchyIsLeafFilter;
Expand Down Expand Up @@ -41,4 +44,26 @@ public String buildSql(SqlParams sqlParams, String tableAlias) {
public boolean isFilterOnAttribute(Attribute attribute) {
return false;
}

public static Optional<ApiFilterTranslator> mergedTranslator(
ApiTranslator apiTranslator,
List<HierarchyIsLeafFilter> hierarchyIsLeafFilters,
LogicalOperator logicalOperator,
Map<Attribute, SqlField> attributeSwapFields) {
// LogicalOperator.AND is not supported for hierarchy filters
if (logicalOperator == LogicalOperator.AND) {
return Optional.empty();
}

// hierarchy must be the same
return hierarchyIsLeafFilters.stream()
.map(HierarchyIsLeafFilter::getHierarchy)
.distinct()
.count()
== 1
? Optional.of(
new BQHierarchyIsLeafFilterTranslator(
apiTranslator, hierarchyIsLeafFilters.get(0), attributeSwapFields))
: Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package bio.terra.tanagra.query.bigquery.translator.filter;

import bio.terra.tanagra.api.filter.BooleanAndOrFilter.LogicalOperator;
import bio.terra.tanagra.api.filter.HierarchyIsMemberFilter;
import bio.terra.tanagra.api.shared.UnaryOperator;
import bio.terra.tanagra.query.sql.SqlField;
Expand All @@ -8,7 +9,9 @@
import bio.terra.tanagra.query.sql.translator.ApiTranslator;
import bio.terra.tanagra.underlay.entitymodel.Attribute;
import bio.terra.tanagra.underlay.indextable.ITEntityMain;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class BQHierarchyIsMemberFilterTranslator extends ApiFilterTranslator {
private final HierarchyIsMemberFilter hierarchyIsMemberFilter;
Expand Down Expand Up @@ -40,4 +43,26 @@ public String buildSql(SqlParams sqlParams, String tableAlias) {
public boolean isFilterOnAttribute(Attribute attribute) {
return false;
}

public static Optional<ApiFilterTranslator> mergedTranslator(
ApiTranslator apiTranslator,
List<HierarchyIsMemberFilter> hierarchyIsMemberFilters,
LogicalOperator logicalOperator,
Map<Attribute, SqlField> attributeSwapFields) {
// LogicalOperator.AND is not supported for hierarchy filters
if (logicalOperator == LogicalOperator.AND) {
return Optional.empty();
}

// hierarchy must be the same
return hierarchyIsMemberFilters.stream()
.map(HierarchyIsMemberFilter::getHierarchy)
.distinct()
.count()
== 1
? Optional.of(
new BQHierarchyIsMemberFilterTranslator(
apiTranslator, hierarchyIsMemberFilters.get(0), attributeSwapFields))
: Optional.empty();
}
}
Loading