com.google.appengine.api.datastore.NormalizedQuery Maven / Gradle / Ivy
/*
* Copyright 2021 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.appengine.api.datastore;
import com.google.apphosting.datastore.DatastoreV3Pb.Query;
import com.google.apphosting.datastore.DatastoreV3Pb.Query.Filter;
import com.google.apphosting.datastore.DatastoreV3Pb.Query.Filter.Operator;
import com.google.apphosting.datastore.DatastoreV3Pb.Query.Order;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.storage.onestore.v3.OnestoreEntity.Property;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
class NormalizedQuery {
static final ImmutableSet INEQUALITY_OPERATORS =
ImmutableSet.of(
Operator.GREATER_THAN,
Operator.GREATER_THAN_OR_EQUAL,
Operator.LESS_THAN,
Operator.LESS_THAN_OR_EQUAL);
protected final Query query;
public NormalizedQuery(Query query) {
this.query = query.clone();
normalizeQuery();
}
public Query getQuery() {
return query;
}
private void normalizeQuery() {
// TODO: consider sharing this code with MegastoreQueryPlanner
// NOTE: Keep in sync with MegastoreQueryPlanner#normalize()
Set equalityFilterProperties = new HashSet();
Set equalityProperties = new HashSet();
Set inequalityProperties = new HashSet();
for (Iterator itr = query.mutableFilters().iterator(); itr.hasNext(); ) {
Filter f = itr.next();
/* Normalize IN filters to EQUAL. */
if (f.propertySize() == 1 && f.getOpEnum() == Operator.IN) {
f.setOp(Operator.EQUAL);
}
if (f.propertySize() >= 1) {
String name = f.getProperty(0).getName();
if (f.getOpEnum() == Operator.EQUAL) {
if (!equalityFilterProperties.add(f.getProperty(0))) {
// The filter is an exact duplicate, remove it.
itr.remove();
} else {
equalityProperties.add(name);
}
} else if (INEQUALITY_OPERATORS.contains(f.getOpEnum())) {
inequalityProperties.add(name);
}
}
}
equalityProperties.removeAll(inequalityProperties);
// Strip repeated orders and orders coinciding with EQUAL filters.
for (Iterator itr = query.mutableOrders().iterator(); itr.hasNext(); ) {
if (!equalityProperties.add(itr.next().getProperty())) {
itr.remove();
}
}
Set allProperties = equalityProperties;
allProperties.addAll(inequalityProperties);
// Removing redundant exists filters.
for (Iterator itr = query.mutableFilters().iterator(); itr.hasNext(); ) {
Filter f = itr.next();
if (f.getOpEnum() == Operator.EXISTS
&& f.propertySize() >= 1
&& !allProperties.add(f.getProperty(0).getName())) {
itr.remove();
}
}
// Adding exist filters for any requested properties or group by properties that need them.
for (String propName : Iterables.concat(query.propertyNames(), query.groupByPropertyNames())) {
if (allProperties.add(propName)) {
query
.addFilter()
.setOp(Operator.EXISTS)
.addProperty()
.setName(propName)
.setMultiple(false)
.getMutableValue();
}
}
// NOTE: Keep in sync with MegastoreQueryPlanner#normalizeForKeyComponents()
/* Strip all orders if filtering on __key__ with equals. */
for (Filter f : query.filters()) {
if (f.getOpEnum() == Operator.EQUAL
&& f.propertySize() >= 1
&& f.getProperty(0).getName().equals(Entity.KEY_RESERVED_PROPERTY)) {
query.clearOrder();
break;
}
}
/* Strip all orders that follow a ordering on __key__ as keys are unique
* thus additional ordering has no effect. */
boolean foundKeyOrder = false;
for (Iterator i = query.mutableOrders().iterator(); i.hasNext(); ) {
String property = i.next().getProperty();
if (foundKeyOrder) {
i.remove();
} else if (property.equals(Entity.KEY_RESERVED_PROPERTY)) {
foundKeyOrder = true;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy