From b4fc65d11f2100cdaaa750cad29dfb7db5192798 Mon Sep 17 00:00:00 2001
From: "Brian S. O'Neill" <bronee@gmail.com>
Date: Mon, 6 Aug 2007 00:49:18 +0000
Subject: Support filters as joined and not joined from one-to-many properties.

---
 .../com/amazon/carbonado/filter/AndFilter.java     | 19 +++++---
 .../java/com/amazon/carbonado/filter/Filter.java   | 52 +++++++++++++---------
 .../java/com/amazon/carbonado/filter/OrFilter.java | 21 ++++++---
 .../amazon/carbonado/filter/PropertyFilter.java    | 13 +++---
 .../amazon/carbonado/qe/JoinedQueryExecutor.java   |  7 ++-
 5 files changed, 73 insertions(+), 39 deletions(-)

(limited to 'src/main')

diff --git a/src/main/java/com/amazon/carbonado/filter/AndFilter.java b/src/main/java/com/amazon/carbonado/filter/AndFilter.java
index be38800..fb158f3 100644
--- a/src/main/java/com/amazon/carbonado/filter/AndFilter.java
+++ b/src/main/java/com/amazon/carbonado/filter/AndFilter.java
@@ -67,17 +67,24 @@ public class AndFilter<S extends Storable> extends BinaryOpFilter<S> {
     }
 
     @Override
