usergrid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From toddn...@apache.org
Subject [02/33] incubator-usergrid git commit: Removed obsolete query object. Now a single utility builder and a ParsedQuery that represents our result
Date Mon, 13 Apr 2015 19:18:09 GMT
Removed obsolete query object.   Now a single utility builder and a ParsedQuery that represents our result

Some tests are failing due to case sensitivity.  This is due to indexing.  This will be fixed later.


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

Branch: refs/heads/two-dot-o-dev
Commit: 2699dd30fdf4bedb939a6eabfaef787a863121f6
Parents: 3c0a8a8
Author: Todd Nine <tnine@apigee.com>
Authored: Wed Apr 1 16:05:19 2015 -0600
Committer: Todd Nine <tnine@apigee.com>
Committed: Wed Apr 1 16:35:35 2015 -0600

----------------------------------------------------------------------
 stack/corepersistence/pom.xml                   |    2 +-
 .../index/query/tree/CpQueryFilter.g            |   20 +-
 .../index/ApplicationEntityIndex.java           |    9 +-
 .../usergrid/persistence/index/EntityIndex.java |    9 -
 .../impl/EsApplicationEntityIndexImpl.java      |   78 +-
 .../impl/SearchRequestBuilderStrategy.java      |   37 +-
 .../persistence/index/query/ParsedQuery.java    |  204 +++
 .../index/query/ParsedQueryBuilder.java         |  108 ++
 .../usergrid/persistence/index/query/Query.java | 1432 ------------------
 .../index/query/SelectFieldMapping.java         |   55 +
 .../persistence/index/query/SortPredicate.java  |  126 ++
 .../persistence/index/impl/EntityIndexTest.java |  334 ++--
 .../index/impl/IndexLoadTestsIT.java            |    5 +-
 .../persistence/query/tree/GrammarTreeTest.java |  155 +-
 14 files changed, 838 insertions(+), 1736 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2699dd30/stack/corepersistence/pom.xml
----------------------------------------------------------------------
diff --git a/stack/corepersistence/pom.xml b/stack/corepersistence/pom.xml
index 3ec7852..b8227f7 100644
--- a/stack/corepersistence/pom.xml
+++ b/stack/corepersistence/pom.xml
@@ -50,7 +50,7 @@ limitations under the License.
         <maven.compiler.source>1.8</maven.compiler.source>
         <maven.compiler.target>1.8</maven.compiler.target>
 
