You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2014/03/27 22:21:34 UTC

[20/50] [abbrv] git commit: Put queryindex classes all under one top-level "index" package to eliminate conflict with old persistence classes.

Put queryindex classes all under one top-level "index" package to eliminate conflict with old persistence classes.


Project: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/commit/8f969d8d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/tree/8f969d8d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/diff/8f969d8d

Branch: refs/pull/77/head
Commit: 8f969d8d969a141a5705c141949e4841cfed8293
Parents: 8043bf3
Author: Dave Johnson <dm...@apigee.com>
Authored: Wed Mar 26 15:12:04 2014 -0400
Committer: Dave Johnson <dm...@apigee.com>
Committed: Wed Mar 26 15:17:08 2014 -0400

----------------------------------------------------------------------
 stack/corepersistence/queryindex/pom.xml        |    2 +-
 .../persistence/index/query/tree/QueryFilter.g  |  311 ++++++
 .../index/EntityCollectionIndex.java            |    4 +-
 .../index/exceptions/IndexException.java        |   41 +
 .../index/exceptions/JsonReadException.java     |   29 +
 .../index/exceptions/JsonWriteException.java    |   29 +
 .../exceptions/NoFullTextIndexException.java    |   52 +
 .../index/exceptions/NoIndexException.java      |   50 +
 .../index/exceptions/PersistenceException.java  |   47 +
 .../index/exceptions/QueryException.java        |   41 +
 .../index/exceptions/QueryParseException.java   |   65 ++
 .../index/exceptions/QueryTokenException.java   |   54 +
 .../index/impl/EsEntityCollectionIndex.java     |    6 +-
 .../persistence/index/impl/EsQueryVistor.java   |   28 +-
 .../index/legacy/EntityManagerFacade.java       |    8 +-
 .../persistence/index/query/EntityRef.java      |   30 +
 .../usergrid/persistence/index/query/Query.java | 1015 ++++++++++++++++++
 .../persistence/index/query/Results.java        |  126 +++
 .../index/query/SimpleEntityRef.java            |  131 +++
 .../index/query/tree/AndOperand.java            |   50 +
 .../index/query/tree/BooleanLiteral.java        |   50 +
 .../index/query/tree/BooleanOperand.java        |   50 +
 .../index/query/tree/ContainsOperand.java       |   71 ++
 .../index/query/tree/ContainsProperty.java      |   59 +
 .../persistence/index/query/tree/Equal.java     |   54 +
 .../index/query/tree/EqualityOperand.java       |   90 ++
 .../index/query/tree/FloatLiteral.java          |   59 +
 .../index/query/tree/GreaterThan.java           |   55 +
 .../index/query/tree/GreaterThanEqual.java      |   59 +
 .../persistence/index/query/tree/LessThan.java  |   55 +
 .../index/query/tree/LessThanEqual.java         |   57 +
 .../persistence/index/query/tree/Literal.java   |   41 +
 .../index/query/tree/LiteralFactory.java        |   61 ++
 .../index/query/tree/LongLiteral.java           |   67 ++
 .../index/query/tree/NotOperand.java            |   45 +
 .../index/query/tree/NumericLiteral.java        |   27 +
 .../persistence/index/query/tree/Operand.java   |   50 +
 .../persistence/index/query/tree/OrOperand.java |   56 +
 .../persistence/index/query/tree/Property.java  |   65 ++
 .../index/query/tree/QueryVisitor.java          |  102 ++
 .../index/query/tree/StringLiteral.java         |   85 ++
 .../index/query/tree/UUIDLiteral.java           |   52 +
 .../index/query/tree/WithinOperand.java         |  111 ++
 .../index/query/tree/WithinProperty.java        |   57 +
 .../persistence/index/utils/ClassUtils.java     |   58 +
 .../index/utils/ConversionUtils.java            |  765 +++++++++++++
 .../persistence/index/utils/EntityBuilder.java  |  177 +++
 .../persistence/index/utils/JsonUtils.java      |  329 ++++++
 .../persistence/index/utils/ListUtils.java      |  232 ++++
 .../persistence/index/utils/MapUtils.java       |  377 +++++++
 .../persistence/index/utils/StringUtils.java    |  172 +++
 .../persistence/index/utils/UUIDUtils.java      |  412 +++++++
 .../persistence/index/impl/CollectionIT.java    |   10 +-
 .../index/impl/CorePerformanceIT.java           |    4 +-
 .../impl/EntityCollectionIndexStressTest.java   |    4 +-
 .../index/impl/EntityCollectionIndexTest.java   |    6 +-
 .../usergrid/persistence/index/impl/GeoIT.java  |   10 +-
 .../persistence/index/impl/IndexIT.java         |    6 +-
 .../persistence/index/legacy/Application.java   |    4 +-
 .../index/legacy/CoreApplication.java           |    4 +-
 .../index/legacy/CoreITSetupImpl.java           |    2 +-
 .../query/AbstractIteratingQueryIT.java         |    2 +
 .../query/AllInConnectionNoTypeIT.java          |    2 +
 .../query/IntersectionUnionPagingIT.java        |    2 +
 .../usergrid/persistence/query/QueryTest.java   |   31 +-
 .../persistence/query/tree/GrammarTreeTest.java |   20 +-
 .../persistence/query/tree/LongLiteralTest.java |    1 +
 .../query/tree/StringLiteralTest.java           |    2 +-
 68 files changed, 6162 insertions(+), 67 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/pom.xml
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/pom.xml b/stack/corepersistence/queryindex/pom.xml
index 9b9e67a..a6f8d43 100644
--- a/stack/corepersistence/queryindex/pom.xml
+++ b/stack/corepersistence/queryindex/pom.xml
@@ -12,7 +12,7 @@
     <parent>
         <artifactId>persistence</artifactId>
         <groupId>org.apache.usergrid</groupId>