-    NotJoined notJoinedFrom(ChainedProperty<S> joinProperty,
-                            Class<? extends Storable> joinPropertyType)
-    {
-        NotJoined left = mLeft.notJoinedFrom(joinProperty, joinPropertyType);
-        NotJoined right = mRight.notJoinedFrom(joinProperty, joinPropertyType);
+    NotJoined notJoinedFromCNF(ChainedProperty<S> joinProperty) {
+        NotJoined left = mLeft.notJoinedFromCNF(joinProperty);
+        NotJoined right = mRight.notJoinedFromCNF(joinProperty);
 
         // Remove wildcards to shut the compiler up.
         Filter leftNotJoined = left.getNotJoinedFilter();
         Filter rightNotJoined = right.getNotJoinedFilter();
 
-        return new NotJoined(leftNotJoined.and(rightNotJoined),
+        Filter notJoined;
+        if (leftNotJoined == null) {
+            notJoined = rightNotJoined;
+        } else if (rightNotJoined == null) {
+            notJoined = leftNotJoined;
+        } else {
+            notJoined = leftNotJoined.and(rightNotJoined);
+        }
+
+        return new NotJoined(notJoined,
                              left.getRemainderFilter().and(right.getRemainderFilter()));
     }
 
diff --git a/src/main/java/com/amazon/carbonado/filter/Filter.java b/src/main/java/com/amazon/carbonado/filter/Filter.java
index cbc37dc..79f0435 100644
--- a/src/main/java/com/amazon/carbonado/filter/Filter.java
+++ b/src/main/java/com/amazon/carbonado/filter/Filter.java
@@ -574,19 +574,18 @@ public abstract class Filter<S extends Storable> implements Appender {
      *
      * @param joinProperty property to not join from
      * @return not join result
-     * @throws IllegalArgumentException if property does not refer to a Storable
+     * @throws IllegalArgumentException if property is not a join
      */
     public final NotJoined notJoinedFrom(ChainedProperty<S> joinProperty) {
-        Class<?> type = joinProperty.getType();
-        if (!Storable.class.isAssignableFrom(type)) {
-            throw new IllegalArgumentException
-                ("Join property type is not a Storable: " + joinProperty);
+        Class<? extends Storable> type = joinProperty.getLastProperty().getJoinedType();
+        if (type == null) {
+            throw new IllegalArgumentException("Not a join property: " + joinProperty);
         }
 
         Filter<S> cnf = conjunctiveNormalForm();
-        NotJoined nj = cnf.notJoinedFrom(joinProperty, (Class<Storable>) type);
+        NotJoined nj = cnf.notJoinedFromCNF(joinProperty);
 
-        if (nj.getNotJoinedFilter() instanceof OpenFilter) {
+        if (nj.getNotJoinedFilter() == null) {
             // Remainder filter should be same as original, but it might have
             // expanded with conjunctive normal form. If so, restore to
             // original, but still bind it to ensure consistent side-effects.
@@ -600,11 +599,17 @@ public abstract class Filter<S extends Storable> implements Appender {
             // conversion from disjunctive normal form to conjunctive normal
             // form may make major changes. If original was dnf, restore the
             // result filters to dnf.
-            
-            if (!(nj.getNotJoinedFilter().isDisjunctiveNormalForm()) ||
-                !(nj.getRemainderFilter().isDisjunctiveNormalForm()))
-            {
-                nj = new NotJoined(nj.getNotJoinedFilter().disjunctiveNormalForm(),
+
+            boolean isNotJoinedDNF = nj.getNotJoinedFilter() == null
+                || nj.getNotJoinedFilter().isDisjunctiveNormalForm();
+
+            boolean isRemainerDNF = nj.getRemainderFilter().isDisjunctiveNormalForm();
+
+            if (!isNotJoinedDNF || !isRemainerDNF) {
+                Filter<?> notJoinedDNF = nj.getNotJoinedFilter() == null ? null
+                    : nj.getNotJoinedFilter().disjunctiveNormalForm();
+
+                nj = new NotJoined(notJoinedDNF,
                                    nj.getRemainderFilter().disjunctiveNormalForm());
             }
         }
@@ -615,10 +620,8 @@ public abstract class Filter<S extends Storable> implements Appender {
     /**
      * Should only be called on a filter in conjunctive normal form.
      */
-    NotJoined notJoinedFrom(ChainedProperty<S> joinProperty,
-                            Class<? extends Storable> joinPropertyType)
-    {
-        return new NotJoined(getOpenFilter(joinPropertyType), this);
+    NotJoined notJoinedFromCNF(ChainedProperty<S> joinProperty) {
+        return new NotJoined(null, this);
     }
 
     abstract Filter<S> buildDisjunctiveNormalForm();
@@ -689,8 +692,11 @@ public abstract class Filter<S extends Storable> implements Appender {
         /**
          * Returns the filter which is no longer as from a join.
          *
-         * @return not joined filter or open filter if none
+         * @return not joined filter or <i>null</i> if none
          */
+        // Design note: Return value might be null since not all join
+        // properties have an open filter representation. For example, some
+        // joins return Query objects.
         public Filter<?> getNotJoinedFilter() {
             return mNotJoined;
         }
@@ -698,14 +704,18 @@ public abstract class Filter<S extends Storable> implements Appender {
         /**
          * Returns the filter which could not be separated.
          *
-         * @return remainder filter or open filter if none
+         * @return remainder filter or <i>open filter</i> if none
          */
         public Filter<S> getRemainderFilter() {
             return mRemainder;
         }
 
         public int hashCode() {
-            return mNotJoined.hashCode() * 31 + mRemainder.hashCode();
+            if (mNotJoined == null) {
+                return mRemainder.hashCode();
+            } else {
+                return mNotJoined.hashCode() * 31 + mRemainder.hashCode();
+            }
         }
 
         public boolean equals(Object obj) {
@@ -714,7 +724,9 @@ public abstract class Filter<S extends Storable> implements Appender {
             }
             if (obj instanceof Filter.NotJoined) {
                 NotJoined other = (NotJoined) obj;
-                return mNotJoined.equals(other.mNotJoined) && mRemainder.equals(other.mRemainder);
+                return (mNotJoined == null ? other.mNotJoined == null
+                        : mNotJoined.equals(other.mNotJoined))
+                    && mRemainder.equals(other.mRemainder);
             }
             return false;
         }
diff --git a/src/main/java/com/amazon/carbonado/filter/OrFilter.java b/src/main/java/com/amazon/carbonado/filter/OrFilter.java
index d5748aa..67da5ba 100644
--- a/src/main/java/com/amazon/carbonado/filter/OrFilter.java
+++ b/src/main/java/com/amazon/carbonado/filter/OrFilter.java
@@ -67,11 +67,9 @@ public class OrFilter<S extends Storable> extends BinaryOpFilter<S> {
     }
 
     @Override
-    NotJoined notJoinedFrom(ChainedProperty<S> joinProperty,
-                            Class<? extends Storable> joinPropertyType)
-    {
-        NotJoined left = mLeft.notJoinedFrom(joinProperty, joinPropertyType);
-        NotJoined right = mRight.notJoinedFrom(joinProperty, joinPropertyType);
+    NotJoined notJoinedFromCNF(ChainedProperty<S> joinProperty) {
+        NotJoined left = mLeft.notJoinedFromCNF(joinProperty);
+        NotJoined right = mRight.notJoinedFromCNF(joinProperty);
 
         // Assert that our child nodes are only OrFilter or PropertyFilter.
         if (!isConjunctiveNormalForm()) {
@@ -88,14 +86,23 @@ public class OrFilter<S extends Storable> extends BinaryOpFilter<S> {
         if (!(left.getRemainderFilter() instanceof OpenFilter) ||
             !(right.getRemainderFilter() instanceof OpenFilter))
         {
-            return super.notJoinedFrom(joinProperty, joinPropertyType);
+            return super.notJoinedFromCNF(joinProperty);
         }
 
         // Remove wildcards to shut the compiler up.
         Filter leftNotJoined = left.getNotJoinedFilter();
         Filter rightNotJoined = right.getNotJoinedFilter();
 
-        return new NotJoined(leftNotJoined.or(rightNotJoined), getOpenFilter(getStorableType()));
+        Filter notJoined;
+        if (leftNotJoined == null) {
+            notJoined = rightNotJoined;
+        } else if (rightNotJoined == null) {
+            notJoined = leftNotJoined;
+        } else {
+            notJoined = leftNotJoined.or(rightNotJoined);
+        }
+
+        return new NotJoined(notJoined, getOpenFilter(getStorableType()));
     }
 
     Filter<S> buildDisjunctiveNormalForm() {
diff --git a/src/main/java/com/amazon/carbonado/filter/PropertyFilter.java b/src/main/java/com/amazon/carbonado/filter/PropertyFilter.java
index 9f12095..deb1f21 100644
--- a/src/main/java/com/amazon/carbonado/filter/PropertyFilter.java
+++ b/src/main/java/com/amazon/carbonado/filter/PropertyFilter.java
@@ -189,7 +189,12 @@ public class PropertyFilter<S extends Storable> extends Filter<S> {
     }
 
     public <T extends Storable> PropertyFilter<T> asJoinedFrom(ChainedProperty<T> joinProperty) {
-        if (joinProperty.getType() != getStorableType()) {
+        Class<?> type = joinProperty.getLastProperty().getJoinedType();
+        if (type == null) {
+            type = joinProperty.getType();
+        }
+
+        if (type != getStorableType()) {
             throw new IllegalArgumentException
                 ("Property is not of type \"" + getStorableType().getName() + "\": " +
                  joinProperty);
@@ -205,9 +210,7 @@ public class PropertyFilter<S extends Storable> extends Filter<S> {
     }
 
     @Override
-    NotJoined notJoinedFrom(ChainedProperty<S> joinProperty,
-                            Class<? extends Storable> joinPropertyType)
-    {
+    NotJoined notJoinedFromCNF(ChainedProperty<S> joinProperty) {
         ChainedProperty<?> notJoinedProp = getChainedProperty();
         ChainedProperty<?> jp = joinProperty;
 
@@ -221,7 +224,7 @@ public class PropertyFilter<S extends Storable> extends Filter<S> {
         }
 
         if (jp != null || notJoinedProp.equals(getChainedProperty())) {
-            return super.notJoinedFrom(joinProperty, joinPropertyType);
+            return super.notJoinedFromCNF(joinProperty);
         }
 
         PropertyFilter<?> notJoinedFilter;
diff --git a/src/main/java/com/amazon/carbonado/qe/JoinedQueryExecutor.java b/src/main/java/com/amazon/carbonado/qe/JoinedQueryExecutor.java
index d947ed7..b1d47e9 100644
--- a/src/main/java/com/amazon/carbonado/qe/JoinedQueryExecutor.java
+++ b/src/main/java/com/amazon/carbonado/qe/JoinedQueryExecutor.java
@@ -395,7 +395,12 @@ public class JoinedQueryExecutor<S extends Storable, T extends Storable>
     private static <T extends Storable> OrderingList<T>
         expectedOrdering(StorageAccess<T> access, Filter<T> filter, OrderingList<T> ordering)
     {
-        List<Filter<T>> split = filter.disjunctiveNormalFormSplit();
+        List<Filter<T>> split;
+        if (filter == null) {
+            split = Filter.getOpenFilter(access.getStorableType()).disjunctiveNormalFormSplit();
+        } else {
+            split = filter.disjunctiveNormalFormSplit();
+        }
 
         Comparator comparator = CompositeScore.fullComparator();
 
-- 
cgit v1.2.3