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/02/21 19:21:18 UTC

[05/21] Rename index to query index, add working query parser code.

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/c0543f5f/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java
new file mode 100644
index 0000000..ee884f7
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java
@@ -0,0 +1,306 @@
+/*
+ * 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.impl;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Maps;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.time.StopWatch;
+import org.apache.usergrid.persistence.collection.CollectionScope;
+import org.apache.usergrid.persistence.collection.util.EntityUtils;
+import org.apache.usergrid.persistence.index.EntityCollectionIndex;
+import org.apache.usergrid.persistence.index.EntitySearchResults;
+import org.apache.usergrid.persistence.model.entity.Entity;
+import org.apache.usergrid.persistence.model.entity.SimpleId;
+import org.apache.usergrid.persistence.model.field.BooleanField;
+import org.apache.usergrid.persistence.model.field.DoubleField;
+import org.apache.usergrid.persistence.model.field.EntityObjectField;
+import org.apache.usergrid.persistence.model.field.IntegerField;
+import org.apache.usergrid.persistence.model.field.ListField;
+import org.apache.usergrid.persistence.model.field.LongField;
+import org.apache.usergrid.persistence.model.field.StringField;
+import org.apache.usergrid.persistence.model.util.UUIDGenerator;
+import org.apache.usergrid.persistence.utils.ElasticSearchRule;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import static org.junit.Assert.assertEquals;
+import org.junit.Rule;
+import org.junit.Test;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class EntityIndexTest {
+    private static final Logger logger = LoggerFactory.getLogger( EntityIndexTest.class );
+
+    @Rule
+    public ElasticSearchRule elasticSearchRule = new ElasticSearchRule(); 
+
+
+    @Test
+    public void testIndex() throws IOException {
+
+        Client client = elasticSearchRule.getClient();
+        final CollectionScope scope = mock( CollectionScope.class );
+        when( scope.getName() ).thenReturn( "contacts" );
+        String index = RandomStringUtils.randomAlphanumeric(20 ).toLowerCase();
+        String type = scope.getName();
+
+        EntityCollectionIndex entityIndex = 
+            new EntityCollectionIndexImpl( client, index, scope, true );  
+
+        InputStream is = this.getClass().getResourceAsStream( "/sample-large.json" );
+        ObjectMapper mapper = new ObjectMapper();
+        List<Object> sampleJson = mapper.readValue( is, new TypeReference<List<Object>>() {} );
+
+        int count = 0;
+        StopWatch timer = new StopWatch();
+        timer.start();
+        for ( Object o : sampleJson ) {
+
+            Map<String, Object> item = (Map<String, Object>)o;
+
+            Entity entity = new Entity(new SimpleId(UUIDGenerator.newTimeUUID(), scope.getName()));
+            entity = EntityIndexTest.mapToEntity( scope.getName(), entity, item );
+            EntityUtils.setVersion( entity, UUIDGenerator.newTimeUUID() );
+
+            entityIndex.index( entity );
+
+            count++;
+        }
+        timer.stop();
+        logger.info( "Total time to index {} entries {}ms, average {}ms/entry", 
+            count, timer.getTime(), timer.getTime() / count );
+
+        // test queries via Java API QueryBuilder
+        testQueries( client, index, type );
+
+        // test queries via Lucene syntax
+        testQueries( entityIndex );
+
+        client.close();
+    }
+
+
+    private void testQuery( Client client, String index, String type, QueryBuilder qb, int num ) {
+
+        StopWatch timer = new StopWatch();
+        timer.start();
+        SearchResponse sr = client.prepareSearch( index ).setTypes( type )
+            .setQuery( qb ).setFrom( 0 ).setSize( 999 ).execute().actionGet();
+        timer.stop();
+
+        assertEquals( num, sr.getHits().getTotalHits() );
+        logger.debug( "Query1 time {}ms", timer.getTime() );
+    }
+   
+
+    private void testQueries( Client client, String index, String type ) {
+
+        testQuery( client, index, type, 
+            QueryBuilders.termQuery( "name", "Morgan Pierce" ), 1 );
+
+        // term query is exact match
+        testQuery( client, index, type, 
+            QueryBuilders.termQuery("name", "Pierce" ), 0 );
+
+        // match query allows partial match 
+        testQuery( client, index, type, 
+            QueryBuilders.matchQuery( "name_ug_analyzed", "Pierce" ), 2 );
+
+        testQuery( client, index, type, 
+            QueryBuilders.termQuery( "company", "Blurrybus" ), 1 );
+
+        testQuery( client, index, type, 
+            QueryBuilders.termQuery( "gender", "female" ), 433 );
+
+        // query of nested object fields supported
+        testQuery( client, index, type, 
+            QueryBuilders.termQuery( "contact.email", "nadiabrown@concility.com" ), 1 ); 
+    }
+
+   
+    private void testQuery( EntityCollectionIndex entityIndex, String query, int num ) {
+
+        StopWatch timer = new StopWatch();
+        timer.start();
+        EntitySearchResults results = entityIndex.simpleQuery( query, 0, 999);
+        timer.stop();
+
+        assertEquals( num, results.count() );
+        logger.debug( "Query2 time {}ms", timer.getTime() );
+    }
+
+
+    private void testQueries( EntityCollectionIndex entityIndex ) {
+
+        testQuery( entityIndex, "name:\"Morgan Pierce\"", 1);
+
+        testQuery( entityIndex, "name:\"Morgan\"", 0);
+
+        testQuery( entityIndex, "name_ug_analyzed:\"Morgan\"", 1);
+
+        testQuery( entityIndex, "gender:female", 433);
+    }
+
+    
+    @Test
+    public void testRemoveIndex() {
+    }
+
+
+    /**
+     * Test of mapToEntity method, of class EntityUtils.
+     */
+    @Test
+    public void testMapToEntityRoundTrip() throws IOException {
+
+        InputStream is = this.getClass().getResourceAsStream( "/sample-large.json" );
+        ObjectMapper mapper = new ObjectMapper();
+        List<Object> contacts = mapper.readValue( is, new TypeReference<List<Object>>() {} );
+
+        for ( Object o : contacts ) {
+
+            Map<String, Object> map1 = (Map<String, Object>)o;
+
+            // convert map to entity
+            Entity entity1 = EntityIndexTest.mapToEntity( "testscope", map1 );
+
+            // convert entity back to map
+            Map map2 = EntityCollectionIndexImpl.entityToMap( entity1 );
+
+            // the two maps should be the same except for the two new _ug_analyzed properties
+            Map diff = Maps.difference( map1, map2 ).entriesDiffering();
+            assertEquals( 2, diff.size() );
+        }
+    }
+
+    
+    public static Entity mapToEntity( String scope, Map<String, Object> item ) {
+        return mapToEntity( scope, null, item );
+    }
+
+
+    public static Entity mapToEntity( String scope, Entity entity, Map<String, Object> map ) {
+
+        if ( entity == null ) {
+            entity = new Entity();
+        }
+
+        for ( String fieldName : map.keySet() ) {
+
+            Object value = map.get( fieldName );
+
+            if ( value instanceof String ) {
+                entity.setField( new StringField(fieldName, (String)value ));
+
+            } else if ( value instanceof Boolean ) {
+                entity.setField( new BooleanField(fieldName, (Boolean)value ));
+                        
+            } else if ( value instanceof Integer ) {
+                entity.setField( new IntegerField(fieldName, (Integer)value ));
+
+            } else if ( value instanceof Double ) {
+                entity.setField( new DoubleField(fieldName, (Double)value ));
+
+            } else if ( value instanceof Long ) {
+                entity.setField( new LongField(fieldName, (Long)value ));
+
+            } else if ( value instanceof List) {
+                entity.setField( listToListField( scope, fieldName, (List)value ));
+
+            } else if ( value instanceof Map ) {
+                entity.setField( new EntityObjectField( fieldName, 
+                    mapToEntity( scope, (Map<String, Object>)value ))); // recursion
+
+            } else {
+                throw new RuntimeException("Unknown type " + value.getClass().getName());
+            }
+        }
+
+        return entity;
+    }
+
+    
+    private static ListField listToListField( String scope, String fieldName, List list ) {
+
+        if (list.isEmpty()) {
+            return new ListField( fieldName );
+        }
+
+        Object sample = list.get(0);
+
+        if ( sample instanceof Map ) {
+            return new ListField<Entity>( fieldName, processListForField( scope, list ));
+
+        } else if ( sample instanceof List ) {
+            return new ListField<List>( fieldName, processListForField( scope, list ));
+            
+        } else if ( sample instanceof String ) {
+            return new ListField<String>( fieldName, (List<String>)list );
+                    
+        } else if ( sample instanceof Boolean ) {
+            return new ListField<Boolean>( fieldName, (List<Boolean>)list );
+                    
+        } else if ( sample instanceof Integer ) {
+            return new ListField<Integer>( fieldName, (List<Integer>)list );
+
+        } else if ( sample instanceof Double ) {
+            return new ListField<Double>( fieldName, (List<Double>)list );
+
+        } else if ( sample instanceof Long ) {
+            return new ListField<Long>( fieldName, (List<Long>)list );
+
+        } else {
+            throw new RuntimeException("Unknown type " + sample.getClass().getName());
+        }
+    }
+
+    
+    private static List processListForField( String scope, List list ) {
+        if ( list.isEmpty() ) {
+            return list;
+        }
+        Object sample = list.get(0);
+
+        if ( sample instanceof Map ) {
+            List<Entity> newList = new ArrayList<Entity>();
+            for ( Map<String, Object> map : (List<Map<String, Object>>)list ) {
+                newList.add( mapToEntity( scope, map ) );
+            }
+            return newList;
+
+        } else if ( sample instanceof List ) {
+            return processListForField( scope, list ); // recursion
+            
+        } else { 
+            return list;
+        } 
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/c0543f5f/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/QueryTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/QueryTest.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/QueryTest.java
new file mode 100644
index 0000000..fa46f4c
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/QueryTest.java
@@ -0,0 +1,312 @@
+/*******************************************************************************
+ * 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.query;
+
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.usergrid.persistence.query.Query.SortDirection;
+import org.apache.usergrid.persistence.query.Query.SortPredicate;
+import org.apache.usergrid.persistence.exceptions.QueryParseException;
+import org.apache.usergrid.persistence.query.Query;
+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.FloatLiteral;
+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.LongLiteral;
+import org.apache.usergrid.persistence.query.tree.NotOperand;
+import org.apache.usergrid.persistence.query.tree.StringLiteral;
+import org.apache.usergrid.persistence.query.tree.WithinOperand;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+
+//@Concurrent()
+public class QueryTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger( QueryTest.class );
+
+
+    @Test
+    public void testQueryTree() throws Exception {
+        LOG.info( "testQuery" );
+
+        Query q = new Query();
+
+        try {
+            q.addFilter( "blah" );
+            fail( "'blah' shouldn't be a valid operation." );
+        }
+        catch ( RuntimeException e ) {
+            // this is correct
+        }
+
+        q.addFilter( "a=5" );
+        q.addFilter( "b='hello'" );
+        q.addFilter( "c < 7" );
+        q.addFilter( "d gt 5" );
+        // q.addFilter("e in 5,6");
+        q.addFilter( "f = 6.0" );
+        q.addFilter( "g = .05" );
+        q.addFilter( "loc within .05 of 5.0,6.0" );
+        q.addFilter( "not h eq 4" );
+
+        AndOperand and = ( AndOperand ) q.getRootOperand();
+
+        NotOperand not = ( NotOperand ) and.getRight();
+        Equal equal = ( Equal ) not.getOperation();
+        assertEquals( "h", equal.getProperty().getValue() );
+        assertEquals( 4.0f, ( ( LongLiteral ) equal.getLiteral() ).getValue(), 0 );
+
+        and = ( AndOperand ) and.getLeft();
+        WithinOperand op = ( WithinOperand ) and.getRight();
+
+        assertEquals( "loc", op.getProperty().getValue() );
+        assertEquals( .05f, op.getDistance().getFloatValue(), 0 );
+        assertEquals( 5f, op.getLattitude().getFloatValue(), 0 );
+        assertEquals( 6f, op.getLongitude().getFloatValue(), 0 );
+
+        and = ( AndOperand ) and.getLeft();
+        equal = ( Equal ) and.getRight();
+
+        assertEquals( "g", equal.getProperty().getValue() );
+        assertEquals( .05f, ( ( FloatLiteral ) equal.getLiteral() ).getValue(), 0 );
+
+        and = ( AndOperand ) and.getLeft();
+        equal = ( Equal ) and.getRight();
+
+        assertEquals( "f", equal.getProperty().getValue() );
+        assertEquals( 6.0f, ( ( FloatLiteral ) equal.getLiteral() ).getValue(), 0 );
+
+        and = ( AndOperand ) and.getLeft();
+        GreaterThan gt = ( GreaterThan ) and.getRight();
+
+        assertEquals( "d", gt.getProperty().getValue() );
+        assertEquals( 5, ( ( LongLiteral ) gt.getLiteral() ).getValue(), 0 );
+
+        and = ( AndOperand ) and.getLeft();
+        LessThan lt = ( LessThan ) and.getRight();
+
+        assertEquals( "c", lt.getProperty().getValue() );
+        assertEquals( 7, ( ( LongLiteral ) lt.getLiteral() ).getValue(), 0 );
+
+        and = ( AndOperand ) and.getLeft();
+        equal = ( Equal ) and.getRight();
+
+        assertEquals( "b", equal.getProperty().getValue() );
+        assertEquals( "hello", ( ( StringLiteral ) equal.getLiteral() ).getValue() );
+
+        equal = ( Equal ) and.getLeft();
+
+        assertEquals( "a", equal.getProperty().getValue() );
+        assertEquals( 5, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+    }
+
+
+    @Test
+    public void testCodeEquals() {
+        Query query = new Query();
+        query.addEqualityFilter( "foo", "bar" );
+
+        Equal equal = ( Equal ) query.getRootOperand();
+
+        assertEquals( "foo", equal.getProperty().getValue() );
+        assertEquals( "bar", equal.getLiteral().getValue() );
+    }
+
+
+    @Test
+    public void testCodeLessThan() {
+        Query query = new Query();
+        query.addLessThanFilter( "foo", 5 );
+
+        LessThan equal = ( LessThan ) query.getRootOperand();
+
+        assertEquals( "foo", equal.getProperty().getValue() );
+        assertEquals( 5l, equal.getLiteral().getValue() );
+    }
+
+
+    @Test
+    public void testCodeLessThanEqual() {
+        Query query = new Query();
+        query.addLessThanEqualFilter( "foo", 5 );
+
+        LessThanEqual equal = ( LessThanEqual ) query.getRootOperand();
+
+        assertEquals( "foo", equal.getProperty().getValue() );
+        assertEquals( 5l, equal.getLiteral().getValue() );
+    }
+
+
+    @Test
+    public void testCodeGreaterThan() {
+        Query query = new Query();
+        query.addGreaterThanFilter( "foo", 5 );
+
+        GreaterThan equal = ( GreaterThan ) query.getRootOperand();
+
+        assertEquals( "foo", equal.getProperty().getValue() );
+        assertEquals( 5l, equal.getLiteral().getValue() );
+    }
+
+
+    @Test
+    public void testCodeGreaterThanEqual() {
+        Query query = new Query();
+        query.addGreaterThanEqualFilter( "foo", 5 );
+
+        GreaterThanEqual equal = ( GreaterThanEqual ) query.getRootOperand();
+
+        assertEquals( "foo", equal.getProperty().getValue() );
+        assertEquals( 5l, equal.getLiteral().getValue() );
+    }
+
+
+    @Test
+    public void testFromJson() throws QueryParseException {
+        String s = "{\"filter\":\"a contains 'ed'\"}";
+        Query q = Query.fromJsonString( s );
+        assertNotNull( q );
+
+        ContainsOperand contains = ( ContainsOperand ) q.getRootOperand();
+
+        assertEquals( "a", contains.getProperty().getValue() );
+        assertEquals( "ed", contains.getString().getValue() );
+    }
+
+
+    @Test
+    public void testCompoundQueryWithNot() throws QueryParseException {
+        String s = "name contains 'm' and not name contains 'grover'";
+        Query q = Query.fromQL( s );
+        assertNotNull( q );
+
+        AndOperand and = ( AndOperand ) q.getRootOperand();
+
+        ContainsOperand contains = ( ContainsOperand ) and.getLeft();
+        assertEquals( "name", contains.getProperty().getValue() );
+        assertEquals( "m", contains.getString().getValue() );
+
+        NotOperand not = ( NotOperand ) and.getRight();
+        contains = ( ContainsOperand ) not.getOperation();
+        assertEquals( "name", contains.getProperty().getValue() );
+        assertEquals( "grover", contains.getString().getValue() );
+    }
+
+
+    @Test
+    public void badGrammar() throws QueryParseException {
+        // from isn't allowed
+        String s = "select * from where name = 'bob'";
+
+        String error = null;
+
+        try {
+            Query.fromQL( s );
+        }
+        catch ( QueryParseException qpe ) {
+            error = qpe.getMessage();
+        }
+        assertNotNull( error );
+        assertTrue( error.startsWith("The query cannot be parsed") );
+    }
+
+
+    @Test
+    public void testTruncation() {
+
+        Query query = new Query();
+        query.setLimit( Query.MAX_LIMIT * 2 );
+
+        assertEquals( Query.MAX_LIMIT, query.getLimit() );
+    }
+
+
+    @Test
+    public void testTruncationFromParams() throws QueryParseException {
+
+        HashMap<String, List<String>> params = new HashMap<String, List<String>>();
+
+        params.put( "limit", Collections.singletonList( "2000" ) );
+
+        Query query = Query.fromQueryParams( params );
+
+        assertEquals( Query.MAX_LIMIT, query.getLimit() );
+    }
+
+
+    @Test
+    public void badOrderByBadGrammar() throws QueryParseException {
+        // from isn't allowed
+        String s = "select * where name = 'bob' order by";
+
+        String error = null;
+
+        try {
+            Query.fromQL( s );
+        }
+        catch ( QueryParseException qpe ) {
+            error = qpe.getMessage();
+        }
+
+        assertEquals( "The query cannot be parsed. The token '<EOF>' at column 13 on line 1 cannot be parsed", error );
+    }
+
+
+    @Test
+    public void badOrderByGrammarAsc() throws QueryParseException {
+        // from isn't allowed
+        String s = "select * where name = 'bob' order by name asc";
+
+        Query q = Query.fromQL( s );
+
+        List<SortPredicate> sorts = q.getSortPredicates();
+
+        assertEquals( 1, sorts.size() );
+
+        assertEquals( "name", sorts.get( 0 ).getPropertyName() );
+        assertEquals( SortDirection.ASCENDING, sorts.get( 0 ).getDirection() );
+    }
+
+
+    @Test
+    public void badOrderByGrammarDesc() throws QueryParseException {
+        // from isn't allowed
+        String s = "select * where name = 'bob' order by name desc";
+
+        Query q = Query.fromQL( s );
+
+        List<SortPredicate> sorts = q.getSortPredicates();
+
+        assertEquals( 1, sorts.size() );
+
+        assertEquals( "name", sorts.get( 0 ).getPropertyName() );
+        assertEquals( SortDirection.DESCENDING, sorts.get( 0 ).getDirection() );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/c0543f5f/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/tree/GrammarTreeTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/tree/GrammarTreeTest.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/tree/GrammarTreeTest.java
new file mode 100644
index 0000000..10324d1
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/tree/GrammarTreeTest.java
@@ -0,0 +1,608 @@
+/*******************************************************************************
+ * 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.query.tree;
+
+
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.TokenRewriteStream;
+import org.junit.Test;
+import org.apache.usergrid.persistence.query.Query;
+import org.apache.usergrid.persistence.exceptions.QueryParseException;
+import org.apache.usergrid.persistence.query.ir.OrNode;
+
+import antlr.NoViableAltException;
+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.LongLiteral;
+import org.apache.usergrid.persistence.query.tree.NotOperand;
+import org.apache.usergrid.persistence.query.tree.Operand;
+import org.apache.usergrid.persistence.query.tree.OrOperand;
+import org.apache.usergrid.persistence.query.tree.QueryFilterLexer;
+import org.apache.usergrid.persistence.query.tree.QueryFilterParser;
+import org.apache.usergrid.persistence.query.tree.StringLiteral;
+import org.apache.usergrid.persistence.query.tree.UUIDLiteral;
+import org.apache.usergrid.persistence.query.tree.WithinOperand;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+
+/** @author tnine */
+public class GrammarTreeTest {
+
+    /** Simple test that constructs and AST from the ANTLR generated files */
+    @Test
+    public void equality() throws RecognitionException {
+
+        String queryString = "select * where a = 5";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Operand root = query.getRootOperand();
+
+        Equal equal = ( Equal ) root;
+
+        assertEquals( "a", equal.getProperty().getValue() );
+
+        assertEquals( 5, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+    }
+
+
+    /** Simple test that constructs and AST from the ANTLR generated files */
+    @Test
+    public void lessThan() throws RecognitionException {
+
+        String queryString = "select * where a < 5";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Operand root = query.getRootOperand();
+
+        LessThan equal = ( LessThan ) root;
+
+        assertEquals( "a", equal.getProperty().getValue() );
+
+        assertEquals( 5, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+
+        // TODO Todd fix this.
+
+        queryString = "select * where a lt 5";
+
+        in = new ANTLRStringStream( queryString );
+        lexer = new QueryFilterLexer( in );
+        tokens = new TokenRewriteStream( lexer );
+        parser = new QueryFilterParser( tokens );
+
+        query = parser.ql().query;
+
+        root = query.getRootOperand();
+
+        equal = ( LessThan ) root;
+
+        assertEquals( "a", equal.getProperty().getValue() );
+
+        assertEquals( 5, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+    }
+
+
+    /** Simple test that constructs and AST from the ANTLR generated files */
+    @Test
+    public void lessThanEqual() throws RecognitionException {
+
+        String queryString = "select * where a <= 5";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Operand root = query.getRootOperand();
+
+        LessThanEqual equal = ( LessThanEqual ) root;
+
+        assertEquals( "a", equal.getProperty().getValue() );
+
+        assertEquals( 5, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+
+        queryString = "select * where a lte 5";
+
+        in = new ANTLRStringStream( queryString );
+        lexer = new QueryFilterLexer( in );
+        tokens = new TokenRewriteStream( lexer );
+        parser = new QueryFilterParser( tokens );
+
+        query = parser.ql().query;
+
+        root = query.getRootOperand();
+
+        equal = ( LessThanEqual ) root;
+
+        assertEquals( "a", equal.getProperty().getValue() );
+
+        assertEquals( 5, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+    }
+
+
+    /** Simple test that constructs and AST from the ANTLR generated files */
+    @Test
+    public void greaterThan() throws RecognitionException {
+
+        String queryString = "select * where a > 5";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Operand root = query.getRootOperand();
+
+        GreaterThan equal = ( GreaterThan ) root;
+
+        assertEquals( "a", equal.getProperty().getValue() );
+
+        assertEquals( 5, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+
+        queryString = "select * where a gt 5";
+
+        in = new ANTLRStringStream( queryString );
+        lexer = new QueryFilterLexer( in );
+        tokens = new TokenRewriteStream( lexer );
+        parser = new QueryFilterParser( tokens );
+
+        query = parser.ql().query;
+
+        root = query.getRootOperand();
+
+        equal = ( GreaterThan ) root;
+
+        assertEquals( "a", equal.getProperty().getValue() );
+
+        assertEquals( 5, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+    }
+
+
+    /** Simple test that constructs and AST from the ANTLR generated files */
+    @Test
+    public void greaterThanEqual() throws RecognitionException {
+
+        String queryString = "select * where a >= 5";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Operand root = query.getRootOperand();
+
+        GreaterThanEqual equal = ( GreaterThanEqual ) root;
+
+        assertEquals( "a", equal.getProperty().getValue() );
+
+        assertEquals( 5, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+
+        queryString = "select * where a gte 5";
+
+        in = new ANTLRStringStream( queryString );
+        lexer = new QueryFilterLexer( in );
+        tokens = new TokenRewriteStream( lexer );
+        parser = new QueryFilterParser( tokens );
+
+        query = parser.ql().query;
+
+        root = query.getRootOperand();
+
+        equal = ( GreaterThanEqual ) root;
+
+        assertEquals( "a", equal.getProperty().getValue() );
+
+        assertEquals( 5, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+    }
+
+
+    /** Test basic && expression */
+    @Test
+    public void andExpression() throws RecognitionException {
+
+        String queryString = "select * where a = 1 and b > 2";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Operand root = query.getRootOperand();
+
+        AndOperand and = ( AndOperand ) root;
+
+        Equal equal = ( Equal ) and.getLeft();
+
+        assertEquals( "a", equal.getProperty().getValue() );
+
+        assertEquals( 1, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+
+        GreaterThan greater = ( GreaterThan ) and.getRight();
+
+        assertEquals( "b", greater.getProperty().getValue() );
+        assertEquals( 2, ( ( LongLiteral ) greater.getLiteral() ).getValue().intValue() );
+    }
+
+
+    /** Test basic || expression */
+    @Test
+    public void orExpression() throws RecognitionException {
+
+        String queryString = "select * where a = 1 or b > 2";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Operand root = query.getRootOperand();
+
+        OrOperand and = ( OrOperand ) root;
+
+        Equal equal = ( Equal ) and.getLeft();
+
+        assertEquals( "a", equal.getProperty().getValue() );
+
+        assertEquals( 1, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+
+        GreaterThan greater = ( GreaterThan ) and.getRight();
+
+        assertEquals( "b", greater.getProperty().getValue() );
+        assertEquals( 2, ( ( LongLiteral ) greater.getLiteral() ).getValue().intValue() );
+    }
+
+
+    /** Test basic not expression */
+    @Test
+    public void notExpression() throws RecognitionException {
+
+        String queryString = "select * where not a = 1";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Operand root = query.getRootOperand();
+
+        NotOperand not = ( NotOperand ) root;
+
+        Equal equal = ( Equal ) not.getOperation();
+
+        assertEquals( "a", equal.getProperty().getValue() );
+
+        assertEquals( 1, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+    }
+
+
+    /** Test basic not expression */
+    @Test
+    public void complexExpression() throws RecognitionException {
+
+        String queryString = "select * where not a = 1";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Operand root = query.getRootOperand();
+
+        NotOperand not = ( NotOperand ) root;
+
+        Equal equal = ( Equal ) not.getOperation();
+
+        assertEquals( "a", equal.getProperty().getValue() );
+
+        assertEquals( 1, ( ( LongLiteral ) equal.getLiteral() ).getValue().intValue() );
+    }
+
+
+    /** Test basic || expression */
+    @Test
+    public void selectAll() throws RecognitionException {
+
+        String queryString = "select * where a = 1 or b > 2";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Set<String> identifiers = query.getSelectSubjects();
+
+        assertEquals( 0, identifiers.size() );
+    }
+
+
+    @Test
+    public void selectGeo() throws RecognitionException {
+        String queryString = "select * where a within .1 of -40.343666, 175.630917";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        WithinOperand operand = ( WithinOperand ) query.getRootOperand();
+
+        assertEquals( "a", operand.getProperty().getValue() );
+        assertEquals( .1f, operand.getDistance().getFloatValue(), 0 );
+        assertEquals( -40.343666f, operand.getLattitude().getFloatValue(), 0 );
+        assertEquals( 175.630917f, operand.getLongitude().getFloatValue(), 0 );
+    }
+
+
+    @Test
+    public void selectGeoWithInt() throws RecognitionException {
+        String queryString = "select * where a within 1 of -40.343666, 175.630917";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        WithinOperand operand = ( WithinOperand ) query.getRootOperand();
+
+        assertEquals( "a", operand.getProperty().getValue() );
+        assertEquals( 1, operand.getDistance().getFloatValue(), 0 );
+        assertEquals( -40.343666f, operand.getLattitude().getFloatValue(), 0 );
+        assertEquals( 175.630917f, operand.getLongitude().getFloatValue(), 0 );
+    }
+
+
+    @Test
+    public void selectDistance() throws RecognitionException {
+        String queryString = "select * where a contains 'foo'";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        ContainsOperand operand = ( ContainsOperand ) query.getRootOperand();
+
+        assertEquals( "a", operand.getProperty().getValue() );
+        assertEquals( "foo", operand.getString().getValue() );
+    }
+
+
+    @Test
+    public void selectField() throws RecognitionException {
+
+        String queryString = "select c where a = 1 or b > 2";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Set<String> identifiers = query.getSelectSubjects();
+
+        assertTrue( identifiers.contains( "c" ) );
+    }
+
+
+    @Test
+    public void selectRename() throws RecognitionException {
+
+        String queryString = "select {source:target} where a = 1 or b > 2";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Map<String, String> identifiers = query.getSelectAssignments();
+
+        assertEquals( "target", identifiers.get( "source" ) );
+    }
+
+
+    @Test
+    public void containsOr() throws Exception {
+        String queryString = "select * where keywords contains 'hot' or title contains 'hot'";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        OrOperand rootNode = ( OrOperand ) query.getRootOperand();
+
+        assertNotNull( rootNode );
+
+        ContainsOperand left = ( ContainsOperand ) rootNode.getLeft();
+
+        assertEquals( "keywords", left.getProperty().getValue() );
+
+        assertEquals( "hot", left.getString().getValue() );
+        assertEquals( "hot", left.getString().getEndValue() );
+
+        ContainsOperand right = ( ContainsOperand ) rootNode.getRight();
+
+        assertEquals( "title", right.getProperty().getValue() );
+
+        assertEquals( "hot", right.getString().getValue() );
+        assertEquals( "hot", right.getString().getEndValue() );
+    }
+
+
+    @Test
+    public void stringLower() throws Exception {
+        String queryString = "select * where  title = 'Hot'";
+
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Equal rootNode = ( Equal ) query.getRootOperand();
+
+        assertEquals( "title", rootNode.getProperty().getValue() );
+        assertEquals( "hot", ( ( StringLiteral ) rootNode.getLiteral() ).getValue() );
+    }
+
+
+    @Test
+    public void nestedBooleanLogic() throws Exception {
+        String queryString = "select * where field1 = 'foo' AND (field2 = 'bar' OR field2 = 'baz')";
+
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        AndOperand rootNode = ( AndOperand ) query.getRootOperand();
+
+        //left should be field1
+        Equal field1Equal = ( Equal ) rootNode.getLeft();
+
+        assertEquals( "field1", field1Equal.getProperty().getValue() );
+        assertEquals( "foo", ( ( StringLiteral ) field1Equal.getLiteral() ).getValue() );
+
+
+        OrOperand orNode = ( OrOperand ) rootNode.getRight();
+
+        Equal field2Bar = ( Equal ) orNode.getLeft();
+        Equal field2Baz = ( Equal ) orNode.getRight();
+
+        assertEquals( "field2", field2Bar.getProperty().getValue() );
+        assertEquals( "bar", ( ( StringLiteral ) field2Bar.getLiteral() ).getValue() );
+
+        assertEquals( "field2", field2Baz.getProperty().getValue() );
+        assertEquals( "baz", ( ( StringLiteral ) field2Baz.getLiteral() ).getValue() );
+    }
+
+
+    @Test
+    public void uuidParse() throws RecognitionException {
+        String queryString = "select * where  title = c6ee8a1c-3ef4-11e2-8861-02e81adcf3d0";
+
+        ANTLRStringStream in = new ANTLRStringStream( queryString );
+        QueryFilterLexer lexer = new QueryFilterLexer( in );
+        TokenRewriteStream tokens = new TokenRewriteStream( lexer );
+        QueryFilterParser parser = new QueryFilterParser( tokens );
+
+        Query query = parser.ql().query;
+
+        Equal rootNode = ( Equal ) query.getRootOperand();
+
+        assertEquals( "title", rootNode.getProperty().getValue() );
+        assertEquals( UUID.fromString( "c6ee8a1c-3ef4-11e2-8861-02e81adcf3d0" ),
+                ( ( UUIDLiteral ) rootNode.getLiteral() ).getValue() );
+    }
+
+
+    @Test
+    public void badOrderByGrammar() throws QueryParseException {
+        // from isn't allowed
+        String s = "select * where name = 'bob' order by";
+
+        String error = null;
+
+        try {
+            Query.fromQL( s );
+        }
+        catch ( QueryParseException qpe ) {
+            error = qpe.getMessage();
+        }
+
+        assertEquals( "The query cannot be parsed. The token '<EOF>' " + "at column 13 on line 1 cannot be parsed",
+                error );
+    }
+
+    @Test
+       public void badOperand() throws QueryParseException {
+           // from isn't allowed
+           String s = "select * where name != 'bob'";
+
+           String error = null;
+
+           try {
+               Query.fromQL( s );
+               fail("should throw an exception");
+           }
+           catch ( RuntimeException qpe ) {
+               error = qpe.getMessage();
+           }
+
+           assertEquals( "NoViableAltException('!'@[1:1: Tokens : ( T__31 | T__32 | T__33 | T__34 | T__35 | T__36 | T__37 | T__38 | T__39 | T__40 | LT | LTE | EQ | GT | GTE | BOOLEAN | AND | OR | NOT | ASC | DESC | CONTAINS | WITHIN | OF | UUID | ID | LONG | FLOAT | STRING | WS );])",
+                   error );
+       }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/c0543f5f/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/tree/LongLiteralTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/tree/LongLiteralTest.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/tree/LongLiteralTest.java
new file mode 100644
index 0000000..b2e2eba
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/tree/LongLiteralTest.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * 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.query.tree;
+
+
+import org.antlr.runtime.CommonToken;
+import org.apache.usergrid.persistence.query.tree.LongLiteral;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+
+/** @author tnine */
+public class LongLiteralTest {
+
+
+    /**
+     * Test method for {@link org.apache.usergrid.persistence.query.tree.LongLiteral#IntegerLiteral(org.antlr.runtime
+     * .Token)}.
+     */
+    @Test
+    public void longMin() {
+
+        long value = Long.MIN_VALUE;
+
+        String stringVal = String.valueOf( value );
+
+        LongLiteral literal = new LongLiteral( new CommonToken( 0, stringVal ) );
+
+        assertEquals( value, literal.getValue().longValue() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.usergrid.persistence.query.tree.LongLiteral#IntegerLiteral(org.antlr.runtime
+     * .Token)}.
+     */
+    @Test
+    public void longMax() {
+
+        long value = Long.MAX_VALUE;
+
+        String stringVal = String.valueOf( value );
+
+        LongLiteral literal = new LongLiteral( new CommonToken( 0, stringVal ) );
+
+        assertEquals( value, literal.getValue().longValue() );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/c0543f5f/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/tree/StringLiteralTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/tree/StringLiteralTest.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/tree/StringLiteralTest.java
new file mode 100644
index 0000000..56ef54d
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/query/tree/StringLiteralTest.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * 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.query.tree;
+
+
+import org.antlr.runtime.CommonToken;
+import org.apache.usergrid.persistence.query.tree.StringLiteral;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+
+/** @author tnine */
+public class StringLiteralTest {
+
+    @Test
+    public void exactToken() {
+
+        StringLiteral literal = new StringLiteral( new CommonToken( 0, "'value'" ) );
+
+        assertEquals( "value", literal.getValue() );
+        assertEquals( "value", literal.getEndValue() );
+    }
+
+
+    @Test
+    public void exactString() {
+
+        StringLiteral literal = new StringLiteral( "value" );
+
+        assertEquals( "value", literal.getValue() );
+        assertEquals( "value", literal.getEndValue() );
+    }
+
+
+    @Test
+    public void wildcardToken() {
+
+        StringLiteral literal = new StringLiteral( new CommonToken( 0, "'*'" ) );
+
+        assertNull( literal.getValue() );
+        assertNull( literal.getEndValue() );
+    }
+
+
+    @Test
+    public void wildcardString() {
+
+        StringLiteral literal = new StringLiteral( "*" );
+
+        assertNull( literal.getValue() );
+        assertNull( literal.getEndValue() );
+    }
+
+
+    @Test
+    public void wildcardEndToken() {
+
+        StringLiteral literal = new StringLiteral( new CommonToken( 0, "'value*'" ) );
+
+        assertEquals( "value", literal.getValue() );
+        assertEquals( "value\uffff", literal.getEndValue() );
+    }
+
+
+    @Test
+    public void wildcardEndString() {
+
+        StringLiteral literal = new StringLiteral( "value*" );
+
+        assertEquals( "value", literal.getValue() );
+        assertEquals( "value\uffff", literal.getEndValue() );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/c0543f5f/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/utils/ElasticSearchRule.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/utils/ElasticSearchRule.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/utils/ElasticSearchRule.java
new file mode 100644
index 0000000..0068fad
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/utils/ElasticSearchRule.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.utils;
+
+import org.apache.usergrid.persistence.collection.util.AvailablePortFinder;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.common.settings.ImmutableSettings;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.node.Node;
+import org.elasticsearch.node.NodeBuilder;
+import org.junit.rules.ExternalResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class ElasticSearchRule extends ExternalResource {
+    private static final Logger log = LoggerFactory.getLogger( ElasticSearchRule.class ); 
+
+    private Client client; 
+
+    @Override
+    protected void after() {
+        client.close();
+    }
+
+    @Override
+    protected void before() throws Throwable {
+
+        // use unique port and directory names so multiple instances of ES can run concurrently.
+        int port = AvailablePortFinder.getNextAvailable(2000);
+        Settings settings = ImmutableSettings.settingsBuilder()
+            .put("node.http.enabled", true)
+            .put("transport.tcp.port", port )
+            .put("path.logs","target/elasticsearch/logs_" + port )
+            .put("path.data","target/elasticsearch/data_" + port )
+            .put("gateway.type", "none" )
+            .put("index.store.type", "memory" )
+            .put("index.number_of_shards", 1 )
+            .put("index.number_of_replicas", 1).build();
+
+        Node node = NodeBuilder.nodeBuilder().local(true).settings(settings).node();
+        client = node.client();
+    }
+
+    public Client getClient() {
+        return client;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/c0543f5f/stack/corepersistence/queryindex/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/resources/log4j.properties b/stack/corepersistence/queryindex/src/test/resources/log4j.properties
new file mode 100644
index 0000000..5d830ee
--- /dev/null
+++ b/stack/corepersistence/queryindex/src/test/resources/log4j.properties
@@ -0,0 +1,15 @@
+log4j.rootLogger=INFO,stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p %c{3}.%M(%L)<%t>- %m%n
+
+log4j.logger.org.safehaus.chop.plugin=DEBUG
+log4j.logger.org.safehaus.guicyfig=ERROR
+log4j.logger.org.safehaus.chop.api.store.amazon=DEBUG
+log4j.logger.org.apache.http=ERROR
+log4j.logger.com.amazonaws.request=ERROR
+
+log4j.logger.org.apache.usergrid=DEBUG
+
+log4j.logger.org.apache.usergrid.persistence.index=DEBUG