diff options
Diffstat (limited to 'src/test/java')
18 files changed, 1506 insertions, 42 deletions
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 <S extends Storable> StorableIndex<S> makeIndex(Class<S> 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<Address> 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<Address> 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<Shipment> 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<Shipment> 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<Shipment> 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<Shipment> 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<Shipment> 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<Shipment> iqa =
+ new IndexedQueryAnalyzer<Shipment>(Shipment.class, IxProvider.INSTANCE);
+ Filter<Shipment> filter = Filter.filterFor
+ (Shipment.class, "order.address.addressState = ? & order.address.addressZip = ?");
+ FilterValues<Shipment> 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 <S extends Storable> Collection<StorableIndex<S>> indexesFor(Class<S> type) {
+ StorableIndex<S>[] 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<StorableTestBasic> 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<StorableTestBasic> 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<StorableTestBasic> 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<StorableTestBasic> 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<S> openCursor(StorableIndex<S> index,
- Object[] identityValues,
- BoundaryType rangeStartBoundary,
- Object rangeStartValue,
- BoundaryType rangeEndBoundary,
- Object rangeEndValue,
- boolean reverseRange,
- boolean reverseOrder)
+ protected Cursor<S> fetch(StorableIndex<S> 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<UserAddress> addressExecutor = addressExecutor();
+
+ QueryExecutor<UserInfo> userExecutor = new JoinedQueryExecutor<UserAddress, UserInfo>
+ (mRepository, UserInfo.class, "address", addressExecutor);
+
+ assertEquals("address.state = ?", userExecutor.getFilter().toString());
+ assertEquals("address.country", userExecutor.getOrdering().get(0).toString());
+
+ // Create some addresses
+ Storage<UserAddress> 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<UserInfo> 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<UserInfo> values = Filter
+ .filterFor(UserInfo.class, "address.state = ?").initialFilterValues().with("IL");
+
+ Cursor<UserInfo> 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<UserAddress, UserInfo>
+ (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<UserAddress> addressExecutor() throws Exception {
+ Storage<UserAddress> addressStorage = mRepository.storageFor(UserAddress.class);
+
+ QueryExecutor<UserAddress> addressExecutor =
+ new ScanQueryExecutor<UserAddress>(addressStorage.query());
+
+ addressExecutor = new FilteredQueryExecutor<UserAddress>
+ (addressExecutor, Filter.filterFor(UserAddress.class, "state = ?"));
+
+ StorableProperty<UserAddress> prop = StorableIntrospector
+ .examine(UserAddress.class).getAllProperties().get("country");
+
+ List<OrderedProperty<UserAddress>> orderings =
+ new ArrayList<OrderedProperty<UserAddress>>();
+
+ orderings.add(OrderedProperty.get(prop, null));
+
+ addressExecutor = new ArraySortedQueryExecutor<UserAddress>
+ (addressExecutor, null, orderings);
+
+ return addressExecutor;
+ }
+
+ static class ScanQueryExecutor<S extends Storable> extends FullScanQueryExecutor<S> {
+ private final Query<S> mQuery;
+
+ ScanQueryExecutor(Query<S> query) {
+ super(query.getStorableType());
+ mQuery = query;
+ }
+
+ protected Cursor<S> 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);
}
}
diff --git a/src/test/java/com/amazon/carbonado/repo/toy/ToyRepository.java b/src/test/java/com/amazon/carbonado/repo/toy/ToyRepository.java new file mode 100644 index 0000000..159f451 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/toy/ToyRepository.java @@ -0,0 +1,106 @@ +/*
+ * 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.repo.toy;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.amazon.carbonado.IsolationLevel;
+import com.amazon.carbonado.Repository;
+import com.amazon.carbonado.RepositoryException;
+import com.amazon.carbonado.Storable;
+import com.amazon.carbonado.Storage;
+import com.amazon.carbonado.SupportException;
+import com.amazon.carbonado.Transaction;
+
+import com.amazon.carbonado.capability.Capability;
+
+import com.amazon.carbonado.spi.SequenceValueGenerator;
+import com.amazon.carbonado.spi.SequenceValueProducer;
+
+/**
+ *
+ * @author Brian S O'Neill
+ */
+public class ToyRepository implements Repository {
+ private final String mName;
+ private final Map<Class, Storage> mStorages;
+ private final Map<String, SequenceValueProducer> mSequences;
+
+ public ToyRepository() {
+ this("toy");
+ }
+
+ public ToyRepository(String name) {
+ mName = name;
+ mStorages = new HashMap<Class, Storage>();
+ mSequences = new HashMap<String, SequenceValueProducer>();
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public <S extends Storable> Storage<S> storageFor(Class<S> type)
+ throws SupportException, RepositoryException
+ {
+ synchronized (mStorages) {
+ Storage<S> storage = (Storage<S>) mStorages.get(type);
+ if (storage == null) {
+ storage = new ToyStorage<S>(this, type);
+ mStorages.put(type, storage);
+ }
+ return storage;
+ }
+ }
+
+ public Transaction enterTransaction() {
+ return new ToyTransaction();
+ }
+
+ public Transaction enterTransaction(IsolationLevel level) {
+ return enterTransaction();
+ }
+
+ public Transaction enterTopTransaction(IsolationLevel level) {
+ return enterTransaction(level);
+ }
+
+ public IsolationLevel getTransactionIsolationLevel() {
+ return null;
+ }
+
+ public <C extends Capability> C getCapability(Class<C> capabilityType) {
+ return null;
+ }
+
+ public void close() {
+ }
+
+ SequenceValueProducer getSequenceValueProducer(String name) throws RepositoryException {
+ synchronized (mSequences) {
+ SequenceValueProducer producer = mSequences.get(name);
+ if (producer == null) {
+ producer = new SequenceValueGenerator(this, name);
+ mSequences.put(name, producer);
+ }
+ return producer;
+ }
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/repo/toy/ToyStorableGenerator.java b/src/test/java/com/amazon/carbonado/repo/toy/ToyStorableGenerator.java new file mode 100644 index 0000000..a72c7d5 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/toy/ToyStorableGenerator.java @@ -0,0 +1,143 @@ +/*
+ * 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.repo.toy;
+
+import java.util.EnumSet;
+import java.util.Map;
+
+import org.cojen.classfile.ClassFile;
+import org.cojen.classfile.CodeBuilder;
+import org.cojen.classfile.MethodInfo;
+import org.cojen.classfile.Modifiers;
+import org.cojen.classfile.TypeDesc;
+
+import org.cojen.util.ClassInjector;
+import org.cojen.util.SoftValuedHashMap;
+
+import com.amazon.carbonado.Storable;
+import com.amazon.carbonado.SupportException;
+import com.amazon.carbonado.Trigger;
+
+import com.amazon.carbonado.spi.MasterFeature;
+import com.amazon.carbonado.spi.MasterStorableGenerator;
+import com.amazon.carbonado.spi.MasterSupport;
+import com.amazon.carbonado.spi.StorableGenerator;
+import com.amazon.carbonado.spi.TriggerSupport;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+public class ToyStorableGenerator<S extends Storable> {
+ private static final Map<Class, Class> cCache;
+
+ static {
+ cCache = new SoftValuedHashMap();
+ }
+
+ /**
+ * Generated class has a constructor that accepts a ToyStorage instance.
+ */
+ public static <S extends Storable> Class<? extends S> getGeneratedClass(Class<S> type)
+ throws SupportException
+ {
+ synchronized (cCache) {
+ Class<? extends S> generatedClass = (Class<? extends S>) cCache.get(type);
+ if (generatedClass != null) {
+ return generatedClass;
+ }
+ generatedClass = new ToyStorableGenerator<S>(type).generateAndInjectClass();
+ cCache.put(type, generatedClass);
+ return generatedClass;
+ }
+ }
+
+ private final Class<S> mStorableType;
+
+ private final ClassInjector mClassInjector;
+ private final ClassFile mClassFile;
+
+ private ToyStorableGenerator(Class<S> type) throws SupportException {
+ mStorableType = type;
+
+ EnumSet<MasterFeature> features = EnumSet
+ .of(MasterFeature.VERSIONING, MasterFeature.INSERT_SEQUENCES);
+
+ final Class<? extends S> abstractClass =
+ MasterStorableGenerator.getAbstractClass(mStorableType, features);
+
+ mClassInjector = ClassInjector.create(mStorableType.getName(),
+ abstractClass.getClassLoader());
+
+ mClassFile = new ClassFile(mClassInjector.getClassName(), abstractClass);
+ mClassFile.markSynthetic();
+ mClassFile.setSourceFile(ToyStorableGenerator.class.getName());
+ mClassFile.setTarget("1.5");
+ }
+
+ private Class<? extends S> generateAndInjectClass() {
+ TypeDesc masterSupportType = TypeDesc.forClass(MasterSupport.class);
+ TypeDesc toyStorageType = TypeDesc.forClass(ToyStorage.class);
+
+ // Add constructor that accepts a ToyStorage.
+ {
+ TypeDesc[] params = {toyStorageType};
+ MethodInfo mi = mClassFile.addConstructor(Modifiers.PUBLIC, params);
+ CodeBuilder b = new CodeBuilder(mi);
+ b.loadThis();
+ b.loadLocal(b.getParameter(0));
+ b.invokeSuperConstructor(new TypeDesc[] {masterSupportType});
+ b.returnVoid();
+ }
+
+ // Implement abstract methods which all delegate to ToyStorage instance.
+
+ generateDelegatedMethod
+ (MasterStorableGenerator.DO_TRY_LOAD_MASTER_METHOD_NAME, "doTryLoad");
+ generateDelegatedMethod
+ (MasterStorableGenerator.DO_TRY_INSERT_MASTER_METHOD_NAME, "doTryInsert");
+ generateDelegatedMethod
+ (MasterStorableGenerator.DO_TRY_UPDATE_MASTER_METHOD_NAME, "doTryUpdate");
+ generateDelegatedMethod
+ (MasterStorableGenerator.DO_TRY_DELETE_MASTER_METHOD_NAME, "doTryDelete");
+
+ Class<? extends S> generatedClass = mClassInjector.defineClass(mClassFile);
+
+ return generatedClass;
+ }
+
+ private void generateDelegatedMethod(String masterMethodName, String supportMethodName) {
+ TypeDesc triggerSupportType = TypeDesc.forClass(TriggerSupport.class);
+ TypeDesc toyStorageType = TypeDesc.forClass(ToyStorage.class);
+
+ TypeDesc[] storableParam = {TypeDesc.forClass(Storable.class)};
+
+ MethodInfo mi = mClassFile.addMethod
+ (Modifiers.PROTECTED, masterMethodName, TypeDesc.BOOLEAN, null);
+ CodeBuilder b = new CodeBuilder(mi);
+
+ b.loadThis();
+ b.loadField(StorableGenerator.SUPPORT_FIELD_NAME, triggerSupportType);
+ b.checkCast(toyStorageType);
+ b.loadThis();
+ b.invokeVirtual(toyStorageType, supportMethodName, TypeDesc.BOOLEAN, storableParam);
+ b.returnValue(TypeDesc.BOOLEAN);
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/repo/toy/ToyStorage.java b/src/test/java/com/amazon/carbonado/repo/toy/ToyStorage.java new file mode 100644 index 0000000..dd29e4b --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/toy/ToyStorage.java @@ -0,0 +1,242 @@ +/*
+ * 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.repo.toy;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import com.amazon.carbonado.FetchException;
+import com.amazon.carbonado.IsolationLevel;
+import com.amazon.carbonado.PersistException;
+import com.amazon.carbonado.Query;
+import com.amazon.carbonado.Repository;
+import com.amazon.carbonado.RepositoryException;
+import com.amazon.carbonado.Storable;
+import com.amazon.carbonado.Storage;
+import com.amazon.carbonado.SupportException;
+import com.amazon.carbonado.Transaction;
+import com.amazon.carbonado.Trigger;
+
+import com.amazon.carbonado.spi.MasterSupport;
+import com.amazon.carbonado.spi.SequenceValueProducer;
+
+import com.amazon.carbonado.util.QuickConstructorGenerator;
+
+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.qe.FilteredQueryExecutor;
+import com.amazon.carbonado.qe.IterableQueryExecutor;
+import com.amazon.carbonado.qe.QueryExecutor;
+import com.amazon.carbonado.qe.SortedQueryExecutor;
+import com.amazon.carbonado.qe.StandardQuery;
+
+/**
+ *
+ * @author Brian S O'Neill
+ */
+public class ToyStorage<S extends Storable> implements Storage<S>, MasterSupport<S> {
+ final ToyRepository mRepo;
+ final Class<S> mType;
+
+ final InstanceFactory mInstanceFactory;
+
+ final Collection<S> mData;
+ final Lock mDataLock;
+
+ public ToyStorage(ToyRepository repo, Class<S> type) throws SupportException {
+ StorableIntrospector.examine(type);
+ mRepo = repo;
+ mType = type;
+
+ Class<? extends S> generatedStorableClass = ToyStorableGenerator.getGeneratedClass(type);
+ mInstanceFactory = QuickConstructorGenerator
+ .getInstance(generatedStorableClass, InstanceFactory.class);
+
+ mData = new LinkedList<S>();
+ mDataLock = new ReentrantLock();
+ }
+
+ public Class<S> getStorableType() {
+ return mType;
+ }
+
+ public S prepare() {
+ return (S) mInstanceFactory.instantiate(this);
+ }
+
+ public Query<S> query() throws FetchException {
+ return new ToyQuery(null);
+ }
+
+ public Query<S> query(String filter) throws FetchException {
+ return query(Filter.filterFor(mType, filter));
+ }
+
+ public Query<S> query(Filter<S> filter) throws FetchException {
+ return new ToyQuery(filter.initialFilterValues());
+ }
+
+ public boolean addTrigger(Trigger<? super S> trigger) {
+ return false;
+ }
+
+ public boolean removeTrigger(Trigger<? super S> trigger) {
+ return false;
+ }
+
+ public boolean doTryLoad(S storable) {
+ mDataLock.lock();
+ try {
+ for (S existing : mData) {
+ if (existing.equalPrimaryKeys(storable)) {
+ storable.markAllPropertiesDirty();
+ existing.copyAllProperties(storable);
+ storable.markAllPropertiesClean();
+ return true;
+ }
+ }
+ return false;
+ } finally {
+ mDataLock.unlock();
+ }
+ }
+
+ public boolean doTryInsert(S storable) {
+ mDataLock.lock();
+ try {
+ for (S existing : mData) {
+ if (existing.equalPrimaryKeys(storable)) {
+ return false;
+ }
+ }
+ storable.markAllPropertiesClean();
+ mData.add((S) storable.copy());
+ return true;
+ } finally {
+ mDataLock.unlock();
+ }
+ }
+
+ public boolean doTryUpdate(S storable) {
+ mDataLock.lock();
+ try {
+ for (S existing : mData) {
+ if (existing.equalPrimaryKeys(storable)) {
+ existing.markAllPropertiesDirty();
+ storable.copyAllProperties(existing);
+ existing.markAllPropertiesClean();
+ existing.copyAllProperties(storable);
+ storable.markAllPropertiesClean();
+ return true;
+ }
+ }
+ return false;
+ } finally {
+ mDataLock.unlock();
+ }
+ }
+
+ public boolean doTryDelete(S storable) {
+ mDataLock.lock();
+ try {
+ Iterator<S> it = mData.iterator();
+ while (it.hasNext()) {
+ S existing = it.next();
+ if (existing.equalPrimaryKeys(storable)) {
+ it.remove();
+ return true;
+ }
+ }
+ return false;
+ } finally {
+ mDataLock.unlock();
+ }
+ }
+
+ public Repository getRootRepository() {
+ return mRepo;
+ }
+
+ public boolean isPropertySupported(String propertyName) {
+ return StorableIntrospector.examine(mType)
+ .getAllProperties().containsKey(propertyName);
+ }
+
+ public Trigger<? super S> getInsertTrigger() {
+ return null;
+ }
+
+ public Trigger<? super S> getUpdateTrigger() {
+ return null;
+ }
+
+ public Trigger<? super S> getDeleteTrigger() {
+ return null;
+ }
+
+ public SequenceValueProducer getSequenceValueProducer(String name) throws PersistException {
+ try {
+ return mRepo.getSequenceValueProducer(name);
+ } catch (RepositoryException e) {
+ throw e.toPersistException();
+ }
+ }
+
+ public static interface InstanceFactory {
+ Storable instantiate(ToyStorage storage);
+ }
+
+ private class ToyQuery extends StandardQuery<S> {
+ ToyQuery(FilterValues<S> values, String... orderings) {
+ super(values, orderings);
+ }
+
+ protected Storage<S> getStorage() {
+ return ToyStorage.this;
+ }
+
+ protected Transaction enterTransactionForDelete(IsolationLevel level) {
+ return mRepo.enterTransaction(level);
+ }
+
+ protected QueryExecutor<S> getExecutor(FilterValues<S> values, String... orderings) {
+ QueryExecutor<S> executor = new IterableQueryExecutor<S>(mType, mData, mDataLock);
+
+ if (values != null) {
+ executor = new FilteredQueryExecutor<S>(executor, values.getFilter());
+ }
+
+ // FIXME: sorting
+
+ return executor;
+ }
+
+ protected StandardQuery<S> newInstance(FilterValues<S> values, String... orderings) {
+ return new ToyQuery(values, orderings);
+ }
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/repo/toy/ToyTransaction.java b/src/test/java/com/amazon/carbonado/repo/toy/ToyTransaction.java new file mode 100644 index 0000000..c16d1f1 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/toy/ToyTransaction.java @@ -0,0 +1,51 @@ +/*
+ * 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.repo.toy;
+
+import java.util.concurrent.TimeUnit;
+
+import com.amazon.carbonado.IsolationLevel;
+import com.amazon.carbonado.PersistException;
+import com.amazon.carbonado.Transaction;
+
+/**
+ *
+ * @author Brian S O'Neill
+ */
+public class ToyTransaction implements Transaction {
+ public void commit() throws PersistException {
+ }
+
+ public void exit() throws PersistException {
+ }
+
+ public void setForUpdate(boolean forUpdate) {
+ }
+
+ public boolean isForUpdate() {
+ return false;
+ }
+
+ public void setDesiredLockTimeout(int timeout, TimeUnit unit) {
+ }
+
+ public IsolationLevel getIsolationLevel() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/test/java/com/amazon/carbonado/repo/toy/package-info.java b/src/test/java/com/amazon/carbonado/repo/toy/package-info.java new file mode 100644 index 0000000..769ea8b --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/toy/package-info.java @@ -0,0 +1,25 @@ +/*
+ * 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.
+ */
+
+/**
+ * Standalone toy repository implementation. This repository is only suitable
+ * for running tests that don't require anything sophisticated. It doesn't
+ * support transactions, nothing is actually persisted, and all queries do full
+ * scans. The repository is thread-safe, however.
+ */
+package com.amazon.carbonado.repo.toy;
diff --git a/src/test/java/com/amazon/carbonado/stored/Order.java b/src/test/java/com/amazon/carbonado/stored/Order.java new file mode 100644 index 0000000..91804d9 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/stored/Order.java @@ -0,0 +1,68 @@ +/*
+ * 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.stored;
+
+import com.amazon.carbonado.Alias;
+import com.amazon.carbonado.Storable;
+import com.amazon.carbonado.FetchException;
+import com.amazon.carbonado.Join;
+import com.amazon.carbonado.Nullable;
+import com.amazon.carbonado.PrimaryKey;
+import com.amazon.carbonado.Query;
+import com.amazon.carbonado.Sequence;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+@Alias("TEST_ORDER")
+@PrimaryKey("orderID")
+public interface Order extends Storable<Order> {
+ @Sequence("TEST_ORDER_ID_SEQ")
+ long getOrderID();
+ void setOrderID(long id);
+
+ String getOrderNumber();
+ void setOrderNumber(String value);
+
+ int getOrderTotal();
+ void setOrderTotal(int value);
+
+ @Nullable
+ String getOrderComments();
+ void setOrderComments(String value);
+
+ long getAddressID();
+ void setAddressID(long value);
+
+ @Join
+ @Nullable
+ Address getAddress() throws FetchException;
+ void setAddress(Address value);
+
+ @Join
+ Query<OrderItem> getOrderItems() throws FetchException;
+
+ @Join
+ Query<Shipment> getShipments() throws FetchException;
+
+ @Join
+ Query<Promotion> getPromotions() throws FetchException;
+}
diff --git a/src/test/java/com/amazon/carbonado/stored/OrderItem.java b/src/test/java/com/amazon/carbonado/stored/OrderItem.java new file mode 100644 index 0000000..dba2477 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/stored/OrderItem.java @@ -0,0 +1,68 @@ +/*
+ * 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.stored;
+
+import com.amazon.carbonado.Alias;
+import com.amazon.carbonado.Storable;
+import com.amazon.carbonado.FetchException;
+import com.amazon.carbonado.Index;
+import com.amazon.carbonado.Indexes;
+import com.amazon.carbonado.Join;
+import com.amazon.carbonado.PrimaryKey;
+import com.amazon.carbonado.Sequence;
+import com.amazon.carbonado.constraint.IntegerConstraint;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+@Alias("TEST_ORDER_ITEM")
+@Indexes({@Index("+orderID"), @Index("+shipmentID")})
+@PrimaryKey("orderItemID")
+public interface OrderItem extends Storable<OrderItem> {
+ @Sequence("TEST_ORDER_ITEM_ID_SEQ")
+ long getOrderItemID();
+ void setOrderItemID(long id);
+
+ long getOrderID();
+ void setOrderID(long value);
+
+ @Join
+ Order getOrder() throws FetchException;
+ void setOrder(Order value);
+
+ String getItemDescription();
+ void setItemDescription(String value);
+
+ int getItemQuantity();
+ @IntegerConstraint(min=1, max=100)
+ void setItemQuantity(int value);
+
+ int getItemPrice();
+ void setItemPrice(int value);
+
+ long getShipmentID();
+ void setShipmentID(long value);
+
+ @Join
+ Shipment getShipment() throws FetchException;
+ void setShipment(Shipment value);
+}
+
diff --git a/src/test/java/com/amazon/carbonado/stored/Promotion.java b/src/test/java/com/amazon/carbonado/stored/Promotion.java new file mode 100644 index 0000000..18f4a2e --- /dev/null +++ b/src/test/java/com/amazon/carbonado/stored/Promotion.java @@ -0,0 +1,55 @@ +/*
+ * 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.stored;
+
+import com.amazon.carbonado.Alias;
+import com.amazon.carbonado.Storable;
+import com.amazon.carbonado.FetchException;
+import com.amazon.carbonado.Join;
+import com.amazon.carbonado.PrimaryKey;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+@Alias("TEST_PROMOTION")
+@PrimaryKey({"orderID", "promotionID"})
+public interface Promotion extends Storable<Promotion> {
+ long getOrderID();
+ void setOrderID(long value);
+
+ String getPromotionID();
+ void setPromotionID(String value);
+
+ @Join
+ Order getOrder() throws FetchException;
+ void setOrder(Order value);
+
+ @Join
+ Promotion getPromotion() throws FetchException;
+ void setPromotion(Promotion value);
+
+ String getPromotionTitle();
+ void setPromotionTitle(String value);
+
+ String getPromotionDetails();
+ void setPromotionDetails(String value);
+}
+
diff --git a/src/test/java/com/amazon/carbonado/stored/Shipment.java b/src/test/java/com/amazon/carbonado/stored/Shipment.java new file mode 100644 index 0000000..670806d --- /dev/null +++ b/src/test/java/com/amazon/carbonado/stored/Shipment.java @@ -0,0 +1,69 @@ +/*
+ * 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.stored;
+
+import org.joda.time.DateTime;
+
+import com.amazon.carbonado.Alias;
+import com.amazon.carbonado.Storable;
+import com.amazon.carbonado.FetchException;
+import com.amazon.carbonado.Index;
+import com.amazon.carbonado.Indexes;
+import com.amazon.carbonado.Join;
+import com.amazon.carbonado.PrimaryKey;
+import com.amazon.carbonado.Query;
+import com.amazon.carbonado.Sequence;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+@Alias("TEST_SHIPMENT")
+@Indexes(@Index("+orderID"))
+@PrimaryKey("shipmentID")
+public interface Shipment extends Storable<Shipment> {
+ @Sequence("TEST_SHIPMENT_ID_SEQ")
+ long getShipmentID();
+ void setShipmentID(long id);
+
+ String getShipmentNotes();
+ void setShipmentNotes(String value);
+
+ DateTime getShipmentDate();
+ void setShipmentDate(DateTime value);
+
+ long getOrderID();
+ void setOrderID(long value);
+
+ @Join
+ Order getOrder() throws FetchException;
+ void setOrder(Order value);
+
+ long getShipperID();
+ void setShipperID(long value);
+
+ @Join
+ Shipper getShipper() throws FetchException;
+ void setShipper(Shipper value);
+
+ @Join
+ Query<OrderItem> getOrderItems() throws FetchException;
+}
+
diff --git a/src/test/java/com/amazon/carbonado/stored/Shipper.java b/src/test/java/com/amazon/carbonado/stored/Shipper.java new file mode 100644 index 0000000..41e60f4 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/stored/Shipper.java @@ -0,0 +1,52 @@ +/*
+ * 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.stored;
+
+import com.amazon.carbonado.Alias;
+import com.amazon.carbonado.Storable;
+import com.amazon.carbonado.FetchException;
+import com.amazon.carbonado.Join;
+import com.amazon.carbonado.PrimaryKey;
+import com.amazon.carbonado.Sequence;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill
+ */
+@Alias("TEST_SHIPPER")
+@PrimaryKey("shipperID")
+public interface Shipper extends Storable<Shipper> {
+ @Sequence("TEST_SHIPPER_ID_SEQ")
+ long getShipperID();
+ void setShipperID(long id);
+
+ String getShipperName();
+ void setShipperName(String value);
+
+ String getShipperDetails();
+ void setShipperDetails(String value);
+
+ long getAddressID();
+ void setAddressID(long value);
+
+ @Join
+ Address getAddress() throws FetchException;
+ void setAddress(Address value);
+}
diff --git a/src/test/java/com/amazon/carbonado/stored/UserAddress.java b/src/test/java/com/amazon/carbonado/stored/UserAddress.java new file mode 100644 index 0000000..466f6eb --- /dev/null +++ b/src/test/java/com/amazon/carbonado/stored/UserAddress.java @@ -0,0 +1,66 @@ +/*
+ * 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.stored;
+
+import com.amazon.carbonado.*;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill (boneill)
+ */
+@Indexes({
+ @Index({"country", "state", "city"}),
+ @Index({"state", "city"}),
+ @Index("city")
+})
+@PrimaryKey("addressID")
+public abstract class UserAddress implements Storable<UserAddress> {
+ public abstract int getAddressID();
+ public abstract void setAddressID(int id);
+
+ public abstract String getLine1();
+ public abstract void setLine1(String value);
+
+ @Nullable
+ public abstract String getLine2();
+ public abstract void setLine2(String value);
+
+ public abstract String getCity();
+ public abstract void setCity(String value);
+
+ public abstract String getState();
+ public abstract void setState(String value);
+
+ public abstract String getCountry();
+ public abstract void setCountry(String value);
+
+ @Nullable
+ public abstract String getPostalCode();
+ public abstract void setPostalCode(String value);
+
+ @Nullable
+ public abstract Integer getNeighborAddressID();
+ public abstract void setNeighborAddressID(Integer id);
+
+ @Nullable
+ @Join(internal="neighborAddressID", external="addressID")
+ public abstract UserAddress getNeighbor() throws FetchException;
+ public abstract void setNeighbor(UserAddress address) throws FetchException;
+}
diff --git a/src/test/java/com/amazon/carbonado/stored/UserInfo.java b/src/test/java/com/amazon/carbonado/stored/UserInfo.java new file mode 100644 index 0000000..e0bffa4 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/stored/UserInfo.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.stored;
+
+import com.amazon.carbonado.*;
+import com.amazon.carbonado.constraint.*;
+
+/**
+ *
+ *
+ * @author Brian S O'Neill (boneill)
+ */
+@Indexes({
+ @Index("firstName"),
+ @Index("lastName"),
+ @Index("addressID")
+})
+@PrimaryKey("userID")
+public abstract class UserInfo implements Storable<UserInfo> {
+ public abstract int getUserID();
+ public abstract void setUserID(int id);
+
+ public abstract int getStateID();
+ @IntegerConstraint(allowed={1, 2, 3})
+ public abstract void setStateID(int state);
+
+ public abstract String getFirstName();
+ @LengthConstraint(min=1, max=50)
+ public abstract void setFirstName(String value);
+
+ public abstract String getLastName();
+ @LengthConstraint(min=1, max=50)
+ public abstract void setLastName(String value);
+
+ public abstract int getAddressID();
+ public abstract void setAddressID(int id);
+
+ @Join
+ public abstract UserAddress getAddress() throws FetchException;
+ public abstract void setAddress(UserAddress address);
+}
|