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

feat: Sum and Avg aggregation feature #1067

Merged
merged 28 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3407779
creating sum aggregation
jainsahab Apr 24, 2023
0aa59ad
creating avg aggregation
jainsahab Apr 24, 2023
426cd04
refactoring code to configure alias into an aggregation
jainsahab Apr 24, 2023
9dd472c
Add method in aggregation query builders to accept aggregation in var…
jainsahab Apr 25, 2023
a10976c
refactoring equals implementation
jainsahab Apr 25, 2023
4ab4bfa
changed visibility from public to protected
jainsahab Apr 27, 2023
0078fd6
Made aggregation result capable of returning double values
jainsahab Apr 27, 2023
d6f834d
clirr ignore new method
jainsahab Apr 27, 2023
4b4fd0e
Made transformer capable of parsing double values
jainsahab May 4, 2023
cc32ee6
mock webserver simulating sum and avg aggregation response
jainsahab May 5, 2023
39f9776
integration tests for sum and avg
jainsahab May 5, 2023
77bf0b3
Marking sum and avg methods with @BetaApi annotation
jainsahab May 8, 2023
403c01c
incorporating feedbacks
jainsahab May 15, 2023
c7fb0de
fixing lint
jainsahab May 15, 2023
2b59751
refactoring dispatcher code
jainsahab May 15, 2023
fc666ba
incorporating feedbacks
jainsahab May 17, 2023
4b8d941
cleaing up proxy code, as sum/avg now can be run against nightly
jainsahab May 18, 2023
b9621d9
remove deprecated annotation
jainsahab May 24, 2023
bf38e67
tests for sum and avg aggregations in GQL query
jainsahab May 26, 2023
066f23f
removing the addaggregation variant accepting list of aggregations
jainsahab May 26, 2023
c322c81
Merge branch 'main' into sum-avg-feature
jainsahab Aug 17, 2023
e43804d
fix lint failures
jainsahab Aug 17, 2023
c590fb4
removed BetaApi annotation from sum and avg aggregation
jainsahab Aug 18, 2023
aa14e8a
adding doc to AggregationResult#getDouble
jainsahab Aug 18, 2023
30c0de3
adding sum/avg aggreggation test with autogenerated alias
jainsahab Aug 18, 2023
52decc7
adding a test to run sum and avg aggregation together
jainsahab Aug 18, 2023
4b46b77
testing sum and avg aggregations with transactions
jainsahab Aug 18, 2023
b60995b
type check before returning the result from aggregation result class
jainsahab Aug 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import com.google.cloud.datastore.aggregation.Aggregation;
import com.google.cloud.datastore.aggregation.AggregationBuilder;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

Expand Down Expand Up @@ -143,6 +144,18 @@ public Builder addAggregation(Aggregation aggregation) {
return this;
}

public Builder addAggregations(AggregationBuilder<?>... aggregationBuilders) {
for (AggregationBuilder<?> builder : aggregationBuilders) {
this.aggregations.add(builder.build());
}
return this;
}

public Builder addAggregations(Aggregation... aggregations) {
jainsahab marked this conversation as resolved.
Show resolved Hide resolved
this.aggregations.addAll(Arrays.asList(aggregations));
return this;
}

