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 18:21:03 UTC
[16/27] 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/heads/entity-manager
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 );
+ }
+}