org.apache.cassandra.cql3.restrictions.RestrictionSet Maven / Gradle / Ivy
Show all versions of cassandra-all Show documentation
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.cassandra.cql3.restrictions;
import java.util.*;
import com.google.common.collect.Iterables;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.restrictions.SingleColumnRestriction.Contains;
import org.apache.cassandra.db.IndexExpression;
import org.apache.cassandra.db.index.SecondaryIndexManager;
import org.apache.cassandra.exceptions.InvalidRequestException;
/**
* Sets of column restrictions.
*
* This class is immutable in order to be use within {@link PrimaryKeyRestrictionSet} which as
* an implementation of {@link Restriction} need to be immutable.
*/
final class RestrictionSet implements Restrictions, Iterable
{
/**
* The comparator used to sort the Restriction
s.
*/
private static final Comparator COLUMN_DEFINITION_COMPARATOR = new Comparator()
{
@Override
public int compare(ColumnDefinition column, ColumnDefinition otherColumn)
{
int value = Integer.compare(column.position(), otherColumn.position());
return value != 0 ? value : column.name.bytes.compareTo(otherColumn.name.bytes);
}
};
/**
* The restrictions per column.
*/
protected final TreeMap restrictions;
public RestrictionSet()
{
this(new TreeMap(COLUMN_DEFINITION_COMPARATOR));
}
private RestrictionSet(TreeMap restrictions)
{
this.restrictions = restrictions;
}
@Override
public final void addIndexExpressionTo(List expressions,
SecondaryIndexManager indexManager,
QueryOptions options) throws InvalidRequestException
{
for (Restriction restriction : restrictions.values())
restriction.addIndexExpressionTo(expressions, indexManager, options);
}
@Override
public final List getColumnDefs()
{
return new ArrayList<>(restrictions.keySet());
}
@Override
public Iterable getFunctions()
{
com.google.common.base.Function> transform =
new com.google.common.base.Function>()
{
public Iterable apply(Restriction restriction)
{
return restriction.getFunctions();
}
};
return Iterables.concat(Iterables.transform(restrictions.values(), transform));
}
@Override
public final boolean isEmpty()
{
return getColumnDefs().isEmpty();
}
@Override
public final int size()
{
return getColumnDefs().size();
}
/**
* Adds the specified restriction to this set of restrictions.
*
* @param restriction the restriction to add
* @return the new set of restrictions
* @throws InvalidRequestException if the new restriction cannot be added
*/
public RestrictionSet addRestriction(Restriction restriction) throws InvalidRequestException
{
// RestrictionSet is immutable so we need to clone the restrictions map.
TreeMap newRestrictions = new TreeMap<>(this.restrictions);
return new RestrictionSet(mergeRestrictions(newRestrictions, restriction));
}
private TreeMap mergeRestrictions(TreeMap restrictions,
Restriction restriction)
throws InvalidRequestException
{
Collection columnDefs = restriction.getColumnDefs();
Set existingRestrictions = getRestrictions(columnDefs);
if (existingRestrictions.isEmpty())
{
for (ColumnDefinition columnDef : columnDefs)
restrictions.put(columnDef, restriction);
}
else
{
for (Restriction existing : existingRestrictions)
{
Restriction newRestriction = mergeRestrictions(existing, restriction);
for (ColumnDefinition columnDef : columnDefs)
restrictions.put(columnDef, newRestriction);
}
}
return restrictions;
}
/**
* Returns all the restrictions applied to the specified columns.
*
* @param columnDefs the column definitions
* @return all the restrictions applied to the specified columns
*/
private Set getRestrictions(Collection columnDefs)
{
Set set = new HashSet<>();
for (ColumnDefinition columnDef : columnDefs)
{
Restriction existing = restrictions.get(columnDef);
if (existing != null)
set.add(existing);
}
return set;
}
@Override
public final boolean hasSupportingIndex(SecondaryIndexManager indexManager)
{
for (Restriction restriction : restrictions.values())
{
if (restriction.hasSupportingIndex(indexManager))
return true;
}
return false;
}
/**
* Returns the column after the specified one.
*
* @param columnDef the column for which the next one need to be found
* @return the column after the specified one.
*/
ColumnDefinition nextColumn(ColumnDefinition columnDef)
{
return restrictions.tailMap(columnDef, false).firstKey();
}
/**
* Returns the definition of the first column.
*
* @return the definition of the first column.
*/
ColumnDefinition firstColumn()
{
return isEmpty() ? null : this.restrictions.firstKey();
}
/**
* Returns the definition of the last column.
*
* @return the definition of the last column.
*/
ColumnDefinition lastColumn()
{
return isEmpty() ? null : this.restrictions.lastKey();
}
/**
* Returns the last restriction.
*
* @return the last restriction.
*/
Restriction lastRestriction()
{
return isEmpty() ? null : this.restrictions.lastEntry().getValue();
}
/**
* Merges the two specified restrictions.
*
* @param restriction the first restriction
* @param otherRestriction the second restriction
* @return the merged restriction
* @throws InvalidRequestException if the two restrictions cannot be merged
*/
private static Restriction mergeRestrictions(Restriction restriction,
Restriction otherRestriction) throws InvalidRequestException
{
return restriction == null ? otherRestriction
: restriction.mergeWith(otherRestriction);
}
/**
* Checks if the restrictions contains multiple contains, contains key, or map[key] = value.
*
* @return true
if the restrictions contains multiple contains, contains key, or ,
* map[key] = value; false
otherwise
*/
public final boolean hasMultipleContains()
{
int numberOfContains = 0;
for (Restriction restriction : restrictions.values())
{
if (restriction.isContains())
{
Contains contains = (Contains) restriction;
numberOfContains += (contains.numberOfValues() + contains.numberOfKeys() + contains.numberOfEntries());
}
}
return numberOfContains > 1;
}
@Override
public Iterator iterator()
{
return new LinkedHashSet<>(restrictions.values()).iterator();
}
}