-        <version>1.0-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
     </parent>
 
     <build>

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/QueryFilter.g
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/QueryFilter.g b/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/QueryFilter.g
new file mode 100644
index 0000000..d8a5f8b
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/QueryFilter.g
@@ -0,0 +1,311 @@
+grammar QueryFilter;
+//NOTES:  '^' denotes operator, all others in the string become operands
+
+options {
+    output=AST;
+//    ASTLabelType=CommonTree;
+}
+
+@rulecatch { }
+
+
+@header {
+package org.apache.usergrid.persistence.index.query.tree;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.usergrid.persistence.index.query.Query;
+import org.apache.usergrid.persistence.index.query.Query.SortPredicate;
+
+}
+
+
+@members {
+	Query query = new Query();
+
+  private static final Logger logger = LoggerFactory
+      .getLogger(QueryFilterLexer.class);
+
+	@Override
+	public void emitErrorMessage(String msg) {
+		logger.info(msg);
+	}
+}
+
+
+@lexer::header {
+package org.apache.usergrid.persistence.index.query.tree;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.usergrid.persistence.index.exceptions.QueryTokenException;
+
+}
+
+@lexer::members {
+
+
+
+  private static final Logger logger = LoggerFactory
+      .getLogger(QueryFilterLexer.class);
+
+
+
+
+	@Override
+	public void emitErrorMessage(String msg) {
+		logger.info(msg);
+	}
+
+	@Override
+    public void recover(RecognitionException e) {
+         //We don't want to recover, we want to re-throw to the user since they passed us invalid input
+         throw new QueryTokenException(e);
+    }
+
+
+}
+
+//these must come before ID. Otherwise lt, lte, eq, etc will be returned as id tokens
+LT  : '<' | 'lt';
+
+LTE : '<=' |  'lte';
+
+EQ  : '=' | 'eq';
+
+GT  : '>' | 'gt';
+
+GTE : '>=' |  'gte';  
+
+
+//keywords before var ids
+BOOLEAN : (TRUE|FALSE);
+
+AND : ('A'|'a')('N'|'n')('D'|'d') | '&&';
+
+OR  : ('O'|'o')('R'|'r') | '||' ;
+
+NOT : ('N'|'n')('O'|'o')('T'|'t');
+
+ASC : ('A'|'a')('S'|'s')('C'|'c');
+
+DESC : ('D'|'d')('E'|'e')('S'|'s')('C'|'c');
+
+CONTAINS : ('C'|'c')('O'|'o')('N'|'n')('T'|'t')('A'|'a')('I'|'i')('N'|'n')('S'|'s');
+
+WITHIN : ('W'|'w')('I'|'i')('T'|'t')('H'|'h')('I'|'i')('N'|'n');
+
+OF : ('O'|'o')('F'|'f');
+
+UUID :  HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+  HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT '-' 
+  HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT '-' 
+  HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT '-' 
+  HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT '-' 
+  HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+  HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+  HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+  ;
+
+//ids and values
+ID  :	('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'.'|'-')*
+    ;
+
+LONG :	('-')? '0'..'9'+
+    ;
+
+FLOAT
+    :  ('-')? ( ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
+    |   '.' ('0'..'9')+ EXPONENT?
+    |   ('0'..'9')+ EXPONENT)
+    ;
+    
+STRING
+    :  '\'' ( ESC_SEQ | ~('\\'|'\'') )* '\''
+    ;
+
+
+    
+WS : (' ' | '\t' | '\n' | '\r' | '\f')+  {$channel=HIDDEN;};
+
+
+
+    
+
+
+
+fragment TRUE : ('T'|'t')('R'|'r')('U'|'u')('E'|'e');
+
+fragment FALSE : ('F'|'f')('A'|'a')('L'|'l')('S'|'s')('E'|'e');
+
+
+fragment
+EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;
+
+fragment
+HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;
+
+fragment
+ESC_SEQ
+    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
+    |   UNICODE_ESC
+    |   OCTAL_ESC
+    ;
+
+fragment
+OCTAL_ESC
+    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
+    |   '\\' ('0'..'7') ('0'..'7')
+    |   '\\' ('0'..'7')
+    ;
+
+fragment
+UNICODE_ESC
+    :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+    ;
+
+
+
+
+//NE : '!=';
+
+
+
+property :	ID<Property>;
+
+containsproperty : ID<ContainsProperty>;
+
+withinproperty : ID<WithinProperty>;
+	
+booleanliteral: BOOLEAN<BooleanLiteral>;
+
+
+longliteral :
+  LONG<LongLiteral> ;
+
+uuidliteral :
+  UUID<UUIDLiteral>;
+
+stringliteral :
+  STRING<StringLiteral>;
+  
+floatliteral :
+  FLOAT<FloatLiteral> ;
+
+//We delegate to each sub class literal so we can get each type	
+value : 
+  booleanliteral
+  | longliteral
+  | uuidliteral
+  | stringliteral
+  | floatliteral
+  ;
+  
+
+
+//Every operand returns with the name of 'op'.  This is used because all subtrees require operands,
+//this allows us to link the java code easily by using the same name as a converntion
+
+//begin search expressions
+  
+//mathmatical equality operations
+equalityop :
+  property LT<LessThan>^ value
+  |property LTE<LessThanEqual>^ value
+  |property EQ<Equal>^ value
+  |property GT<GreaterThan>^ value
+  |property GTE<GreaterThanEqual>^ value
+  ; 
+
+//geo location search
+locationop :
+  withinproperty WITHIN<WithinOperand>^ (floatliteral|longliteral) OF! (floatliteral|longliteral) ','! (floatliteral|longliteral);
+  
+//string search
+containsop :
+  containsproperty CONTAINS<ContainsOperand>^ stringliteral;
+
+//
+operation :
+ '('! expression ')'!
+   | equalityop 
+   | locationop 
+   | containsop 
+   ;
+
+//negations of expressions
+notexp :
+//only link if we have the not
+ NOT<NotOperand>^ operation  
+ |operation 
+ ;
+
+//and expressions contain operands.  These should always be closer to the leaves of a tree, it allows
+//for faster result intersection sooner in the query execution
+andexp :
+ notexp (AND<AndOperand>^ notexp )*;
+ 
+ 
+//or expression should always be after AND expressions.  This will give us a smaller result set to union when evaluating trees
+//also a root level expression
+expression :
+ andexp (OR<OrOperand>^ andexp )*;
+
+
+
+//end expressions
+
+//begin order clauses
+
+//direction for ordering
+direction  : (ASC | DESC);
+
+//order clause
+order
+  : (property direction?){
+		String property = $property.text; 
+		String direction = $direction.text;
+		query.addSort(new SortPredicate(property, direction));
+    
+  };
+
+//end order clauses
+  
+//Begin select clauses
+
+select_subject
+  : ID {
+
+  query.addSelect($ID.text);
+
+};
+
+ 
+
+select_assign
+  : target=ID ':' source=ID {
+
+  query.addSelect($target.text, $source.text);
+
+};
+
+select_expr 
+  : ('*' | select_subject (',' select_subject) * | '{' select_assign (',' select_assign) * '}');  
+   
+//end select clauses
+
+ql returns [Query query]
+  : ('select'! select_expr!)? ('where'!? expression)? ('order by'! order! (','! order!)*)? {
+
+  if($expression.tree instanceof Operand){
+    query.setRootOperand((Operand)$expression.tree);
+  }
+  
+  retval.query = query;
+
+
+};
+
+
+

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityCollectionIndex.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityCollectionIndex.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityCollectionIndex.java
index 7cf318b..f4c04e6 100644
--- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityCollectionIndex.java
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityCollectionIndex.java
@@ -22,8 +22,8 @@ package org.apache.usergrid.persistence.index;
 import java.util.UUID;
 import org.apache.usergrid.persistence.model.entity.Entity;
 import org.apache.usergrid.persistence.model.entity.Id;
-import org.apache.usergrid.persistence.query.Query;
-import org.apache.usergrid.persistence.query.Results;
+import org.apache.usergrid.persistence.index.query.Query;
+import org.apache.usergrid.persistence.index.query.Results;
 
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/IndexException.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/IndexException.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/IndexException.java
new file mode 100644
index 0000000..e492759
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/IndexException.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.index.exceptions;
+
+
+public class IndexException extends RuntimeException {
+
+    public IndexException() {
+        super();
+    }
+
+
+    public IndexException( String message, Throwable cause ) {
+        super( message, cause );
+    }
+
+
+    public IndexException( String message ) {
+        super( message );
+    }
+
+
+    public IndexException( Throwable cause ) {
+        super( cause );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/JsonReadException.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/JsonReadException.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/JsonReadException.java
new file mode 100644
index 0000000..100d7e1
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/JsonReadException.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.usergrid.persistence.index.exceptions;
+
+
+public class JsonReadException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+
+    public JsonReadException( String msg, Throwable t ) {
+        super( msg, t );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/JsonWriteException.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/JsonWriteException.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/JsonWriteException.java
new file mode 100644
index 0000000..a222f92
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/JsonWriteException.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.usergrid.persistence.index.exceptions;
+
+
+public class JsonWriteException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+
+    public JsonWriteException( String msg, Throwable t ) {
+        super( msg, t );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/NoFullTextIndexException.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/NoFullTextIndexException.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/NoFullTextIndexException.java
new file mode 100644
index 0000000..ef36095
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/NoFullTextIndexException.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.index.exceptions;
+
+
+/**
+ * Thrown when the user attempts to perform a "contains" operation on a field that isn't full text indexed
+ *
+ * @author tnine
+ */
+public class NoFullTextIndexException extends PersistenceException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+    final String entityType;
+    final String propertyName;
+
+
+    public NoFullTextIndexException( String entityType, String propertyName ) {
+        super( "Entity '" + entityType + "' with property named '" + propertyName
+                + "' is not full text indexed.  You cannot use the 'contains' operand on this field" );
+        this.entityType = entityType;
+        this.propertyName = propertyName;
+    }
+
+
+    public String getEntityType() {
+        return entityType;
+    }
+
+
+    public String getPropertyName() {
+        return propertyName;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/NoIndexException.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/NoIndexException.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/NoIndexException.java
new file mode 100644
index 0000000..ca9f9cb
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/NoIndexException.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright 2012 Apigee Corporation
+ *
+ * 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 org.apache.usergrid.persistence.index.exceptions;
+
+
+/**
+ * Thrown when the user attempts to perform a "contains" operation on a field that isn't full text indexed
+ *
+ * @author tnine
+ */
+public class NoIndexException extends PersistenceException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+    final String entityType;
+    final String propertyName;
+
+
+    public NoIndexException( String entityType, String propertyName ) {
+        super( "Entity '" + entityType + "' with property named '" + propertyName
+                + "' is not indexed.  You cannot use the this field in queries." );
+        this.entityType = entityType;
+        this.propertyName = propertyName;
+    }
+
+
+    public String getEntityType() {
+        return entityType;
+    }
+
+
+    public String getPropertyName() {
+        return propertyName;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/PersistenceException.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/PersistenceException.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/PersistenceException.java
new file mode 100644
index 0000000..2f983b4
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/PersistenceException.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.index.exceptions;
+
+
+public class PersistenceException extends Exception {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+
+    public PersistenceException() {
+        super();
+    }
+
+
+    public PersistenceException( String message, Throwable cause ) {
+        super( message, cause );
+    }
+
+
+    public PersistenceException( String message ) {
+        super( message );
+    }
+
+
+    public PersistenceException( Throwable cause ) {
+        super( cause );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/QueryException.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/QueryException.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/QueryException.java
new file mode 100644
index 0000000..a9928ec
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/QueryException.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.index.exceptions;
+
+
+public class QueryException extends RuntimeException {
+
+    public QueryException() {
+        super();
+    }
+
+
+    public QueryException( String message, Throwable cause ) {
+        super( message, cause );
+    }
+
+
+    public QueryException( String message ) {
+        super( message );
+    }
+
+
+    public QueryException( Throwable cause ) {
+        super( cause );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/QueryParseException.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/QueryParseException.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/QueryParseException.java
new file mode 100644
index 0000000..4e46bc5
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/QueryParseException.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.index.exceptions;
+
+
+/**
+ * An exception thrown when a query cannot be parsed
+ *
+ * @author tnine
+ */
+public class QueryParseException extends RuntimeException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     *
+     */
+    public QueryParseException() {
+        super();
+    }
+
+
+    /**
+     * @param arg0
+     * @param arg1
+     */
+    public QueryParseException( String arg0, Throwable arg1 ) {
+        super( arg0, arg1 );
+    }
+
+
+    /**
+     * @param arg0
+     */
+    public QueryParseException( String arg0 ) {
+        super( arg0 );
+    }
+
+
+    /**
+     * @param arg0
+     */
+    public QueryParseException( Throwable arg0 ) {
+        super( arg0 );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/QueryTokenException.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/QueryTokenException.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/QueryTokenException.java
new file mode 100644
index 0000000..5bf45d7
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/QueryTokenException.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.index.exceptions;
+
+
+/**
+ * An exception thrown when a query encounters a token it doesn't recognize
+ * @author tnine
+ */
+public class QueryTokenException extends RuntimeException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+
+
+
+    /**
+     * @param arg0
+     */
+    public QueryTokenException( Throwable arg0 ) {
+        super( arg0 );
+    }
+
+
+    @Override
+    public String getMessage() {
+        //antlr errors or strange.  We have to do this, there's no message
+        return getCause().toString();
+    }
+
+
+    @Override
+    public String getLocalizedMessage() {
+        return getMessage();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityCollectionIndex.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityCollectionIndex.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityCollectionIndex.java
index 8e16d88..3c0239c 100644
--- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityCollectionIndex.java
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityCollectionIndex.java
@@ -34,7 +34,7 @@ import org.apache.usergrid.persistence.collection.CollectionScope;
 import org.apache.usergrid.persistence.collection.EntityCollectionManager;
 import org.apache.usergrid.persistence.collection.EntityCollectionManagerFactory;
 import org.apache.usergrid.persistence.collection.mvcc.entity.ValidationUtils;
-import org.apache.usergrid.persistence.exceptions.IndexException;
+import org.apache.usergrid.persistence.index.exceptions.IndexException;
 import org.apache.usergrid.persistence.index.EntityCollectionIndex;
 import org.apache.usergrid.persistence.index.IndexFig;
 import org.apache.usergrid.persistence.model.entity.Entity;
@@ -47,8 +47,8 @@ import org.apache.usergrid.persistence.model.field.ListField;
 import org.apache.usergrid.persistence.model.field.LocationField;
 import org.apache.usergrid.persistence.model.field.SetField;
 import org.apache.usergrid.persistence.model.field.StringField;
-import org.apache.usergrid.persistence.query.Query;
-import org.apache.usergrid.persistence.query.Results;
+import org.apache.usergrid.persistence.index.query.Query;
+import org.apache.usergrid.persistence.index.query.Results;
 import org.elasticsearch.action.admin.indices.exists.types.TypesExistsRequest;
 import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
 import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsQueryVistor.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsQueryVistor.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsQueryVistor.java
index 5998bf2..332c47b 100644
--- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsQueryVistor.java
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsQueryVistor.java
@@ -21,22 +21,22 @@ package org.apache.usergrid.persistence.index.impl;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Stack;
-import org.apache.usergrid.persistence.exceptions.NoFullTextIndexException;
-import org.apache.usergrid.persistence.exceptions.NoIndexException;
-import org.apache.usergrid.persistence.exceptions.PersistenceException;
+import org.apache.usergrid.persistence.index.exceptions.NoFullTextIndexException;
+import org.apache.usergrid.persistence.index.exceptions.NoIndexException;
+import org.apache.usergrid.persistence.index.exceptions.PersistenceException;
 import static org.apache.usergrid.persistence.index.impl.EsEntityCollectionIndex.ANALYZED_SUFFIX;
 import static org.apache.usergrid.persistence.index.impl.EsEntityCollectionIndex.GEO_SUFFIX;
-import org.apache.usergrid.persistence.query.tree.AndOperand;
-import org.apache.usergrid.persistence.query.tree.ContainsOperand;
-import org.apache.usergrid.persistence.query.tree.Equal;
-import org.apache.usergrid.persistence.query.tree.GreaterThan;
-import org.apache.usergrid.persistence.query.tree.GreaterThanEqual;
-import org.apache.usergrid.persistence.query.tree.LessThan;
-import org.apache.usergrid.persistence.query.tree.LessThanEqual;
-import org.apache.usergrid.persistence.query.tree.NotOperand;
-import org.apache.usergrid.persistence.query.tree.OrOperand;
-import org.apache.usergrid.persistence.query.tree.QueryVisitor;
-import org.apache.usergrid.persistence.query.tree.WithinOperand;
+import org.apache.usergrid.persistence.index.query.tree.AndOperand;
+import org.apache.usergrid.persistence.index.query.tree.ContainsOperand;
+import org.apache.usergrid.persistence.index.query.tree.Equal;
+import org.apache.usergrid.persistence.index.query.tree.GreaterThan;
+import org.apache.usergrid.persistence.index.query.tree.GreaterThanEqual;
+import org.apache.usergrid.persistence.index.query.tree.LessThan;
+import org.apache.usergrid.persistence.index.query.tree.LessThanEqual;
+import org.apache.usergrid.persistence.index.query.tree.NotOperand;
+import org.apache.usergrid.persistence.index.query.tree.OrOperand;
+import org.apache.usergrid.persistence.index.query.tree.QueryVisitor;
+import org.apache.usergrid.persistence.index.query.tree.WithinOperand;
 import org.elasticsearch.common.unit.DistanceUnit;
 import org.elasticsearch.index.query.FilterBuilder;
 import org.elasticsearch.index.query.FilterBuilders;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/legacy/EntityManagerFacade.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/legacy/EntityManagerFacade.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/legacy/EntityManagerFacade.java
index 5e57ace..912978f 100644
--- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/legacy/EntityManagerFacade.java
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/legacy/EntityManagerFacade.java
@@ -17,7 +17,7 @@
  */
 package org.apache.usergrid.persistence.index.legacy;
 
-import org.apache.usergrid.utils.EntityBuilder;
+import org.apache.usergrid.persistence.index.utils.EntityBuilder;
 import java.util.HashMap;
 import java.util.Map;
 import org.apache.usergrid.persistence.collection.CollectionScope;
@@ -33,9 +33,9 @@ import org.apache.usergrid.persistence.model.field.LocationField;
 import org.apache.usergrid.persistence.model.field.LongField;
 import org.apache.usergrid.persistence.model.field.value.Location;
 import org.apache.usergrid.persistence.model.util.UUIDGenerator;
-import org.apache.usergrid.persistence.query.EntityRef;
-import org.apache.usergrid.persistence.query.Query;
-import org.apache.usergrid.persistence.query.Results;
+import org.apache.usergrid.persistence.index.query.EntityRef;
+import org.apache.usergrid.persistence.index.query.Query;
+import org.apache.usergrid.persistence.index.query.Results;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/EntityRef.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/EntityRef.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/EntityRef.java
new file mode 100644
index 0000000..2abbbe5
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/EntityRef.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.index.query;
+
+
+import java.util.UUID;
+import org.apache.usergrid.persistence.model.entity.Id;
+
+
+public interface EntityRef {
+
+    public Id getId();
+
+    public UUID getVersion();
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/Query.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/Query.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/Query.java
new file mode 100644
index 0000000..23aad8b
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/Query.java
@@ -0,0 +1,1015 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.index.query;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.UUID;
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.ClassicToken;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenRewriteStream;
+import static org.apache.commons.codec.binary.Base64.decodeBase64;
+import org.apache.commons.lang.StringUtils;
+import static org.apache.commons.lang.StringUtils.isBlank;
+import static org.apache.commons.lang.StringUtils.split;
+import org.apache.usergrid.persistence.index.exceptions.PersistenceException;
+import org.apache.usergrid.persistence.index.exceptions.QueryParseException;
+import org.apache.usergrid.persistence.index.impl.EsQueryVistor;
+import org.apache.usergrid.persistence.model.entity.Id;
+import org.apache.usergrid.persistence.index.query.tree.AndOperand;
+import org.apache.usergrid.persistence.index.query.tree.ContainsOperand;
+import org.apache.usergrid.persistence.index.query.tree.Equal;
+import org.apache.usergrid.persistence.index.query.tree.EqualityOperand;
+import org.apache.usergrid.persistence.index.query.tree.GreaterThan;
+import org.apache.usergrid.persistence.index.query.tree.GreaterThanEqual;
+import org.apache.usergrid.persistence.index.query.tree.LessThan;
+import org.apache.usergrid.persistence.index.query.tree.LessThanEqual;
+import org.apache.usergrid.persistence.index.query.tree.Operand;
+import org.apache.usergrid.persistence.index.query.tree.QueryFilterLexer;
+import org.apache.usergrid.persistence.index.query.tree.QueryFilterParser;
+import org.apache.usergrid.persistence.index.query.tree.QueryVisitor;
+import static org.apache.usergrid.persistence.index.utils.ClassUtils.cast;
+import org.apache.usergrid.persistence.index.utils.JsonUtils;
+import org.apache.usergrid.persistence.index.utils.ListUtils;
+import static org.apache.usergrid.persistence.index.utils.ListUtils.first;
+import static org.apache.usergrid.persistence.index.utils.ListUtils.firstBoolean;
+import static org.apache.usergrid.persistence.index.utils.ListUtils.firstInteger;
+import static org.apache.usergrid.persistence.index.utils.ListUtils.firstLong;
+import static org.apache.usergrid.persistence.index.utils.ListUtils.firstUuid;
+import static org.apache.usergrid.persistence.index.utils.ListUtils.isEmpty;
+import static org.apache.usergrid.persistence.index.utils.MapUtils.toMapList;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.elasticsearch.index.query.FilterBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class Query {
+    private static final Logger logger = LoggerFactory.getLogger( Query.class );
+
+    public static final int PAGE_SIZE = 1000;
+
+    public static final int DEFAULT_LIMIT = 10;
+    public static final int MAX_LIMIT = 1000;
+    public static final String PROPERTY_ID = "id";
+
+    private String type;
+    private List<SortPredicate> sortPredicates = new ArrayList<SortPredicate>();
+    private Operand rootOperand;
+    private UUID startResult;
+    private String cursor;
+    private int limit = 0;
+
+    private Map<String, String> selectAssignments = new LinkedHashMap<String, String>();
+    private boolean mergeSelectResults = false;
+    private String connection;
+    private List<String> permissions;
+    private boolean reversed;
+    private boolean reversedSet = false;
+    private Long startTime;
+    private Long finishTime;
+    private boolean pad;
+    private List<Id> identifiers;
+    private String collection;
+    private String ql;
+
+
+    public Query() {
+    }
+
+
+    public Query( Query q ) {
+        if ( q != null ) {
+            type = q.type;
+            sortPredicates = q.sortPredicates != null 
+                    ? new ArrayList<SortPredicate>( q.sortPredicates ) : null;
+            startResult = q.startResult;
+            cursor = q.cursor;
+            limit = q.limit;
+            selectAssignments = q.selectAssignments != null 
+                    ? new LinkedHashMap<String, String>( q.selectAssignments ) : null;
+            mergeSelectResults = q.mergeSelectResults;
+            connection = q.connection;
+            permissions = q.permissions != null ? new ArrayList<String>( q.permissions ) : null;
+            reversed = q.reversed;
+            reversedSet = q.reversedSet;
+            startTime = q.startTime;
+            finishTime = q.finishTime;
+            pad = q.pad;
+            rootOperand = q.rootOperand;
+            identifiers = q.identifiers != null ? new ArrayList<Id>( q.identifiers ) : null;
+            collection = q.collection;
+        }
+    }
+
+
+    public QueryBuilder createQueryBuilder() {
+
+        QueryBuilder queryBuilder = null;
+
+        if ( getRootOperand() != null ) {
+            QueryVisitor v = new EsQueryVistor();
+            try {
+                getRootOperand().visit( v );
+
+            } catch ( PersistenceException ex ) {
+                throw new RuntimeException( "Error building ElasticSearch query", ex );
+            }
+            queryBuilder = v.getQueryBuilder();
+        } 
+
+		if ( queryBuilder == null ) {
+            queryBuilder = QueryBuilders.matchAllQuery();
+		}
+
+        return queryBuilder;
+    }
+
+
+	public FilterBuilder createFilterBuilder() {
+	    FilterBuilder filterBuilder = null;
+
+        if ( getRootOperand() != null ) {
+            QueryVisitor v = new EsQueryVistor();
+            try {
+                getRootOperand().visit( v );
+
+            } catch ( PersistenceException ex ) {
+                throw new RuntimeException( "Error building ElasticSearch query", ex );
+            }
+            filterBuilder = v.getFilterBuilder();
+        } 
+
+        return filterBuilder;	
+	}
+
+
+    public static Query fromQL( String ql ) throws QueryParseException {
+        if ( ql == null ) {
+            return null;
+        }
+        String originalQl = ql;
+        ql = ql.trim();
+
+        String qlt = ql.toLowerCase();
+        if ( !qlt.startsWith( "select" ) 
+                && !qlt.startsWith( "insert" ) 
+                && !qlt.startsWith( "update" ) 
+                && !qlt.startsWith( "delete" ) ) {
+            if ( qlt.startsWith( "order by" ) ) {
+                ql = "select * " + ql;
+            }
+            else {
+                ql = "select * where " + ql;
+            }
+        }
+
+        ANTLRStringStream in = new ANTLRStringStream( ql.trim() );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        CommonTokenStream tokens = new CommonTokenStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        try {
+            Query q = parser.ql().query;
+            q.setQl( originalQl );
+            return q;
+
+        } catch ( RecognitionException e ) {
+            logger.error( "Unable to parse \"{}\"", ql, e );
+            int index = e.index;
+            int lineNumber = e.line;
+            Token token = e.token;
+            String message = String.format("The query cannot be parsed. "
+                    + "The token '%s' at column %d on line %d cannot be parsed", 
+                    token.getText(), index, lineNumber );
+            throw new QueryParseException( message, e );
+        }
+    }
+
+
+    private static Query newQueryIfNull( Query query ) {
+        if ( query == null ) {
+            query = new Query();
+        }
+        return query;
+    }
+
+
+    public static Query fromJsonString( String json ) throws QueryParseException {
+        Object o = JsonUtils.parse( json );
+        if ( o instanceof Map ) {
+            @SuppressWarnings({ "unchecked", "rawtypes" }) Map<String, List<String>> params =
+                    cast( toMapList( ( Map ) o ) );
+            return fromQueryParams( params );
+        }
+        return null;
+    }
+
+
+    public static Query fromQueryParams( 
+            Map<String, List<String>> params ) throws QueryParseException {
+
+        Query q = null;
+        List<Id> identifiers = null;
+
+        String ql = Query.queryStrFrom( params );
+        String type = first( params.get( "type" ) );
+        Boolean reversed = firstBoolean( params.get( "reversed" ) );
+        String connection = first( params.get( "connection" ) );
+        UUID start = firstUuid( params.get( "start" ) );
+        String cursor = first( params.get( "cursor" ) );
+        Integer limit = firstInteger( params.get( "limit" ) );
+        List<String> permissions = params.get( "permission" );
+        Long startTime = firstLong( params.get( "start_time" ) );
+        Long finishTime = firstLong( params.get( "end_time" ) );
+
+        Boolean pad = firstBoolean( params.get( "pad" ) );
+
+        for ( Entry<String, List<String>> param : params.entrySet() ) {
+            Id identifier = null;
+            if ( ( param.getValue() == null ) || ( param.getValue().size() == 0 ) ) {
+                if ( identifier != null ) {
+                    if ( identifiers == null ) {
+                        identifiers = new ArrayList<Id>();
+                    }
+                    identifiers.add( identifier );
+                }
+            }
+        }
+
+        if ( ql != null ) {
+            q = Query.fromQL( decode( ql ) );
+        }
+
+        List<String> l = params.get( "filter" );
+
+        if ( !isEmpty( l ) ) {
+            q = newQueryIfNull( q );
+            for ( String s : l ) {
+                q.addFilter( decode( s ) );
+            }
+        }
+
+        l = params.get( "sort" );
+        if ( !isEmpty( l ) ) {
+            q = newQueryIfNull( q );
+            for ( String s : l ) {
+                q.addSort( decode( s ) );
+            }
+        }
+
+        if ( type != null ) {
+            q = newQueryIfNull( q );
+            q.setEntityType( type );
+        }
+
+        if ( connection != null ) {
+            q = newQueryIfNull( q );
+            q.setConnectionType( connection );
+        }
+
+        if ( permissions != null ) {
+            q = newQueryIfNull( q );
+            q.setPermissions( permissions );
+        }
+
+        if ( start != null ) {
+            q = newQueryIfNull( q );
+            q.setStartResult( start );
+        }
+
+        if ( cursor != null ) {
+            q = newQueryIfNull( q );
+            q.setCursor( cursor );
+        }
+
+        if ( limit != null ) {
+            q = newQueryIfNull( q );
+            q.setLimit( limit );
+        }
+
+        if ( startTime != null ) {
+            q = newQueryIfNull( q );
+            q.setStartTime( startTime );
+        }
+
+        if ( finishTime != null ) {
+            q = newQueryIfNull( q );
+            q.setFinishTime( finishTime );
+        }
+
+        if ( pad != null ) {
+            q = newQueryIfNull( q );
+            q.setPad( pad );
+        }
+
+        if ( identifiers != null ) {
+            q = newQueryIfNull( q );
+            q.setIdentifiers( identifiers );
+        }
+
+        if ( reversed != null ) {
+            q = newQueryIfNull( q );
+            q.setReversed( reversed );
+        }
+
+        return q;
+    }
+
+
+    public static Query searchForProperty( String propertyName, Object propertyValue ) {
+        Query q = new Query();
+        q.addEqualityFilter( propertyName, propertyValue );
+        return q;
+    }
+
+
+    public static Query findForProperty( String propertyName, Object propertyValue ) {
+        Query q = new Query();
+        q.addEqualityFilter( propertyName, propertyValue );
+        q.setLimit( 1 );
+        return q;
+    }
+
+
+    public static Query fromId( Id id ) {
+        Query q = new Query();
+        q.addIdentifier( id );
+        return q;
+    }
+
+    public boolean hasQueryPredicates() {
+        return rootOperand != null;
+    }
+
+    public Query addSort( SortPredicate sort ) {
+        if ( sort == null ) {
+            return this;
+        }
+
+        for ( SortPredicate s : sortPredicates ) {
+            if ( s.getPropertyName().equals( sort.getPropertyName() ) ) {
+                throw new QueryParseException(
+                    String.format( 
+                        "Attempted to set sort order for %s more than once", s.getPropertyName()));
+            }
+        }
+        sortPredicates.add( sort );
+        return this;
+    }
+
+
+    public Query withReversed( boolean reversed ) {
+        setReversed( reversed );
+        return this;
+    }
+
+
+    public String getEntityType() {
+        return type;
+    }
+
+
+    public void setEntityType( String type ) {
+        this.type = type;
+    }
+
+
+    public String getConnectionType() {
+        return connection;
+    }
+
+
+    public void setConnectionType( String connection ) {
+        this.connection = connection;
+    }
+
+
+    public List<String> getPermissions() {
+        return permissions;
+    }
+
+
+    public void setPermissions( List<String> permissions ) {
+        this.permissions = permissions;
+    }
+
+
+    public Query addSelect( String select ) {
+
+        return addSelect( select, null );
+    }
+
+
+    public Query addSelect( String select, String output ) {
+        // be paranoid with the null checks because
+        // the query parser sometimes flakes out
+        if ( select == null ) {
+            return this;
+        }
+        select = select.trim();
+
+        if ( select.equals( "*" ) ) {
+            return this;
+        }
+
+        mergeSelectResults = StringUtils.isNotEmpty( output );
+
+        if ( output == null ) {
+            output = "";
+        }
+
+        selectAssignments.put( select, output );
+
+        return this;
+    }
+
+
+    public boolean hasSelectSubjects() {
+        return !selectAssignments.isEmpty();
+    }
+
+
+    @JsonIgnore
+    public Set<String> getSelectSubjects() {
+        return selectAssignments.keySet();
+    }
+
+
+    public Map<String, String> getSelectAssignments() {
+        return selectAssignments;
+    }
+
+
+    boolean isMergeSelectResults() {
+        return mergeSelectResults;
+    }
+
+
+    public Query addSort( String propertyName ) {
+        if ( isBlank( propertyName ) ) {
+            return this;
+        }
+        propertyName = propertyName.trim();
+        if ( propertyName.indexOf( ',' ) >= 0 ) {
+            String[] propertyNames = split( propertyName, ',' );
+            for ( String s : propertyNames ) {
+                addSort( s );
+            }
+            return this;
+        }
+
+        SortDirection direction = SortDirection.ASCENDING;
+        if ( propertyName.indexOf( ' ' ) >= 0 ) {
+            String[] parts = split( propertyName, ' ' );
+            if ( parts.length > 1 ) {
+                propertyName = parts[0];
+                direction = SortDirection.find( parts[1] );
+            }
+        }
+        else if ( propertyName.startsWith( "-" ) ) {
+            propertyName = propertyName.substring( 1 );
+            direction = SortDirection.DESCENDING;
+        }
+        else if ( propertyName.startsWith( "+" ) ) {
+            propertyName = propertyName.substring( 1 );
+            direction = SortDirection.ASCENDING;
+        }
+
+        return addSort( propertyName, direction );
+    }
+
+
+    public Query addSort( String propertyName, SortDirection direction ) {
+        if ( isBlank( propertyName ) ) {
+            return this;
+        }
+        propertyName = propertyName.trim();
+        for ( SortPredicate s : sortPredicates ) {
+            if ( s.getPropertyName().equals( propertyName ) ) {
+                logger.error(
+                        "Attempted to set sort order for " + s.getPropertyName() + " more than once, discarding..." );
+                return this;
+            }
+        }
+        sortPredicates.add( new SortPredicate( propertyName, direction ) );
+        return this;
+    }
+
+
+    @JsonIgnore
+    public boolean isSortSet() {
+        return !sortPredicates.isEmpty();
+    }
+
+
+    public List<SortPredicate> getSortPredicates() {
+        return sortPredicates;
+    }
+
+
+    public Query addFilter( String filter ) {
+
+        ANTLRStringStream in = new ANTLRStringStream( filter );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+        Operand root = null;
+
+        try {
+            root = parser.ql().query.getRootOperand();
+        }
+        catch ( RecognitionException e ) {
+            // TODO: should we create a specific Exception for this? checked?
+            throw new RuntimeException( "Unknown operation: " + filter, e );
+        }
+
+        if ( root != null ) {
+            addClause( root );
+        }
+
+        return this;
+    }
+
+
+    /** Add a less than filter to this query. && with existing clauses */
+    public Query addLessThanFilter( String propName, Object value ) {
+        LessThan equality = new LessThan( null );
+
+        addClause( equality, propName, value );
+
+        return this;
+    }
+
+
+    /** Add a less than equal filter to this query. && with existing clauses */
+    public Query addLessThanEqualFilter( String propName, Object value ) {
+        LessThanEqual equality = new LessThanEqual( null );
+
+        addClause( equality, propName, value );
+
+        return this;
+    }
+
+
+    /** Add a equal filter to this query. && with existing clauses */
+    public Query addEqualityFilter( String propName, Object value ) {
+        Equal equality = new Equal( new ClassicToken( 0, "=" ) );
+
+        addClause( equality, propName, value );
+
+        return this;
+    }
+
+
+    /** Add a greater than equal filter to this query. && with existing clauses */
+    public Query addGreaterThanEqualFilter( String propName, Object value ) {
+        GreaterThanEqual equality = new GreaterThanEqual( null );
+
+        addClause( equality, propName, value );
+
+        return this;
+    }
+
+
+    /** Add a less than filter to this query. && with existing clauses */
+    public Query addGreaterThanFilter( String propName, Object value ) {
+        GreaterThan equality = new GreaterThan( null );
+
+        addClause( equality, propName, value );
+
+        return this;
+    }
+
+
+    public Query addContainsFilter( String propName, String keyword ) {
+        ContainsOperand equality = new ContainsOperand( new ClassicToken( 0, "contains" ) );
+
+        equality.setProperty( propName );
+        equality.setLiteral( keyword );
+
+        addClause( equality );
+
+        return this;
+    }
+
+
+    private void addClause( EqualityOperand equals, String propertyName, Object value ) {
+        equals.setProperty( propertyName );
+        equals.setLiteral( value );
+        addClause( equals );
+    }
+
+
+    private void addClause( Operand equals ) {
+
+        if ( rootOperand == null ) {
+            rootOperand = equals;
+            return;
+        }
+
+        AndOperand and = new AndOperand();
+        and.addChild( rootOperand );
+        and.addChild( equals );
+
+        // redirect the root to new && clause
+        rootOperand = and;
+    }
+
+
+    @JsonIgnore
+    public Operand getRootOperand() {
+        if ( rootOperand == null ) { // attempt deserialization
+            if ( ql != null ) {
+                try {
+                    Query q = Query.fromQL( ql );
+                    rootOperand = q.rootOperand;
+                }
+                catch ( QueryParseException e ) {
+                    logger.error( "error parsing sql for rootOperand", e ); // shouldn't happen
+                }
+            }
+        }
+        return rootOperand;
+    }
+
+
+    public void setRootOperand( Operand root ) {
+        this.rootOperand = root;
+    }
+
+
+    void setStartResult( UUID startResult ) {
+        this.startResult = startResult;
+    }
+
+
+    public Query withStartResult( UUID startResult ) {
+        this.startResult = startResult;
+        return this;
+    }
+
+
+    public UUID getStartResult() {
+        if ( ( startResult == null ) && ( cursor != null ) ) {
+            byte[] cursorBytes = decodeBase64( cursor );
+            if ( ( cursorBytes != null ) && ( cursorBytes.length == 16 ) ) {
+                startResult = null; 
+            }
+        }
+        return startResult;
+    }
+
+
+    public String getCursor() {
+        return cursor;
+    }
+
+
+    public void setCursor( String cursor ) {
+        this.cursor = cursor;
+    }
+
+
+    public Query withCursor( String cursor ) {
+        setCursor( cursor );
+        return this;
+    }
+
+
+    public int getLimit() {
+        return getLimit( DEFAULT_LIMIT );
+    }
+
+
+    public int getLimit( int defaultLimit ) {
+        if ( limit <= 0 ) {
+            if ( defaultLimit > 0 ) {
+                return defaultLimit;
+            }
+            else {
+                return DEFAULT_LIMIT;
+            }
+        }
+        return limit;
+    }
+
+
+    public void setLimit( int limit ) {
+
+        //      tnine.  After users have had time to change their query limits,
+        // this needs to be uncommented and enforced.
+        //        if(limit > MAX_LIMIT){
+        //          throw new IllegalArgumentException(String.format("Query limit must be <= to %d", MAX_LIMIT));
+        //        }
+
+        if ( limit > MAX_LIMIT ) {
+            limit = MAX_LIMIT;
+        }
+
+        this.limit = limit;
+    }
+
+
+    public Query withLimit( int limit ) {
+        setLimit( limit );
+        return this;
+    }
+
+
+    public boolean isReversed() {
+        return reversed;
+    }
+
+
+    public void setReversed( boolean reversed ) {
+        reversedSet = true;
+        this.reversed = reversed;
+    }
+
+
+    public boolean isReversedSet() {
+        return reversedSet;
+    }
+
+
+    public Long getStartTime() {
+        return startTime;
+    }
+
+
+    public void setStartTime( Long startTime ) {
+        this.startTime = startTime;
+    }
+
+
+    public Long getFinishTime() {
+        return finishTime;
+    }
+
+
+    public void setFinishTime( Long finishTime ) {
+        this.finishTime = finishTime;
+    }
+
+
+    public boolean isPad() {
+        return pad;
+    }
+
+
+    public void setPad( boolean pad ) {
+        this.pad = pad;
+    }
+
+
+    public void addIdentifier( Id id ) {
+        if ( identifiers == null ) {
+            identifiers = new ArrayList<Id>();
+        }
+        identifiers.add( id );
+    }
+
+
+    void setIdentifiers( List<Id> identifiers ) {
+        this.identifiers = identifiers;
+    }
+
+
+    @Override
+    public String toString() {
+        if ( ql != null ) {
+            return ql;
+        }
+        StringBuilder s = new StringBuilder( "select " );
+        if ( selectAssignments.isEmpty() ) {
+            s.append( "*" );
+        }
+        else {
+            if ( mergeSelectResults ) {
+                s.append( "{ " );
+                boolean first = true;
+                for ( Map.Entry<String, String> select : selectAssignments.entrySet() ) {
+                    if ( !first ) {
+                        s.append( ", " );
+                    }
+                    s.append( select.getValue() ).append( " : " ).append( select.getKey() );
+                    first = false;
+                }
+                s.append( " }" );
+            }
+            else {
+                boolean first = true;
+                for ( String select : selectAssignments.keySet() ) {
+                    if ( !first ) {
+                        s.append( ", " );
+                    }
+                    s.append( select );
+                    first = false;
+                }
+            }
+        }
+        s.append( " from " );
+        s.append( type );
+        if ( !sortPredicates.isEmpty() ) {
+            boolean first = true;
+            s.append( " order by " );
+            for ( SortPredicate sp : sortPredicates ) {
+                if ( !first ) {
+                    s.append( ", " );
+                }
+                s.append( sp );
+                first = false;
+            }
+        }
+        return s.toString();
+    }
+
+
+    public static enum SortDirection {
+        ASCENDING, DESCENDING;
+
+
+        public static SortDirection find( String s ) {
+            if ( s == null ) {
+                return ASCENDING;
+            }
+            s = s.toLowerCase();
+            if ( s.startsWith( "asc" ) ) {
+                return ASCENDING;
+            }
+            if ( s.startsWith( "des" ) ) {
+                return DESCENDING;
+            }
+            if ( s.equals( "+" ) ) {
+                return ASCENDING;
+            }
+            if ( s.equals( "-" ) ) {
+                return DESCENDING;
+            }
+            return ASCENDING;
+        }
+    }
+
+
+    public static final class SortPredicate implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private final String propertyName;
+        private final Query.SortDirection direction;
+
+
+        public SortPredicate( String propertyName, Query.SortDirection direction ) {
+            if ( propertyName == null ) {
+                throw new NullPointerException( "Property name was null" );
+            }
+
+            if ( direction == null ) {
+                direction = SortDirection.ASCENDING;
+            }
+
+            this.propertyName = propertyName.trim();
+            this.direction = direction;
+        }
+
+
+        public SortPredicate( String propertyName, String direction ) {
+            this( propertyName, SortDirection.find( direction ) );
+        }
+
+
+        public String getPropertyName() {
+            return propertyName;
+        }
+
+
+        public Query.SortDirection getDirection() {
+            return direction;
+        }
+
+
+        @Override
+        public boolean equals( Object o ) {
+            if ( this == o ) {
+                return true;
+            }
+            if ( ( o == null ) || ( super.getClass() != o.getClass() ) ) {
+                return false;
+            }
+
+            SortPredicate that = ( SortPredicate ) o;
+
+            if ( direction != that.direction ) {
+                return false;
+            }
+
+            return ( propertyName.equals( that.propertyName ) );
+        }
+
+
+        @Override
+        public int hashCode() {
+            int result = propertyName.hashCode();
+            result = ( 31 * result ) + direction.hashCode();
+            return result;
+        }
+
+
+        @Override
+        public String toString() {
+            return propertyName + ( ( direction == Query.SortDirection.DESCENDING ) ? " DESC" : "" );
+        }
+    }
+
+
+    private static String decode( String input ) {
+        try {
+            return URLDecoder.decode( input, "UTF-8" );
+        }
+        catch ( UnsupportedEncodingException e ) {
+            // shouldn't happen, but just in case
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    // note: very likely to be null
+    public String getCollection() {
+        return collection;
+    }
+
+
+    public void setCollection( String collection ) {
+        this.collection = collection;
+    }
+
+
+    // may be null
+    public String getQl() {
+        return ql;
+    }
+
+
+    public void setQl( String ql ) {
+        this.ql = ql;
+    }
+
+
+    public List<Id> getIdentifiers() {
+        return identifiers;
+    }
+
+
+    public String getConnection() {
+        return connection;
+    }
+
+
+    public String getType() {
+        return type;
+    }
+
+    
+    public static final String PARAM_QL = "ql";
+    public static final String PARAM_Q = "q";
+    public static final String PARAM_QUERY = "query";
+
+    public static String queryStrFrom( Map<String, List<String>> params ) {
+        if ( params.containsKey( PARAM_QL ) ) {
+            return ListUtils.first( params.get( PARAM_QL ) );
+        }
+        else if ( params.containsKey( PARAM_Q ) ) {
+            return ListUtils.first( params.get( PARAM_Q ) );
+        }
+        else if ( params.containsKey( PARAM_QUERY ) ) {
+            return ListUtils.first( params.get( PARAM_QUERY ) );
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/Results.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/Results.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/Results.java
new file mode 100644
index 0000000..7be9f28
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/Results.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.index.query;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import org.apache.usergrid.persistence.collection.EntityCollectionManager;
+import org.apache.usergrid.persistence.index.exceptions.IndexException;
+
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+import org.apache.usergrid.persistence.model.entity.Entity;
+import org.apache.usergrid.persistence.model.entity.Id;
+
+
+@XmlRootElement
+public class Results implements Iterable<Entity> {
+
+    final List<Id> ids;
+    final Query query;
+    final EntityCollectionManager ecm;
+
+    String cursor = null;
+    List<Entity> entities = null;
+    List<EntityRef> refs = null;
+
+    public Results( EntityCollectionManager ecm, Query query, List<Id> ids ) {
+        this.ecm = ecm;
+        this.query = query;
+        this.ids = ids;
+    }
+
+
+    public boolean hasCursor() {
+        return cursor != null;
+    }
+
+
+    public String getCursor() {
+        return cursor;
+    }
+
+
+    public void setCursor(String cursor) {
+        this.cursor = cursor;
+    }
+
+
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    public Query getQuery() {
+        return query;
+    }
+
+
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    public List<Id> getIds() {
+        return Collections.unmodifiableList( ids );
+    }
+
+
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    @SuppressWarnings("unchecked")
+    public List<EntityRef> getRefs() {
+        if ( entities == null ) {
+            getEntities();
+        }
+        return Collections.unmodifiableList( refs );
+    }
+
+
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    public List<Entity> getEntities() {
+        if ( entities == null ) {
+            entities = new ArrayList<Entity>();
+            refs = new ArrayList<EntityRef>();
+            for ( Id id : ids ) {
+                Entity entity = ecm.load( id ).toBlockingObservable().last();
+                if (entity == null) {
+                    throw new IndexException("Entity id [" + id + "] not found");
+                }
+                entities.add( entity );
+                refs.add( new SimpleEntityRef( entity.getId(), entity.getVersion() ));
+            }
+        }
+        return Collections.unmodifiableList( entities );
+    }
+
+
+    public int size() {
+        return ids.size();
+    }
+
+
+    public boolean isEmpty() {
+        return ids.isEmpty();
+    }
+
+
+    @Override
+    public Iterator<Entity> iterator() {
+        return getEntities().iterator();
+    }
+
+    public void setIds(List<Id> ids) {
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/SimpleEntityRef.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/SimpleEntityRef.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/SimpleEntityRef.java
new file mode 100644
index 0000000..34cca44
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/SimpleEntityRef.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.index.query;
+
+
+import java.util.UUID;
+import org.apache.usergrid.persistence.model.entity.Id;
+
+
+public class SimpleEntityRef implements EntityRef {
+
+    private final Id id;
+
+    private final UUID version;
+
+
+    public SimpleEntityRef( Id id, UUID version ) {
+        this.id = id;
+        this.version = version;
+    }
+
+
+    public SimpleEntityRef( EntityRef entityRef ) {
+        this.id = entityRef.getId();
+        this.version = entityRef.getVersion(); 
+    }
+
+
+    public static EntityRef ref() {
+        return new SimpleEntityRef( null, null );
+    }
+
+    public static EntityRef ref( Id id ) {
+        return new SimpleEntityRef( id, null );
+    }
+
+    public static EntityRef ref( Id id, UUID version ) {
+        return new SimpleEntityRef(  id, version );
+    }
+
+
+    public static EntityRef ref( EntityRef ref ) {
+        return new SimpleEntityRef( ref );
+    }
+
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ( ( id == null ) ? 0 : id.hashCode() );
+        result = prime * result + ( ( version == null ) ? 0 : version.hashCode() );
+        return result;
+    }
+
+
+    @Override
+    public boolean equals( Object obj ) {
+        if ( this == obj ) {
+            return true;
+        }
+        if ( obj == null ) {
+            return false;
+        }
+        if ( getClass() != obj.getClass() ) {
+            return false;
+        }
+        SimpleEntityRef other = ( SimpleEntityRef ) obj;
+        if ( id == null ) {
+            if ( other.id != null ) {
+                return false;
+            }
+        }
+        else if ( !id.equals( other.id ) ) {
+            return false;
+        }
+        if ( version == null ) {
+            if ( other.version != null ) {
+                return false;
+            }
+        }
+        else if ( !version.equals( other.version ) ) {
+            return false;
+        }
+        return true;
+    }
+
+
+    @Override
+    public String toString() {
+        return id.toString() + "|" + version.toString();
+    }
+
+    public static Id getId( EntityRef ref ) {
+        if ( ref == null ) {
+            return null;
+        }
+        return ref.getId();
+    }
+
+
+    public static String getType( EntityRef ref ) {
+        if ( ref == null ) {
+            return null;
+        }
+        return ref.getId().getType();
+    }
+
+    public Id getId() {
+        return id;
+    }
+
+    public UUID getVersion() {
+        return version;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/AndOperand.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/AndOperand.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/AndOperand.java
new file mode 100644
index 0000000..88e1d38
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/AndOperand.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.index.query.tree;
+
+
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.Token;
+import org.apache.usergrid.persistence.index.exceptions.PersistenceException;
+
+
+/** @author tnine */
+public class AndOperand extends BooleanOperand {
+
+    public AndOperand() {
+        super( new CommonToken( 0, "and" ) );
+    }
+
+
+    public AndOperand( Token t ) {
+        super( t );
+    }
+
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * org.apache.usergrid.persistence.query.tree.Operand#visit(org.apache.usergrid.persistence
+     * .query.tree.QueryVisitor)
+     */
+    @Override
+    public void visit( QueryVisitor visitor ) throws PersistenceException {
+        visitor.visit( this );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/BooleanLiteral.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/BooleanLiteral.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/BooleanLiteral.java
new file mode 100644
index 0000000..87adeaf
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/BooleanLiteral.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.index.query.tree;
+
+
+import org.antlr.runtime.ClassicToken;
+import org.antlr.runtime.Token;
+
+
+/** @author tnine */
+public class BooleanLiteral extends Literal<Boolean> {
+
+    private boolean value;
+
+
+    /**
+     * @param t
+     */
+    protected BooleanLiteral( Token t ) {
+        super( t );
+        value = Boolean.valueOf( t.getText() );
+    }
+
+
+    /** The boolean literal */
+    public BooleanLiteral( boolean value ) {
+        super( new ClassicToken( 0, String.valueOf( value ) ) );
+        this.value = value;
+    }
+
+
+    public Boolean getValue() {
+        return value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8f969d8d/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/BooleanOperand.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/BooleanOperand.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/BooleanOperand.java
new file mode 100644
index 0000000..9c5324c
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/BooleanOperand.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.index.query.tree;
+
+
+import org.antlr.runtime.Token;
+
+
+/**
+ * A base class for any equality expression.  Expressions must have a property and a value. Examples are >=, >, =, <,
+ * <=,
+ *
+ * @author tnine
+ */
+public abstract class BooleanOperand extends Operand {
+
+
+    /**
+     * @param property
+     * @param literal
+     */
+    public BooleanOperand( Token t ) {
+        super( t );
+    }
+
+
+    public Operand getLeft() {
+        return ( Operand ) this.children.get( 0 );
+    }
+
+
+    public Operand getRight() {
+        return ( Operand ) this.children.get( 1 );
+    }
+}