From effcf7627c90d0ec9692f05e74b5d5e7fe48d961 Mon Sep 17 00:00:00 2001 From: hchen04 Date: Thu, 13 Feb 2020 15:31:36 -0600 Subject: [PATCH] remove relationshp, update model --- .../aggregation/AggregationDataStore.java | 2 +- .../datastores/aggregation/QueryEngine.java | 13 +- .../aggregation/QueryValidator.java | 13 +- .../aggregation/metadata/MetaDataStore.java | 11 - .../metadata/enums/Aggregation.java | 15 - .../aggregation/metadata/enums/ValueType.java | 34 ++- .../aggregation/metadata/models/Column.java | 40 +-- .../aggregation/metadata/models/DataType.java | 58 ---- .../metadata/models/Dimension.java | 4 +- .../metadata/models/FunctionArgument.java | 10 +- .../aggregation/metadata/models/Metric.java | 5 +- .../metadata/models/RelationshipType.java | 22 -- .../aggregation/metadata/models/Table.java | 35 ++- .../metadata/models/TimeDimension.java | 11 +- .../queryengines/AbstractEntityHydrator.java | 8 +- .../queryengines/sql/SQLQueryConstructor.java | 8 +- .../sql/metadata/SQLDimension.java | 6 +- .../queryengines/sql/metadata/SQLMetric.java | 5 +- .../queryengines/sql/metadata/SQLTable.java | 14 +- .../sql/metadata/SQLTimeDimension.java | 6 +- .../EntityProjectionTranslatorTest.java | 15 +- .../aggregation/QueryValidatorTest.java | 40 +-- .../aggregation/example/CountryView.java | 16 +- .../example/CountryViewNested.java | 4 +- .../aggregation/example/PlayerStats.java | 80 +++--- .../aggregation/example/PlayerStatsView.java | 7 +- .../example/PlayerStatsWithView.java | 19 +- .../AggregationDataStoreIntegrationTest.java | 272 ++++-------------- .../queryengines/sql/QueryEngineTest.java | 238 ++++++--------- .../queryengines/sql/SubselectTest.java | 123 +------- .../queryengines/sql/ViewTest.java | 28 +- .../graphql/responses/testGraphQLSchema.json | 49 ---- 32 files changed, 326 insertions(+), 885 deletions(-) delete mode 100644 elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/enums/Aggregation.java delete mode 100644 elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/DataType.java delete mode 100644 elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/RelationshipType.java diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/AggregationDataStore.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/AggregationDataStore.java index 11cdf8b02b..2238a89762 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/AggregationDataStore.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/AggregationDataStore.java @@ -53,7 +53,7 @@ public void populateEntityDictionary(EntityDictionary dictionary) { for (Table table : queryEngine.getMetaDataStore().getMetaData(Table.class)) { for (TimeDimension timeDim : table.getColumns(TimeDimension.class)) { dictionary.addArgumentToAttribute( - dictionary.getEntityClass(table.getName()), + dictionary.getEntityClass(table.getId()), timeDim.getName(), new ArgumentType("grain", String.class)); } diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/QueryEngine.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/QueryEngine.java index ff7a1a6b68..43e8be5cee 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/QueryEngine.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/QueryEngine.java @@ -8,6 +8,7 @@ import com.yahoo.elide.core.DataStore; import com.yahoo.elide.core.DataStoreTransaction; import com.yahoo.elide.core.EntityDictionary; +import com.yahoo.elide.core.exceptions.InvalidPredicateException; import com.yahoo.elide.datastores.aggregation.metadata.MetaDataStore; import com.yahoo.elide.datastores.aggregation.metadata.models.Table; import com.yahoo.elide.datastores.aggregation.query.Query; @@ -67,7 +68,6 @@ public abstract class QueryEngine { @Getter private final EntityDictionary metadataDictionary; - @Getter private final Map tables; /** @@ -81,7 +81,7 @@ public QueryEngine(MetaDataStore metaDataStore) { this.metadataDictionary = metaDataStore.getDictionary(); populateMetaData(metaDataStore); this.tables = metaDataStore.getMetaData(Table.class).stream() - .collect(Collectors.toMap(Table::getName, Functions.identity())); + .collect(Collectors.toMap(Table::getId, Functions.identity())); } /** @@ -99,6 +99,15 @@ public QueryEngine(MetaDataStore metaDataStore) { * @param metaDataStore metadata store to populate */ private void populateMetaData(MetaDataStore metaDataStore) { + metaDataStore.getModelsToBind() + .forEach(model -> { + if (!metadataDictionary.isJPAEntity(model) + && !metadataDictionary.getRelationships(model).isEmpty()) { + throw new InvalidPredicateException( + "Non-JPA entities " + model.getSimpleName() + " is not allowed to have relationship."); + } + }); + metaDataStore.getModelsToBind().stream() .map(model -> constructTable(model, metadataDictionary)) .forEach(metaDataStore::addTable); diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/QueryValidator.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/QueryValidator.java index 678d7e306a..1b17a944cc 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/QueryValidator.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/QueryValidator.java @@ -71,7 +71,7 @@ private void validateHavingClause(FilterExpression havingClause) { Class cls = last.getType(); String fieldName = last.getFieldName(); - Class tableClass = dictionary.getEntityClass(queriedTable.getName()); + Class tableClass = dictionary.getEntityClass(queriedTable.getId()); if (cls != tableClass) { throw new InvalidOperationException( @@ -128,17 +128,6 @@ public void validateSorting() { private void validateSortingPath(Path path, Set allFields) { List pathElements = path.getPathElements(); - // TODO: add support for double nested sorting - if (pathElements.size() > 2) { - throw new UnsupportedOperationException( - "Currently sorting on double nested fields is not supported"); - } - - if (metrics.isEmpty() && pathElements.size() > 1) { - throw new UnsupportedOperationException( - "Query with no metric can't sort on nested field."); - } - Path.PathElement currentElement = pathElements.get(0); String currentField = currentElement.getFieldName(); Class currentClass = currentElement.getType(); diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/MetaDataStore.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/MetaDataStore.java index 2db399d844..6b9c3294d8 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/MetaDataStore.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/MetaDataStore.java @@ -12,7 +12,6 @@ import com.yahoo.elide.datastores.aggregation.annotation.Join; import com.yahoo.elide.datastores.aggregation.annotation.MetricAggregation; import com.yahoo.elide.datastores.aggregation.metadata.models.Column; -import com.yahoo.elide.datastores.aggregation.metadata.models.DataType; import com.yahoo.elide.datastores.aggregation.metadata.models.FunctionArgument; import com.yahoo.elide.datastores.aggregation.metadata.models.Metric; import com.yahoo.elide.datastores.aggregation.metadata.models.MetricFunction; @@ -83,7 +82,6 @@ public void addTable(Table table) { */ private void addColumn(Column column) { addMetaData(column); - addDataType(column.getDataType()); if (column instanceof TimeDimension) { ((TimeDimension) column).getSupportedGrains().forEach(this::addTimeDimensionGrain); @@ -102,15 +100,6 @@ private void addMetricFunction(MetricFunction metricFunction) { metricFunction.getArguments().forEach(this::addFunctionArgument); } - /** - * Add a datatype metadata object. - * - * @param dataType datatype metadata - */ - private void addDataType(DataType dataType) { - addMetaData(dataType); - } - /** * Add a function argument metadata object. * diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/enums/Aggregation.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/enums/Aggregation.java deleted file mode 100644 index 828f00b523..0000000000 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/enums/Aggregation.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2019, Yahoo Inc. - * Licensed under the Apache License, Version 2.0 - * See LICENSE file in project root for terms. - */ -package com.yahoo.elide.datastores.aggregation.metadata.enums; - -/** - * Aggregation functions. - */ -public enum Aggregation { - SUM, - MIN, - MAX; -} diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/enums/ValueType.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/enums/ValueType.java index 6df6643e9e..f80dc2c814 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/enums/ValueType.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/enums/ValueType.java @@ -5,15 +5,43 @@ */ package com.yahoo.elide.datastores.aggregation.metadata.enums; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; + /** * Actual value type of a data type. */ public enum ValueType { - DATE, - NUMBER, + TIME, + INTEGER, + DECIMAL, + MONEY, TEXT, COORDINATE, BOOLEAN, RELATIONSHIP, - ID + ID; + + private static final Map, ValueType> SCALAR_TYPES = new HashMap, ValueType>() {{ + put(short.class, INTEGER); + put(Short.class, INTEGER); + put(int.class, INTEGER); + put(Integer.class, INTEGER); + put(long.class, INTEGER); + put(Long.class, INTEGER); + put(BigDecimal.class, DECIMAL); + put(float.class, DECIMAL); + put(Float.class, DECIMAL); + put(double.class, DECIMAL); + put(Double.class, DECIMAL); + put(boolean.class, BOOLEAN); + put(Boolean.class, BOOLEAN); + put(char.class, TEXT); + put(String.class, TEXT); + }}; + + public static ValueType getScalarType(Class fieldClass) { + return SCALAR_TYPES.get(fieldClass); + } } diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Column.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Column.java index b1b1fc27a3..8b34693590 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Column.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Column.java @@ -6,19 +6,19 @@ package com.yahoo.elide.datastores.aggregation.metadata.models; import com.yahoo.elide.annotation.Include; +import com.yahoo.elide.annotation.ToOne; import com.yahoo.elide.core.EntityDictionary; import com.yahoo.elide.datastores.aggregation.annotation.Meta; import com.yahoo.elide.datastores.aggregation.metadata.enums.ValueType; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.ToString; import java.util.Date; import java.util.HashSet; -import java.util.Locale; import java.util.Set; import javax.persistence.Id; -import javax.persistence.ManyToOne; /** * Column is the super class of a field in a table, it can be either dimension or metric. @@ -34,21 +34,25 @@ public abstract class Column { private String longName; - private String tableName; - private String description; private String category; - @ManyToOne - private DataType dataType; + @ToOne + @ToString.Exclude + @EqualsAndHashCode.Exclude + private Table table; + + private ValueType valueType; @ToString.Exclude private Set columnTags; - protected Column(Class tableClass, String fieldName, EntityDictionary dictionary) { - this.tableName = dictionary.getJsonAliasFor(tableClass); - this.id = tableName + "." + fieldName; + protected Column(Table table, String fieldName, EntityDictionary dictionary) { + this.table = table; + Class tableClass = dictionary.getEntityClass(table.getId()); + + this.id = table.getId() + "." + fieldName; this.name = fieldName; this.columnTags = new HashSet<>(); @@ -58,29 +62,25 @@ protected Column(Class tableClass, String fieldName, EntityDictionary diction this.description = meta.description(); } - dataType = getDataType(tableClass, fieldName, dictionary); - if (dataType == null) { + valueType = getValueType(tableClass, fieldName, dictionary); + if (valueType == null) { throw new IllegalArgumentException("Unknown data type for " + this.id); } } - public static DataType getDataType(Class tableClass, String fieldName, EntityDictionary dictionary) { - String tableName = dictionary.getJsonAliasFor(tableClass); - DataType dataType; + public static ValueType getValueType(Class tableClass, String fieldName, EntityDictionary dictionary) { if (dictionary.isRelation(tableClass, fieldName)) { - Class relationshipClass = dictionary.getParameterizedType(tableClass, fieldName); - dataType = new RelationshipType(dictionary.getJsonAliasFor(relationshipClass)); + return ValueType.RELATIONSHIP; } else { Class fieldClass = dictionary.getType(tableClass, fieldName); if (fieldName.equals(dictionary.getIdFieldName(tableClass))) { - dataType = new DataType(tableName + "." + fieldName, ValueType.ID); + return ValueType.ID; } else if (Date.class.isAssignableFrom(fieldClass)) { - dataType = new DataType(fieldClass.getSimpleName().toLowerCase(Locale.ENGLISH), ValueType.DATE); + return ValueType.TIME; } else { - dataType = DataType.getScalarType(fieldClass); + return ValueType.getScalarType(fieldClass); } } - return dataType; } } diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/DataType.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/DataType.java deleted file mode 100644 index de8a0d2b81..0000000000 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/DataType.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2019, Yahoo Inc. - * Licensed under the Apache License, Version 2.0 - * See LICENSE file in project root for terms. - */ -package com.yahoo.elide.datastores.aggregation.metadata.models; - -import static com.yahoo.elide.datastores.aggregation.metadata.enums.ValueType.BOOLEAN; -import static com.yahoo.elide.datastores.aggregation.metadata.enums.ValueType.NUMBER; -import static com.yahoo.elide.datastores.aggregation.metadata.enums.ValueType.TEXT; - -import com.yahoo.elide.annotation.Include; -import com.yahoo.elide.datastores.aggregation.metadata.enums.ValueType; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.ToString; - -import java.math.BigDecimal; -import java.util.HashMap; -import java.util.Map; -import javax.persistence.Id; - -/** - * Data type of a column. - */ -@Include(rootLevel = true, type = "dataType") -@Data -@AllArgsConstructor -@ToString -public class DataType { - private static final Map, DataType> SCALAR_TYPES = new HashMap, DataType>() {{ - put(short.class, new DataType("p_short", NUMBER)); - put(Short.class, new DataType("short", NUMBER)); - put(int.class, new DataType("p_int", NUMBER)); - put(Integer.class, new DataType("int", NUMBER)); - put(long.class, new DataType("p_bigint", NUMBER)); - put(Long.class, new DataType("bigint", NUMBER)); - put(BigDecimal.class, new DataType("bigDecimal", NUMBER)); - put(float.class, new DataType("p_float", NUMBER)); - put(Float.class, new DataType("float", NUMBER)); - put(double.class, new DataType("p_double", NUMBER)); - put(Double.class, new DataType("double", NUMBER)); - put(boolean.class, new DataType("p_boolean", BOOLEAN)); - put(Boolean.class, new DataType("boolean", BOOLEAN)); - put(char.class, new DataType("p_char", TEXT)); - put(String.class, new DataType("string", TEXT)); - }}; - - @Id - private String name; - - private ValueType valueType; - - public static DataType getScalarType(Class valueClass) { - return SCALAR_TYPES.get(valueClass); - } -} diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Dimension.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Dimension.java index 1eabdd3674..e27ab6d93d 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Dimension.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Dimension.java @@ -18,7 +18,7 @@ @Include(type = "dimension") @Data public class Dimension extends Column { - public Dimension(Class tableClass, String fieldName, EntityDictionary dictionary) { - super(tableClass, fieldName, dictionary); + public Dimension(Table table, String fieldName, EntityDictionary dictionary) { + super(table, fieldName, dictionary); } } diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/FunctionArgument.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/FunctionArgument.java index d7b1de386b..73045eb4f0 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/FunctionArgument.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/FunctionArgument.java @@ -6,12 +6,12 @@ package com.yahoo.elide.datastores.aggregation.metadata.models; import com.yahoo.elide.annotation.Include; +import com.yahoo.elide.datastores.aggregation.metadata.enums.ValueType; import lombok.Data; import lombok.ToString; import javax.persistence.Id; -import javax.persistence.ManyToOne; /** * Arguments that can be provided into a metric function. @@ -27,13 +27,15 @@ public class FunctionArgument { private String description; - @ManyToOne - private DataType dataType; + private ValueType type; + + private String subType; public FunctionArgument(String functionName, FunctionArgument argument) { this.id = functionName + "." + argument.getName(); this.name = argument.getName(); this.description = argument.getDescription(); - this.dataType = argument.getDataType(); + this.type = argument.getType(); + this.subType = argument.getSubType(); } } diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Metric.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Metric.java index 26f2fd9831..fd8b320122 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Metric.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Metric.java @@ -31,8 +31,9 @@ public class Metric extends Column { @ToString.Exclude private MetricFunction metricFunction; - public Metric(Class tableClass, String fieldName, EntityDictionary dictionary) { - super(tableClass, fieldName, dictionary); + public Metric(Table table, String fieldName, EntityDictionary dictionary) { + super(table, fieldName, dictionary); + Class tableClass = dictionary.getEntityClass(table.getId()); MetricAggregation metric = dictionary.getAttributeOrRelationAnnotation( tableClass, diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/RelationshipType.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/RelationshipType.java deleted file mode 100644 index c0e8f49587..0000000000 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/RelationshipType.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2019, Yahoo Inc. - * Licensed under the Apache License, Version 2.0 - * See LICENSE file in project root for terms. - */ -package com.yahoo.elide.datastores.aggregation.metadata.models; - -import com.yahoo.elide.datastores.aggregation.metadata.enums.ValueType; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * Special data type that represents a relationship between tables. - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class RelationshipType extends DataType { - public RelationshipType(String name) { - super(name, ValueType.RELATIONSHIP); - } -} diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Table.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Table.java index 17247e5828..23f0ef244f 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Table.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/Table.java @@ -6,7 +6,7 @@ package com.yahoo.elide.datastores.aggregation.metadata.models; import static com.yahoo.elide.datastores.aggregation.metadata.MetaDataStore.isMetricField; -import static com.yahoo.elide.datastores.aggregation.metadata.models.Column.getDataType; +import static com.yahoo.elide.datastores.aggregation.metadata.models.Column.getValueType; import com.yahoo.elide.annotation.Exclude; import com.yahoo.elide.annotation.Include; @@ -35,9 +35,9 @@ @ToString public class Table { @Id - private String name; + private String id; - private String longName; + private String name; private String description; @@ -70,7 +70,7 @@ public Table(Class cls, EntityDictionary dictionary) { String.format("Table class {%s} is not defined in dictionary.", cls)); } - this.name = dictionary.getJsonAliasFor(cls); + this.id = dictionary.getJsonAliasFor(cls); this.tableTags = new HashSet<>(); this.columns = constructColumns(cls, dictionary); @@ -87,7 +87,7 @@ public Table(Class cls, EntityDictionary dictionary) { Meta meta = cls.getAnnotation(Meta.class); if (meta != null) { - this.longName = meta.longName(); + this.name = meta.longName(); this.description = meta.description(); } @@ -106,21 +106,21 @@ public Table(Class cls, EntityDictionary dictionary) { */ private Set constructColumns(Class cls, EntityDictionary dictionary) { Set columns = dictionary.getAllFields(cls).stream() - .filter(field -> getDataType(cls, field, dictionary) != null) + .filter(field -> getValueType(cls, field, dictionary) != null) .map(field -> { if (isMetricField(dictionary, cls, field)) { - return constructMetric(cls, field, dictionary); + return constructMetric(field, dictionary); } else if (dictionary.attributeOrRelationAnnotationExists(cls, field, Temporal.class)) { - return constructTimeDimension(cls, field, dictionary); + return constructTimeDimension(field, dictionary); } else { - return constructDimension(cls, field, dictionary); + return constructDimension(field, dictionary); } }) .collect(Collectors.toSet()); // add id field if exists if (dictionary.getIdFieldName(cls) != null) { - columns.add(constructDimension(cls, dictionary.getIdFieldName(cls), dictionary)); + columns.add(constructDimension(dictionary.getIdFieldName(cls), dictionary)); } return columns; @@ -129,37 +129,34 @@ private Set constructColumns(Class cls, EntityDictionary dictionary) /** * Construct a Metric instance. * - * @param cls table class * @param fieldName field name * @param dictionary dictionary contains the table class * @return Metric metadata instance */ - protected Metric constructMetric(Class cls, String fieldName, EntityDictionary dictionary) { - return new Metric(cls, fieldName, dictionary); + protected Metric constructMetric(String fieldName, EntityDictionary dictionary) { + return new Metric(this, fieldName, dictionary); } /** * Construct a Dimension instance. * - * @param cls table class * @param fieldName field name * @param dictionary dictionary contains the table class * @return Dimension metadata instance */ - protected TimeDimension constructTimeDimension(Class cls, String fieldName, EntityDictionary dictionary) { - return new TimeDimension(cls, fieldName, dictionary); + protected TimeDimension constructTimeDimension(String fieldName, EntityDictionary dictionary) { + return new TimeDimension(this, fieldName, dictionary); } /** * Construct a TimeDimension instance. * - * @param cls table class * @param fieldName field name * @param dictionary dictionary contains the table class * @return TimeDimension metadata instance */ - protected Dimension constructDimension(Class cls, String fieldName, EntityDictionary dictionary) { - return new Dimension(cls, fieldName, dictionary); + protected Dimension constructDimension(String fieldName, EntityDictionary dictionary) { + return new Dimension(this, fieldName, dictionary); } /** diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/TimeDimension.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/TimeDimension.java index 22b06e3fd8..6174f3dfb2 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/TimeDimension.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/metadata/models/TimeDimension.java @@ -11,6 +11,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.Arrays; import java.util.LinkedHashSet; @@ -28,14 +29,18 @@ @Data public class TimeDimension extends Dimension { @ManyToMany + @ToString.Exclude Set supportedGrains; private TimeZone timezone; - public TimeDimension(Class tableClass, String fieldName, EntityDictionary dictionary) { - super(tableClass, fieldName, dictionary); + public TimeDimension(Table table, String fieldName, EntityDictionary dictionary) { + super(table, fieldName, dictionary); - Temporal temporal = dictionary.getAttributeOrRelationAnnotation(tableClass, Temporal.class, fieldName); + Temporal temporal = dictionary.getAttributeOrRelationAnnotation( + dictionary.getEntityClass(table.getId()), + Temporal.class, + fieldName); this.supportedGrains = Arrays.stream(temporal.grains()) .map(grain -> new TimeDimensionGrain(getId(), grain)) diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/AbstractEntityHydrator.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/AbstractEntityHydrator.java index caec8cd31e..c23fe1870f 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/AbstractEntityHydrator.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/AbstractEntityHydrator.java @@ -7,9 +7,9 @@ import com.yahoo.elide.core.EntityDictionary; import com.yahoo.elide.datastores.aggregation.QueryEngine; +import com.yahoo.elide.datastores.aggregation.metadata.enums.ValueType; import com.yahoo.elide.datastores.aggregation.metadata.metric.MetricFunctionInvocation; import com.yahoo.elide.datastores.aggregation.metadata.models.Dimension; -import com.yahoo.elide.datastores.aggregation.metadata.models.RelationshipType; import com.yahoo.elide.datastores.aggregation.query.ColumnProjection; import com.yahoo.elide.datastores.aggregation.query.Query; @@ -151,7 +151,7 @@ public Iterable hydrate() { * @return A hydrated entity object. */ protected Object coerceObjectToEntity(Map result, MutableInt counter) { - Class entityClass = entityDictionary.getEntityClass(query.getTable().getName()); + Class entityClass = entityDictionary.getEntityClass(query.getTable().getId()); //Construct the object. Object entityInstance; @@ -164,7 +164,7 @@ protected Object coerceObjectToEntity(Map result, MutableInt cou result.forEach((fieldName, value) -> { Dimension dim = query.getTable().getDimension(fieldName); - if (dim != null && dim.getDataType() instanceof RelationshipType) { + if (dim != null && dim.getValueType().equals(ValueType.RELATIONSHIP)) { getStitchList().todo(entityInstance, fieldName, value); // We don't hydrate relationships here. } else { getEntityDictionary().setValue(entityInstance, fieldName, value); @@ -194,7 +194,7 @@ private void populateObjectLookupTable() { String joinField = entry.getKey(); List joinFieldIds = entry.getValue(); Class relationshipType = getEntityDictionary().getParameterizedType( - entityDictionary.getEntityClass(getQuery().getTable().getName()), + entityDictionary.getEntityClass(getQuery().getTable().getId()), joinField); getStitchList().populateLookup(relationshipType, getRelationshipValues(relationshipType, joinFieldIds)); diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/SQLQueryConstructor.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/SQLQueryConstructor.java index 4d1fcf9107..5f4572f552 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/SQLQueryConstructor.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/SQLQueryConstructor.java @@ -73,7 +73,7 @@ public SQLQuery resolveTemplate(Query clientQuery, FilterExpression whereClause, FilterExpression havingClause) { SQLTable table = (SQLTable) clientQuery.getTable(); - Class tableCls = dictionary.getEntityClass(clientQuery.getTable().getName()); + Class tableCls = dictionary.getEntityClass(clientQuery.getTable().getId()); String tableAlias = getClassAlias(tableCls); SQLQuery.SQLQueryBuilder builder = SQLQuery.builder().clientQuery(clientQuery); @@ -84,7 +84,7 @@ public SQLQuery resolveTemplate(Query clientQuery, ? "(" + tableCls.getAnnotation(FromSubquery.class).sql() + ")" : tableCls.isAnnotationPresent(FromTable.class) ? tableCls.getAnnotation(FromTable.class).name() - : table.getName(); + : table.getId(); builder.fromClause(String.format("%s AS %s", tableStatement, tableAlias)); @@ -155,7 +155,7 @@ private String constructHavingClauseWithReference(FilterPredicate predicate, Class lastClass = last.getType(); String fieldName = last.getFieldName(); - if (!lastClass.equals(dictionary.getEntityClass(table.getName()))) { + if (!lastClass.equals(dictionary.getEntityClass(table.getId()))) { throw new InvalidPredicateException("The having clause can only reference fact table aggregations."); } @@ -186,7 +186,7 @@ private String constructProjectionWithReference(SQLQueryTemplate template, SQLTa .map(invocation -> invocation.getFunctionExpression() + " AS " + invocation.getAlias()) .collect(Collectors.toList()); - Class tableClass = dictionary.getEntityClass(table.getName()); + Class tableClass = dictionary.getEntityClass(table.getId()); List dimensionProjections = template.getGroupByDimensions().stream() .map(dimension -> resolveSQLColumnReference(dimension, table) + " AS " + dimension.getAlias()) diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLDimension.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLDimension.java index c5d46f4156..7381063f82 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLDimension.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLDimension.java @@ -11,6 +11,7 @@ import com.yahoo.elide.core.EntityDictionary; import com.yahoo.elide.datastores.aggregation.core.JoinPath; import com.yahoo.elide.datastores.aggregation.metadata.models.Dimension; +import com.yahoo.elide.datastores.aggregation.metadata.models.Table; import com.yahoo.elide.datastores.aggregation.queryengines.sql.annotation.JoinTo; import lombok.Getter; @@ -25,8 +26,9 @@ public class SQLDimension extends Dimension implements SQLColumn { @Getter private final JoinPath joinPath; - public SQLDimension(Class tableClass, String fieldName, EntityDictionary dictionary) { - super(tableClass, fieldName, dictionary); + public SQLDimension(Table table, String fieldName, EntityDictionary dictionary) { + super(table, fieldName, dictionary); + Class tableClass = dictionary.getEntityClass(table.getId()); JoinTo joinTo = dictionary.getAttributeOrRelationAnnotation(tableClass, JoinTo.class, fieldName); diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLMetric.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLMetric.java index 9adb42c333..00aa2e4dad 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLMetric.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLMetric.java @@ -9,6 +9,7 @@ import com.yahoo.elide.datastores.aggregation.metadata.models.FunctionArgument; import com.yahoo.elide.datastores.aggregation.metadata.models.Metric; import com.yahoo.elide.datastores.aggregation.metadata.models.MetricFunction; +import com.yahoo.elide.datastores.aggregation.metadata.models.Table; import com.yahoo.elide.datastores.aggregation.queryengines.sql.metric.SQLMetricFunction; import java.util.Set; @@ -17,8 +18,8 @@ * SQLMetric would contain {@link SQLMetricFunction} instead of {@link MetricFunction}. */ public class SQLMetric extends Metric { - public SQLMetric(Class tableClass, String fieldName, EntityDictionary dictionary) { - super(tableClass, fieldName, dictionary); + public SQLMetric(Table table, String fieldName, EntityDictionary dictionary) { + super(table, fieldName, dictionary); } @Override diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLTable.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLTable.java index c787232dec..6f15cf764d 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLTable.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLTable.java @@ -8,14 +8,12 @@ import com.yahoo.elide.core.EntityDictionary; import com.yahoo.elide.datastores.aggregation.metadata.models.Table; -import lombok.Data; import lombok.EqualsAndHashCode; /** * SQL extension of {@link Table} which also contains sql column meta data. */ @EqualsAndHashCode(callSuper = true) -@Data public class SQLTable extends Table { public SQLTable(Class cls, EntityDictionary dictionary) { super(cls, dictionary); @@ -27,17 +25,17 @@ public final SQLColumn getSQLColumn(String fieldName) { } @Override - protected SQLMetric constructMetric(Class cls, String fieldName, EntityDictionary dictionary) { - return new SQLMetric(cls, fieldName, dictionary); + protected SQLMetric constructMetric(String fieldName, EntityDictionary dictionary) { + return new SQLMetric(this, fieldName, dictionary); } @Override - protected SQLTimeDimension constructTimeDimension(Class cls, String fieldName, EntityDictionary dictionary) { - return new SQLTimeDimension(cls, fieldName, dictionary); + protected SQLTimeDimension constructTimeDimension(String fieldName, EntityDictionary dictionary) { + return new SQLTimeDimension(this, fieldName, dictionary); } @Override - protected SQLDimension constructDimension(Class cls, String fieldName, EntityDictionary dictionary) { - return new SQLDimension(cls, fieldName, dictionary); + protected SQLDimension constructDimension(String fieldName, EntityDictionary dictionary) { + return new SQLDimension(this, fieldName, dictionary); } } diff --git a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLTimeDimension.java b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLTimeDimension.java index 17241405c2..fff0a73be0 100644 --- a/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLTimeDimension.java +++ b/elide-datastore/elide-datastore-aggregation/src/main/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/metadata/SQLTimeDimension.java @@ -10,6 +10,7 @@ import com.yahoo.elide.core.EntityDictionary; import com.yahoo.elide.datastores.aggregation.core.JoinPath; +import com.yahoo.elide.datastores.aggregation.metadata.models.Table; import com.yahoo.elide.datastores.aggregation.metadata.models.TimeDimension; import com.yahoo.elide.datastores.aggregation.queryengines.sql.annotation.JoinTo; @@ -25,8 +26,9 @@ public class SQLTimeDimension extends TimeDimension implements SQLColumn { @Getter private final JoinPath joinPath; - public SQLTimeDimension(Class tableClass, String fieldName, EntityDictionary dictionary) { - super(tableClass, fieldName, dictionary); + public SQLTimeDimension(Table table, String fieldName, EntityDictionary dictionary) { + super(table, fieldName, dictionary); + Class tableClass = dictionary.getEntityClass(table.getId()); JoinTo joinTo = dictionary.getAttributeOrRelationAnnotation(tableClass, JoinTo.class, fieldName); diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/EntityProjectionTranslatorTest.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/EntityProjectionTranslatorTest.java index 661e378edb..bfe356df5c 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/EntityProjectionTranslatorTest.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/EntityProjectionTranslatorTest.java @@ -11,7 +11,6 @@ import com.yahoo.elide.core.exceptions.InvalidOperationException; import com.yahoo.elide.core.filter.dialect.ParseException; import com.yahoo.elide.core.filter.expression.FilterExpression; -import com.yahoo.elide.datastores.aggregation.example.Country; import com.yahoo.elide.datastores.aggregation.example.PlayerStats; import com.yahoo.elide.datastores.aggregation.filter.visitor.FilterConstraints; import com.yahoo.elide.datastores.aggregation.filter.visitor.SplitFilterExpressionVisitor; @@ -23,7 +22,6 @@ import com.yahoo.elide.request.Argument; import com.yahoo.elide.request.Attribute; import com.yahoo.elide.request.EntityProjection; -import com.yahoo.elide.request.Relationship; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -43,16 +41,6 @@ public class EntityProjectionTranslatorTest extends SQLUnitTest { .type(String.class) .name("overallRating") .build()) - .relationship(Relationship.builder() - .name("country") - .projection(EntityProjection.builder() - .type(Country.class) - .attribute(Attribute.builder() - .type(String.class) - .name("name") - .build()) - .build()) - .build()) .build(); @BeforeAll @@ -73,11 +61,10 @@ public void testBasicTranslation() { assertEquals(playerStatsTable, query.getTable()); assertEquals(1, query.getMetrics().size()); assertEquals("lowScore", query.getMetrics().get(0).getAlias()); - assertEquals(2, query.getGroupByDimensions().size()); + assertEquals(1, query.getGroupByDimensions().size()); List dimensions = new ArrayList<>(query.getGroupByDimensions()); assertEquals("overallRating", dimensions.get(0).getColumn().getName()); - assertEquals("country", dimensions.get(1).getColumn().getName()); } @Test diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/QueryValidatorTest.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/QueryValidatorTest.java index 5d69ce4747..08583135f3 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/QueryValidatorTest.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/QueryValidatorTest.java @@ -35,23 +35,6 @@ public static void init() { SQLUnitTest.init(); } - @Test - public void testNoMetricQuery() { - Map sortMap = new TreeMap<>(); - sortMap.put("country.name", Sorting.SortOrder.asc); - - Query query = Query.builder() - .table(playerStatsTable) - .groupByDimension(toProjection(playerStatsTable.getDimension("overallRating"))) - .sorting(new SortingImpl(sortMap, PlayerStats.class, dictionary)) - .build(); - - QueryValidator validator = new QueryValidator(query, Collections.singleton("overallRating"), dictionary); - - UnsupportedOperationException exception = assertThrows(UnsupportedOperationException.class, validator::validate); - assertEquals("Query with no metric can't sort on nested field.", exception.getMessage()); - } - @Test public void testSortingOnId() { Map sortMap = new TreeMap<>(); @@ -75,7 +58,7 @@ public void testSortingOnId() { @Test public void testSortingOnNotQueriedDimension() { Map sortMap = new TreeMap<>(); - sortMap.put("country.name", Sorting.SortOrder.asc); + sortMap.put("countryIsoCode", Sorting.SortOrder.asc); Query query = Query.builder() .table(playerStatsTable) @@ -88,7 +71,7 @@ public void testSortingOnNotQueriedDimension() { QueryValidator validator = new QueryValidator(query, allFields, dictionary); InvalidOperationException exception = assertThrows(InvalidOperationException.class, validator::validate); - assertEquals("Invalid operation: 'Can't sort on country as it is not present in query'", exception.getMessage()); + assertEquals("Invalid operation: 'Can't sort on countryIsoCode as it is not present in query'", exception.getMessage()); } @Test @@ -110,25 +93,6 @@ public void testSortingOnNotQueriedMetric() { assertEquals("Invalid operation: 'Can't sort on highScore as it is not present in query'", exception.getMessage()); } - @Test - public void testSortingOnNestedDimensionField() { - Map sortMap = new TreeMap<>(); - sortMap.put("country.continent.name", Sorting.SortOrder.asc); - - Query query = Query.builder() - .table(playerStatsTable) - .metric(invoke(playerStatsTable.getMetric("lowScore"))) - .groupByDimension(toProjection(playerStatsTable.getDimension("country"))) - .sorting(new SortingImpl(sortMap, PlayerStats.class, dictionary)) - .build(); - - Set allFields = new HashSet<>(Arrays.asList("country", "lowScore")); - QueryValidator validator = new QueryValidator(query, allFields, dictionary); - - UnsupportedOperationException exception = assertThrows(UnsupportedOperationException.class, validator::validate); - assertEquals("Currently sorting on double nested fields is not supported", exception.getMessage()); - } - @Test public void testHavingFilterPromotionUngroupedDimension() throws ParseException { FilterExpression originalFilter = filterParser.parseFilterExpression("countryIsoCode==USA,lowScore<45", diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/CountryView.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/CountryView.java index 96fcc23fad..17ed251a29 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/CountryView.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/CountryView.java @@ -6,22 +6,21 @@ package com.yahoo.elide.datastores.aggregation.example; import com.yahoo.elide.annotation.Include; -import com.yahoo.elide.annotation.ToOne; import com.yahoo.elide.datastores.aggregation.annotation.FriendlyName; import com.yahoo.elide.datastores.aggregation.annotation.Join; +import com.yahoo.elide.datastores.aggregation.queryengines.sql.annotation.FromTable; import com.yahoo.elide.datastores.aggregation.queryengines.sql.annotation.JoinTo; import lombok.Data; import javax.persistence.Column; -import javax.persistence.Table; /** * A view version of table countries. */ @Data @Include -@Table(name = "countries") +@FromTable(name = "countries") public class CountryView { @Column(name = "id") private String countryId; @@ -40,17 +39,6 @@ public CountryViewNested getNestedView() { @JoinTo(path = "nestedView.isoCode") private String nestedViewIsoCode; - private Country nestedRelationship; - - @ToOne - @Column(name = "id") - public Country getNestedRelationship() { - return nestedRelationship; - } - - @JoinTo(path = "nestedRelationship.isoCode") - private String nestedRelationshipIsoCode; - public String getCountryId() { return countryId; } diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/CountryViewNested.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/CountryViewNested.java index c77ef81a0f..87fd3fbb12 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/CountryViewNested.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/CountryViewNested.java @@ -7,18 +7,18 @@ import com.yahoo.elide.annotation.Include; import com.yahoo.elide.datastores.aggregation.annotation.FriendlyName; +import com.yahoo.elide.datastores.aggregation.queryengines.sql.annotation.FromTable; import lombok.Data; import javax.persistence.Id; -import javax.persistence.Table; /** * A nested view for testing. */ @Data @Include -@Table(name = "countries") +@FromTable(name = "countries") public class CountryViewNested { private String id; diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/PlayerStats.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/PlayerStats.java index 60f394bafc..b6e5c99bac 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/PlayerStats.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/PlayerStats.java @@ -9,6 +9,7 @@ import com.yahoo.elide.datastores.aggregation.annotation.Cardinality; import com.yahoo.elide.datastores.aggregation.annotation.CardinalitySize; import com.yahoo.elide.datastores.aggregation.annotation.FriendlyName; +import com.yahoo.elide.datastores.aggregation.annotation.Join; import com.yahoo.elide.datastores.aggregation.annotation.Meta; import com.yahoo.elide.datastores.aggregation.annotation.MetricAggregation; import com.yahoo.elide.datastores.aggregation.annotation.Temporal; @@ -26,8 +27,6 @@ import java.util.Date; import javax.persistence.Column; import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; /** * A root level entity for testing AggregationDataStore. */ @@ -138,8 +137,7 @@ public void setOverallRating(final String overallRating) { this.overallRating = overallRating; } - @ManyToOne - @JoinColumn(name = "country_id") + @Join("%from.country_id = %join.id") public Country getCountry() { return country; } @@ -148,43 +146,6 @@ public void setCountry(final Country country) { this.country = country; } - @ManyToOne - @JoinColumn(name = "sub_country_id") - public SubCountry getSubCountry() { - return subCountry; - } - - public void setSubCountry(final SubCountry subCountry) { - this.subCountry = subCountry; - } - - @ManyToOne - @JoinColumn(name = "player_id") - public Player getPlayer() { - return player; - } - - public void setPlayer(final Player player) { - this.player = player; - } - - /** - * DO NOT put {@link Cardinality} annotation on this field. See - * - * @return the date of the player session. - */ - @Temporal(grains = { - @TimeGrainDefinition(grain = TimeGrain.DAY, expression = DAY_FORMAT), - @TimeGrainDefinition(grain = TimeGrain.MONTH, expression = MONTH_FORMAT) - }, timeZone = "UTC") - public Date getRecordedDate() { - return recordedDate; - } - - public void setRecordedDate(final Date recordedDate) { - this.recordedDate = recordedDate; - } - @JoinTo(path = "country.isoCode") public String getCountryIsoCode() { return countryIsoCode; @@ -194,6 +155,14 @@ public void setCountryIsoCode(String isoCode) { this.countryIsoCode = isoCode; } + @Join("%from.sub_country_id = %join.id") + public SubCountry getSubCountry() { + return subCountry; + } + + public void setSubCountry(final SubCountry subCountry) { + this.subCountry = subCountry; + } @JoinTo(path = "subCountry.isoCode") @Column(updatable = false, insertable = false) // subselect field should be read-only @@ -205,8 +174,16 @@ public void setSubCountryIsoCode(String isoCode) { this.subCountryIsoCode = isoCode; } - @JoinColumn(name = "player2_id") - @ManyToOne + @Join("%from.player_id = %join.id") + public Player getPlayer() { + return player; + } + + public void setPlayer(final Player player) { + this.player = player; + } + + @Join("%from.player2_id = %join.id") public Player getPlayer2() { return player2; } @@ -232,4 +209,21 @@ public String getPlayer2Name() { public void setPlayer2Name(String player2Name) { this.player2Name = player2Name; } + + /** + * DO NOT put {@link Cardinality} annotation on this field. See + * + * @return the date of the player session. + */ + @Temporal(grains = { + @TimeGrainDefinition(grain = TimeGrain.DAY, expression = DAY_FORMAT), + @TimeGrainDefinition(grain = TimeGrain.MONTH, expression = MONTH_FORMAT) + }, timeZone = "UTC") + public Date getRecordedDate() { + return recordedDate; + } + + public void setRecordedDate(final Date recordedDate) { + this.recordedDate = recordedDate; + } } diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/PlayerStatsView.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/PlayerStatsView.java index 22562b204a..90d0809277 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/PlayerStatsView.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/PlayerStatsView.java @@ -6,14 +6,14 @@ package com.yahoo.elide.datastores.aggregation.example; import com.yahoo.elide.annotation.Include; +import com.yahoo.elide.datastores.aggregation.annotation.Join; import com.yahoo.elide.datastores.aggregation.annotation.MetricAggregation; import com.yahoo.elide.datastores.aggregation.queryengines.sql.annotation.FromSubquery; import com.yahoo.elide.datastores.aggregation.queryengines.sql.metric.functions.SqlMax; + import lombok.Data; import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; /** * A root level entity for testing AggregationDataStore. @@ -40,7 +40,6 @@ public class PlayerStatsView { */ private String countryName; - @OneToOne - @JoinColumn(name = "player_id") + @Join("%from.player_id = %join.id") private Player player; } diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/PlayerStatsWithView.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/PlayerStatsWithView.java index c6d437e919..e2cd45928a 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/PlayerStatsWithView.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/example/PlayerStatsWithView.java @@ -27,8 +27,6 @@ import java.util.Date; import javax.persistence.Column; import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; /** * A root level entity for testing AggregationDataStore. @@ -78,9 +76,6 @@ public class PlayerStatsWithView { @Setter private String countryViewViewIsoCode; - @Setter - private String countryViewRelationshipIsoCode; - /** * A dimension field joined to this table. */ @@ -136,8 +131,7 @@ public void setOverallRating(final String overallRating) { this.overallRating = overallRating; } - @ManyToOne - @JoinColumn(name = "country_id") + @Join("%from.country_id = %join.id") public Country getCountry() { return country; } @@ -146,8 +140,7 @@ public void setCountry(final Country country) { this.country = country; } - @ManyToOne - @JoinColumn(name = "sub_country_id") + @Join("%from.sub_country_id = %join.id") public SubCountry getSubCountry() { return subCountry; } @@ -156,8 +149,7 @@ public void setSubCountry(final SubCountry subCountry) { this.subCountry = subCountry; } - @ManyToOne - @JoinColumn(name = "player_id") + @Join("%from.player_id = %join.id") public Player getPlayer() { return player; } @@ -214,9 +206,4 @@ public String getCountryViewIsoCode() { public String getCountryViewViewIsoCode() { return countryViewViewIsoCode; } - - @JoinTo(path = "countryView.nestedRelationship.isoCode") - public String getCountryViewRelationshipIsoCode() { - return countryViewRelationshipIsoCode; - } } diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/integration/AggregationDataStoreIntegrationTest.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/integration/AggregationDataStoreIntegrationTest.java index 6c64bafd1a..0b4f981854 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/integration/AggregationDataStoreIntegrationTest.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/integration/AggregationDataStoreIntegrationTest.java @@ -87,15 +87,13 @@ public void basicAggregationTest() throws Exception { selection( field( "playerStats", + arguments( + argument("sort", "\"highScore\"") + ), selections( field("highScore"), field("overallRating"), - field( - "country", - selections( - field("name") - ) - ) + field("countryIsoCode") ) ) ) @@ -105,35 +103,20 @@ public void basicAggregationTest() throws Exception { selections( field( "playerStats", + selections( + field("highScore", 1000), + field("overallRating", "Good"), + field("countryIsoCode", "HKG") + ), selections( field("highScore", 1234), field("overallRating", "Good"), - field( - "country", - selections( - field("name", "United States") - ) - ) + field("countryIsoCode", "USA") ), selections( field("highScore", 2412), field("overallRating", "Great"), - field( - "country", - selections( - field("name", "United States") - ) - ) - ), - selections( - field("highScore", 1000), - field("overallRating", "Good"), - field( - "country", - selections( - field("name", "Hong Kong") - ) - ) + field("countryIsoCode", "USA") ) ) ) @@ -149,17 +132,10 @@ public void noMetricQueryTest() throws Exception { field( "playerStatsWithView", arguments( - argument("sort", "\"countryViewRelationshipIsoCode\"") + argument("sort", "\"countryViewViewIsoCode\"") ), selections( - field( - "country", - selections( - field("name"), - field("isoCode") - ) - ), - field("countryViewRelationshipIsoCode") + field("countryViewViewIsoCode") ) ) ) @@ -170,24 +146,10 @@ public void noMetricQueryTest() throws Exception { field( "playerStatsWithView", selections( - field( - "country", - selections( - field("name", "Hong Kong"), - field("isoCode", "HKG") - ) - ), - field("countryViewRelationshipIsoCode", "HKG") + field("countryViewViewIsoCode", "HKG") ), selections( - field( - "country", - selections( - field("name", "United States"), - field("isoCode", "USA") - ) - ), - field("countryViewRelationshipIsoCode", "USA") + field("countryViewViewIsoCode", "USA") ) ) ) @@ -240,12 +202,7 @@ public void havingFilterTest() throws Exception { selections( field("lowScore"), field("overallRating"), - field( - "player", - selections( - field("name") - ) - ) + field("playerName") ) ) ) @@ -258,12 +215,7 @@ public void havingFilterTest() throws Exception { selections( field("lowScore", 35), field("overallRating", "Good"), - field( - "player", - selections( - field("name", "Jon Doe") - ) - ) + field("playerName", "Jon Doe") ) ) ) @@ -283,17 +235,13 @@ public void wherePromotionTest() throws Exception { field( "playerStats", arguments( - argument("filter", "\"overallRating==\\\"Good\\\",lowScore<\\\"45\\\"\"") + argument("filter", "\"overallRating==\\\"Good\\\",lowScore<\\\"45\\\"\""), + argument("sort", "\"lowScore\"") ), selections( field("lowScore"), field("overallRating"), - field( - "player", - selections( - field("name") - ) - ) + field("playerName") ) ) ) @@ -306,22 +254,12 @@ public void wherePromotionTest() throws Exception { selections( field("lowScore", 35), field("overallRating", "Good"), - field( - "player", - selections( - field("name", "Jon Doe") - ) - ) + field("playerName", "Jon Doe") ), selections( field("lowScore", 72), field("overallRating", "Good"), - field( - "player", - selections( - field("name", "Han") - ) - ) + field("playerName", "Han") ) ) ) @@ -347,12 +285,7 @@ public void havingClauseJoinTest() throws Exception { selections( field("lowScore"), field("countryIsoCode"), - field( - "player", - selections( - field("name") - ) - ) + field("playerName") ) ) ) @@ -365,22 +298,12 @@ public void havingClauseJoinTest() throws Exception { selections( field("lowScore", 35), field("countryIsoCode", "USA"), - field( - "player", - selections( - field("name", "Jon Doe") - ) - ) + field("playerName", "Jon Doe") ), selections( field("lowScore", 241), field("countryIsoCode", "USA"), - field( - "player", - selections( - field("name", "Jane Doe") - ) - ) + field("playerName", "Jane Doe") ) ) ) @@ -515,12 +438,7 @@ public void metricSortingTest() throws Exception { ), selections( field("highScore"), - field( - "country", - selections( - field("name") - ) - ) + field("countryIsoCode") ) ) ) @@ -532,21 +450,11 @@ public void metricSortingTest() throws Exception { "playerStats", selections( field("highScore", 2412), - field( - "country", - selections( - field("name", "United States") - ) - ) + field("countryIsoCode", "USA") ), selections( field("highScore", 1000), - field( - "country", - selections( - field("name", "Hong Kong") - ) - ) + field("countryIsoCode", "HKG") ) ) ) @@ -562,17 +470,12 @@ public void multipleColumnsSortingTest() throws Exception { field( "playerStats", arguments( - argument("sort", "\"overallRating,player.name\"") + argument("sort", "\"overallRating,playerName\"") ), selections( field("lowScore"), field("overallRating"), - field( - "player", - selections( - field("name") - ) - ) + field("playerName") ) ) ) @@ -585,32 +488,17 @@ public void multipleColumnsSortingTest() throws Exception { selections( field("lowScore", 72), field("overallRating", "Good"), - field( - "player", - selections( - field("name", "Han") - ) - ) + field("playerName", "Han") ), selections( field("lowScore", 35), field("overallRating", "Good"), - field( - "player", - selections( - field("name", "Jon Doe") - ) - ) + field("playerName", "Jon Doe") ), selections( field("lowScore", 241), field("overallRating", "Great"), - field( - "player", - selections( - field("name", "Jane Doe") - ) - ) + field("playerName", "Jane Doe") ) ) ) @@ -648,7 +536,7 @@ public void nestedDimensionNotInQuerySortingTest() throws Exception { field( "playerStats", arguments( - argument("sort", "\"-country.name,lowScore\"") + argument("sort", "\"-countryIsoCode,lowScore\"") ), selections( field("lowScore") @@ -657,7 +545,7 @@ public void nestedDimensionNotInQuerySortingTest() throws Exception { ) ).toQuery(); - String expected = "\"Exception while fetching data (/playerStats) : Invalid operation: 'Can't sort on country as it is not present in query'\""; + String expected = "\"Exception while fetching data (/playerStats) : Invalid operation: 'Can't sort on countryIsoCode as it is not present in query'\""; runQueryWithExpectedError(graphQLRequest, expected); } @@ -673,12 +561,7 @@ public void sortingOnMetricNotInQueryTest() throws Exception { ), selections( field("lowScore"), - field( - "country", - selections( - field("name") - ) - ) + field("countryIsoCode") ) ) ) @@ -689,39 +572,6 @@ public void sortingOnMetricNotInQueryTest() throws Exception { runQueryWithExpectedError(graphQLRequest, expected); } - @Test - public void sortingMultipleLevelNesting() throws Exception { - String graphQLRequest = document( - selection( - field( - "playerStats", - arguments( - argument("sort", "\"country.continent.name\"") - ), - selections( - field("lowScore"), - field( - "country", - selections( - field("name"), - field( - "continent", - selections( - field("name") - ) - ) - ) - ) - ) - ) - ) - ).toQuery(); - - String expected = "\"Exception while fetching data (/playerStats) : Currently sorting on double nested fields is not supported\""; - - runQueryWithExpectedError(graphQLRequest, expected); - } - @Test @Disabled //FIXME Needs metric computation support for test case to be valid. @@ -763,14 +613,11 @@ public void basicViewAggregationTest() throws Exception { selection( field( "playerStatsWithView", + arguments( + argument("sort", "\"highScore\"") + ), selections( field("highScore"), - field( - "country", - selections( - field("name") - ) - ), field("countryViewIsoCode") ) ) @@ -783,22 +630,10 @@ public void basicViewAggregationTest() throws Exception { "playerStatsWithView", selections( field("highScore", 1000), - field( - "country", - selections( - field("name", "Hong Kong") - ) - ), field("countryViewIsoCode", "HKG") ), selections( field("highScore", 2412), - field( - "country", - selections( - field("name", "United States") - ) - ), field("countryViewIsoCode", "USA") ) ) @@ -817,7 +652,7 @@ public void jsonApiAggregationTest() { .statusCode(HttpStatus.SC_OK) .body("data.id", hasItems("0", "1", "2")) .body("data.attributes.highScore", hasItems(1000, 1234, 2412)) - .body("data.relationships.country.data.id", hasItems("840", "344")); + .body("data.attributes.countryIsoCode", hasItems("USA", "HKG")); } @Test @@ -840,23 +675,22 @@ public void metaDataTest() { "data.relationships.dimensions.data.id", hasItems( "playerStats.id", - "playerStats.player", - "playerStats.country", - "playerStats.subCountry", - "playerStats.recordedDate", - "playerStats.overallRating", + "playerStats.playerName", + "playerStats.player2Name", "playerStats.countryIsoCode", - "playerStats.subCountryIsoCode")) + "playerStats.subCountryIsoCode", + "playerStats.recordedDate", + "playerStats.overallRating")) .body("data.relationships.metrics.data.id", hasItems("playerStats.lowScore", "playerStats.highScore")); given() .accept("application/vnd.api+json") - .get("/dimension/playerStats.player") + .get("/dimension/playerStats.playerName") .then() .statusCode(HttpStatus.SC_OK) - .body("data.attributes.name", equalTo("player")) - .body("data.attributes.tableName", equalTo("playerStats")) - .body("data.relationships.dataType.data.id", equalTo("player")); + .body("data.attributes.name", equalTo("playerName")) + .body("data.attributes.valueType", equalTo("TEXT")) + .body("data.relationships.table.data.id", equalTo("playerStats")); given() .accept("application/vnd.api+json") @@ -864,8 +698,8 @@ public void metaDataTest() { .then() .statusCode(HttpStatus.SC_OK) .body("data.attributes.name", equalTo("lowScore")) - .body("data.attributes.tableName", equalTo("playerStats")) - .body("data.relationships.dataType.data.id", equalTo("p_bigint")) + .body("data.attributes.valueType", equalTo("INTEGER")) + .body("data.relationships.table.data.id", equalTo("playerStats")) .body("data.relationships.metricFunction.data.id", equalTo("playerStats.lowScore[min]")) .body("included.id", hasItem("playerStats.lowScore[min]")) .body("included.attributes.description", hasItem("sql min function")) @@ -878,8 +712,8 @@ public void metaDataTest() { .then() .statusCode(HttpStatus.SC_OK) .body("data.attributes.name", equalTo("recordedDate")) - .body("data.attributes.tableName", equalTo("playerStats")) - .body("data.relationships.dataType.data.id", equalTo("date")) + .body("data.attributes.valueType", equalTo("TIME")) + .body("data.relationships.table.data.id", equalTo("playerStats")) .body( "data.relationships.supportedGrains.data.id", hasItems("playerStats.recordedDate.day", "playerStats.recordedDate.month")) diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/QueryEngineTest.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/QueryEngineTest.java index 5d870e1c3e..f5e5949215 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/QueryEngineTest.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/QueryEngineTest.java @@ -7,7 +7,6 @@ package com.yahoo.elide.datastores.aggregation.queryengines.sql; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import com.yahoo.elide.core.Path; import com.yahoo.elide.core.filter.FilterPredicate; @@ -20,6 +19,7 @@ import com.yahoo.elide.datastores.aggregation.metadata.enums.TimeGrain; import com.yahoo.elide.datastores.aggregation.metadata.models.Table; import com.yahoo.elide.datastores.aggregation.query.Query; +import com.yahoo.elide.datastores.aggregation.queryengines.sql.annotation.FromSubquery; import com.yahoo.elide.datastores.aggregation.queryengines.sql.metadata.SQLTable; import com.yahoo.elide.request.Sorting; @@ -84,63 +84,86 @@ public void testFullTableLoad() { } /** - * Test group by a degenerate dimension with a filter applied. + * Test loading records using {@link FromSubquery} + */ + @Test + public void testFromSubQuery() { + Query query = Query.builder() + .table(playerStatsViewTable) + .metric(invoke(playerStatsTable.getMetric("highScore"))) + .build(); + + List results = StreamSupport.stream(engine.executeQuery(query).spliterator(), false) + .collect(Collectors.toList()); + + PlayerStatsView stats2 = new PlayerStatsView(); + stats2.setId("0"); + stats2.setHighScore(2412); + + assertEquals(1, results.size()); + assertEquals(stats2, results.get(0)); + } + + /** + * Test group by, having, dimension, metric at the same time. * * @throws Exception exception */ @Test - public void testDegenerateDimensionFilter() throws Exception { + public void testAllArgumentQuery() throws Exception { + Map sortMap = new TreeMap<>(); + sortMap.put("countryName", Sorting.SortOrder.asc); + Query query = Query.builder() - .table(playerStatsTable) - .metric(invoke(playerStatsTable.getMetric("lowScore"))) - .groupByDimension(toProjection(playerStatsTable.getDimension("overallRating"))) - .timeDimension(toProjection(playerStatsTable.getTimeDimension("recordedDate"), TimeGrain.DAY)) - .whereFilter(filterParser.parseFilterExpression("overallRating==Great", - PlayerStats.class, false)) + .table(playerStatsViewTable) + .metric(invoke(playerStatsTable.getMetric("highScore"))) + .groupByDimension(toProjection(playerStatsViewTable.getDimension("countryName"))) + .whereFilter(filterParser.parseFilterExpression("countryName=='United States'", + PlayerStatsView.class, false)) + .havingFilter(filterParser.parseFilterExpression("highScore > 300", + PlayerStatsView.class, false)) + .sorting(new SortingImpl(sortMap, PlayerStatsView.class, dictionary)) .build(); List results = StreamSupport.stream(engine.executeQuery(query).spliterator(), false) .collect(Collectors.toList()); - PlayerStats stats1 = new PlayerStats(); - stats1.setId("0"); - stats1.setLowScore(241); - stats1.setOverallRating("Great"); - stats1.setRecordedDate(Timestamp.valueOf("2019-07-11 00:00:00")); + PlayerStatsView stats2 = new PlayerStatsView(); + stats2.setId("0"); + stats2.setHighScore(2412); + stats2.setCountryName("United States"); assertEquals(1, results.size()); - assertEquals(stats1, results.get(0)); + assertEquals(stats2, results.get(0)); } /** - * Test filtering on a dimension attribute. + * Test group by a degenerate dimension with a filter applied. * * @throws Exception exception */ @Test - public void testFilterJoin() throws Exception { + public void testDegenerateDimensionFilter() throws Exception { Query query = Query.builder() .table(playerStatsTable) .metric(invoke(playerStatsTable.getMetric("lowScore"))) - .groupByDimension(toProjection(playerStatsTable.getDimension("country"))) - .whereFilter(filterParser.parseFilterExpression("country.name=='United States'", + .groupByDimension(toProjection(playerStatsTable.getDimension("overallRating"))) + .timeDimension(toProjection(playerStatsTable.getTimeDimension("recordedDate"), TimeGrain.DAY)) + .whereFilter(filterParser.parseFilterExpression("overallRating==Great", PlayerStats.class, false)) .build(); List results = StreamSupport.stream(engine.executeQuery(query).spliterator(), false) .collect(Collectors.toList()); - PlayerStats usa0 = new PlayerStats(); - usa0.setId("0"); - usa0.setLowScore(35); - usa0.setCountry(USA); + PlayerStats stats1 = new PlayerStats(); + stats1.setId("0"); + stats1.setLowScore(241); + stats1.setOverallRating("Great"); + stats1.setRecordedDate(Timestamp.valueOf("2019-07-11 00:00:00")); assertEquals(1, results.size()); - assertEquals(usa0, results.get(0)); - - // test relationship hydration - PlayerStats actualStats1 = (PlayerStats) results.get(0); - assertNotNull(actualStats1.getCountry()); + assertEquals(stats1, results.get(0)); } /** @@ -149,11 +172,11 @@ public void testFilterJoin() throws Exception { * @throws Exception exception */ @Test - public void testSubqueryFilterJoin() throws Exception { + public void testNotProjectedFilter() throws Exception { Query query = Query.builder() .table(playerStatsViewTable) .metric(invoke(playerStatsTable.getMetric("highScore"))) - .whereFilter(filterParser.parseFilterExpression("player.name=='Jane Doe'", + .whereFilter(filterParser.parseFilterExpression("countryName=='United States'", PlayerStatsView.class, false)) .build(); @@ -168,25 +191,34 @@ public void testSubqueryFilterJoin() throws Exception { assertEquals(stats2, results.get(0)); } - /** - * Test a view which filters on "stats.overallRating = 'Great'". - */ @Test - public void testSubqueryLoad() { + public void testSortAggregatedMetric() { + Map sortMap = new TreeMap<>(); + sortMap.put("lowScore", Sorting.SortOrder.desc); + Query query = Query.builder() - .table(playerStatsViewTable) - .metric(invoke(playerStatsTable.getMetric("highScore"))) + .table(playerStatsTable) + .groupByDimension(toProjection(playerStatsTable.getDimension("overallRating"))) + .metric(invoke(playerStatsTable.getMetric("lowScore"))) + .sorting(new SortingImpl(sortMap, PlayerStats.class, dictionary)) .build(); List results = StreamSupport.stream(engine.executeQuery(query).spliterator(), false) .collect(Collectors.toList()); - PlayerStatsView stats2 = new PlayerStatsView(); - stats2.setId("0"); - stats2.setHighScore(2412); + PlayerStats stats0 = new PlayerStats(); + stats0.setId("0"); + stats0.setLowScore(241); + stats0.setOverallRating("Great"); - assertEquals(1, results.size()); - assertEquals(stats2, results.get(0)); + PlayerStats stats1 = new PlayerStats(); + stats1.setId("1"); + stats1.setLowScore(35); + stats1.setOverallRating("Good"); + + assertEquals(2, results.size()); + assertEquals(stats0, results.get(0)); + assertEquals(stats1, results.get(1)); } /** @@ -195,7 +227,7 @@ public void testSubqueryLoad() { @Test public void testSortJoin() { Map sortMap = new TreeMap<>(); - sortMap.put("player.name", Sorting.SortOrder.asc); + sortMap.put("playerName", Sorting.SortOrder.asc); Query query = Query.builder() .table(playerStatsTable) @@ -334,39 +366,6 @@ public void testHavingClauseJoin() throws Exception { assertEquals(stats1, results.get(1)); } - /** - * Test group by, having, dimension, metric at the same time. - * - * @throws Exception exception - */ - @Test - public void testEdgeCasesQuery() throws Exception { - Map sortMap = new TreeMap<>(); - sortMap.put("player.name", Sorting.SortOrder.asc); - - Query query = Query.builder() - .table(playerStatsViewTable) - .metric(invoke(playerStatsTable.getMetric("highScore"))) - .groupByDimension(toProjection(playerStatsViewTable.getDimension("countryName"))) - .whereFilter(filterParser.parseFilterExpression("player.name=='Jane Doe'", - PlayerStatsView.class, false)) - .havingFilter(filterParser.parseFilterExpression("highScore > 300", - PlayerStatsView.class, false)) - .sorting(new SortingImpl(sortMap, PlayerStatsView.class, dictionary)) - .build(); - - List results = StreamSupport.stream(engine.executeQuery(query).spliterator(), false) - .collect(Collectors.toList()); - - PlayerStatsView stats2 = new PlayerStatsView(); - stats2.setId("0"); - stats2.setHighScore(2412); - stats2.setCountryName("United States"); - - assertEquals(1, results.size()); - assertEquals(stats2, results.get(0)); - } - /** * Test sorting by two different columns-one metric and one dimension. */ @@ -374,7 +373,7 @@ public void testEdgeCasesQuery() throws Exception { public void testSortByMultipleColumns() { Map sortMap = new TreeMap<>(); sortMap.put("lowScore", Sorting.SortOrder.desc); - sortMap.put("player.name", Sorting.SortOrder.asc); + sortMap.put("playerName", Sorting.SortOrder.asc); Query query = Query.builder() .table(playerStatsTable) @@ -411,54 +410,6 @@ public void testSortByMultipleColumns() { assertEquals(stats2, results.get(2)); } - /** - * Test hydrating multiple relationship values. Make sure the objects are constructed correctly. - */ - @Test - public void testRelationshipHydration() { - Map sortMap = new TreeMap<>(); - sortMap.put("country.name", Sorting.SortOrder.desc); - sortMap.put("overallRating", Sorting.SortOrder.desc); - - Query query = Query.builder() - .table(playerStatsTable) - .metric(invoke(playerStatsTable.getMetric("lowScore"))) - .groupByDimension(toProjection(playerStatsTable.getDimension("overallRating"))) - .groupByDimension(toProjection(playerStatsTable.getDimension("country"))) - .sorting(new SortingImpl(sortMap, PlayerStats.class, dictionary)) - .build(); - - List results = StreamSupport.stream(engine.executeQuery(query).spliterator(), false) - .collect(Collectors.toList()); - - PlayerStats usa0 = new PlayerStats(); - usa0.setId("0"); - usa0.setLowScore(241); - usa0.setOverallRating("Great"); - usa0.setCountry(USA); - - PlayerStats usa1 = new PlayerStats(); - usa1.setId("1"); - usa1.setLowScore(35); - usa1.setOverallRating("Good"); - usa1.setCountry(USA); - - PlayerStats hk2 = new PlayerStats(); - hk2.setId("2"); - hk2.setLowScore(72); - hk2.setOverallRating("Good"); - hk2.setCountry(HONG_KONG); - - assertEquals(3, results.size()); - assertEquals(usa0, results.get(0)); - assertEquals(usa1, results.get(1)); - assertEquals(hk2, results.get(2)); - - // test join - PlayerStats actualStats1 = (PlayerStats) results.get(0); - assertNotNull(actualStats1.getCountry()); - } - /** * Test grouping by a dimension with a JoinTo annotation. */ @@ -528,12 +479,13 @@ public void testJoinToFilter() throws Exception { public void testJoinToSort() { Map sortMap = new TreeMap<>(); sortMap.put("countryIsoCode", Sorting.SortOrder.asc); + sortMap.put("highScore", Sorting.SortOrder.asc); Query query = Query.builder() .table(playerStatsTable) .metric(invoke(playerStatsTable.getMetric("highScore"))) .groupByDimension(toProjection(playerStatsTable.getDimension("overallRating"))) - .groupByDimension(toProjection(playerStatsTable.getDimension("country"))) + .groupByDimension(toProjection(playerStatsTable.getDimension("countryIsoCode"))) .sorting(new SortingImpl(sortMap, PlayerStats.class, dictionary)) .build(); @@ -543,19 +495,19 @@ public void testJoinToSort() { PlayerStats stats1 = new PlayerStats(); stats1.setId("0"); stats1.setOverallRating("Good"); - stats1.setCountry(HONG_KONG); + stats1.setCountryIsoCode("HKG"); stats1.setHighScore(1000); PlayerStats stats2 = new PlayerStats(); stats2.setId("1"); stats2.setOverallRating("Good"); - stats2.setCountry(USA); + stats2.setCountryIsoCode("USA"); stats2.setHighScore(1234); PlayerStats stats3 = new PlayerStats(); stats3.setId("2"); stats3.setOverallRating("Great"); - stats3.setCountry(USA); + stats3.setCountryIsoCode("USA"); stats3.setHighScore(2412); assertEquals(3, results.size()); @@ -616,36 +568,6 @@ public void testFilterByTemporalDimension() { assertEquals(stats0, results.get(0)); } - @Test - public void testSortAggregatedMetric() { - Map sortMap = new TreeMap<>(); - sortMap.put("lowScore", Sorting.SortOrder.desc); - - Query query = Query.builder() - .table(playerStatsTable) - .groupByDimension(toProjection(playerStatsTable.getDimension("overallRating"))) - .metric(invoke(playerStatsTable.getMetric("lowScore"))) - .sorting(new SortingImpl(sortMap, PlayerStats.class, dictionary)) - .build(); - - List results = StreamSupport.stream(engine.executeQuery(query).spliterator(), false) - .collect(Collectors.toList()); - - PlayerStats stats0 = new PlayerStats(); - stats0.setId("0"); - stats0.setLowScore(241); - stats0.setOverallRating("Great"); - - PlayerStats stats1 = new PlayerStats(); - stats1.setId("1"); - stats1.setLowScore(35); - stats1.setOverallRating("Good"); - - assertEquals(2, results.size()); - assertEquals(stats0, results.get(0)); - assertEquals(stats1, results.get(1)); - } - @Test public void testAmbiguousFields() { Map sortMap = new TreeMap<>(); diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/SubselectTest.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/SubselectTest.java index bed32e8a87..d6fc403633 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/SubselectTest.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/SubselectTest.java @@ -7,20 +7,17 @@ package com.yahoo.elide.datastores.aggregation.queryengines.sql; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import com.yahoo.elide.core.sort.SortingImpl; import com.yahoo.elide.datastores.aggregation.example.PlayerStats; import com.yahoo.elide.datastores.aggregation.example.SubCountry; import com.yahoo.elide.datastores.aggregation.framework.SQLUnitTest; -import com.yahoo.elide.datastores.aggregation.metadata.enums.TimeGrain; import com.yahoo.elide.datastores.aggregation.query.Query; import com.yahoo.elide.request.Sorting; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import java.sql.Timestamp; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -44,117 +41,6 @@ public static void init() { SUB_USA.setId("840"); } - /** - * Test filtering on a dimension attribute. - * - * @throws Exception exception - */ - @Test - public void testFilterJoin() throws Exception { - Query query = Query.builder() - .table(playerStatsTable) - .metric(invoke(playerStatsTable.getMetric("lowScore"))) - .metric(invoke(playerStatsTable.getMetric("highScore"))) - .groupByDimension(toProjection(playerStatsTable.getDimension("overallRating"))) - .groupByDimension(toProjection(playerStatsTable.getDimension("subCountry"))) - .groupByDimension(toProjection(playerStatsTable.getDimension("country"))) - .timeDimension(toProjection(playerStatsTable.getTimeDimension("recordedDate"), TimeGrain.DAY)) - .whereFilter(filterParser.parseFilterExpression("subCountry.name=='United States'", - PlayerStats.class, false)) - .build(); - - - List results = StreamSupport.stream(engine.executeQuery(query).spliterator(), false) - .collect(Collectors.toList()); - - PlayerStats usa0 = new PlayerStats(); - usa0.setId("0"); - usa0.setLowScore(35); - usa0.setHighScore(1234); - usa0.setOverallRating("Good"); - usa0.setCountry(USA); - usa0.setSubCountry(SUB_USA); - usa0.setRecordedDate(Timestamp.valueOf("2019-07-12 00:00:00")); - - PlayerStats usa1 = new PlayerStats(); - usa1.setId("1"); - usa1.setLowScore(241); - usa1.setHighScore(2412); - usa1.setOverallRating("Great"); - usa1.setCountry(USA); - usa1.setSubCountry(SUB_USA); - usa1.setRecordedDate(Timestamp.valueOf("2019-07-11 00:00:00")); - - assertEquals(2, results.size()); - assertEquals(usa0, results.get(0)); - assertEquals(usa1, results.get(1)); - - // test join - PlayerStats actualStats0 = (PlayerStats) results.get(0); - assertNotNull(actualStats0.getSubCountry()); - assertNotNull(actualStats0.getCountry()); - } - - /** - * Test hydrating multiple relationship values. Make sure the objects are constructed correctly. - */ - @Test - public void testRelationshipHydration() { - Map sortMap = new TreeMap<>(); - sortMap.put("subCountry.name", Sorting.SortOrder.desc); - - Query query = Query.builder() - .table(playerStatsTable) - .metric(invoke(playerStatsTable.getMetric("lowScore"))) - .metric(invoke(playerStatsTable.getMetric("highScore"))) - .groupByDimension(toProjection(playerStatsTable.getDimension("overallRating"))) - .groupByDimension(toProjection(playerStatsTable.getDimension("country"))) - .groupByDimension(toProjection(playerStatsTable.getDimension("subCountry"))) - .timeDimension(toProjection(playerStatsTable.getTimeDimension("recordedDate"), TimeGrain.DAY)) - .sorting(new SortingImpl(sortMap, PlayerStats.class, dictionary)) - .build(); - - List results = StreamSupport.stream(engine.executeQuery(query).spliterator(), false) - .collect(Collectors.toList()); - - PlayerStats usa0 = new PlayerStats(); - usa0.setId("0"); - usa0.setLowScore(35); - usa0.setHighScore(1234); - usa0.setOverallRating("Good"); - usa0.setCountry(USA); - usa0.setSubCountry(SUB_USA); - usa0.setRecordedDate(Timestamp.valueOf("2019-07-12 00:00:00")); - - PlayerStats usa1 = new PlayerStats(); - usa1.setId("1"); - usa1.setLowScore(241); - usa1.setHighScore(2412); - usa1.setOverallRating("Great"); - usa1.setCountry(USA); - usa1.setSubCountry(SUB_USA); - usa1.setRecordedDate(Timestamp.valueOf("2019-07-11 00:00:00")); - - PlayerStats hk2 = new PlayerStats(); - hk2.setId("2"); - hk2.setLowScore(72); - hk2.setHighScore(1000); - hk2.setOverallRating("Good"); - hk2.setCountry(HONG_KONG); - hk2.setSubCountry(SUB_HONG_KONG); - hk2.setRecordedDate(Timestamp.valueOf("2019-07-13 00:00:00")); - - assertEquals(3, results.size()); - assertEquals(usa0, results.get(0)); - assertEquals(usa1, results.get(1)); - assertEquals(hk2, results.get(2)); - - // test join - PlayerStats actualStats0 = (PlayerStats) results.get(0); - assertNotNull(actualStats0.getSubCountry()); - assertNotNull(actualStats0.getCountry()); - } - /** * Test grouping by a dimension with a JoinTo annotation. * @@ -228,12 +114,13 @@ public void testJoinToFilter() throws Exception { public void testJoinToSort() throws Exception { Map sortMap = new TreeMap<>(); sortMap.put("subCountryIsoCode", Sorting.SortOrder.asc); + sortMap.put("highScore", Sorting.SortOrder.asc); Query query = Query.builder() .table(playerStatsTable) .metric(invoke(playerStatsTable.getMetric("highScore"))) .groupByDimension(toProjection(playerStatsTable.getDimension("overallRating"))) - .groupByDimension(toProjection(playerStatsTable.getDimension("subCountry"))) + .groupByDimension(toProjection(playerStatsTable.getDimension("subCountryIsoCode"))) .sorting(new SortingImpl(sortMap, PlayerStats.class, dictionary)) .build(); @@ -243,19 +130,19 @@ public void testJoinToSort() throws Exception { PlayerStats stats1 = new PlayerStats(); stats1.setId("0"); stats1.setOverallRating("Good"); - stats1.setSubCountry(SUB_HONG_KONG); + stats1.setSubCountryIsoCode("HKG"); stats1.setHighScore(1000); PlayerStats stats2 = new PlayerStats(); stats2.setId("1"); stats2.setOverallRating("Good"); - stats2.setSubCountry(SUB_USA); + stats2.setSubCountryIsoCode("USA"); stats2.setHighScore(1234); PlayerStats stats3 = new PlayerStats(); stats3.setId("2"); stats3.setOverallRating("Great"); - stats3.setSubCountry(SUB_USA); + stats3.setSubCountryIsoCode("USA"); stats3.setHighScore(2412); assertEquals(3, results.size()); diff --git a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/ViewTest.java b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/ViewTest.java index b4424f2db9..1cd56d7e53 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/ViewTest.java +++ b/elide-datastore/elide-datastore-aggregation/src/test/java/com/yahoo/elide/datastores/aggregation/queryengines/sql/ViewTest.java @@ -112,7 +112,7 @@ public void testNestedRelationshipAttribute() throws Exception { .table(playerStatsWithViewSchema) .metric(invoke(playerStatsWithViewSchema.getMetric("lowScore"))) .groupByDimension( - toProjection(playerStatsWithViewSchema.getDimension("countryViewRelationshipIsoCode"))) + toProjection(playerStatsWithViewSchema.getDimension("countryViewViewIsoCode"))) .sorting(new SortingImpl(sortMap, PlayerStatsWithView.class, dictionary)) .build(); @@ -122,12 +122,12 @@ public void testNestedRelationshipAttribute() throws Exception { PlayerStatsWithView usa0 = new PlayerStatsWithView(); usa0.setId("0"); usa0.setLowScore(35); - usa0.setCountryViewRelationshipIsoCode("USA"); + usa0.setCountryViewViewIsoCode("USA"); PlayerStatsWithView hk1 = new PlayerStatsWithView(); hk1.setId("1"); hk1.setLowScore(72); - hk1.setCountryViewRelationshipIsoCode("HKG"); + hk1.setCountryViewViewIsoCode("HKG"); assertEquals(2, results.size()); assertEquals(usa0, results.get(0)); @@ -147,7 +147,7 @@ public void testSortingViewAttribute() throws Exception { .table(playerStatsWithViewSchema) .metric(invoke(playerStatsWithViewSchema.getMetric("lowScore"))) .groupByDimension( - toProjection(playerStatsWithViewSchema.getDimension("countryViewRelationshipIsoCode"))) + toProjection(playerStatsWithViewSchema.getDimension("countryViewViewIsoCode"))) .sorting(new SortingImpl(sortMap, PlayerStatsWithView.class, dictionary)) .build(); @@ -157,12 +157,12 @@ public void testSortingViewAttribute() throws Exception { PlayerStatsWithView usa0 = new PlayerStatsWithView(); usa0.setId("0"); usa0.setLowScore(35); - usa0.setCountryViewRelationshipIsoCode("USA"); + usa0.setCountryViewViewIsoCode("USA"); PlayerStatsWithView hk1 = new PlayerStatsWithView(); hk1.setId("1"); hk1.setLowScore(72); - hk1.setCountryViewRelationshipIsoCode("HKG"); + hk1.setCountryViewViewIsoCode("HKG"); assertEquals(2, results.size()); assertEquals(usa0, results.get(0)); @@ -176,13 +176,13 @@ public void testSortingViewAttribute() throws Exception { @Test public void testSortingNestedViewAttribute() throws Exception { Map sortMap = new TreeMap<>(); - sortMap.put("countryViewRelationshipIsoCode", Sorting.SortOrder.desc); + sortMap.put("countryViewViewIsoCode", Sorting.SortOrder.desc); Query query = Query.builder() .table(playerStatsWithViewSchema) .metric(invoke(playerStatsWithViewSchema.getMetric("lowScore"))) .groupByDimension( - toProjection(playerStatsWithViewSchema.getDimension("countryViewRelationshipIsoCode"))) + toProjection(playerStatsWithViewSchema.getDimension("countryViewViewIsoCode"))) .sorting(new SortingImpl(sortMap, PlayerStatsWithView.class, dictionary)) .build(); @@ -192,12 +192,12 @@ public void testSortingNestedViewAttribute() throws Exception { PlayerStatsWithView usa0 = new PlayerStatsWithView(); usa0.setId("0"); usa0.setLowScore(35); - usa0.setCountryViewRelationshipIsoCode("USA"); + usa0.setCountryViewViewIsoCode("USA"); PlayerStatsWithView hk1 = new PlayerStatsWithView(); hk1.setId("1"); hk1.setLowScore(72); - hk1.setCountryViewRelationshipIsoCode("HKG"); + hk1.setCountryViewViewIsoCode("HKG"); assertEquals(2, results.size()); assertEquals(usa0, results.get(0)); @@ -211,13 +211,13 @@ public void testSortingNestedViewAttribute() throws Exception { @Test public void testSortingNestedRelationshipAttribute() throws Exception { Map sortMap = new TreeMap<>(); - sortMap.put("countryViewRelationshipIsoCode", Sorting.SortOrder.desc); + sortMap.put("countryViewViewIsoCode", Sorting.SortOrder.desc); Query query = Query.builder() .table(playerStatsWithViewSchema) .metric(invoke(playerStatsWithViewSchema.getMetric("lowScore"))) .groupByDimension( - toProjection(playerStatsWithViewSchema.getDimension("countryViewRelationshipIsoCode"))) + toProjection(playerStatsWithViewSchema.getDimension("countryViewViewIsoCode"))) .sorting(new SortingImpl(sortMap, PlayerStatsWithView.class, dictionary)) .build(); @@ -227,12 +227,12 @@ public void testSortingNestedRelationshipAttribute() throws Exception { PlayerStatsWithView usa0 = new PlayerStatsWithView(); usa0.setId("0"); usa0.setLowScore(35); - usa0.setCountryViewRelationshipIsoCode("USA"); + usa0.setCountryViewViewIsoCode("USA"); PlayerStatsWithView hk1 = new PlayerStatsWithView(); hk1.setId("1"); hk1.setLowScore(72); - hk1.setCountryViewRelationshipIsoCode("HKG"); + hk1.setCountryViewViewIsoCode("HKG"); assertEquals(2, results.size()); assertEquals(usa0, results.get(0)); diff --git a/elide-datastore/elide-datastore-aggregation/src/test/resources/graphql/responses/testGraphQLSchema.json b/elide-datastore/elide-datastore-aggregation/src/test/resources/graphql/responses/testGraphQLSchema.json index b1d12f5f94..e026183b0a 100644 --- a/elide-datastore/elide-datastore-aggregation/src/test/resources/graphql/responses/testGraphQLSchema.json +++ b/elide-datastore/elide-datastore-aggregation/src/test/resources/graphql/responses/testGraphQLSchema.json @@ -29,13 +29,6 @@ "fields": null } }, - { - "name": "countryViewRelationshipIsoCode", - "type": { - "name": "String", - "fields": null - } - }, { "name": "countryViewViewIsoCode", "type": { @@ -77,48 +70,6 @@ "name": "String", "fields": null } - }, - { - "name": "country", - "type": { - "name": "country", - "fields": [ - { - "name": "edges" - }, - { - "name": "pageInfo" - } - ] - } - }, - { - "name": "player", - "type": { - "name": "player", - "fields": [ - { - "name": "edges" - }, - { - "name": "pageInfo" - } - ] - } - }, - { - "name": "subCountry", - "type": { - "name": "subCountry", - "fields": [ - { - "name": "edges" - }, - { - "name": "pageInfo" - } - ] - } } ] }