From 39fce59a840b723eb013bc79285687986592b2da Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Sun, 3 Sep 2006 06:14:41 +0000 Subject: More work on query engine. --- .../carbonado/qe/TestFilteredQueryExecutor.java | 2 +- .../carbonado/qe/TestIndexedQueryAnalyzer.java | 259 +++++++++++++++++++++ .../carbonado/qe/TestIndexedQueryExecutor.java | 76 +++--- .../carbonado/qe/TestJoinedQueryExecutor.java | 203 ++++++++++++++++ .../carbonado/qe/TestSortedQueryExecutor.java | 4 +- .../carbonado/qe/TestUnionQueryExecutor.java | 2 +- 6 files changed, 504 insertions(+), 42 deletions(-) create mode 100644 src/test/java/com/amazon/carbonado/qe/TestIndexedQueryAnalyzer.java create mode 100644 src/test/java/com/amazon/carbonado/qe/TestJoinedQueryExecutor.java (limited to 'src/test/java/com/amazon/carbonado/qe') diff --git a/src/test/java/com/amazon/carbonado/qe/TestFilteredQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestFilteredQueryExecutor.java index 76ea081..1210bd4 100644 --- a/src/test/java/com/amazon/carbonado/qe/TestFilteredQueryExecutor.java +++ b/src/test/java/com/amazon/carbonado/qe/TestFilteredQueryExecutor.java @@ -52,6 +52,6 @@ public class TestFilteredQueryExecutor extends TestQueryExecutor { assertEquals(0, executor.getOrdering().size()); - compareElements(executor.openCursor(values.with("country_2")), 3, 4); + compareElements(executor.fetch(values.with("country_2")), 3, 4); } } diff --git a/src/test/java/com/amazon/carbonado/qe/TestIndexedQueryAnalyzer.java b/src/test/java/com/amazon/carbonado/qe/TestIndexedQueryAnalyzer.java new file mode 100644 index 0000000..85c78cb --- /dev/null +++ b/src/test/java/com/amazon/carbonado/qe/TestIndexedQueryAnalyzer.java @@ -0,0 +1,259 @@ +/* + * 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.Repository; +import com.amazon.carbonado.Storable; + +import com.amazon.carbonado.info.StorableIndex; + +import com.amazon.carbonado.filter.Filter; +import com.amazon.carbonado.filter.FilterValues; + +import com.amazon.carbonado.repo.toy.ToyRepository; + +import com.amazon.carbonado.stored.Address; +import com.amazon.carbonado.stored.Order; +import com.amazon.carbonado.stored.Shipment; +import com.amazon.carbonado.stored.Shipper; + +import static com.amazon.carbonado.qe.TestIndexedQueryExecutor.Mock; + +/** + * + * + * @author Brian S O'Neill + */ +public class TestIndexedQueryAnalyzer extends TestCase { + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public static TestSuite suite() { + return new TestSuite(TestIndexedQueryAnalyzer.class); + } + + static StorableIndex makeIndex(Class type, String... props) { + return TestOrderingScore.makeIndex(type, props); + } + + public TestIndexedQueryAnalyzer(String name) { + super(name); + } + + // Note: these tests don't perform exhaustive tests to find the best index, as those tests + // are performed by TestFilteringScore and TestOrderingScore. + + public void testFullScan() throws Exception { + IndexedQueryAnalyzer iqa = new IndexedQueryAnalyzer(Address.class, IxProvider.INSTANCE); + Filter
filter = Filter.filterFor(Address.class, "addressZip = ?"); + filter = filter.bind(); + IndexedQueryAnalyzer.Result result = iqa.analyze(filter); + + assertFalse(result.handlesAnything()); + assertEquals(filter, result.getCompositeScore().getFilteringScore().getRemainderFilter()); + assertEquals(makeIndex(Address.class, "addressID"), result.getLocalIndex()); + assertEquals(null, result.getForeignIndex()); + assertEquals(null, result.getForeignProperty()); + } + + public void testIndexScan() throws Exception { + IndexedQueryAnalyzer iqa = new IndexedQueryAnalyzer(Address.class, IxProvider.INSTANCE); + Filter
filter = Filter.filterFor(Address.class, "addressID = ?"); + filter = filter.bind(); + IndexedQueryAnalyzer.Result result = iqa.analyze(filter); + + assertTrue(result.handlesAnything()); + assertEquals(filter, result.getCompositeScore().getFilteringScore().getIdentityFilter()); + assertEquals(makeIndex(Address.class, "addressID"), result.getLocalIndex()); + assertEquals(null, result.getForeignIndex()); + assertEquals(null, result.getForeignProperty()); + } + + public void testBasic() throws Exception { + IndexedQueryAnalyzer iqa = new IndexedQueryAnalyzer(Shipment.class, IxProvider.INSTANCE); + Filter filter = Filter.filterFor(Shipment.class, "shipmentID = ?"); + filter = filter.bind(); + IndexedQueryAnalyzer.Result result = iqa.analyze(filter); + + assertTrue(result.handlesAnything()); + assertEquals(filter, result.getCompositeScore().getFilteringScore().getIdentityFilter()); + assertEquals(makeIndex(Shipment.class, "shipmentID"), result.getLocalIndex()); + assertEquals(null, result.getForeignIndex()); + assertEquals(null, result.getForeignProperty()); + + filter = Filter.filterFor(Shipment.class, "orderID = ?"); + filter = filter.bind(); + result = iqa.analyze(filter); + + assertTrue(result.handlesAnything()); + assertEquals(filter, result.getCompositeScore().getFilteringScore().getIdentityFilter()); + assertEquals(makeIndex(Shipment.class, "orderID"), result.getLocalIndex()); + assertEquals(null, result.getForeignIndex()); + assertEquals(null, result.getForeignProperty()); + } + + public void testSimpleJoin() throws Exception { + IndexedQueryAnalyzer iqa = new IndexedQueryAnalyzer(Shipment.class, IxProvider.INSTANCE); + Filter filter = Filter.filterFor(Shipment.class, "order.orderTotal >= ?"); + filter = filter.bind(); + IndexedQueryAnalyzer.Result result = iqa.analyze(filter); + + assertTrue(result.handlesAnything()); + assertTrue(result.getCompositeScore().getFilteringScore().hasRangeStart()); + assertEquals(null, result.getLocalIndex()); + assertEquals(makeIndex(Order.class, "orderTotal"), result.getForeignIndex()); + assertEquals("order", result.getForeignProperty().toString()); + } + + public void testJoinPriority() throws Exception { + // Selects foreign index because filter score is better. + + IndexedQueryAnalyzer iqa = new IndexedQueryAnalyzer(Shipment.class, IxProvider.INSTANCE); + Filter filter = Filter.filterFor + (Shipment.class, "shipmentNotes = ? & order.orderTotal >= ?"); + filter = filter.bind(); + IndexedQueryAnalyzer.Result result = iqa.analyze(filter); + + assertTrue(result.handlesAnything()); + assertTrue(result.getCompositeScore().getFilteringScore().hasRangeStart()); + assertEquals(Filter.filterFor(Shipment.class, "shipmentNotes = ?").bind(), + result.getCompositeScore().getFilteringScore().getRemainderFilter()); + assertEquals(null, result.getLocalIndex()); + assertEquals(makeIndex(Order.class, "orderTotal"), result.getForeignIndex()); + assertEquals("order", result.getForeignProperty().toString()); + } + + public void testJoinNonPriority() throws Exception { + // Selects local index because filter score is just as good and local + // indexes are preferred. + + IndexedQueryAnalyzer iqa = new IndexedQueryAnalyzer(Shipment.class, IxProvider.INSTANCE); + Filter filter = Filter.filterFor + (Shipment.class, "orderID >= ? & order.orderTotal >= ?"); + filter = filter.bind(); + IndexedQueryAnalyzer.Result result = iqa.analyze(filter); + + assertTrue(result.handlesAnything()); + assertTrue(result.getCompositeScore().getFilteringScore().hasRangeStart()); + assertEquals(Filter.filterFor(Shipment.class, "order.orderTotal >= ?").bind(), + result.getCompositeScore().getFilteringScore().getRemainderFilter()); + assertEquals(makeIndex(Shipment.class, "orderID"), result.getLocalIndex()); + assertEquals(null, result.getForeignIndex()); + assertEquals(null, result.getForeignProperty()); + } + + public void testChainedJoin() throws Exception { + IndexedQueryAnalyzer iqa = new IndexedQueryAnalyzer(Shipment.class, IxProvider.INSTANCE); + Filter filter = Filter.filterFor + (Shipment.class, "order.address.addressState = ?"); + filter = filter.bind(); + IndexedQueryAnalyzer.Result result = iqa.analyze(filter); + + assertTrue(result.handlesAnything()); + assertEquals(filter, result.getCompositeScore().getFilteringScore().getIdentityFilter()); + assertEquals(null, result.getLocalIndex()); + assertEquals(makeIndex(Address.class, "addressState"), result.getForeignIndex()); + assertEquals("order.address", result.getForeignProperty().toString()); + } + + public void testChainedJoinExecutor() throws Exception { + Repository repo = new ToyRepository(); + + IndexedQueryAnalyzer iqa = + new IndexedQueryAnalyzer(Shipment.class, IxProvider.INSTANCE); + Filter filter = Filter.filterFor + (Shipment.class, "order.address.addressState = ? & order.address.addressZip = ?"); + FilterValues values = filter.initialFilterValues(); + filter = values.getFilter(); + IndexedQueryAnalyzer.Result result = iqa.analyze(filter); + + assertTrue(result.handlesAnything()); + assertEquals(Filter.filterFor(Shipment.class, "order.address.addressState = ?").bind(), + result.getCompositeScore().getFilteringScore().getIdentityFilter()); + assertEquals(Filter.filterFor(Shipment.class, "order.address.addressZip = ?").bind(), + result.getCompositeScore().getFilteringScore().getRemainderFilter()); + assertEquals(null, result.getLocalIndex()); + assertEquals(makeIndex(Address.class, "addressState"), result.getForeignIndex()); + assertEquals("order.address", result.getForeignProperty().toString()); + + Mock ixExec = new Mock(result.getForeignIndex(), result.getCompositeScore()); + + QueryExecutor joinExec = new JoinedQueryExecutor + (repo, result.getForeignProperty(), ixExec); + + QueryExecutor filteredExec = new FilteredQueryExecutor + (joinExec, result.getCompositeScore().getFilteringScore().getRemainderFilter()); + + //System.out.println(); + //filteredExec.printPlan(System.out, 0, null); + + joinExec.fetch(values.with("WA")); + + assertEquals(1, ixExec.mIdentityValues.length); + assertEquals("WA", ixExec.mIdentityValues[0]); + assertEquals(BoundaryType.OPEN, ixExec.mRangeStartBoundary); + assertEquals(null, ixExec.mRangeStartValue); + assertEquals(BoundaryType.OPEN, ixExec.mRangeEndBoundary); + assertEquals(null, ixExec.mRangeEndValue); + assertFalse(ixExec.mReverseRange); + assertFalse(ixExec.mReverseOrder); + } + + static class IxProvider implements IndexProvider { + static final IxProvider INSTANCE = new IxProvider(); + + public Collection> indexesFor(Class type) { + StorableIndex[] indexes; + + if (Address.class.isAssignableFrom(type)) { + indexes = new StorableIndex[] { + makeIndex(type, "addressID"), + makeIndex(type, "addressState") + }; + } else if (Order.class.isAssignableFrom(type)) { + indexes = new StorableIndex[] { + makeIndex(type, "orderID"), + makeIndex(type, "orderTotal"), + makeIndex(type, "addressID") + }; + } else if (Shipment.class.isAssignableFrom(type)) { + indexes = new StorableIndex[] { + makeIndex(type, "shipmentID"), + makeIndex(type, "orderID"), + }; + } else if (Shipper.class.isAssignableFrom(type)) { + indexes = new StorableIndex[] { + makeIndex(type, "shipperID") + }; + } else { + indexes = new StorableIndex[0]; + } + + return Arrays.asList(indexes); + } + } +} diff --git a/src/test/java/com/amazon/carbonado/qe/TestIndexedQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestIndexedQueryExecutor.java index a039e63..3f865e6 100644 --- a/src/test/java/com/amazon/carbonado/qe/TestIndexedQueryExecutor.java +++ b/src/test/java/com/amazon/carbonado/qe/TestIndexedQueryExecutor.java @@ -78,7 +78,7 @@ public class TestIndexedQueryExecutor extends TestCase { Mock executor = new Mock(index, score); - executor.openCursor(values.with(100)); + executor.fetch(values.with(100)); assertEquals(1, executor.mIdentityValues.length); assertEquals(100, executor.mIdentityValues[0]); @@ -98,7 +98,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(100).with(5)); + executor.fetch(values.with(100).with(5)); assertEquals(2, executor.mIdentityValues.length); assertEquals(100, executor.mIdentityValues[0]); @@ -119,7 +119,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(200)); + executor.fetch(values.with(200)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary); @@ -142,7 +142,7 @@ public class TestIndexedQueryExecutor extends TestCase { Mock executor = new Mock(index, score); - executor.openCursor(values.with(100)); + executor.fetch(values.with(100)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary); @@ -161,7 +161,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(100)); + executor.fetch(values.with(100)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.INCLUSIVE, executor.mRangeStartBoundary); @@ -180,7 +180,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(10).with(30)); + executor.fetch(values.with(10).with(30)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary); @@ -199,7 +199,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(10).with(30)); + executor.fetch(values.with(10).with(30)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary); @@ -218,7 +218,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(10).with(10)); + executor.fetch(values.with(10).with(10)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary); @@ -237,7 +237,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(30).with(10)); + executor.fetch(values.with(30).with(10)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.INCLUSIVE, executor.mRangeStartBoundary); @@ -257,7 +257,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(100).with(30)); + executor.fetch(values.with(100).with(30)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary); @@ -278,7 +278,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(100)); + executor.fetch(values.with(100)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary); @@ -298,7 +298,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(100)); + executor.fetch(values.with(100)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary); @@ -318,7 +318,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(100)); + executor.fetch(values.with(100)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary); @@ -341,7 +341,7 @@ public class TestIndexedQueryExecutor extends TestCase { Mock executor = new Mock(index, score); - executor.openCursor(values.with(100)); + executor.fetch(values.with(100)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary); @@ -360,7 +360,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(100)); + executor.fetch(values.with(100)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary); @@ -379,7 +379,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(10).with(30)); + executor.fetch(values.with(10).with(30)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary); @@ -398,7 +398,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(10).with(30)); + executor.fetch(values.with(10).with(30)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary); @@ -417,7 +417,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(10).with(10)); + executor.fetch(values.with(10).with(10)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary); @@ -436,7 +436,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(30).with(10)); + executor.fetch(values.with(30).with(10)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary); @@ -456,7 +456,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(100).with(30)); + executor.fetch(values.with(100).with(30)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary); @@ -477,7 +477,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(100)); + executor.fetch(values.with(100)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary); @@ -497,7 +497,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(100)); + executor.fetch(values.with(100)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary); @@ -517,7 +517,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(100)); + executor.fetch(values.with(100)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.OPEN, executor.mRangeStartBoundary); @@ -543,7 +543,7 @@ public class TestIndexedQueryExecutor extends TestCase { Mock executor = new Mock(index, score); - executor.openCursor(values.with(100).with(200)); + executor.fetch(values.with(100).with(200)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary); @@ -562,7 +562,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(100).with(10)); + executor.fetch(values.with(100).with(10)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.INCLUSIVE, executor.mRangeStartBoundary); @@ -582,7 +582,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(10).with(100).with(30)); + executor.fetch(values.with(10).with(100).with(30)); assertEquals(null, executor.mIdentityValues); assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary); @@ -614,7 +614,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(3).with(56.5).with(200.2)); + executor.fetch(values.with(3).with(56.5).with(200.2)); assertEquals(3, executor.mIdentityValues[0]); assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary); @@ -630,7 +630,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(3).with(56.5).with(200.2)); + executor.fetch(values.with(3).with(56.5).with(200.2)); assertEquals(3, executor.mIdentityValues[0]); assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary); @@ -646,7 +646,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(3).with(56.5).with(200.2)); + executor.fetch(values.with(3).with(56.5).with(200.2)); assertEquals(3, executor.mIdentityValues[0]); assertEquals(BoundaryType.EXCLUSIVE, executor.mRangeStartBoundary); @@ -667,7 +667,7 @@ public class TestIndexedQueryExecutor extends TestCase { executor = new Mock(index, score); - executor.openCursor(values.with(3).with(56.5).with("foo")); + executor.fetch(values.with(3).with(56.5).with("foo")); assertEquals(3, executor.mIdentityValues[0]); assertEquals(56.5, executor.mIdentityValues[1]); @@ -701,14 +701,14 @@ public class TestIndexedQueryExecutor extends TestCase { super(index, score); } - protected Cursor openCursor(StorableIndex index, - Object[] identityValues, - BoundaryType rangeStartBoundary, - Object rangeStartValue, - BoundaryType rangeEndBoundary, - Object rangeEndValue, - boolean reverseRange, - boolean reverseOrder) + protected Cursor fetch(StorableIndex index, + Object[] identityValues, + BoundaryType rangeStartBoundary, + Object rangeStartValue, + BoundaryType rangeEndBoundary, + Object rangeEndValue, + boolean reverseRange, + boolean reverseOrder) { mIdentityValues = identityValues; mRangeStartBoundary = rangeStartBoundary; diff --git a/src/test/java/com/amazon/carbonado/qe/TestJoinedQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestJoinedQueryExecutor.java new file mode 100644 index 0000000..8a82758 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/qe/TestJoinedQueryExecutor.java @@ -0,0 +1,203 @@ +/* + * 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.ArrayList; +import java.util.List; + +import junit.framework.TestSuite; + +import com.amazon.carbonado.Cursor; +import com.amazon.carbonado.FetchException; +import com.amazon.carbonado.Query; +import com.amazon.carbonado.Repository; +import com.amazon.carbonado.Storable; +import com.amazon.carbonado.Storage; + +import com.amazon.carbonado.filter.Filter; +import com.amazon.carbonado.filter.FilterValues; + +import com.amazon.carbonado.info.OrderedProperty; +import com.amazon.carbonado.info.StorableIntrospector; +import com.amazon.carbonado.info.StorableProperty; + +import com.amazon.carbonado.repo.toy.ToyRepository; + +import com.amazon.carbonado.stored.UserAddress; +import com.amazon.carbonado.stored.UserInfo; + +/** + * + * + * @author Brian S O'Neill + */ +public class TestJoinedQueryExecutor extends TestQueryExecutor { + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public static TestSuite suite() { + return new TestSuite(TestJoinedQueryExecutor.class); + } + + private Repository mRepository; + + protected void setUp() throws Exception { + super.setUp(); + mRepository = new ToyRepository(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testJoin() throws Exception { + QueryExecutor addressExecutor = addressExecutor(); + + QueryExecutor userExecutor = new JoinedQueryExecutor + (mRepository, UserInfo.class, "address", addressExecutor); + + assertEquals("address.state = ?", userExecutor.getFilter().toString()); + assertEquals("address.country", userExecutor.getOrdering().get(0).toString()); + + // Create some addresses + Storage addressStorage = mRepository.storageFor(UserAddress.class); + UserAddress addr = addressStorage.prepare(); + addr.setAddressID(1); + addr.setLine1("4567, 123 Street"); + addr.setCity("Springfield"); + addr.setState("IL"); + addr.setCountry("USA"); + addr.insert(); + + addr = addressStorage.prepare(); + addr.setAddressID(2); + addr.setLine1("1111 Apt 1, 1st Ave"); + addr.setCity("Somewhere"); + addr.setState("AA"); + addr.setCountry("USA"); + addr.setNeighborAddressID(1); + addr.insert(); + + addr = addressStorage.prepare(); + addr.setAddressID(3); + addr.setLine1("9999"); + addr.setCity("Chicago"); + addr.setState("IL"); + addr.setCountry("USA"); + addr.insert(); + + // Create some users + Storage userStorage = mRepository.storageFor(UserInfo.class); + UserInfo user = userStorage.prepare(); + user.setUserID(1); + user.setStateID(1); + user.setFirstName("Bob"); + user.setLastName("Loblaw"); + user.setAddressID(1); + user.insert(); + + user = userStorage.prepare(); + user.setUserID(2); + user.setStateID(1); + user.setFirstName("Deb"); + user.setLastName("Loblaw"); + user.setAddressID(1); + user.insert(); + + user = userStorage.prepare(); + user.setUserID(3); + user.setStateID(1); + user.setFirstName("No"); + user.setLastName("Body"); + user.setAddressID(2); + user.insert(); + + // Now do a basic join, finding everyone in IL. + + FilterValues values = Filter + .filterFor(UserInfo.class, "address.state = ?").initialFilterValues().with("IL"); + + Cursor cursor = userExecutor.fetch(values); + assertTrue(cursor.hasNext()); + assertEquals(1, cursor.next().getUserID()); + assertEquals(2, cursor.next().getUserID()); + assertFalse(cursor.hasNext()); + cursor.close(); + + assertEquals(2L, userExecutor.count(values)); + + // Now do a multi join, finding everyone with an explicit neighbor in IL. + + userExecutor = new JoinedQueryExecutor + (mRepository, UserInfo.class, "address.neighbor", addressExecutor); + + assertEquals("address.neighbor.state = ?", userExecutor.getFilter().toString()); + assertEquals("address.neighbor.country", userExecutor.getOrdering().get(0).toString()); + + values = Filter + .filterFor(UserInfo.class, "address.neighbor.state = ?") + .initialFilterValues().with("IL"); + + cursor = userExecutor.fetch(values); + assertTrue(cursor.hasNext()); + assertEquals(3, cursor.next().getUserID()); + assertFalse(cursor.hasNext()); + cursor.close(); + + assertEquals(1L, userExecutor.count(values)); + + } + + protected QueryExecutor addressExecutor() throws Exception { + Storage addressStorage = mRepository.storageFor(UserAddress.class); + + QueryExecutor addressExecutor = + new ScanQueryExecutor(addressStorage.query()); + + addressExecutor = new FilteredQueryExecutor + (addressExecutor, Filter.filterFor(UserAddress.class, "state = ?")); + + StorableProperty prop = StorableIntrospector + .examine(UserAddress.class).getAllProperties().get("country"); + + List> orderings = + new ArrayList>(); + + orderings.add(OrderedProperty.get(prop, null)); + + addressExecutor = new ArraySortedQueryExecutor + (addressExecutor, null, orderings); + + return addressExecutor; + } + + static class ScanQueryExecutor extends FullScanQueryExecutor { + private final Query mQuery; + + ScanQueryExecutor(Query query) { + super(query.getStorableType()); + mQuery = query; + } + + protected Cursor fetch() throws FetchException { + return mQuery.fetch(); + } + } +} diff --git a/src/test/java/com/amazon/carbonado/qe/TestSortedQueryExecutor.java b/src/test/java/com/amazon/carbonado/qe/TestSortedQueryExecutor.java index 0972e94..9e9906f 100644 --- a/src/test/java/com/amazon/carbonado/qe/TestSortedQueryExecutor.java +++ b/src/test/java/com/amazon/carbonado/qe/TestSortedQueryExecutor.java @@ -58,7 +58,7 @@ public class TestSortedQueryExecutor extends TestQueryExecutor { assertEquals(ordered, executor.getOrdering()); - compareElements(executor.openCursor(values), 1, 2, 3, 4); + compareElements(executor.fetch(values), 1, 2, 3, 4); } public void testBasicFinisherSorting() throws Exception { @@ -79,6 +79,6 @@ public class TestSortedQueryExecutor extends TestQueryExecutor { assertEquals(handled.get(0), executor.getOrdering().get(0)); assertEquals(finisher.get(0), executor.getOrdering().get(1)); - compareElements(executor.openCursor(values), 1, 2, 3, 4); + compareElements(executor.fetch(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 index 639176c..07716bb 100644 --- a/src/test/java/com/amazon/carbonado/qe/TestUnionQueryExecutor.java +++ b/src/test/java/com/amazon/carbonado/qe/TestUnionQueryExecutor.java @@ -70,6 +70,6 @@ public class TestUnionQueryExecutor extends TestQueryExecutor { assertEquals(primary.getOrdering(), union.getOrdering()); - compareElements(union.openCursor(values), 1, 2, 3, 7, 8); + compareElements(union.fetch(values), 1, 2, 3, 7, 8); } } -- cgit v1.2.3