-        <antlr.version>3.4</antlr.version>
+        <antlr.version>3.5.2</antlr.version>
         <archaius.version>0.5.12</archaius.version>
         <astyanax.version>1.56.49-SNAPSHOT-UG-1</astyanax.version>
         <cassandra.version>1.2.18</cassandra.version>

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2699dd30/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/CpQueryFilter.g
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/CpQueryFilter.g b/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/CpQueryFilter.g
index f1ae62f..605aed4 100644
--- a/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/CpQueryFilter.g
+++ b/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/CpQueryFilter.g
@@ -31,18 +31,20 @@ 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;
+import org.apache.usergrid.persistence.index.query.ParsedQuery;
+import org.apache.usergrid.persistence.index.query.SortPredicate;
 
 }
 
 
 @members {
-	Query query = new Query();
 
   private static final Logger logger = LoggerFactory
       .getLogger(CpQueryFilterLexer.class);
 
+   //the object that represents a parsed query
+   private ParsedQuery parsedQuery = new ParsedQuery();
+
 	@Override
 	public void emitErrorMessage(String msg) {
 		logger.info(msg);
@@ -300,7 +302,7 @@ order
   : (property direction?){
 		String property = $property.text; 
 		String direction = $direction.text;
-		query.addSort(new SortPredicate(property, direction));
+		parsedQuery.addSort(new SortPredicate(property, direction));
     
   };
 
@@ -311,7 +313,7 @@ order
 select_subject
   : ID {
 
-  query.addSelect($ID.text);
+  parsedQuery.addSelect($ID.text);
 
 };
 
@@ -320,7 +322,7 @@ select_subject
 select_assign
   : target=ID ':' source=ID {
 
-  query.addSelect($target.text, $source.text);
+  parsedQuery.addSelect($target.text, $source.text);
 
 };
 
@@ -329,14 +331,14 @@ select_expr
    
 //end select clauses
 
-ql returns [Query query]
+ql returns [ParsedQuery parsedQuery]
   : ('select'! select_expr!)? ('where'!? expression)? ('order by'! order! (','! order!)*)? {
 
   if($expression.tree instanceof Operand){
-    query.setRootOperand((Operand)$expression.tree);
+    parsedQuery.setRootOperand((Operand)$expression.tree);
   }
   
-  retval.query = query;
+  retval.parsedQuery = parsedQuery;
 
 
 };

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2699dd30/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/ApplicationEntityIndex.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/ApplicationEntityIndex.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/ApplicationEntityIndex.java
index c78d6b6..595cd66 100644
--- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/ApplicationEntityIndex.java
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/ApplicationEntityIndex.java
@@ -19,8 +19,9 @@
  */
 package org.apache.usergrid.persistence.index;
 
+
 import org.apache.usergrid.persistence.index.query.CandidateResults;
-import org.apache.usergrid.persistence.index.query.Query;
+
 import rx.Observable;
 
 /**
@@ -34,11 +35,7 @@ public interface ApplicationEntityIndex {
      */
     public EntityIndexBatch createBatch();
 
-    /**
-     * Execute query in Usergrid syntax.
-     */
-    public CandidateResults search(final IndexScope indexScope, final SearchTypes searchTypes, final Query query);
-    public CandidateResults search(final IndexScope indexScope, final SearchTypes searchTypes, final Query query, final int limit);
+    public CandidateResults search(final IndexScope indexScope, final SearchTypes searchTypes, final String query, final int limit);
 
 
 

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2699dd30/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java
index 54a4127..7693b61 100644
--- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java
@@ -19,18 +19,9 @@
 
 package org.apache.usergrid.persistence.index;
 
-import java.util.UUID;
 
 import org.apache.usergrid.persistence.core.CPManager;
 import org.apache.usergrid.persistence.core.util.Health;
-import org.apache.usergrid.persistence.index.query.Query;
-import org.apache.usergrid.persistence.index.query.CandidateResults;
-import org.apache.usergrid.persistence.model.entity.Id;
-import org.elasticsearch.action.ListenableActionFuture;
-import rx.Observable;
-
-import java.util.Map;
-import java.util.concurrent.Future;
 
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2699dd30/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsApplicationEntityIndexImpl.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsApplicationEntityIndexImpl.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsApplicationEntityIndexImpl.java
index 25b926d..dfe1c85 100644
--- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsApplicationEntityIndexImpl.java
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsApplicationEntityIndexImpl.java
@@ -19,24 +19,12 @@
  */
 package org.apache.usergrid.persistence.index.impl;
 
-import com.codahale.metrics.Meter;
-import com.codahale.metrics.Timer;
-import com.google.common.base.Preconditions;
-import com.google.inject.Inject;
-import com.google.inject.assistedinject.Assisted;
-import org.apache.usergrid.persistence.core.metrics.MetricsFactory;
-import org.apache.usergrid.persistence.core.scope.ApplicationScope;
-import org.apache.usergrid.persistence.core.util.ValidationUtils;
-import org.apache.usergrid.persistence.index.*;
-import org.apache.usergrid.persistence.index.query.CandidateResult;
-import org.apache.usergrid.persistence.index.query.CandidateResults;
-import org.apache.usergrid.persistence.index.query.Query;
-import org.apache.usergrid.persistence.map.MapManager;
-import org.apache.usergrid.persistence.map.MapManagerFactory;
-import org.apache.usergrid.persistence.map.MapScope;
-import org.apache.usergrid.persistence.map.impl.MapScopeImpl;
-import org.apache.usergrid.persistence.model.entity.Id;
-import org.apache.usergrid.persistence.model.entity.SimpleId;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
 import org.elasticsearch.action.ActionListener;
 import org.elasticsearch.action.ListenableActionFuture;
 import org.elasticsearch.action.ShardOperationFailedException;
@@ -45,17 +33,47 @@ import org.elasticsearch.action.deletebyquery.IndexDeleteByQueryResponse;
 import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.action.search.SearchScrollRequestBuilder;
-import org.elasticsearch.index.query.*;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.index.query.TermQueryBuilder;
 import org.elasticsearch.search.SearchHit;
 import org.elasticsearch.search.SearchHits;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import rx.Observable;
 
-import java.util.*;
-import java.util.concurrent.TimeUnit;
+import org.apache.usergrid.persistence.core.metrics.MetricsFactory;
+import org.apache.usergrid.persistence.core.scope.ApplicationScope;
+import org.apache.usergrid.persistence.core.util.ValidationUtils;
+import org.apache.usergrid.persistence.index.AliasedEntityIndex;
+import org.apache.usergrid.persistence.index.ApplicationEntityIndex;
+import org.apache.usergrid.persistence.index.EntityIndexBatch;
+import org.apache.usergrid.persistence.index.IndexAlias;
+import org.apache.usergrid.persistence.index.IndexBufferProducer;
+import org.apache.usergrid.persistence.index.IndexCache;
+import org.apache.usergrid.persistence.index.IndexFig;
+import org.apache.usergrid.persistence.index.IndexIdentifier;
+import org.apache.usergrid.persistence.index.IndexScope;
+import org.apache.usergrid.persistence.index.SearchTypes;
+import org.apache.usergrid.persistence.index.query.CandidateResult;
+import org.apache.usergrid.persistence.index.query.CandidateResults;
+import org.apache.usergrid.persistence.index.query.ParsedQuery;
+import org.apache.usergrid.persistence.index.query.ParsedQueryBuilder;
+import org.apache.usergrid.persistence.map.MapManager;
+import org.apache.usergrid.persistence.map.MapManagerFactory;
+import org.apache.usergrid.persistence.map.MapScope;
+import org.apache.usergrid.persistence.map.impl.MapScopeImpl;
+import org.apache.usergrid.persistence.model.entity.Id;
+import org.apache.usergrid.persistence.model.entity.SimpleId;
+
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.Timer;
+import com.google.common.base.Preconditions;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
 
-import static org.apache.usergrid.persistence.index.impl.IndexingUtils.*;
+import rx.Observable;
+
+import static org.apache.usergrid.persistence.index.impl.IndexingUtils.APPLICATION_ID_FIELDNAME;
 import static org.apache.usergrid.persistence.index.impl.IndexingUtils.SPLITTER;
 
 /**
@@ -123,19 +141,15 @@ public class EsApplicationEntityIndexImpl implements ApplicationEntityIndex{
     }
 
     @Override
-    public CandidateResults search(final IndexScope indexScope, final SearchTypes searchTypes, final Query query) {
-        return search(indexScope,searchTypes,query,query.getLimit());
-    }
-    @Override
-    public CandidateResults search(final IndexScope indexScope, final SearchTypes searchTypes, final Query query, final int limit){
+      public CandidateResults search( final IndexScope indexScope, final SearchTypes searchTypes, final String query,
+                                      final int limit ) {
 
-        if(query.getCursor()!=null){
-            return getNextPage(query.getCursor(), query.getLimit());
-        }
 
         SearchResponse searchResponse;
 
-        SearchRequestBuilder srb = searchRequest.getBuilder(indexScope, searchTypes, query,limit);
+        final ParsedQuery parsedQuery = ParsedQueryBuilder.build( query );
+
+        final SearchRequestBuilder srb = searchRequest.getBuilder(indexScope, searchTypes, parsedQuery,limit);
 
         if (logger.isDebugEnabled()) {
             logger.debug("Searching index (read alias): {}\n  scope: {} \n type: {}\n   query: {} ",

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2699dd30/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/SearchRequestBuilderStrategy.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/SearchRequestBuilderStrategy.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/SearchRequestBuilderStrategy.java
index 207a7a8..8a378b8 100644
--- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/SearchRequestBuilderStrategy.java
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/SearchRequestBuilderStrategy.java
@@ -19,13 +19,7 @@
  */
 package org.apache.usergrid.persistence.index.impl;
 
-import com.google.common.base.Preconditions;
-import org.apache.usergrid.persistence.core.scope.ApplicationScope;
-import org.apache.usergrid.persistence.core.util.ValidationUtils;
-import org.apache.usergrid.persistence.index.*;
-import org.apache.usergrid.persistence.index.exceptions.IndexException;
-import org.apache.usergrid.persistence.index.query.Query;
-import org.apache.usergrid.persistence.index.query.tree.QueryVisitor;
+
 import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.index.query.BoolQueryBuilder;
 import org.elasticsearch.index.query.FilterBuilder;
@@ -37,7 +31,22 @@ import org.elasticsearch.search.sort.SortOrder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.usergrid.persistence.index.impl.IndexingUtils.*;
+import org.apache.usergrid.persistence.core.scope.ApplicationScope;
+import org.apache.usergrid.persistence.index.EntityIndex;
+import org.apache.usergrid.persistence.index.IndexAlias;
+import org.apache.usergrid.persistence.index.IndexScope;
+import org.apache.usergrid.persistence.index.SearchTypes;
+import org.apache.usergrid.persistence.index.exceptions.IndexException;
+import org.apache.usergrid.persistence.index.query.ParsedQuery;
+import org.apache.usergrid.persistence.index.query.SortPredicate;
+import org.apache.usergrid.persistence.index.query.tree.QueryVisitor;
+
+import com.google.common.base.Preconditions;
+
+import static org.apache.usergrid.persistence.index.impl.IndexingUtils.BOOLEAN_PREFIX;
+import static org.apache.usergrid.persistence.index.impl.IndexingUtils.DOUBLE_PREFIX;
+import static org.apache.usergrid.persistence.index.impl.IndexingUtils.LONG_PREFIX;
+import static org.apache.usergrid.persistence.index.impl.IndexingUtils.STRING_PREFIX;
 import static org.apache.usergrid.persistence.index.impl.IndexingUtils.createContextName;
 import static org.apache.usergrid.persistence.index.impl.IndexingUtils.createLegacyContextName;
 
@@ -62,7 +71,7 @@ public class SearchRequestBuilderStrategy {
         this.cursorTimeout = cursorTimeout;
     }
 
-    public SearchRequestBuilder getBuilder(final IndexScope indexScope, final SearchTypes searchTypes, final Query query,  final int limit) {
+    public SearchRequestBuilder getBuilder(final IndexScope indexScope, final SearchTypes searchTypes, final ParsedQuery query,  final int limit) {
 
         Preconditions.checkArgument(limit <= EntityIndex.MAX_LIMIT, "limit is greater than max "+ EntityIndex.MAX_LIMIT);
 
@@ -82,10 +91,10 @@ public class SearchRequestBuilderStrategy {
 
         srb = srb.setFrom(0).setSize(limit);
 
-        for (Query.SortPredicate sp : query.getSortPredicates()) {
+        for (SortPredicate sp : query.getSortPredicates()) {
 
             final SortOrder order;
-            if (sp.getDirection().equals(Query.SortDirection.ASCENDING)) {
+            if (sp.getDirection().equals( SortPredicate.SortDirection.ASCENDING)) {
                 order = SortOrder.ASC;
             } else {
                 order = SortOrder.DESC;
@@ -127,7 +136,7 @@ public class SearchRequestBuilderStrategy {
     }
 
 
-    public QueryBuilder createQueryBuilder( IndexScope indexScope, Query query) {
+    public QueryBuilder createQueryBuilder( IndexScope indexScope, ParsedQuery query) {
         String[] contexts = new String[]{createContextName(applicationScope, indexScope),createLegacyContextName(applicationScope,indexScope)};
 
         QueryBuilder queryBuilder = null;
@@ -161,7 +170,7 @@ public class SearchRequestBuilderStrategy {
         for(String context : contexts){
             boolQueryBuilder = boolQueryBuilder.should(QueryBuilders.termQuery( IndexingUtils.ENTITY_CONTEXT_FIELDNAME, context ));
         }
-        boolQueryBuilder = boolQueryBuilder.minimumNumberShouldMatch(1);
+        boolQueryBuilder = boolQueryBuilder.minimumNumberShouldMatch( 1 );
         if ( queryBuilder != null ) {
             queryBuilder =  boolQueryBuilder.must( queryBuilder );
         }
@@ -175,7 +184,7 @@ public class SearchRequestBuilderStrategy {
     }
 
 
-    public FilterBuilder createFilterBuilder(Query query) {
+    public FilterBuilder createFilterBuilder(ParsedQuery query) {
         FilterBuilder filterBuilder = null;
 
         if ( query.getRootOperand() != null ) {

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2699dd30/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/ParsedQuery.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/ParsedQuery.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/ParsedQuery.java
new file mode 100644
index 0000000..a55f8ea
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/ParsedQuery.java
@@ -0,0 +1,204 @@
+/*
+ *
+ *  *
+ *  * Licensed to the Apache Software Foundation (ASF) under one
+ *  * or more contributor license agreements.  See the NOTICE file
+ *  * distributed with this work for additional information
+ *  * regarding copyright ownership.  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.
+ *  *
+ *
+ */
+
+package org.apache.usergrid.persistence.index.query;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.usergrid.persistence.index.exceptions.QueryParseException;
+import org.apache.usergrid.persistence.index.query.tree.Operand;
+
+
+/**
+ * Our object that represents our parsed query
+ */
+public class ParsedQuery {
+
+    //fast lookup for our sort predicates
+    private Set<String> sortPropertyNames = new HashSet<>();
+
+    //The sort predicates ordered by their input order in the grammar
+    private List<SortPredicate> sortPredicateList = new ArrayList<>();
+
+    /**
+     * Our map that contains field mappings
+     */
+    private Map<String, SelectFieldMapping> fieldMappings = new HashMap<>();
+
+    /**
+     * The root operand of our query
+     */
+    private Operand rootOperand;
+
+    private String originalQuery;
+
+
+    /**
+     * Get the original query
+     * @return
+     */
+    public String getOriginalQuery() {
+        return originalQuery;
+    }
+
+
+    /**
+     * Set the original query
+     * @param originalQuery
+     */
+    public void setOriginalQuery( final String originalQuery ) {
+        this.originalQuery = originalQuery;
+    }
+
+
+    /**
+     * Set the root operand of our query tree
+     * @param rootOperand
+     * @return
+     */
+    public ParsedQuery setRootOperand(final Operand rootOperand){
+        this.rootOperand = rootOperand;
+
+        return this;
+    }
+
+
+    /**
+     * Get our field mappings from the parsed query
+     * @return
+     */
+    public Collection<SelectFieldMapping> getSelectFieldMappings(){
+        return fieldMappings.values();
+    }
+
+    /**
+     * Add a sort predicate to our list
+     */
+    public ParsedQuery addSort( final SortPredicate sort ) {
+        if ( sort == null ) {
+            return this;
+        }
+
+        final String sortPropertyName = sort.getPropertyName();
+
+        if ( sortPropertyNames.contains( sortPropertyName ) ) {
+            throw new QueryParseException(
+                    String.format( "Attempted to set sort order for %s more than once", sort.getPropertyName() ) );
+        }
+
+
+        sortPredicateList.add( sort );
+        sortPropertyNames.add( sortPropertyName );
+
+        return this;
+    }
+
+
+    /**
+     * Get the list of sort predicates
+     * @return
+     */
+    public List<SortPredicate> getSortPredicates() {
+        return sortPredicateList;
+    }
+
+
+    /**
+     * Possiblly add a single select to our results
+     */
+    public ParsedQuery addSelect( final String select ) {
+
+        final String normalizedSelect = getSelect( select );
+
+        if ( normalizedSelect == null ) {
+            return this;
+        }
+
+        fieldMappings.put( select, new SelectFieldMapping( normalizedSelect, normalizedSelect ) );
+
+        return this;
+    }
+
+
+    /**
+     * Use this when the user does a "select id:mynewidname " in the select clause of the grammar
+     * @param select
+     * @param output
+     * @return
+     */
+    public ParsedQuery addSelect( final String select, final String output ) {
+        final String normalizedSelect = getSelect( select );
+
+        if ( normalizedSelect == null ) {
+            return this;
+        }
+
+        final String normalizedOutput = getSelect( output );
+
+        if ( normalizedOutput == null ) {
+            return this;
+        }
+
+
+        fieldMappings.put( select, new SelectFieldMapping( normalizedSelect, normalizedOutput ) );
+
+        return this;
+    }
+
+
+    /**
+     * Get the field for select.  This trims the field and validates the input.  If the field is not valid, null willl
+     * be returned.  If null is returned, the caller should short circuit.
+     */
+    private String getSelect( final String select ) {
+        // be paranoid with the null checks because
+        // the query parser sometimes flakes out
+        if ( select == null ) {
+            return null;
+        }
+
+        final String trimmedSelect = select.trim();
+
+        if ( trimmedSelect.equals( "*" ) ) {
+            return null;
+        }
+
+        return trimmedSelect;
+    }
+
+
+    /**
+     * Get the root operand
+     * @return
+     */
+    public Operand getRootOperand() {
+        return rootOperand;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2699dd30/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/ParsedQueryBuilder.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/ParsedQueryBuilder.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/ParsedQueryBuilder.java
new file mode 100644
index 0000000..3498f3c
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/ParsedQueryBuilder.java
@@ -0,0 +1,108 @@
+/*
+ *
+ *  *
+ *  * Licensed to the Apache Software Foundation (ASF) under one
+ *  * or more contributor license agreements.  See the NOTICE file
+ *  * distributed with this work for additional information
+ *  * regarding copyright ownership.  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.
+ *  *
+ *
+ */
+
+package org.apache.usergrid.persistence.index.query;
+
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.commons.lang.StringUtils;
+
+import org.apache.usergrid.persistence.index.exceptions.QueryParseException;
+import org.apache.usergrid.persistence.index.query.tree.CpQueryFilterLexer;
+import org.apache.usergrid.persistence.index.query.tree.CpQueryFilterParser;
+
+
+/**
+ * A utility class that will parse our query, then return it's parsed representation
+ */
+public class ParsedQueryBuilder {
+
+    private static final Logger logger = LoggerFactory.getLogger( ParsedQueryBuilder.class );
+
+
+    /**
+     * Generate a parsedQuery from the ql
+     */
+    public static ParsedQuery build( final String ql ) throws QueryParseException {
+        if ( StringUtils.isEmpty( ql ) ) {
+            return null;
+        }
+        logger.debug( "Processing raw query: " + ql );
+
+        final String trimmedLowercaseQuery = ql.trim().toLowerCase();
+
+
+        //the output query after post processing
+        final String outputQuery;
+
+        //it doesn't start with select, rewrite it to be a correct query grammar
+        if ( !trimmedLowercaseQuery.startsWith( "select" ) ) {
+
+            //just an order by, add the select
+            //just starts with a where, add the select
+            if ( trimmedLowercaseQuery.startsWith( "order by" ) || trimmedLowercaseQuery.startsWith( "where" )) {
+                outputQuery = "select * " + trimmedLowercaseQuery;
+            }
+
+
+            //junk, bail
+            else {
+               outputQuery = "select * where" + trimmedLowercaseQuery;
+            }
+        }
+        else {
+            outputQuery = trimmedLowercaseQuery;
+        }
+
+        ANTLRStringStream in = new ANTLRStringStream( outputQuery );
+        CpQueryFilterLexer lexer = new CpQueryFilterLexer( in );
+        CommonTokenStream tokens = new CommonTokenStream( lexer );
+        CpQueryFilterParser parser = new CpQueryFilterParser( tokens );
+
+
+        try {
+            final ParsedQuery query = parser.ql().parsedQuery;
+            query.setOriginalQuery( ql );
+            return query;
+        }
+        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 );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2699dd30/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
deleted file mode 100644
index 5567382..0000000
--- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/Query.java
+++ /dev/null
@@ -1,1432 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * 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.
- */
-package org.apache.usergrid.persistence.index.query;
-
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-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 com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import java.io.IOException;
-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 org.apache.commons.codec.binary.Base64;
-import org.apache.commons.lang.StringUtils;
-import org.apache.usergrid.persistence.index.exceptions.IndexException;
-import org.apache.usergrid.persistence.index.exceptions.QueryParseException;
-import org.apache.usergrid.persistence.index.impl.EsQueryVistor;
-import org.apache.usergrid.persistence.index.impl.IndexingUtils;
-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.CpQueryFilterLexer;
-import org.apache.usergrid.persistence.index.query.tree.CpQueryFilterParser;
-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.QueryVisitor;
-import org.apache.usergrid.persistence.index.utils.ClassUtils;
-import org.apache.usergrid.persistence.index.utils.ConversionUtils;
-import org.apache.usergrid.persistence.index.utils.ListUtils;
-import org.apache.usergrid.persistence.index.utils.MapUtils;
-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;
-
-
-/**
- * TODO, this is a copy from 1.0 and a mess.  Clean this up to be clearer as we iterate on our refactor of EM/RM
- * Query should only be used for term querying, not identity of name lookup, that should
- * come directly from cassandra
- */
-public class Query {
-    private static final Logger logger = LoggerFactory.getLogger( Query.class );
-
-    public enum Level {
-        IDS, REFS, CORE_PROPERTIES, ALL_PROPERTIES, LINKED_PROPERTIES
-    }
-
-    public static final int DEFAULT_LIMIT = 10;
-
-    public static final int MAX_LIMIT = 1000;
-
-    public static final String PROPERTY_UUID = "uuid";
-
-    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 Level level = Level.ALL_PROPERTIES;
-    private String connectionType;
-    private List<String> permissions;
-    private boolean reversed;
-    private boolean reversedSet = false;
-    private Long startTime;
-    private Long finishTime;
-    private boolean pad;
-    private CounterResolution resolution = CounterResolution.ALL;
-    private List<Identifier> identifiers;
-    private List<CounterFilterPredicate> counterFilters;
-    private String collection;
-    private String ql;
-
-    private static ObjectMapper mapper = new ObjectMapper();
-
-
-    List<Operand> filterClauses = new ArrayList<Operand>();
-
-    public Query() {
-    }
-
-
-    /**
-     * Creates a deep copy of a query from another query
-     * @param q
-     */
-    public Query( Query q ) {
-        if ( q == null ) {
-            return;
-        }
-
-        type = q.type;
-        sortPredicates = q.sortPredicates != null
-            ? new ArrayList<>( q.sortPredicates ) : null;
-        startResult = q.startResult;
-        cursor = q.cursor;
-        limit = q.limit;
-        selectAssignments = q.selectAssignments != null
-            ? new LinkedHashMap<>( q.selectAssignments ) : null;
-        mergeSelectResults = q.mergeSelectResults;
-        //level = q.level;
-        connectionType = q.connectionType;
-        permissions = q.permissions != null ? new ArrayList<>( q.permissions ) : null;
-        reversed = q.reversed;
-        reversedSet = q.reversedSet;
-        startTime = q.startTime;
-        finishTime = q.finishTime;
-        resolution = q.resolution;
-        pad = q.pad;
-        rootOperand = q.rootOperand;
-        identifiers = q.identifiers != null
-            ? new ArrayList<>( q.identifiers ) : null;
-        counterFilters = q.counterFilters != null
-            ? new ArrayList<>( q.counterFilters ) : null;
-        collection = q.collection;
-        level = q.level;
-
-    }
-
-
-    public QueryBuilder createQueryBuilder( final String context ) {
-
-
-        QueryBuilder queryBuilder = null;
-
-
-        //we have a root operand.  Translate our AST into an ES search
-        if ( getRootOperand() != null ) {
-            // In the case of geo only queries, this will return null into the query builder.
-            // Once we start using tiles, we won't need this check any longer, since a geo query
-            // will return a tile query + post filter
-            QueryVisitor v = new EsQueryVistor();
-
-            try {
-                getRootOperand().visit( v );
-            }
-            catch ( IndexException ex ) {
-                throw new RuntimeException( "Error building ElasticSearch query", ex );
-            }
-
-
-            queryBuilder = v.getQueryBuilder();
-        }
-
-
-        // Add our filter for context to our query for fast execution.
-        // Fast because it utilizes bitsets internally. See this post for more detail.
-        // http://www.elasticsearch.org/blog/all-about-elasticsearch-filter-bitsets/
-
-        // TODO evaluate performance when it's an all query.
-        // Do we need to put the context term first for performance?
-        if ( queryBuilder != null ) {
-            queryBuilder = QueryBuilders.boolQuery().must( queryBuilder ).must( QueryBuilders
-                .termQuery( IndexingUtils.ENTITY_CONTEXT_FIELDNAME, context ) );
-        }
-
-        //nothing was specified ensure we specify the context in the search
-        else {
-            queryBuilder = QueryBuilders.termQuery( IndexingUtils.ENTITY_CONTEXT_FIELDNAME, context );
-        }
-
-        return queryBuilder;
-    }
-
-
-    public FilterBuilder createFilterBuilder() {
-        FilterBuilder filterBuilder = null;
-
-        if ( getRootOperand() != null ) {
-            QueryVisitor v = new EsQueryVistor();
-            try {
-                getRootOperand().visit( v );
-
-            } catch ( IndexException ex ) {
-                throw new RuntimeException( "Error building ElasticSearch query", ex );
-            }
-            filterBuilder = v.getFilterBuilder();
-        }
-
-        return filterBuilder;
-    }
-
-
-    /**
-     * Create a query instance from the QL.  If the string is null, return an empty query
-     * @param ql
-     * @return
-     */
-    public static Query fromQLNullSafe(final String ql){
-        final Query query = fromQL(ql);
-
-        if(query != null){
-            return query;
-        }
-
-        return new Query();
-    }
-
-    public static Query fromQL( String ql ) throws QueryParseException {
-        if ( StringUtils.isEmpty(ql) ) {
-            return null;
-        }
-        logger.debug("Processing raw query: " + ql);
-        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().toLowerCase() );
-        CpQueryFilterLexer lexer = new CpQueryFilterLexer( in );
-        CommonTokenStream tokens = new CommonTokenStream( lexer );
-        CpQueryFilterParser parser = new CpQueryFilterParser( 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;
-        try {
-            o = mapper.readValue( json, Object.class );
-        } catch (IOException ex) {
-            throw new QueryParseException("Error parsing JSON query string " + json, ex);
-        }
-
-        if ( o instanceof Map ) {
-            @SuppressWarnings({ "unchecked", "rawtypes" }) Map<String, List<String>> params =
-                ClassUtils.cast( MapUtils.toMapList( ( Map ) o ) );
-            return fromQueryParams( params );
-        }
-        return null;
-    }
-
-
-    public static Query fromQueryParams( Map<String, List<String>> params )
-        throws QueryParseException {
-        Query q = null;
-        CounterResolution resolution = null;
-        List<Identifier> identifiers = null;
-        List<CounterFilterPredicate> counterFilters = null;
-
-        String ql = QueryUtils.queryStrFrom( params );
-        String type = ListUtils.first( params.get( "type" ) );
-        Boolean reversed = ListUtils.firstBoolean( params.get( "reversed" ) );
-        String connection = ListUtils.first( params.get( "connectionType" ) );
-        UUID start = ListUtils.firstUuid( params.get( "start" ) );
-        String cursor = ListUtils.first( params.get( "cursor" ) );
-        Integer limit = ListUtils.firstInteger( params.get( "limit" ) );
-        List<String> permissions = params.get( "permission" );
-        Long startTime = ListUtils.firstLong( params.get( "start_time" ) );
-        Long finishTime = ListUtils.firstLong( params.get( "end_time" ) );
-
-        List<String> l = params.get( "resolution" );
-        if ( !ListUtils.isEmpty( l ) ) {
-            resolution = CounterResolution.fromString( l.get( 0 ) );
-        }
-
-        l = params.get( "counter" );
-
-        if ( !ListUtils.isEmpty( l ) ) {
-            counterFilters = CounterFilterPredicate.fromList( l );
-        }
-
-        Boolean pad = ListUtils.firstBoolean( params.get( "pad" ) );
-
-        for ( Entry<String, List<String>> param : params.entrySet() ) {
-            Identifier identifier = Identifier.from( param.getKey() );
-            if ( ( param.getValue() == null ) || ( param.getValue().size() == 0 ) || identifier.isUUID() ) {
-                if ( identifier != null ) {
-                    if ( identifiers == null ) {
-                        identifiers = new ArrayList<Identifier>();
-                    }
-                    identifiers.add( identifier );
-                }
-            }
-        }
-
-        if ( ql != null ) {
-            q = Query.fromQL( decode( ql ) );
-        }
-
-        l = params.get( "filter" );
-
-        if ( !ListUtils.isEmpty( l ) ) {
-            q = newQueryIfNull( q );
-            for ( String s : l ) {
-                q.addFilter( decode( s ) );
-            }
-        }
-
-        l = params.get( "sort" );
-        if ( !ListUtils.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 ( resolution != null ) {
-            q = newQueryIfNull( q );
-            q.setResolution( resolution );
-        }
-
-        if ( counterFilters != null ) {
-            q = newQueryIfNull( q );
-            q.setCounterFilters( counterFilters );
-        }
-
-        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 fromUUID( UUID uuid ) {
-        Query q = new Query();
-        q.addIdentifier( Identifier.fromUUID( uuid ) );
-        return q;
-    }
-
-
-    public static Query fromIdentifier( Object id ) {
-        Query q = new Query();
-        q.addIdentifier( Identifier.from( id ) );
-        return q;
-    }
-
-
-    public boolean hasQueryPredicates() {
-        return rootOperand != null;
-    }
-
-
-    public boolean containsNameOrEmailIdentifiersOnly() {
-        if ( hasQueryPredicates() ) {
-            return false;
-        }
-        if ( ( identifiers == null ) || identifiers.isEmpty() ) {
-            return false;
-        }
-        for ( Identifier identifier : identifiers ) {
-            if ( !identifier.isEmail() && !identifier.isName() ) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-
-    @JsonIgnore
-    public String getSingleNameOrEmailIdentifier() {
-        if ( !containsSingleNameOrEmailIdentifier() ) {
-            return null;
-        }
-        return ( identifiers.get( 0 ).toString() );
-    }
-
-
-    public boolean containsSingleNameOrEmailIdentifier() {
-        return containsNameOrEmailIdentifiersOnly() && ( identifiers.size() == 1 );
-    }
-
-
-    @JsonIgnore
-    public Identifier getSingleIdentifier() {
-        return identifiers != null && identifiers.size() == 1 ? identifiers.get( 0 ) : null;
-    }
-
-
-    public boolean containsSingleUuidIdentifier() {
-        return containsUuidIdentifiersOnly() && ( identifiers.size() == 1 );
-    }
-
-
-    boolean containsUuidIdentifiersOnly() {
-        if ( hasQueryPredicates() ) {
-            return false;
-        }
-        if ( ( identifiers == null ) || identifiers.isEmpty() ) {
-            return false;
-        }
-
-        for ( Identifier identifier : identifiers ) {
-            if ( !identifier.isUUID() ) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-
-    @JsonIgnore
-    public UUID getSingleUuidIdentifier() {
-        if ( !containsSingleUuidIdentifier() ) {
-            return null;
-        }
-        return ( identifiers.get( 0 ).getUUID() );
-    }
-
-
-    @JsonIgnore
-    boolean isIdsOnly() {
-        if ( ( selectAssignments.size() == 1 ) && selectAssignments.containsKey( PROPERTY_UUID ) ) {
-            level = Level.IDS;
-            return true;
-        }
-        return false;
-    }
-
-    private void setIdsOnly( boolean idsOnly ) {
-        if ( idsOnly ) {
-            selectAssignments = new LinkedHashMap<String, String>();
-            selectAssignments.put( PROPERTY_UUID, PROPERTY_UUID );
-            level = Level.IDS;
-        }
-        else if ( isIdsOnly() ) {
-            selectAssignments = new LinkedHashMap<String, String>();
-            level = Level.ALL_PROPERTIES;
-        }
-    }
-
-
-    public Level getResultsLevel() {
-        isIdsOnly();
-        return level;
-    }
-
-
-    public void setResultsLevel( Level level ) {
-        setIdsOnly( level == Level.IDS );
-        this.level = level;
-    }
-
-
-    public Query withResultsLevel( Level level ) {
-        setIdsOnly( level == Level.IDS );
-        this.level = level;
-        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 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;
-    }
-
-
-    public boolean isMergeSelectResults() {
-        return mergeSelectResults;
-    }
-
-
-    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 addSort( String propertyName ) {
-        if ( StringUtils.isBlank( propertyName ) ) {
-            return this;
-        }
-        propertyName = propertyName.trim();
-        if ( propertyName.indexOf( ',' ) >= 0 ) {
-            String[] propertyNames = StringUtils.split( propertyName, ',' );
-            for ( String s : propertyNames ) {
-                addSort( s );
-            }
-            return this;
-        }
-
-        SortDirection direction = SortDirection.ASCENDING;
-        if ( propertyName.indexOf( ' ' ) >= 0 ) {
-            String[] parts = StringUtils.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 ( StringUtils.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 );
-        CpQueryFilterLexer lexer = new CpQueryFilterLexer( in );
-        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
-        CpQueryFilterParser parser = new CpQueryFilterParser( 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( 1, "=" ) );
-
-        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 clause ) {
-        filterClauses.add(clause);
-
-        if ( rootOperand == null ) {
-            rootOperand = clause;
-            return;
-        }
-
-        AndOperand and = new AndOperand();
-        and.addChild( rootOperand );
-        and.addChild( clause );
-
-
-        // 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;
-    }
-
-
-    public List<Operand> getFilterClauses() {
-        return filterClauses;
-    }
-
-
-    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 = Base64.decodeBase64( cursor );
-            if ( ( cursorBytes != null ) && ( cursorBytes.length == 16 ) ) {
-                startResult = ConversionUtils.uuid( cursorBytes );
-            }
-        }
-        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 ) {
-
-        // TODO 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 setResolution( CounterResolution resolution ) {
-        this.resolution = resolution;
-    }
-
-
-    public CounterResolution getResolution() {
-        return resolution;
-    }
-
-
-    public void addIdentifier( Identifier identifier ) {
-        if ( identifiers == null ) {
-            identifiers = new ArrayList<Identifier>();
-        }
-        identifiers.add( identifier );
-    }
-
-
-    void setIdentifiers( List<Identifier> identifiers ) {
-        this.identifiers = identifiers;
-    }
-
-
-    public List<CounterFilterPredicate> getCounterFilters() {
-        return counterFilters;
-    }
-
-
-    public void addCounterFilter( String counter ) {
-        CounterFilterPredicate p = CounterFilterPredicate.fromString( counter );
-        if ( p == null ) {
-            return;
-        }
-        if ( counterFilters == null ) {
-            counterFilters = new ArrayList<CounterFilterPredicate>();
-        }
-        counterFilters.add( p );
-    }
-
-
-    void setCounterFilters( List<CounterFilterPredicate> counterFilters ) {
-        this.counterFilters = counterFilters;
-    }
-
-
-    @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;
-            }
-        }
-        //      if (!filterPredicates.isEmpty()) {
-        //        s.append(" where ");
-        //        boolean first = true;
-        //        for (FilterPredicate f : filterPredicates) {
-        //          if (!first) {
-        //            s.append(" and ");
-        //          }
-        //          s.append(f.toString());
-        //          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(@JsonProperty("propertyName")  String propertyName,
-                             @JsonProperty("direction")  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" : "" );
-        }
-    }
-
-
-    public static final class CounterFilterPredicate implements Serializable {
-
-        private static final long serialVersionUID = 1L;
-        private final String name;
-        private final Identifier user;
-        private final Identifier group;
-        private final String queue;
-        private final String category;
-
-
-        public CounterFilterPredicate( String name, Identifier user, Identifier group, String queue, String category ) {
-            this.name = name;
-            this.user = user;
-            this.group = group;
-            this.queue = queue;
-            this.category = category;
-        }
-
-
-        public Identifier getUser() {
-            return user;
-        }
-
-
-        public Identifier getGroup() {
-            return group;
-        }
-
-
-        public String getQueue() {
-            return queue;
-        }
-
-
-        public String getCategory() {
-            return category;
-        }
-
-
-        public String getName() {
-            return name;
-        }
-
-
-        public static CounterFilterPredicate fromString( String s ) {
-            Identifier user = null;
-            Identifier group = null;
-            String category = null;
-            String name = null;
-            String[] l = StringUtils.split( s, ':' );
-
-            if ( l.length > 0 ) {
-                if ( !"*".equals( l[0] ) ) {
-                    name = l[0];
-                }
-            }
-
-            if ( l.length > 1 ) {
-                if ( !"*".equals( l[1] ) ) {
-                    user = Identifier.from( l[1] );
-                }
-            }
-
-            if ( l.length > 2 ) {
-                if ( !"*".equals( l[2] ) ) {
-                    group = Identifier.from( l[3] );
-                }
-            }
-
-            if ( l.length > 3 ) {
-                if ( !"*".equals( l[3] ) ) {
-                    category = l[3];
-                }
-            }
-
-            if ( ( user == null ) && ( group == null ) && ( category == null ) && ( name == null)) {
-                return null;
-            }
-
-            return new CounterFilterPredicate( name, user, group, null, category );
-        }
-
-
-        public static List<CounterFilterPredicate> fromList( List<String> l ) {
-            if ( ( l == null ) || ( l.size() == 0 ) ) {
-                return null;
-            }
-            List<CounterFilterPredicate> counterFilters = new ArrayList<CounterFilterPredicate>();
-            for ( String s : l ) {
-                CounterFilterPredicate filter = CounterFilterPredicate.fromString( s );
-                if ( filter != null ) {
-                    counterFilters.add( filter );
-                }
-            }
-            if ( counterFilters.size() == 0 ) {
-                return null;
-            }
-            return counterFilters;
-        }
-    }
-
-
-//    public List<Object> getSelectionResults( Results rs ) {
-//
-//        List<Entity> entities = rs.getEntities();
-//        if ( entities == null ) {
-//            return null;
-//        }
-//
-//        if ( !hasSelectSubjects() ) {
-//            return cast( entities );
-//        }
-//
-//        List<Object> results = new ArrayList<Object>();
-//
-//        for ( Entity entity : entities ) {
-//            if ( isMergeSelectResults() ) {
-//                boolean include = false;
-//                Map<String, Object> result = new LinkedHashMap<String, Object>();
-//                Map<String, String> selects = getSelectAssignments();
-//                for ( Map.Entry<String, String> select : selects.entrySet() ) {
-//                    Object obj = JsonUtils.select( entity, select.getValue(), false );
-//                    if ( obj != null ) {
-//                        include = true;
-//                    }
-//                    result.put( select.getKey(), obj );
-//                }
-//                if ( include ) {
-//                    results.add( result );
-//                }
-//            }
-//            else {
-//                boolean include = false;
-//                List<Object> result = new ArrayList<Object>();
-//                Set<String> selects = getSelectSubjects();
-//                for ( String select : selects ) {
-//                    Object obj = JsonUtils.select( entity, select );
-//                    if ( obj != null ) {
-//                        include = true;
-//                    }
-//                    result.add( obj );
-//                }
-//                if ( include ) {
-//                    results.add( result );
-//                }
-//            }
-//        }
-//
-//        if ( results.size() == 0 ) {
-//            return null;
-//        }
-//
-//        return results;
-//    }
-
-
-//    public Object getSelectionResult( Results rs ) {
-//        List<Object> r = getSelectionResults( rs );
-//        if ( ( r != null ) && ( r.size() > 0 ) ) {
-//            return r.get( 0 );
-//        }
-//        return null;
-//    }
-
-
-    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 Query setQl( String ql ) {
-        this.ql = ql;
-        return this;
-    }
-
-
-    /**
-     * Get the connection type
-     * @return
-     */
-    public String getConnectionType() {
-        return connectionType;
-    }
-
-
-    /**
-     * Set the connection type
-     * @param connection
-     * @return
-     */
-    public Query setConnectionType( final String connection ) {
-        this.connectionType = connection;
-        return this;
-    }
-
-
-    public String getType() {
-        return type;
-    }
-
-
-    public Level getLevel() {
-        return level;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2699dd30/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/SelectFieldMapping.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/SelectFieldMapping.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/SelectFieldMapping.java
new file mode 100644
index 0000000..88a2780
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/SelectFieldMapping.java
@@ -0,0 +1,55 @@
+/*
+ *
+ *  *
+ *  * Licensed to the Apache Software Foundation (ASF) under one
+ *  * or more contributor license agreements.  See the NOTICE file
+ *  * distributed with this work for additional information
+ *  * regarding copyright ownership.  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.
+ *  *
+ *
+ */
+
+package org.apache.usergrid.persistence.index.query;
+
+
+/**
+ * A simple object that represents a field mapping.
+ *
+ * Examples:
+ *  "select id", which will return id
+ *
+ *  "select id:appfield" which will return id, but rename it appfield
+ */
+public class SelectFieldMapping {
+
+    private final String sourceFieldName;
+    private final String targetFieldName;
+
+
+    public SelectFieldMapping( final String sourceFieldName, final String targetFieldName ) {
+        this.sourceFieldName = sourceFieldName;
+        this.targetFieldName = targetFieldName;
+    }
+
+
+    public String getSourceFieldName() {
+        return sourceFieldName;
+    }
+
+
+    public String getTargetFieldName() {
+        return targetFieldName;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2699dd30/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/SortPredicate.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/SortPredicate.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/SortPredicate.java
new file mode 100644
index 0000000..70d0b30
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/SortPredicate.java
@@ -0,0 +1,126 @@
+/*
+ *
+ *  *
+ *  * Licensed to the Apache Software Foundation (ASF) under one
+ *  * or more contributor license agreements.  See the NOTICE file
+ *  * distributed with this work for additional information
+ *  * regarding copyright ownership.  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.
+ *  *
+ *
+ */
+
+package org.apache.usergrid.persistence.index.query;
+
+
+import java.io.Serializable;
+
+
+/**
+ * An object that represents a sort predicate
+ */
+public final class SortPredicate implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private final String propertyName;
+    private final SortDirection direction;
+
+
+    public SortPredicate( String propertyName, 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 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 == SortDirection.DESCENDING ) ? " DESC" : "" );
+    }
+
+
+    public 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;
+        }
+    }
+}


Mime
View raw message