diff options
Diffstat (limited to 'src/test/java/com/amazon/carbonado/qe')
8 files changed, 2507 insertions, 0 deletions
diff --git a/src/test/java/com/amazon/carbonado/qe/TestFilteredQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestFilteredQueryExecutor.java new file mode 100644 index 0000000..76ea081 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/qe/TestFilteredQueryExecutor.java @@ -0,0 +1,57 @@ +/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * 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
+ *
+ * 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 com.amazon.carbonado.qe;
+
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.filter.Filter;
+import com.amazon.carbonado.filter.FilterValues;
+
+import com.amazon.carbonado.stored.Address;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestFilteredQueryExecutor extends TestQueryExecutor {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestFilteredQueryExecutor.class);
+ }
+
+ public void testBasicFiltering() throws Exception {
+ QueryExecutor<Address> unfiltered = createExecutor(1, 2, 3, 4);
+ Filter<Address> filter = Filter.filterFor(Address.class, "addressCountry > ?");
+ FilterValues<Address> values = filter.initialFilterValues();
+
+ QueryExecutor<Address> executor = new FilteredQueryExecutor<Address>(unfiltered, filter);
+
+ assertEquals(values.getFilter(), executor.getFilter());
+
+ assertEquals(2, executor.count(values.with("country_2")));
+
+ assertEquals(0, executor.getOrdering().size());
+
+ compareElements(executor.openCursor(values.with("country_2")), 3, 4);
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestFilteringScore.java b/src/test/java/com/amazon/carbonado/qe/TestFilteringScore.java new file mode 100644 index 0000000..e6b4374 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/qe/TestFilteringScore.java @@ -0,0 +1,746 @@ +/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * 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
+ *
+ * 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 com.amazon.carbonado.qe;
+
+import java.util.Comparator;
+import java.util.List;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.Storable;
+
+import com.amazon.carbonado.info.Direction;
+import static com.amazon.carbonado.info.Direction.*;
+import com.amazon.carbonado.info.OrderedProperty;
+import com.amazon.carbonado.info.StorableIndex;
+import com.amazon.carbonado.info.StorableInfo;
+import com.amazon.carbonado.info.StorableIntrospector;
+import com.amazon.carbonado.info.StorableProperty;
+
+import com.amazon.carbonado.filter.Filter;
+import com.amazon.carbonado.filter.PropertyFilter;
+
+import com.amazon.carbonado.stored.StorableTestBasic;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestFilteringScore extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestFilteringScore.class);
+ }
+
+ static <S extends Storable> StorableIndex<S> makeIndex(Class<S> type, String... props) {
+ return TestOrderingScore.makeIndex(type, props);
+ }
+
+ public TestFilteringScore(String name) {
+ super(name);
+ }
+
+ public void testNoFilter() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class, "id");
+ Filter<StorableTestBasic> filter = Filter.getOpenFilter(StorableTestBasic.class);
+ FilteringScore score = FilteringScore.evaluate(ix, filter);
+
+ assertFalse(score.isIndexClustered());
+ assertEquals(1, score.getIndexPropertyCount());
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertFalse(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ }
+
+ public void testSimpleIndexMisses() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class, "intProp");
+ // Filter by a property not in index.
+ Filter<StorableTestBasic> filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+
+ FilteringScore score = FilteringScore.evaluate(ix, filter);
+
+ assertFalse(score.isIndexClustered());
+ assertEquals(1, score.getIndexPropertyCount());
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertFalse(score.hasAnyMatches());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals(1, score.getRemainderFilters().size());
+ assertEquals(filter, score.getRemainderFilters().get(0));
+ assertEquals(filter, score.getRemainderFilter());
+
+ // Try again with matching property, but with an operator that cannot be used by index.
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp != ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertFalse(score.isIndexClustered());
+ assertEquals(1, score.getIndexPropertyCount());
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertFalse(score.hasAnyMatches());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals(1, score.getRemainderFilters().size());
+ assertEquals(filter, score.getRemainderFilters().get(0));
+ assertEquals(filter, score.getRemainderFilter());
+ }
+
+ public void testSimpleIndexMatches() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class, "id");
+ // Filter by a property in index.
+ Filter<StorableTestBasic> filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+
+ FilteringScore score = FilteringScore.evaluate(ix, filter);
+
+ assertFalse(score.isIndexClustered());
+ assertEquals(1, score.getIndexPropertyCount());
+
+ assertEquals(1, score.getIdentityCount());
+ assertEquals(1, score.getArrangementScore());
+ assertEquals(filter, score.getIdentityFilters().get(0));
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ assertEquals(null, score.getRemainderFilter());
+
+ // Try again with open ranges.
+ for (int i=0; i<4; i++) {
+ String expr;
+ switch (i) {
+ default: expr = "id > ?"; break;
+ case 1: expr = "id >= ?"; break;
+ case 2: expr = "id < ?"; break;
+ case 3: expr = "id <= ?"; break;
+ }
+
+ filter = Filter.filterFor(StorableTestBasic.class, expr);
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ assertEquals(null, score.getRemainderFilter());
+
+ if (i < 2) {
+ assertTrue(score.hasRangeStart());
+ assertEquals(1, score.getRangeStartFilters().size());
+ assertEquals(filter, score.getRangeStartFilters().get(0));
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+ } else {
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertTrue(score.hasRangeEnd());
+ assertEquals(1, score.getRangeEndFilters().size());
+ assertEquals(filter, score.getRangeEndFilters().get(0));
+ }
+ }
+
+ // Try with duplicate open ranges.
+ filter = Filter.filterFor(StorableTestBasic.class, "id > ? & id > ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ assertEquals(null, score.getRemainderFilter());
+
+ assertTrue(score.hasRangeStart());
+ assertEquals(2, score.getRangeStartFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id > ?"),
+ score.getRangeStartFilters().get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id > ?"),
+ score.getRangeStartFilters().get(1));
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+
+ // Try with duplicate end ranges and slightly different operator.
+ filter = Filter.filterFor(StorableTestBasic.class, "id < ? & id <= ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ assertEquals(null, score.getRemainderFilter());
+
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertTrue(score.hasRangeEnd());
+ assertEquals(2, score.getRangeEndFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id < ?"),
+ score.getRangeEndFilters().get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id <= ?"),
+ score.getRangeEndFilters().get(1));
+
+ // Try with complete range.
+ filter = Filter.filterFor(StorableTestBasic.class, "id > ? & id < ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+ assertTrue(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ assertEquals(null, score.getRemainderFilter());
+
+ assertTrue(score.hasRangeStart());
+ assertEquals(1, score.getRangeStartFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id > ?"),
+ score.getRangeStartFilters().get(0));
+ assertTrue(score.hasRangeEnd());
+ assertEquals(1, score.getRangeEndFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id < ?"),
+ score.getRangeEndFilters().get(0));
+
+ // Try with an identity filter consuming others.
+ filter = Filter.filterFor(StorableTestBasic.class, "id > ? & id = ? & id = ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(1, score.getIdentityCount());
+ assertEquals(1, score.getIdentityFilters().size());
+ assertEquals(1, score.getArrangementScore());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id = ?"),
+ score.getIdentityFilters().get(0));
+
+ assertFalse(score.hasRangeStart());
+ assertFalse(score.hasRangeEnd());
+ assertFalse(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(2, score.getRemainderCount());
+ assertEquals(2, score.getRemainderFilters().size());
+ // Order of properties in filter accounts for sorting by PropertyFilterList.
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id = ? & id > ?"),
+ score.getRemainderFilter());
+
+ // Try with complex mix of non-identity matches.
+ filter = Filter.filterFor
+ (StorableTestBasic.class,
+ "id > ? & id != ? & id <= ? & id >= ? & id != ? & id > ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertEquals(0, score.getIdentityFilters().size());
+
+ assertTrue(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+
+ assertTrue(score.hasRangeStart());
+ assertEquals(3, score.getRangeStartFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id > ?"),
+ score.getRangeStartFilters().get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id >= ?"),
+ score.getRangeStartFilters().get(1));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id > ?"),
+ score.getRangeStartFilters().get(2));
+
+ assertTrue(score.hasRangeEnd());
+ assertEquals(1, score.getRangeEndFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id <= ?"),
+ score.getRangeEndFilters().get(0));
+
+ assertEquals(2, score.getRemainderCount());
+ assertEquals(2, score.getRemainderFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id != ? & id != ?"),
+ score.getRemainderFilter());
+ }
+
+ public void testCompositeIndexMatches() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class,
+ "id", "intProp", "stringProp");
+ // Filter by a property in index.
+ Filter<StorableTestBasic> filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+
+ FilteringScore score = FilteringScore.evaluate(ix, filter);
+
+ assertFalse(score.isIndexClustered());
+ assertEquals(3, score.getIndexPropertyCount());
+
+ assertEquals(1, score.getIdentityCount());
+ assertEquals(1, score.getArrangementScore());
+ assertEquals(filter, score.getIdentityFilters().get(0));
+ assertFalse(score.hasRangeStart());
+ assertEquals(0, score.getRangeStartFilters().size());
+ assertFalse(score.hasRangeEnd());
+ assertEquals(0, score.getRangeEndFilters().size());
+ assertFalse(score.hasRangeMatch());
+ assertTrue(score.hasAnyMatches());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(0, score.getRemainderFilters().size());
+ assertEquals(null, score.getRemainderFilter());
+
+ // Filter by a property with a gap. (filter must include "id" to use index)
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp = ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertFalse(score.hasAnyMatches());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals(1, score.getRemainderFilters().size());
+ assertEquals(filter, score.getRemainderFilter());
+
+ // Filter by a property with a gap and a range operator. (index still cannot be used)
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp = ? & stringProp < ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertFalse(score.hasAnyMatches());
+ assertEquals(2, score.getRemainderCount());
+ assertEquals(2, score.getRemainderFilters().size());
+ assertEquals(filter, score.getRemainderFilter());
+
+ // Filter with range match before identity match. Identity cannot be used.
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp = ? & id < ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(0, score.getIdentityCount());
+ assertTrue(score.hasAnyMatches());
+
+ assertTrue(score.hasRangeEnd());
+ assertEquals(1, score.getRangeEndFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id < ?"),
+ score.getRangeEndFilters().get(0));
+
+ assertEquals(1, score.getRemainderCount());
+ assertEquals(1, score.getRemainderFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "intProp = ?"),
+ score.getRemainderFilter());
+
+ // Filter with fully specified identity match, but a few remaining.
+ filter = Filter.filterFor
+ (StorableTestBasic.class,
+ "intProp = ? & id = ? & stringProp = ? & stringProp > ? & doubleProp = ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertTrue(score.hasAnyMatches());
+ assertEquals(3, score.getIdentityCount());
+ assertEquals(2, score.getArrangementScore());
+
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id = ?"),
+ score.getIdentityFilters().get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "intProp = ?"),
+ score.getIdentityFilters().get(1));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "stringProp = ?"),
+ score.getIdentityFilters().get(2));
+
+ assertEquals(2, score.getRemainderCount());
+ assertEquals(2, score.getRemainderFilters().size());
+ // Order of remainder properties accounts for sorting by PropertyFilterList.
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "doubleProp = ?"),
+ score.getRemainderFilters().get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "stringProp > ?"),
+ score.getRemainderFilters().get(1));
+
+ // Filter with identity and range matches.
+ filter = Filter.filterFor
+ (StorableTestBasic.class,
+ "intProp > ? & id = ? & stringProp = ? & intProp <= ? & " +
+ "stringProp < ? & doubleProp = ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertTrue(score.hasAnyMatches());
+ assertEquals(1, score.getIdentityCount());
+ assertEquals(1, score.getArrangementScore());
+
+ assertEquals(3, score.getRemainderCount());
+ assertEquals(3, score.getRemainderFilters().size());
+ // Order of remainder properties accounts for sorting by PropertyFilterList.
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "stringProp = ?"),
+ score.getRemainderFilters().get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "doubleProp = ?"),
+ score.getRemainderFilters().get(1));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "stringProp < ?"),
+ score.getRemainderFilters().get(2));
+
+ assertTrue(score.hasRangeMatch());
+ assertTrue(score.hasRangeStart());
+ assertEquals(1, score.getRangeStartFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "intProp > ?"),
+ score.getRangeStartFilters().get(0));
+
+ assertTrue(score.hasRangeEnd());
+ assertEquals(1, score.getRangeEndFilters().size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "intProp <= ?"),
+ score.getRangeEndFilters().get(0));
+
+ // Filter with fully specified identity match, with backwards arrangement.
+ filter = Filter.filterFor
+ (StorableTestBasic.class, "stringProp = ? & intProp = ? & id = ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertTrue(score.hasAnyMatches());
+ assertEquals(3, score.getIdentityCount());
+ // Arrangement score is always at least one if identity count is not zero.
+ assertEquals(1, score.getArrangementScore());
+ }
+
+ public void testReverseRange() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class,
+ "id", "intProp");
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "id = ? & intProp > ?");
+
+ FilteringScore score = FilteringScore.evaluate(ix, filter);
+
+ assertFalse(score.shouldReverseRange());
+
+ ix = makeIndex(StorableTestBasic.class, "id", "-intProp");
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertTrue(score.shouldReverseRange());
+ }
+
+ public void testRangeComparator() throws Exception {
+ StorableIndex<StorableTestBasic> ix_1, ix_2;
+ Filter<StorableTestBasic> filter;
+ FilteringScore score_1, score_2;
+ Comparator<FilteringScore<?>> comp = FilteringScore.rangeComparator();
+
+ ix_1 = makeIndex(StorableTestBasic.class, "id", "intProp", "doubleProp", "-stringProp");
+ ix_2 = makeIndex(StorableTestBasic.class, "id", "stringProp", "intProp");
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ score_1 = FilteringScore.evaluate(ix_1.clustered(true), filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "stringProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "stringProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1.clustered(true), filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & stringProp != ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & stringProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ // Both indexes are as good, since range is open.
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & stringProp > ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "id = ? & intProp = ? & stringProp > ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ // Test range match with tie resolved by clustered index.
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ? & id < ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ? & id < ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2.clustered(true), filter);
+
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ // Test open range match with tie still not resolved by clustered index.
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2.clustered(true), filter);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+ }
+
+ public void testFullComparator() throws Exception {
+ StorableIndex<StorableTestBasic> ix_1, ix_2;
+ Filter<StorableTestBasic> filter;
+ FilteringScore score_1, score_2;
+ Comparator<FilteringScore<?>> comp = FilteringScore.fullComparator();
+
+ ix_1 = makeIndex(StorableTestBasic.class, "id", "intProp", "doubleProp", "-stringProp");
+ ix_2 = makeIndex(StorableTestBasic.class, "id", "stringProp", "intProp");
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ // Second is better because it has fewer properties.
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ score_1 = FilteringScore.evaluate(ix_1.clustered(true), filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "stringProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ // Although no property matches, second is better just because it has fewer properties.
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "stringProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1.clustered(true), filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ // Although no property matches, first is better just because it is clustered.
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & stringProp != ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ // Second is better because it has fewer properties.
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & stringProp = ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ // Second index is better since the open range matches.
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & stringProp > ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "id = ? & intProp = ? & stringProp > ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ // Test range match with tie resolved by clustered index.
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ? & id < ?");
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ // Second is better because it has fewer properties.
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ? & id < ?");
+ score_1 = FilteringScore.evaluate(ix_1.clustered(true), filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ // First is better because it is clusted.
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ // Test range match with tie resolved by clustered index.
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ? & id < ?");
+ score_1 = FilteringScore.evaluate(ix_1.clustered(true), filter);
+ score_2 = FilteringScore.evaluate(ix_2.clustered(true), filter);
+
+ // Second is better because it has fewer properties.
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+ }
+
+ public void testArrangementFullComparator() throws Exception {
+ StorableIndex<StorableTestBasic> ix_1, ix_2;
+ Filter<StorableTestBasic> filter;
+ FilteringScore score_1, score_2;
+
+ ix_1 = makeIndex(StorableTestBasic.class, "id", "intProp", "-stringProp");
+ ix_2 = makeIndex(StorableTestBasic.class, "id", "stringProp", "intProp");
+
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "id = ? & intProp = ? & stringProp = ?");
+
+ score_1 = FilteringScore.evaluate(ix_1, filter);
+ score_2 = FilteringScore.evaluate(ix_2, filter);
+
+ Comparator<FilteringScore<?>> comp = FilteringScore.rangeComparator();
+
+ // With just range comparison, either index works.
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+
+ comp = FilteringScore.fullComparator();
+
+ // First index is better because property arrangement matches.
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+ }
+
+ public void testRangeFilterSubset() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class, "id");
+ Filter<StorableTestBasic> filter;
+ FilteringScore score;
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id >= ? & id >= ? & id < ? & id <= ?");
+
+ score = FilteringScore.evaluate(ix, filter);
+
+ assertEquals(2, score.getRangeStartFilters().size());
+
+ List<PropertyFilter<?>> exStart = score.getExclusiveRangeStartFilters();
+ assertEquals(0, exStart.size());
+
+ List<PropertyFilter<?>> inStart = score.getInclusiveRangeStartFilters();
+ assertEquals(2, inStart.size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id >= ?"), inStart.get(0));
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id >= ?"), inStart.get(1));
+
+ assertEquals(2, score.getRangeEndFilters().size());
+
+ List<PropertyFilter<?>> exEnd = score.getExclusiveRangeEndFilters();
+ assertEquals(1, exEnd.size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id < ?"), exEnd.get(0));
+
+ List<PropertyFilter<?>> inEnd = score.getInclusiveRangeEndFilters();
+ assertEquals(1, inEnd.size());
+ assertEquals(Filter.filterFor(StorableTestBasic.class, "id <= ?"), inEnd.get(0));
+ }
+
+ public void testKeyMatch() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class, "id", "intProp");
+ ix = ix.unique(true);
+ Filter<StorableTestBasic> filter;
+ FilteringScore score;
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+ score = FilteringScore.evaluate(ix, filter);
+ assertFalse(score.isKeyMatch());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp > ?");
+ score = FilteringScore.evaluate(ix, filter);
+ assertFalse(score.isKeyMatch());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ?");
+ score = FilteringScore.evaluate(ix, filter);
+ assertTrue(score.isKeyMatch());
+
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "id = ? & intProp = ? & doubleProp = ?");
+ score = FilteringScore.evaluate(ix, filter);
+ assertTrue(score.isKeyMatch());
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestIndexedQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestIndexedQueryExecutor.java new file mode 100644 index 0000000..a039e63 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/qe/TestIndexedQueryExecutor.java @@ -0,0 +1,725 @@ +/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * 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
+ *
+ * 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 com.amazon.carbonado.qe;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.Cursor;
+import com.amazon.carbonado.Storable;
+
+import com.amazon.carbonado.cursor.IteratorCursor;
+
+import com.amazon.carbonado.filter.Filter;
+import com.amazon.carbonado.filter.FilterValues;
+
+import com.amazon.carbonado.info.OrderedProperty;
+import com.amazon.carbonado.info.StorableIndex;
+
+import com.amazon.carbonado.stored.StorableTestBasic;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestIndexedQueryExecutor extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestIndexedQueryExecutor.class);
+ }
+
+ static <S extends Storable> StorableIndex<S> makeIndex(Class<S> type, String... props) {
+ return TestOrderingScore.makeIndex(type, props);
+ }
+
+ static <S extends Storable> OrderedProperty<S>[] makeOrderings(Class<S> type, String... props)
+ {
+ return TestOrderingScore.makeOrderings(type, props);
+ }
+
+ public TestIndexedQueryExecutor(String name) {
+ super(name);
+ }
+
+ public void testIdentityMatch() throws Exception {
+ StorableIndex<StorableTestBasic> index =
+ makeIndex(StorableTestBasic.class, "id", "-intProp", "doubleProp");
+
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "id = ?");
+ FilterValues<StorableTestBasic> values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ CompositeScore<StorableTestBasic> score = CompositeScore.evaluate(index, filter);
+
+ Mock<StorableTestBasic> executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(1, executor.mIdentityValues.length);
+ assertEquals(100, executor.mIdentityValues[0]);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100).with(5));
+
+ assertEquals(2, executor.mIdentityValues.length);
+ assertEquals(100, executor.mIdentityValues[0]);
+ assertEquals(5, executor.mIdentityValues[1]);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp = ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(200));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+ }
+
+ public void testOpenRangeStartMatch() throws Exception {
+ StorableIndex<StorableTestBasic> index = makeIndex(StorableTestBasic.class, "intProp");
+
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "intProp > ?");
+ FilterValues<StorableTestBasic> values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ CompositeScore<StorableTestBasic> score = CompositeScore.evaluate(index, filter);
+
+ Mock<StorableTestBasic> executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp >= ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.INCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp > ? & intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(30, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp >= ? & intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(30, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp >= ? & intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(10));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(10, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp >= ? & intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(30).with(10));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.INCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(30, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp > ? & intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "-intProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertTrue(executor.mReverseOrder);
+
+ ///////
+ index = makeIndex(StorableTestBasic.class, "-intProp");
+
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "-intProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "intProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.OPEN, executor.mRangeEndBoundary);
+ assertEquals(null, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertTrue(executor.mReverseOrder);
+ }
+
+ public void testOpenRangeEndMatch() throws Exception {
+ StorableIndex<StorableTestBasic> index = makeIndex(StorableTestBasic.class, "intProp");
+
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "intProp < ?");
+ FilterValues<StorableTestBasic> values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ CompositeScore<StorableTestBasic> score = CompositeScore.evaluate(index, filter);
+
+ Mock<StorableTestBasic> executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(100, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp <= ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.INCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(100, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp < ? & intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(10, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp <= ? & intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.INCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(10, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp <= ? & intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(10));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(10, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp <= ? & intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(30).with(10));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(10, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp < ? & intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "-intProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(30, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertTrue(executor.mReverseOrder);
+
+ ///////
+ index = makeIndex(StorableTestBasic.class, "-intProp");
+
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(100, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "-intProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(100, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "intProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(100, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertTrue(executor.mReverseOrder);
+ }
+
+ public void testClosedRangeMatch() throws Exception {
+ // These tests are not as exhaustive, as I don't expect the combination
+ // of start and end ranges to interfere with each other.
+
+ StorableIndex<StorableTestBasic> index = makeIndex(StorableTestBasic.class, "intProp");
+
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "intProp > ? & intProp < ?");
+ FilterValues<StorableTestBasic> values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ CompositeScore<StorableTestBasic> score = CompositeScore.evaluate(index, filter);
+
+ Mock<StorableTestBasic> executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100).with(200));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(200, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class, "intProp >= ? & intProp <= ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(100).with(10));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.INCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(100, executor.mRangeStartValue);
+ assertEquals(BoundaryType.INCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(10, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "intProp > ? & intProp < ? & intProp > ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(10).with(100).with(30));
+
+ assertEquals(null, executor.mIdentityValues);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(30, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(100, executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+ }
+
+ public void testIdentityAndRangeMatch() throws Exception {
+ // These tests are not as exhaustive, as I don't expect the combination
+ // of identity and ranges to interfere with each other.
+
+ StorableIndex<StorableTestBasic> index;
+ Filter<StorableTestBasic> filter;
+ FilterValues<StorableTestBasic> values;
+ CompositeScore<StorableTestBasic> score;
+ Mock<StorableTestBasic> executor;
+
+ index = makeIndex(StorableTestBasic.class, "intProp", "-doubleProp", "stringProp");
+
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "intProp = ? & doubleProp > ? & doubleProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter);
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(3).with(56.5).with(200.2));
+
+ assertEquals(3, executor.mIdentityValues[0]);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(56.5, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(200.2, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "doubleProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(3).with(56.5).with(200.2));
+
+ assertEquals(3, executor.mIdentityValues[0]);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(56.5, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(200.2, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertTrue(executor.mReverseOrder);
+
+ ///////
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "stringProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(3).with(56.5).with(200.2));
+
+ assertEquals(3, executor.mIdentityValues[0]);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary);
+ assertEquals(56.5, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals(200.2, executor.mRangeEndValue);
+ assertTrue(executor.mReverseRange);
+ assertFalse(executor.mReverseOrder);
+
+ ///////
+ filter = Filter.filterFor(StorableTestBasic.class,
+ "intProp = ? & doubleProp = ? & stringProp < ?");
+ values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ score = CompositeScore.evaluate(index, filter,
+ makeOrderings(StorableTestBasic.class, "-stringProp"));
+
+ executor = new Mock(index, score);
+
+ executor.openCursor(values.with(3).with(56.5).with("foo"));
+
+ assertEquals(3, executor.mIdentityValues[0]);
+ assertEquals(56.5, executor.mIdentityValues[1]);
+ assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary);
+ assertEquals(null, executor.mRangeStartValue);
+ assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeEndBoundary);
+ assertEquals("foo", executor.mRangeEndValue);
+ assertFalse(executor.mReverseRange);
+ assertTrue(executor.mReverseOrder);
+
+ assertEquals(values.getFilter(), executor.getFilter());
+ OrderedProperty<StorableTestBasic>[] expectedOrdering =
+ makeOrderings(StorableTestBasic.class, "intProp", "-doubleProp", "stringProp");
+ assertEquals(Arrays.asList(expectedOrdering), executor.getOrdering());
+ }
+
+ /**
+ * Mock object doesn't really open a cursor -- it just captures the passed
+ * parameters.
+ */
+ static class Mock<S extends Storable> extends IndexedQueryExecutor<S> {
+ Object[] mIdentityValues;
+ BoundaryType mRangeStartBoundary;
+ Object mRangeStartValue;
+ BoundaryType mRangeEndBoundary;
+ Object mRangeEndValue;
+ boolean mReverseRange;
+ boolean mReverseOrder;
+
+ public Mock(StorableIndex<S> index, CompositeScore<S> score) {
+ super(index, score);
+ }
+
+ protected Cursor<S> openCursor(StorableIndex<S> index,
+ Object[] identityValues,
+ BoundaryType rangeStartBoundary,
+ Object rangeStartValue,
+ BoundaryType rangeEndBoundary,
+ Object rangeEndValue,
+ boolean reverseRange,
+ boolean reverseOrder)
+ {
+ mIdentityValues = identityValues;
+ mRangeStartBoundary = rangeStartBoundary;
+ mRangeStartValue = rangeStartValue;
+ mRangeEndBoundary = rangeEndBoundary;
+ mRangeEndValue = rangeEndValue;
+ mReverseRange = reverseRange;
+ mReverseOrder = reverseOrder;
+
+ Collection<S> empty = Collections.emptyList();
+ return new IteratorCursor<S>(empty);
+ }
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestOrderingScore.java b/src/test/java/com/amazon/carbonado/qe/TestOrderingScore.java new file mode 100644 index 0000000..3929f59 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/qe/TestOrderingScore.java @@ -0,0 +1,517 @@ +/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * 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
+ *
+ * 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 com.amazon.carbonado.qe;
+
+import java.util.Comparator;
+import java.util.List;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.Storable;
+
+import com.amazon.carbonado.info.Direction;
+import static com.amazon.carbonado.info.Direction.*;
+import com.amazon.carbonado.info.OrderedProperty;
+import com.amazon.carbonado.info.StorableIndex;
+import com.amazon.carbonado.info.StorableInfo;
+import com.amazon.carbonado.info.StorableIntrospector;
+import com.amazon.carbonado.info.StorableProperty;
+
+import com.amazon.carbonado.filter.Filter;
+
+import com.amazon.carbonado.stored.StorableTestBasic;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestOrderingScore extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestOrderingScore.class);
+ }
+
+ static <S extends Storable> StorableIndex<S> makeIndex(Class<S> type, String... props) {
+ return new StorableIndex<S>(makeOrderings(type, props), UNSPECIFIED);
+ }
+
+ static <S extends Storable> OrderedProperty<S>[] makeOrderings(Class<S> type, String... props)
+ {
+ StorableInfo<S> info = StorableIntrospector.examine(type);
+ OrderedProperty<S>[] ops = new OrderedProperty[props.length];
+ for (int i=0; i<props.length; i++) {
+ ops[i] = OrderedProperty.parse(info, props[i]);
+ }
+ return ops;
+ }
+
+ public TestOrderingScore(String name) {
+ super(name);
+ }
+
+ public void testEmpty() throws Exception {
+ StorableIndex<StorableTestBasic> ix = makeIndex(StorableTestBasic.class, "id");
+
+ OrderingScore score = OrderingScore.evaluate(ix, null);
+
+ assertEquals(0, score.getHandledCount());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+ }
+
+ public void testOneProp() throws Exception {
+ StorableIndex<StorableTestBasic> ix;
+ OrderedProperty<StorableTestBasic>[] ops;
+ OrderingScore<StorableTestBasic> score;
+
+ /////////////
+ ix = makeIndex(StorableTestBasic.class, "id");
+
+ ops = makeOrderings(StorableTestBasic.class, "id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "+id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ /////////////
+ ix = makeIndex(StorableTestBasic.class, "+id");
+
+ ops = makeOrderings(StorableTestBasic.class, "id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "+id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ /////////////
+ ix = makeIndex(StorableTestBasic.class, "-id");
+
+ ops = makeOrderings(StorableTestBasic.class, "id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "+id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ /////////////
+ ix = makeIndex(StorableTestBasic.class, "intProp");
+
+ ops = makeOrderings(StorableTestBasic.class, "id");
+ score = OrderingScore.evaluate(ix, null, ops);
+
+ assertEquals(0, score.getHandledCount());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("+id", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+ }
+
+ public void testMultipleProps() throws Exception {
+ final StorableIndex<StorableTestBasic> ix;
+ OrderedProperty<StorableTestBasic>[] ops;
+ OrderingScore<StorableTestBasic> score;
+
+ ix = makeIndex(StorableTestBasic.class, "id", "intProp");
+
+ ops = makeOrderings(StorableTestBasic.class, "id");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-id");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "intProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(2, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals("+intProp", score.getHandledOrderings().get(1).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-id", "-intProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(2, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals("-intProp", score.getHandledOrderings().get(1).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-id", "+intProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("+intProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "+id", "-intProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("-intProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "intProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(0, score.getHandledCount());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("+intProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ // Gap is allowed if identity filtered.
+
+ Filter<StorableTestBasic> filter;
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+
+ ops = makeOrderings(StorableTestBasic.class, "intProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+intProp", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-intProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-intProp", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "intProp", "id");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+intProp", score.getHandledOrderings().get(0).toString());
+ // Since "id" is filtered, don't count as remainder.
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "-intProp", "id");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-intProp", score.getHandledOrderings().get(0).toString());
+ // Since "id" is filtered, don't count as remainder.
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "intProp", "doubleProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+intProp", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("+doubleProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "intProp", "-doubleProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+intProp", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("-doubleProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id > ? & doubleProp = ?");
+
+ ops = makeOrderings(StorableTestBasic.class, "intProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(0, score.getHandledCount());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("+intProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ ops = makeOrderings(StorableTestBasic.class, "doubleProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(0, score.getHandledCount());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "doubleProp = ? & id = ?");
+
+ ops = makeOrderings(StorableTestBasic.class, "doubleProp", "-intProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-intProp", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+ }
+
+ public void testMidGap() throws Exception {
+ final StorableIndex<StorableTestBasic> ix;
+ OrderedProperty<StorableTestBasic>[] ops;
+ OrderingScore score;
+ Filter<StorableTestBasic> filter;
+
+ ix = makeIndex(StorableTestBasic.class, "id", "intProp", "doubleProp", "-stringProp");
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "intProp", "doubleProp", "-stringProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(4, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals("+intProp", score.getHandledOrderings().get(1).toString());
+ assertEquals("+doubleProp", score.getHandledOrderings().get(2).toString());
+ assertEquals("-stringProp", score.getHandledOrderings().get(3).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ // Now ignore mid index properties, creating a gap.
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "-stringProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("-stringProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ // Gap can be bridged if property is filtered out. First test with
+ // incomplete bridges.
+
+ filter = Filter.filterFor(StorableTestBasic.class, "doubleProp = ? & intProp > ?");
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "-stringProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("-stringProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "doubleProp >= ? & intProp = ?");
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "-stringProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("-stringProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(false, score.shouldReverseOrder());
+
+ // Now a complete bridge.
+
+ filter = Filter.filterFor(StorableTestBasic.class, "doubleProp = ? & intProp = ?");
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "-stringProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(2, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals("-stringProp", score.getHandledOrderings().get(1).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ // Again in reverse.
+
+ ops = makeOrderings(StorableTestBasic.class, "-id", "stringProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(2, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals("+stringProp", score.getHandledOrderings().get(1).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(true, score.shouldReverseOrder());
+
+ // Failed double reverse.
+
+ ops = makeOrderings(StorableTestBasic.class, "-id", "-stringProp");
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("-id", score.getHandledOrderings().get(0).toString());
+ assertEquals(1, score.getRemainderCount());
+ assertEquals("-stringProp", score.getRemainderOrderings().get(0).toString());
+ assertEquals(true, score.shouldReverseOrder());
+ }
+
+ public void testComparator() throws Exception {
+ StorableIndex<StorableTestBasic> ix_1, ix_2;
+ OrderedProperty<StorableTestBasic>[] ops;
+ OrderingScore score_1, score_2;
+ Filter<StorableTestBasic> filter;
+ Comparator<OrderingScore<?>> comp = OrderingScore.fullComparator();
+
+ ix_1 = makeIndex(StorableTestBasic.class, "id", "intProp", "doubleProp", "-stringProp");
+ ix_2 = makeIndex(StorableTestBasic.class, "intProp", "doubleProp", "id");
+
+ ops = makeOrderings(StorableTestBasic.class, "-id", "-intProp");
+ score_1 = OrderingScore.evaluate(ix_1, null, ops);
+ score_2 = OrderingScore.evaluate(ix_2, null, ops);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+ score_1 = OrderingScore.evaluate(ix_1, filter, ops);
+ score_2 = OrderingScore.evaluate(ix_2, filter, ops);
+
+ // Index 2 has less properties, so it is better.
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ // Keep ix_2 slightly better by matching desired order.
+ ix_2 = makeIndex(StorableTestBasic.class, "-intProp", "doubleProp", "id", "stringProp");
+
+ score_1 = OrderingScore.evaluate(ix_1, filter, ops);
+ score_2 = OrderingScore.evaluate(ix_2, filter, ops);
+
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ // Make ix_1 slightly better by making it clustered.
+ ix_1 = ix_1.clustered(true);
+
+ score_1 = OrderingScore.evaluate(ix_1, filter, ops);
+ score_2 = OrderingScore.evaluate(ix_2, filter, ops);
+
+ assertEquals(-1, comp.compare(score_1, score_2));
+ assertEquals(1, comp.compare(score_2, score_1));
+
+ // Make ix_2 better when clustered.
+ ix_2 = ix_2.clustered(true);
+
+ score_1 = OrderingScore.evaluate(ix_1, filter, ops);
+ score_2 = OrderingScore.evaluate(ix_2, filter, ops);
+
+ assertEquals(1, comp.compare(score_1, score_2));
+ assertEquals(-1, comp.compare(score_2, score_1));
+
+ // Make ix_1 same by reversing order.
+ ix_1 = ix_1.reverse();
+
+ score_1 = OrderingScore.evaluate(ix_1, filter, ops);
+ score_2 = OrderingScore.evaluate(ix_2, filter, ops);
+
+ assertEquals(0, comp.compare(score_1, score_2));
+ assertEquals(0, comp.compare(score_2, score_1));
+ }
+
+ public void testIndexNotNeeded() throws Exception {
+ // Test an index which matches desired orderings, but ordering
+ // properties are filtered out. Thus the index is not needed.
+
+ final StorableIndex<StorableTestBasic> ix;
+ OrderedProperty<StorableTestBasic>[] ops;
+ OrderingScore score;
+ Filter<StorableTestBasic> filter;
+
+ ix = makeIndex(StorableTestBasic.class, "id", "intProp", "doubleProp");
+
+ ops = makeOrderings(StorableTestBasic.class, "id", "intProp", "doubleProp");
+ score = OrderingScore.evaluate(ix, null, ops);
+ assertEquals(3, score.getHandledCount());
+ assertEquals("+id", score.getHandledOrderings().get(0).toString());
+ assertEquals("+intProp", score.getHandledOrderings().get(1).toString());
+ assertEquals("+doubleProp", score.getHandledOrderings().get(2).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ?");
+
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(1, score.getHandledCount());
+ assertEquals("+doubleProp", score.getHandledOrderings().get(0).toString());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ? & doubleProp =?");
+
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(0, score.getHandledCount());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+ }
+
+ public void testUniqueIndexNotNeeded() throws Exception {
+ // Test a unique index which has been fully specified. Ordering is not
+ // needed at all.
+ final StorableIndex<StorableTestBasic> ix;
+ OrderedProperty<StorableTestBasic>[] ops;
+ OrderingScore score;
+ Filter<StorableTestBasic> filter;
+
+ ix = makeIndex(StorableTestBasic.class, "id", "intProp", "doubleProp").unique(true);
+ ops = makeOrderings(StorableTestBasic.class, "stringProp", "doubleProp");
+ filter = Filter.filterFor(StorableTestBasic.class, "id = ? & intProp = ? & doubleProp =?");
+
+ score = OrderingScore.evaluate(ix, filter, ops);
+ assertEquals(0, score.getHandledCount());
+ assertEquals(0, score.getRemainderCount());
+ assertEquals(false, score.shouldReverseOrder());
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestPropertyFilterList.java b/src/test/java/com/amazon/carbonado/qe/TestPropertyFilterList.java new file mode 100644 index 0000000..b0af52f --- /dev/null +++ b/src/test/java/com/amazon/carbonado/qe/TestPropertyFilterList.java @@ -0,0 +1,108 @@ +/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * 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
+ *
+ * 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 com.amazon.carbonado.qe;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.filter.Filter;
+import com.amazon.carbonado.filter.PropertyFilter;
+
+import com.amazon.carbonado.stored.StorableTestBasic;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestPropertyFilterList extends TestCase {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestPropertyFilterList.class);
+ }
+
+ public TestPropertyFilterList(String name) {
+ super(name);
+ }
+
+ public void testNull() throws Exception {
+ assertEquals(0, PropertyFilterList.get(null).size());
+ }
+
+ public void testOpen() throws Exception {
+ Filter<StorableTestBasic> filter = Filter.getOpenFilter(StorableTestBasic.class);
+ assertEquals(0, PropertyFilterList.get(filter).size());
+ }
+
+ public void testClosed() throws Exception {
+ Filter<StorableTestBasic> filter = Filter.getClosedFilter(StorableTestBasic.class);
+ assertEquals(0, PropertyFilterList.get(filter).size());
+ }
+
+ public void testSingleton() throws Exception {
+ Filter<StorableTestBasic> filter = Filter.filterFor(StorableTestBasic.class, "id = ?");
+
+ List<PropertyFilter<StorableTestBasic>> list = PropertyFilterList.get(filter);
+
+ assertEquals(1, list.size());
+ assertEquals(filter, list.get(0));
+
+ List<PropertyFilter<StorableTestBasic>> list2 = PropertyFilterList.get(filter);
+
+ assertTrue(list == list2);
+ }
+
+ public void testMultiple() throws Exception {
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "id = ? & intProp > ?");
+
+ List<PropertyFilter<StorableTestBasic>> list = PropertyFilterList.get(filter);
+
+ assertEquals(2, list.size());
+
+ Filter<StorableTestBasic> subFilter =
+ Filter.filterFor(StorableTestBasic.class, "id = ?");
+
+ assertEquals(subFilter, list.get(0));
+
+ subFilter = Filter.filterFor(StorableTestBasic.class, "intProp > ?");
+
+ assertEquals(subFilter, list.get(1));
+
+ List<PropertyFilter<StorableTestBasic>> list2 = PropertyFilterList.get(filter);
+
+ assertTrue(list == list2);
+ }
+
+ public void testIllegal() throws Exception {
+ Filter<StorableTestBasic> filter =
+ Filter.filterFor(StorableTestBasic.class, "id = ? | intProp > ?");
+
+ try {
+ List<PropertyFilter<StorableTestBasic>> list = PropertyFilterList.get(filter);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestQueryExecutor.java new file mode 100644 index 0000000..4727a56 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/qe/TestQueryExecutor.java @@ -0,0 +1,195 @@ +/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * 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
+ *
+ * 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 com.amazon.carbonado.qe;
+
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import com.amazon.carbonado.Cursor;
+import com.amazon.carbonado.FetchException;
+
+import com.amazon.carbonado.info.Direction;
+import com.amazon.carbonado.info.OrderedProperty;
+import com.amazon.carbonado.info.StorableInfo;
+import com.amazon.carbonado.info.StorableIntrospector;
+import com.amazon.carbonado.info.StorableProperty;
+
+import com.amazon.carbonado.stored.Dummy;
+import com.amazon.carbonado.stored.Address;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public abstract class TestQueryExecutor extends TestCase {
+
+ protected QueryExecutor<Address> createExecutor(int... ids) {
+ return new IterableQueryExecutor<Address>(Address.class, createCollection(ids));
+ }
+
+ protected Collection<Address> createCollection(int... ids) {
+ Collection<Address> elements = new ArrayList<Address>(ids.length);
+ for (int i=0; i<ids.length; i++) {
+ elements.add(new DummyAddress(ids[i]));
+ }
+ return elements;
+ }
+
+ protected void compareElements(Cursor<Address> elements, int... expectedIDs)
+ throws FetchException
+ {
+ for (int id : expectedIDs) {
+ if (elements.hasNext()) {
+ Address e = elements.next();
+ if (e.getAddressID() != id) {
+ fail("Element mismatch: expected=" + id + ", actual=" + e.getAddressID());
+ elements.close();
+ return;
+ }
+ } else {
+ fail("Too few elements in cursor");
+ return;
+ }
+ }
+
+ if (elements.hasNext()) {
+ Address e = elements.next();
+ fail("Too many elements in cursor: " + e.getAddressID());
+ elements.close();
+ }
+ }
+
+ protected List<OrderedProperty<Address>> createOrdering(String... properties) {
+ StorableInfo<Address> info = StorableIntrospector.examine(Address.class);
+ Map<String, ? extends StorableProperty<Address>> props = info.getAllProperties();
+
+ List<OrderedProperty<Address>> ordered = new ArrayList<OrderedProperty<Address>>();
+
+ for (String prop : properties) {
+ ordered.add(OrderedProperty.get(props.get(prop), Direction.ASCENDING));
+ }
+
+ return ordered;
+ }
+
+ static void printPlan(QueryExecutor executor) {
+ try {
+ executor.printPlan(System.out, 0, null);
+ } catch (IOException e) {
+ }
+ }
+
+ private static class DummyAddress extends Dummy implements Address {
+ private long mID;
+ private String mLine1;
+ private String mLine2;
+ private String mCity;
+ private String mState;
+ private String mZip;
+ private String mCountry;
+ private String mData;
+
+ DummyAddress(long id) {
+ mID = id;
+ mLine1 = "line1_" + id;
+ mLine2 = "line2_" + id;
+ mCity = "city_" + id;
+ mState = "state_" + id;
+ mZip = "zip_" + id;
+ mCountry = "country_" + id;
+ mData = "data_" + id;
+ }
+
+ public long getAddressID() {
+ return mID;
+ }
+
+ public void setAddressID(long id) {
+ mID = id;
+ }
+
+ public String getAddressLine1() {
+ return mLine1;
+ }
+
+ public void setAddressLine1(String value) {
+ mLine1 = value;
+ }
+
+ public String getAddressLine2() {
+ return mLine2;
+ }
+
+ public void setAddressLine2(String value) {
+ mLine2 = value;
+ }
+
+ public String getAddressCity() {
+ return mCity;
+ }
+
+ public void setAddressCity(String value) {
+ mCity = value;
+ }
+
+ public String getAddressState() {
+ return mState;
+ }
+
+ public void setAddressState(String value) {
+ mState = value;
+ }
+
+ public String getAddressZip() {
+ return mZip;
+ }
+
+ public void setAddressZip(String value) {
+ mZip = value;
+ }
+
+ public String getAddressCountry() {
+ return mCountry;
+ }
+
+ public void setAddressCountry(String value) {
+ mCountry = value;
+ }
+
+ public String getCustomData() {
+ return mData;
+ }
+
+ public void setCustomData(String str) {
+ mData = str;
+ }
+
+ public String toString() {
+ return "address " + mID;
+ }
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestSortedQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestSortedQueryExecutor.java new file mode 100644 index 0000000..0972e94 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/qe/TestSortedQueryExecutor.java @@ -0,0 +1,84 @@ +/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * 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
+ *
+ * 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 com.amazon.carbonado.qe;
+
+import java.util.List;
+
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.filter.Filter;
+import com.amazon.carbonado.filter.FilterValues;
+
+import com.amazon.carbonado.info.OrderedProperty;
+
+import com.amazon.carbonado.stored.Address;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestSortedQueryExecutor extends TestQueryExecutor {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestSortedQueryExecutor.class);
+ }
+
+ public void testBasicSorting() throws Exception {
+ QueryExecutor<Address> unsorted = createExecutor(4, 2, 3, 1);
+ Filter<Address> filter = Filter.getOpenFilter(Address.class);
+ FilterValues<Address> values = filter.initialFilterValues();
+ List<OrderedProperty<Address>> ordered = createOrdering("addressCountry");
+
+ QueryExecutor<Address> executor =
+ new ArraySortedQueryExecutor<Address>(unsorted, null, ordered);
+
+ assertEquals(filter, executor.getFilter());
+
+ assertEquals(4, executor.count(values));
+
+ assertEquals(ordered, executor.getOrdering());
+
+ compareElements(executor.openCursor(values), 1, 2, 3, 4);
+ }
+
+ public void testBasicFinisherSorting() throws Exception {
+ QueryExecutor<Address> unsorted = createExecutor(1, 2, 3, 4);
+ Filter<Address> filter = Filter.getOpenFilter(Address.class);
+ FilterValues<Address> values = filter.initialFilterValues();
+ List<OrderedProperty<Address>> handled = createOrdering("addressCountry");
+ List<OrderedProperty<Address>> finisher = createOrdering("addressState");
+
+ QueryExecutor<Address> executor =
+ new ArraySortedQueryExecutor<Address>(unsorted, handled, finisher);
+
+ assertEquals(filter, executor.getFilter());
+
+ assertEquals(4, executor.count(values));
+
+ assertEquals(2, executor.getOrdering().size());
+ assertEquals(handled.get(0), executor.getOrdering().get(0));
+ assertEquals(finisher.get(0), executor.getOrdering().get(1));
+
+ compareElements(executor.openCursor(values), 1, 2, 3, 4);
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/qe/TestUnionQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestUnionQueryExecutor.java new file mode 100644 index 0000000..639176c --- /dev/null +++ b/src/test/java/com/amazon/carbonado/qe/TestUnionQueryExecutor.java @@ -0,0 +1,75 @@ +/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * 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
+ *
+ * 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 com.amazon.carbonado.qe;
+
+import java.util.List;
+
+import junit.framework.TestSuite;
+
+import com.amazon.carbonado.filter.Filter;
+import com.amazon.carbonado.filter.FilterValues;
+
+import com.amazon.carbonado.info.OrderedProperty;
+
+import com.amazon.carbonado.stored.Address;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class TestUnionQueryExecutor extends TestQueryExecutor {
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static TestSuite suite() {
+ return new TestSuite(TestUnionQueryExecutor.class);
+ }
+
+ public void testBasicUnion() throws Exception {
+ QueryExecutor<Address> primary = new ArraySortedQueryExecutor<Address>
+ (createExecutor(1, 2, 3, 4, 5, 6, 7, 8), null, createOrdering("addressID"));
+
+ Filter<Address> filter_1 = Filter.filterFor(Address.class, "addressCountry > ?");
+ FilterValues<Address> values_1 = filter_1.initialFilterValues();
+ QueryExecutor<Address> executor_1 = new FilteredQueryExecutor<Address>(primary, filter_1);
+
+ Filter<Address> filter_2 = Filter.filterFor(Address.class, "addressState <= ?");
+ FilterValues<Address> values_2 = filter_2.initialFilterValues();
+ QueryExecutor<Address> executor_2 = new FilteredQueryExecutor<Address>(primary, filter_2);
+
+ QueryExecutor<Address> union = new UnionQueryExecutor<Address>(executor_1, executor_2);
+
+ Filter<Address> filter = Filter
+ .filterFor(Address.class, "addressCountry > ? | addressState <= ?");
+ FilterValues<Address> values = filter.initialFilterValues();
+ filter = values.getFilter();
+
+ assertEquals(filter, union.getFilter());
+
+ values = values.with("country_6").with("state_3");
+
+ assertEquals(5, union.count(values));
+
+ assertEquals(primary.getOrdering(), union.getOrdering());
+
+ compareElements(union.openCursor(values), 1, 2, 3, 7, 8);
+ }
+}
|