http://git-wip-us.apache.org/repos/asf/cassandra/blob/831bebdb/test/unit/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictionsTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictionsTest.java b/test/unit/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictionsTest.java new file mode 100644 index 0000000..5c816da --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictionsTest.java @@ -0,0 +1,1919 @@ +/* + * 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.nio.ByteBuffer; +import java.util.*; + +import com.google.common.collect.Iterables; +import org.junit.Test; + +import org.apache.cassandra.config.CFMetaData; +import org.apache.cassandra.config.ColumnDefinition; +import org.apache.cassandra.cql3.*; +import org.apache.cassandra.cql3.Term.MultiItemTerminal; +import org.apache.cassandra.cql3.statements.Bound; + +import org.apache.cassandra.db.*; +import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.Int32Type; +import org.apache.cassandra.db.marshal.ReversedType; +import org.apache.cassandra.utils.ByteBufferUtil; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class ClusteringColumnRestrictionsTest +{ + @Test + public void testBoundsAsClusteringWithNoRestrictions() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC); + + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyStart(get(bounds, 0)); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + } + + /** + * Test 'clustering_0 = 1' with only one clustering column + */ + @Test + public void testBoundsAsClusteringWithOneEqRestrictionsAndOneClusteringColumn() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC); + + ByteBuffer clustering_0 = ByteBufferUtil.bytes(1); + Restriction eq = newSingleEq(cfMetaData, 0, clustering_0); + + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(eq); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, clustering_0); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, clustering_0); + } + + /** + * Test 'clustering_1 = 1' with 2 clustering columns + */ + @Test + public void testBoundsAsClusteringWithOneEqRestrictionsAndTwoClusteringColumns() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC); + + ByteBuffer clustering_0 = ByteBufferUtil.bytes(1); + Restriction eq = newSingleEq(cfMetaData, 0, clustering_0); + + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(eq); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, clustering_0); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, clustering_0); + } + + /** + * Test 'clustering_0 IN (1, 2, 3)' with only one clustering column + */ + @Test + public void testBoundsAsClusteringWithOneInRestrictionsAndOneClusteringColumn() + { + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + ByteBuffer value3 = ByteBufferUtil.bytes(3); + + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC); + + Restriction in = newSingleIN(cfMetaData, 0, value1, value2, value3); + + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(in); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(3, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + assertStartBound(get(bounds, 1), true, value2); + assertStartBound(get(bounds, 2), true, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(3, bounds.size()); + assertEndBound(get(bounds, 0), true, value1); + assertEndBound(get(bounds, 1), true, value2); + assertEndBound(get(bounds, 2), true, value3); + } + + /** + * Test slice restriction (e.g 'clustering_0 > 1') with only one clustering column + */ + @Test + public void testBoundsAsClusteringWithSliceRestrictionsAndOneClusteringColumn() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + + Restriction slice = newSingleSlice(cfMetaData, 0, Bound.START, false, value1); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + + slice = newSingleSlice(cfMetaData, 0, Bound.START, true, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + + slice = newSingleSlice(cfMetaData, 0, Bound.END, true, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyStart(get(bounds, 0)); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1); + + slice = newSingleSlice(cfMetaData, 0, Bound.END, false, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyStart(get(bounds, 0)); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value1); + + slice = newSingleSlice(cfMetaData, 0, Bound.START, false, value1); + Restriction slice2 = newSingleSlice(cfMetaData, 0, Bound.END, false, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value2); + + slice = newSingleSlice(cfMetaData, 0, Bound.START, true, value1); + slice2 = newSingleSlice(cfMetaData, 0, Bound.END, true, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value2); + } + + /** + * Test slice restriction (e.g 'clustering_0 > 1') with only one descending clustering column + */ + @Test + public void testBoundsAsClusteringWithSliceRestrictionsAndOneDescendingClusteringColumn() + { + CFMetaData cfMetaData = newCFMetaData(Sort.DESC, Sort.DESC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + + Restriction slice = newSingleSlice(cfMetaData, 0, Bound.START, false, value1); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyStart(get(bounds, 0)); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value1); + + slice = newSingleSlice(cfMetaData, 0, Bound.START, true, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyStart(get(bounds, 0)); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1); + + slice = newSingleSlice(cfMetaData, 0, Bound.END, true, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + + slice = newSingleSlice(cfMetaData, 0, Bound.END, false, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + + slice = newSingleSlice(cfMetaData, 0, Bound.START, false, value1); + Restriction slice2 = newSingleSlice(cfMetaData, 0, Bound.END, false, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value1); + + slice = newSingleSlice(cfMetaData, 0, Bound.START, true, value1); + slice2 = newSingleSlice(cfMetaData, 0, Bound.END, true, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1); + } + + /** + * Test 'clustering_0 = 1 AND clustering_1 IN (1, 2, 3)' + */ + @Test + public void testBoundsAsClusteringWithEqAndInRestrictions() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + ByteBuffer value3 = ByteBufferUtil.bytes(3); + Restriction eq = newSingleEq(cfMetaData, 0, value1); + Restriction in = newSingleIN(cfMetaData, 1, value1, value2, value3); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(eq).mergeWith(in); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(3, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value1); + assertStartBound(get(bounds, 1), true, value1, value2); + assertStartBound(get(bounds, 2), true, value1, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(3, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value1); + assertEndBound(get(bounds, 1), true, value1, value2); + assertEndBound(get(bounds, 2), true, value1, value3); + } + + /** + * Test equal and slice restrictions (e.g 'clustering_0 = 0 clustering_1 > 1') + */ + @Test + public void testBoundsAsClusteringWithEqAndSliceRestrictions() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + ByteBuffer value3 = ByteBufferUtil.bytes(3); + + Restriction eq = newSingleEq(cfMetaData, 0, value3); + + Restriction slice = newSingleSlice(cfMetaData, 1, Bound.START, false, value1); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(eq).mergeWith(slice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value3, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value3); + + slice = newSingleSlice(cfMetaData, 1, Bound.START, true, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(eq).mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value3, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value3); + + slice = newSingleSlice(cfMetaData, 1, Bound.END, true, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(eq).mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value3, value1); + + slice = newSingleSlice(cfMetaData, 1, Bound.END, false, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(eq).mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value3, value1); + + slice = newSingleSlice(cfMetaData, 1, Bound.START, false, value1); + Restriction slice2 = newSingleSlice(cfMetaData, 1, Bound.END, false, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(eq).mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value3, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value3, value2); + + slice = newSingleSlice(cfMetaData, 1, Bound.START, true, value1); + slice2 = newSingleSlice(cfMetaData, 1, Bound.END, true, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(eq).mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value3, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value3, value2); + } + + /** + * Test '(clustering_0, clustering_1) = (1, 2)' with two clustering column + */ + @Test + public void testBoundsAsClusteringWithMultiEqRestrictions() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + Restriction eq = newMultiEq(cfMetaData, 0, value1, value2); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(eq); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2); + } + + /** + * Test '(clustering_0, clustering_1) IN ((1, 2), (2, 3))' with two clustering column + */ + @Test + public void testBoundsAsClusteringWithMultiInRestrictions() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + ByteBuffer value3 = ByteBufferUtil.bytes(3); + Restriction in = newMultiIN(cfMetaData, 0, asList(value1, value2), asList(value2, value3)); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(in); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2); + assertStartBound(get(bounds, 1), true, value2, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2); + assertEndBound(get(bounds, 1), true, value2, value3); + } + + /** + * Test multi-column slice restrictions (e.g '(clustering_0) > (1)') with only one clustering column + */ + @Test + public void testBoundsAsClusteringWithMultiSliceRestrictionsWithOneClusteringColumn() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC); + + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + + Restriction slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + + slice = newMultiSlice(cfMetaData, 0, Bound.END, true, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyStart(get(bounds, 0)); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1); + + slice = newMultiSlice(cfMetaData, 0, Bound.END, false, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyStart(get(bounds, 0)); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value1); + + slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1); + Restriction slice2 = newMultiSlice(cfMetaData, 0, Bound.END, false, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value2); + + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1); + slice2 = newMultiSlice(cfMetaData, 0, Bound.END, true, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value2); + } + + /** + * Test multi-column slice restrictions (e.g '(clustering_0) > (1)') with only one clustering column in reverse + * order + */ + @Test + public void testBoundsAsClusteringWithMultiSliceRestrictionsWithOneDescendingClusteringColumn() + { + CFMetaData cfMetaData = newCFMetaData(Sort.DESC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + + Restriction slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyStart(get(bounds, 0)); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value1); + + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyStart(get(bounds, 0)); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1); + + slice = newMultiSlice(cfMetaData, 0, Bound.END, true, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + + slice = newMultiSlice(cfMetaData, 0, Bound.END, false, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + + slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1); + Restriction slice2 = newMultiSlice(cfMetaData, 0, Bound.END, false, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value1); + + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1); + slice2 = newMultiSlice(cfMetaData, 0, Bound.END, true, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1); + } + + /** + * Test multi-column slice restrictions (e.g '(clustering_0, clustering_1) > (1, 2)') + */ + @Test + public void testBoundsAsClusteringWithMultiSliceRestrictionsWithTwoClusteringColumn() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + + // (clustering_0, clustering1) > (1, 2) + Restriction slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1, value2); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + + // (clustering_0, clustering1) >= (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + + // (clustering_0, clustering1) <= (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.END, true, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyStart(get(bounds, 0)); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2); + + // (clustering_0, clustering1) < (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.END, false, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyStart(get(bounds, 0)); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2); + + // (clustering_0, clustering1) > (1, 2) AND (clustering_0) < (2) + slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1, value2); + Restriction slice2 = newMultiSlice(cfMetaData, 0, Bound.END, false, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value2); + + // (clustering_0, clustering1) >= (1, 2) AND (clustering_0, clustering1) <= (2, 1) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2); + slice2 = newMultiSlice(cfMetaData, 0, Bound.END, true, value2, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value2, value1); + } + + /** + * Test multi-column slice restrictions with 2 descending clustering columns (e.g '(clustering_0, clustering_1) > (1, 2)') + */ + @Test + public void testBoundsAsClusteringWithMultiSliceRestrictionsWithTwoDescendingClusteringColumns() + { + CFMetaData cfMetaData = newCFMetaData(Sort.DESC, Sort.DESC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + + // (clustering_0, clustering1) > (1, 2) + Restriction slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1, value2); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyStart(get(bounds, 0)); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2); + + // (clustering_0, clustering1) >= (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyStart(get(bounds, 0)); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2); + + // (clustering_0, clustering1) <= (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.END, true, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + + // (clustering_0, clustering1) < (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.END, false, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + + + // (clustering_0, clustering1) > (1, 2) AND (clustering_0) < (2) + slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1, value2); + Restriction slice2 = newMultiSlice(cfMetaData, 0, Bound.END, false, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2); + + // (clustering_0, clustering1) >= (1, 2) AND (clustering_0, clustering1) <= (2, 1) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2); + slice2 = newMultiSlice(cfMetaData, 0, Bound.END, true, value2, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value2, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2); + } + + /** + * Test multi-column slice restrictions with 1 descending clustering column and 1 ascending + * (e.g '(clustering_0, clustering_1) > (1, 2)') + */ + @Test + public void testBoundsAsClusteringWithMultiSliceRestrictionsWithOneDescendingAndOneAscendingClusteringColumns() + { + CFMetaData cfMetaData = newCFMetaData(Sort.DESC, Sort.ASC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + + // (clustering_0, clustering1) > (1, 2) + Restriction slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1, value2); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEmptyStart(get(bounds, 0)); + assertStartBound(get(bounds, 1), false, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value1); + assertEndBound(get(bounds, 1), true, value1); + + // (clustering_0, clustering1) >= (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEmptyStart(get(bounds, 0)); + assertStartBound(get(bounds, 1), true, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value1); + assertEndBound(get(bounds, 1), true, value1); + + // (clustering_0, clustering1) <= (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.END, true, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + assertStartBound(get(bounds, 1), false, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2); + assertEmptyEnd(get(bounds, 1)); + + // (clustering_0, clustering1) < (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.END, false, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + assertStartBound(get(bounds, 1), false, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2); + assertEmptyEnd(get(bounds, 1)); + + // (clustering_0, clustering1) > (1, 2) AND (clustering_0) < (2) + slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1, value2); + Restriction slice2 = newMultiSlice(cfMetaData, 0, Bound.END, false, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), false, value2); + assertStartBound(get(bounds, 1), false, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value1); + assertEndBound(get(bounds, 1), true, value1); + + // (clustering_0) > (1) AND (clustering_0, clustering1) < (2, 1) + slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1); + slice2 = newMultiSlice(cfMetaData, 0, Bound.END, false, value2, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value2); + assertStartBound(get(bounds, 1), false, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value2, value1); + assertEndBound(get(bounds, 1), false, value1); + + // (clustering_0, clustering1) >= (1, 2) AND (clustering_0, clustering1) <= (2, 1) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2); + slice2 = newMultiSlice(cfMetaData, 0, Bound.END, true, value2, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(3, bounds.size()); + assertStartBound(get(bounds, 0), true, value2); + assertStartBound(get(bounds, 1), false, value2); + assertStartBound(get(bounds, 2), true, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(3, bounds.size()); + assertEndBound(get(bounds, 0), true, value2, value1); + assertEndBound(get(bounds, 1), false, value1); + assertEndBound(get(bounds, 2), true, value1); + } + + /** + * Test multi-column slice restrictions with 1 descending clustering column and 1 ascending + * (e.g '(clustering_0, clustering_1) > (1, 2)') + */ + @Test + public void testBoundsAsClusteringWithMultiSliceRestrictionsWithOneAscendingAndOneDescendingClusteringColumns() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.DESC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + + // (clustering_0, clustering1) > (1, 2) + Restriction slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1, value2); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + assertStartBound(get(bounds, 1), false, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2); + assertEmptyEnd(get(bounds, 1)); + + // (clustering_0, clustering1) >= (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + assertStartBound(get(bounds, 1), false, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2); + assertEmptyEnd(get(bounds, 1)); + + // (clustering_0, clustering1) <= (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.END, true, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEmptyStart(get(bounds, 0)); + assertStartBound(get(bounds, 1), true, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value1); + assertEndBound(get(bounds, 1), true, value1); + + // (clustering_0, clustering1) < (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.END, false, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEmptyStart(get(bounds, 0)); + assertStartBound(get(bounds, 1), false, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value1); + assertEndBound(get(bounds, 1), true, value1); + + // (clustering_0, clustering1) > (1, 2) AND (clustering_0) < (2) + slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1, value2); + Restriction slice2 = newMultiSlice(cfMetaData, 0, Bound.END, false, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + assertStartBound(get(bounds, 1), false, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2); + assertEndBound(get(bounds, 1), false, value2); + + // (clustering_0, clustering1) >= (1, 2) AND (clustering_0, clustering1) <= (2, 1) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2); + slice2 = newMultiSlice(cfMetaData, 0, Bound.END, true, value2, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(3, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + assertStartBound(get(bounds, 1), false, value1); + assertStartBound(get(bounds, 2), true, value2, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(3, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2); + assertEndBound(get(bounds, 1), false, value2); + assertEndBound(get(bounds, 2), true, value2); + } + + /** + * Test multi-column slice restrictions with 2 ascending clustering column and 2 descending + * (e.g '(clustering_0, clustering1, clustering_3, clustering4) > (1, 2, 3, 4)') + */ + @Test + public void testBoundsAsClusteringWithMultiSliceRestrictionsWithTwoAscendingAndTwoDescendingClusteringColumns() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC, Sort.DESC, Sort.DESC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + ByteBuffer value3 = ByteBufferUtil.bytes(3); + ByteBuffer value4 = ByteBufferUtil.bytes(4); + + // (clustering_0, clustering1, clustering_2, clustering_3) > (1, 2, 3, 4) + Restriction slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1, value2, value3, value4); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2); + assertStartBound(get(bounds, 1), false, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2, value3, value4); + assertEmptyEnd(get(bounds, 1)); + + // clustering_0 = 1 AND (clustering_1, clustering_2, clustering_3) > (2, 3, 4) + Restriction eq = newSingleEq(cfMetaData, 0, value1); + slice = newMultiSlice(cfMetaData, 1, Bound.START, false, value2, value3, value4); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + restrictions = restrictions.mergeWith(eq); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2); + assertStartBound(get(bounds, 1), false, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2, value3, value4); + assertEndBound(get(bounds, 1), true, value1); + + // clustering_0 IN (1, 2) AND (clustering_1, clustering_2, clustering_3) > (2, 3, 4) + Restriction in = newSingleIN(cfMetaData, 0, value1, value2); + slice = newMultiSlice(cfMetaData, 1, Bound.START, false, value2, value3, value4); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + restrictions = restrictions.mergeWith(in); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(4, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2); + assertStartBound(get(bounds, 1), false, value1, value2); + assertStartBound(get(bounds, 2), true, value2, value2); + assertStartBound(get(bounds, 3), false, value2, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(4, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2, value3, value4); + assertEndBound(get(bounds, 1), true, value1); + assertEndBound(get(bounds, 2), false, value2, value2, value3, value4); + assertEndBound(get(bounds, 3), true, value2); + + // (clustering_0, clustering1) >= (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEmptyEnd(get(bounds, 0)); + + // (clustering_0, clustering1, clustering_2, clustering_3) >= (1, 2, 3, 4) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2, value3, value4); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2); + assertStartBound(get(bounds, 1), false, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2, value3, value4); + assertEmptyEnd(get(bounds, 1)); + + // (clustering_0, clustering1, clustering_2, clustering_3) <= (1, 2, 3, 4) + slice = newMultiSlice(cfMetaData, 0, Bound.END, true, value1, value2, value3, value4); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEmptyStart(get(bounds, 0)); + assertStartBound(get(bounds, 1), true, value1, value2, value3, value4); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2); + assertEndBound(get(bounds, 1), true, value1, value2); + + // (clustering_0, clustering1, clustering_2, clustering_3) < (1, 2, 3, 4) + slice = newMultiSlice(cfMetaData, 0, Bound.END, false, value1, value2, value3, value4); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEmptyStart(get(bounds, 0)); + assertStartBound(get(bounds, 1), false, value1, value2, value3, value4); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2); + assertEndBound(get(bounds, 1), true, value1, value2); + + // (clustering_0, clustering1, clustering_2, clustering_3) > (1, 2, 3, 4) AND (clustering_0, clustering_1) < (2, 3) + slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1, value2, value3, value4); + Restriction slice2 = newMultiSlice(cfMetaData, 0, Bound.END, false, value2, value3); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2); + assertStartBound(get(bounds, 1), false, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2, value3, value4); + assertEndBound(get(bounds, 1), false, value2, value3); + + // (clustering_0, clustering1, clustering_2, clustering_3) >= (1, 2, 3, 4) AND (clustering_0, clustering1, clustering_2, clustering_3) <= (4, 3, 2, 1) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2, value3, value4); + slice2 = newMultiSlice(cfMetaData, 0, Bound.END, true, value4, value3, value2, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(3, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2); + assertStartBound(get(bounds, 1), false, value1, value2); + assertStartBound(get(bounds, 2), true, value4, value3, value2, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(3, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2, value3, value4); + assertEndBound(get(bounds, 1), false, value4, value3); + assertEndBound(get(bounds, 2), true, value4, value3); + } + + /** + * Test multi-column slice restrictions with ascending, descending, ascending and descending columns + * (e.g '(clustering_0, clustering1, clustering_3, clustering4) > (1, 2, 3, 4)') + */ + @Test + public void testBoundsAsClusteringWithMultiSliceRestrictionsWithAscendingDescendingColumnMix() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.DESC, Sort.ASC, Sort.DESC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + ByteBuffer value3 = ByteBufferUtil.bytes(3); + ByteBuffer value4 = ByteBufferUtil.bytes(4); + + // (clustering_0, clustering1, clustering_2, clustering_3) > (1, 2, 3, 4) + Restriction slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1, value2, value3, value4); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(4, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + assertStartBound(get(bounds, 1), true, value1, value2, value3); + assertStartBound(get(bounds, 2), false, value1, value2, value3); + assertStartBound(get(bounds, 3), false, value1); + + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(4, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2); + assertEndBound(get(bounds, 1), false, value1, value2, value3, value4); + assertEndBound(get(bounds, 2), true, value1, value2); + assertEmptyEnd(get(bounds, 3)); + + // clustering_0 = 1 AND (clustering_1, clustering_2, clustering_3) > (2, 3, 4) + Restriction eq = newSingleEq(cfMetaData, 0, value1); + slice = newMultiSlice(cfMetaData, 1, Bound.START, false, value2, value3, value4); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + restrictions = restrictions.mergeWith(eq); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(3, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + assertStartBound(get(bounds, 1), true, value1, value2, value3); + assertStartBound(get(bounds, 2), false, value1, value2, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(3, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2); + assertEndBound(get(bounds, 1), false, value1, value2, value3, value4); + assertEndBound(get(bounds, 2), true, value1, value2); + + // (clustering_0, clustering1) >= (1, 2) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + assertStartBound(get(bounds, 1), false, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2); + assertEmptyEnd(get(bounds, 1)); + + // (clustering_0, clustering1, clustering_2, clustering_3) >= (1, 2, 3, 4) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2, value3, value4); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(4, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + assertStartBound(get(bounds, 1), true, value1, value2, value3); + assertStartBound(get(bounds, 2), false, value1, value2, value3); + assertStartBound(get(bounds, 3), false, value1); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(4, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2); + assertEndBound(get(bounds, 1), true, value1, value2, value3, value4); + assertEndBound(get(bounds, 2), true, value1, value2); + assertEmptyEnd(get(bounds, 3)); + + // (clustering_0, clustering1, clustering_2, clustering_3) <= (1, 2, 3, 4) + slice = newMultiSlice(cfMetaData, 0, Bound.END, true, value1, value2, value3, value4); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(4, bounds.size()); + assertEmptyStart(get(bounds, 0)); + assertStartBound(get(bounds, 1), true, value1, value2); + assertStartBound(get(bounds, 2), true, value1, value2, value3, value4); + assertStartBound(get(bounds, 3), false, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(4, bounds.size()); + assertEndBound(get(bounds, 0), false, value1); + assertEndBound(get(bounds, 1), false, value1, value2, value3); + assertEndBound(get(bounds, 2), true, value1, value2, value3); + assertEndBound(get(bounds, 3), true, value1); + + // (clustering_0, clustering1, clustering_2, clustering_3) < (1, 2, 3, 4) + slice = newMultiSlice(cfMetaData, 0, Bound.END, false, value1, value2, value3, value4); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(4, bounds.size()); + assertEmptyStart(get(bounds, 0)); + assertStartBound(get(bounds, 1), true, value1, value2); + assertStartBound(get(bounds, 2), false, value1, value2, value3, value4); + assertStartBound(get(bounds, 3), false, value1, value2); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(4, bounds.size()); + assertEndBound(get(bounds, 0), false, value1); + assertEndBound(get(bounds, 1), false, value1, value2, value3); + assertEndBound(get(bounds, 2), true, value1, value2, value3); + assertEndBound(get(bounds, 3), true, value1); + + // (clustering_0, clustering1, clustering_2, clustering_3) > (1, 2, 3, 4) AND (clustering_0, clustering_1) < (2, 3) + slice = newMultiSlice(cfMetaData, 0, Bound.START, false, value1, value2, value3, value4); + Restriction slice2 = newMultiSlice(cfMetaData, 0, Bound.END, false, value2, value3); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(5, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + assertStartBound(get(bounds, 1), true, value1, value2, value3); + assertStartBound(get(bounds, 2), false, value1, value2, value3); + assertStartBound(get(bounds, 3), false, value1); + assertStartBound(get(bounds, 4), false, value2, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(5, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2); + assertEndBound(get(bounds, 1), false, value1, value2, value3, value4); + assertEndBound(get(bounds, 2), true, value1, value2); + assertEndBound(get(bounds, 3), false, value2); + assertEndBound(get(bounds, 4), true, value2); + + // (clustering_0, clustering1, clustering_2, clustering_3) >= (1, 2, 3, 4) AND (clustering_0, clustering1, clustering_2, clustering_3) <= (4, 3, 2, 1) + slice = newMultiSlice(cfMetaData, 0, Bound.START, true, value1, value2, value3, value4); + slice2 = newMultiSlice(cfMetaData, 0, Bound.END, true, value4, value3, value2, value1); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(slice).mergeWith(slice2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(7, bounds.size()); + assertStartBound(get(bounds, 0), true, value1); + assertStartBound(get(bounds, 1), true, value1, value2, value3); + assertStartBound(get(bounds, 2), false, value1, value2, value3); + assertStartBound(get(bounds, 3), false, value1); + assertStartBound(get(bounds, 4), true, value4, value3); + assertStartBound(get(bounds, 5), true, value4, value3, value2, value1); + assertStartBound(get(bounds, 6), false, value4, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(7, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value2); + assertEndBound(get(bounds, 1), true, value1, value2, value3, value4); + assertEndBound(get(bounds, 2), true, value1, value2); + assertEndBound(get(bounds, 3), false, value4); + assertEndBound(get(bounds, 4), false, value4, value3, value2); + assertEndBound(get(bounds, 5), true, value4, value3, value2); + assertEndBound(get(bounds, 6), true, value4); + } + + /** + * Test mixing single and multi equals restrictions (e.g. clustering_0 = 1 AND (clustering_1, clustering_2) = (2, 3)) + */ + @Test + public void testBoundsAsClusteringWithSingleEqAndMultiEqRestrictions() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC, Sort.ASC, Sort.ASC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + ByteBuffer value3 = ByteBufferUtil.bytes(3); + ByteBuffer value4 = ByteBufferUtil.bytes(4); + + // clustering_0 = 1 AND (clustering_1, clustering_2) = (2, 3) + Restriction singleEq = newSingleEq(cfMetaData, 0, value1); + Restriction multiEq = newMultiEq(cfMetaData, 1, value2, value3); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(singleEq).mergeWith(multiEq); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2, value3); + + // clustering_0 = 1 AND clustering_1 = 2 AND (clustering_2, clustering_3) = (3, 4) + singleEq = newSingleEq(cfMetaData, 0, value1); + Restriction singleEq2 = newSingleEq(cfMetaData, 1, value2); + multiEq = newMultiEq(cfMetaData, 2, value3, value4); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(singleEq).mergeWith(singleEq2).mergeWith(multiEq); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2, value3, value4); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2, value3, value4); + + // (clustering_0, clustering_1) = (1, 2) AND clustering_2 = 3 + singleEq = newSingleEq(cfMetaData, 2, value3); + multiEq = newMultiEq(cfMetaData, 0, value1, value2); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(singleEq).mergeWith(multiEq); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2, value3); + + // clustering_0 = 1 AND (clustering_1, clustering_2) = (2, 3) AND clustering_3 = 4 + singleEq = newSingleEq(cfMetaData, 0, value1); + singleEq2 = newSingleEq(cfMetaData, 3, value4); + multiEq = newMultiEq(cfMetaData, 1, value2, value3); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(singleEq).mergeWith(multiEq).mergeWith(singleEq2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2, value3, value4); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2, value3, value4); + } + + /** + * Test clustering_0 = 1 AND (clustering_1, clustering_2) IN ((2, 3), (4, 5)) + */ + @Test + public void testBoundsAsClusteringWithSingleEqAndMultiINRestrictions() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC, Sort.ASC, Sort.ASC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + ByteBuffer value3 = ByteBufferUtil.bytes(3); + ByteBuffer value4 = ByteBufferUtil.bytes(4); + ByteBuffer value5 = ByteBufferUtil.bytes(5); + + // clustering_0 = 1 AND (clustering_1, clustering_2) IN ((2, 3), (4, 5)) + Restriction singleEq = newSingleEq(cfMetaData, 0, value1); + Restriction multiIN = newMultiIN(cfMetaData, 1, asList(value2, value3), asList(value4, value5)); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(singleEq).mergeWith(multiIN); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2, value3); + assertStartBound(get(bounds, 1), true, value1, value4, value5); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2, value3); + assertEndBound(get(bounds, 1), true, value1, value4, value5); + + // clustering_0 = 1 AND (clustering_1, clustering_2) IN ((2, 3)) + singleEq = newSingleEq(cfMetaData, 0, value1); + multiIN = newMultiIN(cfMetaData, 1, asList(value2, value3)); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(multiIN).mergeWith(singleEq); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2, value3); + + // clustering_0 = 1 AND clustering_1 = 5 AND (clustering_2, clustering_3) IN ((2, 3), (4, 5)) + singleEq = newSingleEq(cfMetaData, 0, value1); + Restriction singleEq2 = newSingleEq(cfMetaData, 1, value5); + multiIN = newMultiIN(cfMetaData, 2, asList(value2, value3), asList(value4, value5)); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(singleEq).mergeWith(multiIN).mergeWith(singleEq2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value5, value2, value3); + assertStartBound(get(bounds, 1), true, value1, value5, value4, value5); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value5, value2, value3); + assertEndBound(get(bounds, 1), true, value1, value5, value4, value5); + } + + /** + * Test mixing single equal restrictions with multi-column slice restrictions + * (e.g. clustering_0 = 1 AND (clustering_1, clustering_2) > (2, 3)) + */ + @Test + public void testBoundsAsClusteringWithSingleEqAndSliceRestrictions() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC, Sort.ASC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + ByteBuffer value3 = ByteBufferUtil.bytes(3); + ByteBuffer value4 = ByteBufferUtil.bytes(4); + ByteBuffer value5 = ByteBufferUtil.bytes(5); + + // clustering_0 = 1 AND (clustering_1, clustering_2) > (2, 3) + Restriction singleEq = newSingleEq(cfMetaData, 0, value1); + Restriction multiSlice = newMultiSlice(cfMetaData, 1, Bound.START, false, value2, value3); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(singleEq).mergeWith(multiSlice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value1, value2, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1); + + // clustering_0 = 1 AND (clustering_1, clustering_2) > (2, 3) AND (clustering_1) < (4) + singleEq = newSingleEq(cfMetaData, 0, value1); + multiSlice = newMultiSlice(cfMetaData, 1, Bound.START, false, value2, value3); + Restriction multiSlice2 = newMultiSlice(cfMetaData, 1, Bound.END, false, value4); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(multiSlice2).mergeWith(singleEq).mergeWith(multiSlice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value1, value2, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), false, value1, value4); + + // clustering_0 = 1 AND (clustering_1, clustering_2) => (2, 3) AND (clustering_1, clustering_2) <= (4, 5) + singleEq = newSingleEq(cfMetaData, 0, value1); + multiSlice = newMultiSlice(cfMetaData, 1, Bound.START, true, value2, value3); + multiSlice2 = newMultiSlice(cfMetaData, 1, Bound.END, true, value4, value5); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(multiSlice2).mergeWith(singleEq).mergeWith(multiSlice); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value4, value5); + } + + /** + * Test mixing multi equal restrictions with single-column slice restrictions + * (e.g. clustering_0 = 1 AND (clustering_1, clustering_2) > (2, 3)) + */ + @Test + public void testBoundsAsClusteringWithMultiEqAndSingleSliceRestrictions() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC, Sort.ASC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + ByteBuffer value3 = ByteBufferUtil.bytes(3); + + // (clustering_0, clustering_1) = (1, 2) AND clustering_2 > 3 + Restriction multiEq = newMultiEq(cfMetaData, 0, value1, value2); + Restriction singleSlice = newSingleSlice(cfMetaData, 2, Bound.START, false, value3); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(multiEq).mergeWith(singleSlice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value1, value2, value3); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2); + } + + @Test + public void testBoundsAsClusteringWithSeveralMultiColumnRestrictions() + { + CFMetaData cfMetaData = newCFMetaData(Sort.ASC, Sort.ASC, Sort.ASC, Sort.ASC); + + ByteBuffer value1 = ByteBufferUtil.bytes(1); + ByteBuffer value2 = ByteBufferUtil.bytes(2); + ByteBuffer value3 = ByteBufferUtil.bytes(3); + ByteBuffer value4 = ByteBufferUtil.bytes(4); + ByteBuffer value5 = ByteBufferUtil.bytes(5); + + // (clustering_0, clustering_1) = (1, 2) AND (clustering_2, clustering_3) > (3, 4) + Restriction multiEq = newMultiEq(cfMetaData, 0, value1, value2); + Restriction multiSlice = newMultiSlice(cfMetaData, 2, Bound.START, false, value3, value4); + ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(multiEq).mergeWith(multiSlice); + + SortedSet<Slice.Bound> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), false, value1, value2, value3, value4); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2); + + // (clustering_0, clustering_1) = (1, 2) AND (clustering_2, clustering_3) IN ((3, 4), (4, 5)) + multiEq = newMultiEq(cfMetaData, 0, value1, value2); + Restriction multiIN = newMultiIN(cfMetaData, 2, asList(value3, value4), asList(value4, value5)); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(multiEq).mergeWith(multiIN); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2, value3, value4); + assertStartBound(get(bounds, 1), true, value1, value2, value4, value5); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(2, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2, value3, value4); + assertEndBound(get(bounds, 1), true, value1, value2, value4, value5); + + // (clustering_0, clustering_1) = (1, 2) AND (clustering_2, clustering_3) = (3, 4) + multiEq = newMultiEq(cfMetaData, 0, value1, value2); + Restriction multiEq2 = newMultiEq(cfMetaData, 2, value3, value4); + restrictions = new ClusteringColumnRestrictions(cfMetaData); + restrictions = restrictions.mergeWith(multiEq).mergeWith(multiEq2); + + bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertStartBound(get(bounds, 0), true, value1, value2, value3, value4); + + bounds = restrictions.boundsAsClustering(Bound.END, QueryOptions.DEFAULT); + assertEquals(1, bounds.size()); + assertEndBound(get(bounds, 0), true, value1, value2, value3, value4); + } + + /** + * Asserts that the specified <code>Bound</code> is an empty start. + * + * @param bound the bound to check + */ + private static void assertEmptyStart(Slice.Bound bound) + { + assertEquals(Slice.Bound.BOTTOM, bound); + } + + /** + * Asserts that the specified <code>Bound</code> is an empty end. + * + * @param bound the bound to check + */ + private static void assertEmptyEnd(Slice.Bound bound) + { + assertEquals(Slice.Bound.TOP, bound); + } + + /** + * Asserts that the specified <code>Slice.Bound</code> is a start with the specified elements. + * + * @param bound the bound to check + * @param isInclusive if the bound is expected to be inclusive + * @param elements the expected elements of the clustering + */ + private static void assertStartBound(Slice.Bound bound, boolean isInclusive, ByteBuffer... elements) + { + assertBound(bound, true, isInclusive, elements); + } + + /** + * Asserts that the specified <code>Slice.Bound</code> is a end with the specified elements. + * + * @param bound the bound to check + * @param isInclusive if the bound is expected to be inclusive + * @param elements the expected elements of the clustering + */ + private static void assertEndBound(Slice.Bound bound, boolean isInclusive, ByteBuffer... elements) + { + assertBound(bound, false, isInclusive, elements); + } + + private static void assertBound(Slice.Bound bound, boolean isStart, boolean isInclusive, ByteBuffer... elements) + { + assertEquals("the bound size is not the expected one:", elements.length, bound.size()); + assertEquals("the bound should be a " + (isStart ? "start" : "end") + " but is a " + (bound.isStart() ? "start" : "end"), isStart, bound.isStart()); + assertEquals("the bound inclusiveness is not the expected one", isInclusive, bound.isInclusive()); + for (int i = 0, m = elements.length; i < m; i++) + { + ByteBuffer element = elements[i]; + assertTrue(String.format("the element %s of the bound is not the expected one: expected %s but was %s", + i, + ByteBufferUtil.toInt(element), + ByteBufferUtil.toInt(bound.get(i))), + element.equals(bound.get(i))); + } + } + + /** + * Creates a new <code>CFMetaData</code> instance. + * + * @param numberOfClusteringColumns the number of clustering column + * @return a new <code>CFMetaData</code> instance + */ + private static CFMetaData newCFMetaData(Sort... sorts) + { + List<AbstractType<?>> types = new ArrayList<>(); + + for (Sort sort : sorts) + types.add(sort == Sort.ASC ? Int32Type.instance : ReversedType.getInstance(Int32Type.instance)); + + CFMetaData.Builder builder = CFMetaData.Builder.create("keyspace", "test") + .addPartitionKey("partition_key", Int32Type.instance); + + for (int i = 0; i < sorts.length; i++) + builder.addClusteringColumn("clustering_" + i, types.get(i)); + + return builder.build(); + } + + /** + * Creates a new <code>SingleColumnRestriction.EQ</code> instance for the specified clustering column. + * + * @param cfMetaData the column family meta data + * @param index the clustering column index + * @param value the equality value + * @return a new <code>SingleColumnRestriction.EQ</code> instance for the specified clustering column + */ + private static Restriction newSingleEq(CFMetaData cfMetaData, int index, ByteBuffer value) + { + ColumnDefinition columnDef = getClusteringColumnDefinition(cfMetaData, index); + return new SingleColumnRestriction.EQRestriction(columnDef, toTerm(value)); + } + + /** + * Creates a new <code>MultiColumnRestriction.EQ</code> instance for the specified clustering column. + * + * @param cfMetaData the column family meta data + * @param index the clustering column index + * @param value the equality value + * @return a new <code>MultiColumnRestriction.EQ</code> instance for the specified clustering column + */ + private static Restriction newMultiEq(CFMetaData cfMetaData, int firstIndex, ByteBuffer... values) + { + List<ColumnDefinition> columnDefinitions = new ArrayList<>(); + for (int i = 0; i < values.length; i++) + { + columnDefinitions.add(getClusteringColumnDefinition(cfMetaData, firstIndex + i)); + } + return new MultiColumnRestriction.EQRestriction(columnDefinitions, toMultiItemTerminal(values)); + } + + /** + * Creates a new <code>MultiColumnRestriction.IN</code> instance for the specified clustering co
<TRUNCATED>