public Builder over(StructuredQuery<?> nestedQuery) {
this.nestedStructuredQuery = nestedQuery;
this.mode = STRUCTURED;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*/
package com.google.cloud.datastore;

import static com.google.cloud.datastore.ValueType.DOUBLE;
import static com.google.cloud.datastore.ValueType.LONG;

import com.google.common.base.MoreObjects;
import com.google.common.base.MoreObjects.ToStringHelper;
import java.util.Map;
Expand All @@ -24,21 +27,45 @@
/** Represents a result of an {@link AggregationQuery} query submission. */
public class AggregationResult {

private final Map<String, LongValue> properties;
private final Map<String, Value<?>> properties;

public AggregationResult(Map<String, LongValue> properties) {
public AggregationResult(Map<String, Value<?>> properties) {
jainsahab marked this conversation as resolved.
Show resolved Hide resolved
this.properties = properties;
}

/**
* Returns a result value for the given alias.
* Returns a result value for the given alias. {@link #getLong(String)} is preferred over this
* method, Use {@link #getLong(String)} wherever possible.
*
* @param alias A custom alias provided in the query or an autogenerated alias in the form of
* 'property_\d'
* @return An aggregation result value for the given alias.
*/
public Long get(String alias) {
kolea2 marked this conversation as resolved.
Show resolved Hide resolved
return properties.get(alias).get();
return getLong(alias);
}

/**
* Returns a result value for the given alias.
*
* @param alias A custom alias provided in the query or an autogenerated alias in the form of
* 'property_\d'
* @return An aggregation result value for the given alias.
*/
public Long getLong(String alias) {
Value<?> value = properties.get(alias);
if (value.getType() == DOUBLE) {
return ((Double) value.get()).longValue();
}
return (Long) value.get();
jainsahab marked this conversation as resolved.
Show resolved Hide resolved
}

public Double getDouble(String alias) {
Value<?> value = properties.get(alias);
if (value.getType() == LONG) {
return ((Long) value.get()).doubleValue();
}
return (Double) value.get();
jainsahab marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
Expand All @@ -61,7 +88,7 @@ public int hashCode() {
@Override
public String toString() {
ToStringHelper toStringHelper = MoreObjects.toStringHelper(this);
for (Entry<String, LongValue> entry : properties.entrySet()) {
for (Entry<String, Value<?>> entry : properties.entrySet()) {
toStringHelper.add(entry.getKey(), entry.getValue().get());
}
return toStringHelper.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.google.cloud.datastore.aggregation;

import com.google.api.core.BetaApi;
import com.google.api.core.InternalApi;
import com.google.datastore.v1.AggregationQuery;

Expand All @@ -38,8 +39,30 @@ public String getAlias() {
@InternalApi
public abstract AggregationQuery.Aggregation toPb();

@InternalApi
protected AggregationQuery.Aggregation.Builder aggregationBuilder() {
AggregationQuery.Aggregation.Builder aggregationBuilder =
AggregationQuery.Aggregation.newBuilder();
if (this.getAlias() != null) {
aggregationBuilder.setAlias(this.getAlias());
}
return aggregationBuilder;
}

/** Returns a {@link CountAggregation} builder. */
public static CountAggregation.Builder count() {
return new CountAggregation.Builder();
}

/** Returns a {@link SumAggregation} builder. */
@BetaApi
kolea2 marked this conversation as resolved.
Show resolved Hide resolved
public static SumAggregation.Builder sum(String propertyReference) {
return new SumAggregation.Builder().propertyReference(propertyReference);
}

/** Returns a {@link AvgAggregation} builder. */
@BetaApi
public static AvgAggregation.Builder avg(String propertyReference) {
return new AvgAggregation.Builder().propertyReference(propertyReference);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.cloud.datastore.aggregation;
kolea2 marked this conversation as resolved.
Show resolved Hide resolved

import static com.google.common.base.Preconditions.checkArgument;

import com.google.api.core.BetaApi;
import com.google.api.core.InternalApi;
import com.google.datastore.v1.AggregationQuery;
import com.google.datastore.v1.AggregationQuery.Aggregation.Avg;
import com.google.datastore.v1.PropertyReference;
import java.util.Objects;

/** Represents an {@link Aggregation} which returns average of numerical values. */
@BetaApi
public class AvgAggregation extends Aggregation {

private final String propertyReference;

public AvgAggregation(String alias, String propertyReference) {
super(alias);
checkArgument(propertyReference != null, "Property reference can't be null");
this.propertyReference = propertyReference;
}

@InternalApi
@Override
public AggregationQuery.Aggregation toPb() {
kolea2 marked this conversation as resolved.
Show resolved Hide resolved
PropertyReference reference =
PropertyReference.newBuilder().setName(this.propertyReference).build();
Avg avg = Avg.newBuilder().setProperty(reference).build();
return aggregationBuilder().setAvg(avg).build();
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AvgAggregation that = (AvgAggregation) o;
return Objects.equals(this.propertyReference, that.propertyReference)
&& Objects.equals(getAlias(), that.getAlias());
}

@Override
public int hashCode() {
return Objects.hash(getAlias(), this.propertyReference);
}

/** A builder class to create and customize a {@link AvgAggregation}. */
public static class Builder implements AggregationBuilder<AvgAggregation> {

private String alias;
private String propertyReference;

public AvgAggregation.Builder propertyReference(String propertyReference) {
this.propertyReference = propertyReference;
return this;
}

public AvgAggregation.Builder as(String alias) {
this.alias = alias;
return this;
}

@Override
public AvgAggregation build() {
return new AvgAggregation(alias, propertyReference);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,7 @@ public CountAggregation(String alias) {

@Override
public AggregationQuery.Aggregation toPb() {
Count.Builder countBuilder = Count.newBuilder();

AggregationQuery.Aggregation.Builder aggregationBuilder =
AggregationQuery.Aggregation.newBuilder().setCount(countBuilder);
if (this.getAlias() != null) {
aggregationBuilder.setAlias(this.getAlias());
}
return aggregationBuilder.build();
return aggregationBuilder().setCount(Count.newBuilder()).build();
}

@Override
Expand All @@ -49,13 +42,7 @@ public boolean equals(Object o) {
return false;
}
CountAggregation that = (CountAggregation) o;
boolean bothAliasAreNull = getAlias() == null && that.getAlias() == null;
if (bothAliasAreNull) {
return true;
} else {
boolean bothArePresent = getAlias() != null && that.getAlias() != null;
return bothArePresent && getAlias().equals(that.getAlias());
}
return Objects.equals(getAlias(), that.getAlias());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.cloud.datastore.aggregation;
kolea2 marked this conversation as resolved.
Show resolved Hide resolved

import static com.google.common.base.Preconditions.checkArgument;

import com.google.api.core.BetaApi;
import com.google.api.core.InternalApi;
import com.google.datastore.v1.AggregationQuery;
import com.google.datastore.v1.AggregationQuery.Aggregation.Sum;
import com.google.datastore.v1.PropertyReference;
import java.util.Objects;

/** Represents an {@link Aggregation} which returns sum of numerical values. */
@BetaApi
public class SumAggregation extends Aggregation {

private final String propertyReference;

public SumAggregation(String alias, String propertyReference) {
super(alias);
checkArgument(propertyReference != null, "Property reference can't be null");
this.propertyReference = propertyReference;
}

@InternalApi
@Override
public AggregationQuery.Aggregation toPb() {
kolea2 marked this conversation as resolved.
Show resolved Hide resolved
PropertyReference reference =
PropertyReference.newBuilder().setName(this.propertyReference).build();
Sum sum = Sum.newBuilder().setProperty(reference).build();
return aggregationBuilder().setSum(sum).build();
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SumAggregation that = (SumAggregation) o;
return Objects.equals(this.propertyReference, that.propertyReference)
&& Objects.equals(getAlias(), that.getAlias());
}

@Override
public int hashCode() {
return Objects.hash(getAlias(), this.propertyReference);
}

/** A builder class to create and customize a {@link SumAggregation}. */
public static class Builder implements AggregationBuilder<SumAggregation> {

private String alias;
private String propertyReference;

public SumAggregation.Builder propertyReference(String propertyReference) {
this.propertyReference = propertyReference;
return this;
}

public SumAggregation.Builder as(String alias) {
this.alias = alias;
return this;
}

@Override
public SumAggregation build() {
return new SumAggregation(alias, propertyReference);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import com.google.cloud.Timestamp;
import com.google.cloud.datastore.AggregationResult;
import com.google.cloud.datastore.AggregationResults;
import com.google.cloud.datastore.LongValue;
import com.google.datastore.v1.RunAggregationQueryResponse;
import com.google.datastore.v1.Value;
import java.util.AbstractMap.SimpleEntry;
Expand All @@ -39,20 +38,19 @@ public AggregationResults transform(RunAggregationQueryResponse response) {
Timestamp readTime = Timestamp.fromProto(response.getBatch().getReadTime());
List<AggregationResult> aggregationResults =
response.getBatch().getAggregationResultsList().stream()
.map(
aggregationResult -> new AggregationResult(resultWithLongValues(aggregationResult)))
.map(aggregationResult -> new AggregationResult(transformValues(aggregationResult)))
.collect(Collectors.toCollection(LinkedList::new));
return new AggregationResults(aggregationResults, readTime);
}

private Map<String, LongValue> resultWithLongValues(
private Map<String, com.google.cloud.datastore.Value<?>> transformValues(
com.google.datastore.v1.AggregationResult aggregationResult) {
return aggregationResult.getAggregatePropertiesMap().entrySet().stream()
.map(
(Function<Entry<String, Value>, Entry<String, LongValue>>)
(Function<Entry<String, Value>, Entry<String, com.google.cloud.datastore.Value<?>>>)
entry ->
new SimpleEntry<>(
entry.getKey(), (LongValue) LongValue.fromPb(entry.getValue())))
entry.getKey(), com.google.cloud.datastore.Value.fromPb(entry.getValue())))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
}
}
Loading