Ensure that field names are treated consistently and in a case-insensitive way.
Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/5452d68c Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/5452d68c Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/5452d68c Branch: refs/heads/release-2.1.1 Commit: 5452d68c29bb59ec8794639cdc8d6d819792e8bb Parents: 151abf7 Author: Dave Johnson <[email protected]> Authored: Wed Jun 1 09:56:01 2016 -0400 Committer: Dave Johnson <[email protected]> Committed: Wed Jun 1 09:56:01 2016 -0400 ---------------------------------------------------------------------- .../read/search/CandidateEntityFilter.java | 13 +++ .../model/field/value/EntityObject.java | 15 ++- .../queries/SelectMappingsQueryTest.java | 105 +++++++++++++++++++ 3 files changed, 128 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/usergrid/blob/5452d68c/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java ---------------------------------------------------------------------- diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java index 4aa6c8d..7770436 100644 --- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java +++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java @@ -161,6 +161,13 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate } + /** + * Sets field in result map with support for nested fields via recursion. + * + * @param result The result map of filtered fields + * @param parts The parts of the field name (more than one if field is nested) + * @param fieldMap Map of fields of the object + */ private void nestedFieldSet( Map<String, Field> result, String[] parts, Map<String, Field> fieldMap) { if ( parts.length > 0 ) { @@ -184,6 +191,12 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate } + /** + * Check to see if field should be included in filtered result with support for nested fields via recursion. + * + * @param parts The parts of the field name (more than one if field is nested) + * @param fieldMap Map of fields of the object + */ private boolean nestedFieldCheck( String[] parts, Map<String, Field> fieldMap) { if ( parts.length > 0 ) { http://git-wip-us.apache.org/repos/asf/usergrid/blob/5452d68c/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/value/EntityObject.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/value/EntityObject.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/value/EntityObject.java index db44e87..a157029 100644 --- a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/value/EntityObject.java +++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/value/EntityObject.java @@ -19,10 +19,7 @@ package org.apache.usergrid.persistence.model.field.value; import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import org.apache.usergrid.persistence.model.field.Field; @@ -41,11 +38,19 @@ public class EntityObject implements Serializable { @JsonIgnore private long size; + // field names are treated in case-insensitive way by design + static class CaseInsensitiveComparator implements Comparator<String> { + public int compare(String o1, String o2) { + return o1.compareToIgnoreCase(o2); + } + } + public static final CaseInsensitiveComparator INSTANCE = new CaseInsensitiveComparator(); + /** * Fields the users can set */ @JsonTypeInfo( use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class" ) - private final Map<String, Field> fields = new HashMap<String, Field>(); + private Map<String, Field> fields = new TreeMap<String, Field>(INSTANCE); /** * Add the field, return the old one if it existed http://git-wip-us.apache.org/repos/asf/usergrid/blob/5452d68c/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java new file mode 100644 index 0000000..eb6aeee --- /dev/null +++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java @@ -0,0 +1,105 @@ +/* + * 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.rest.applications.queries; + +import org.apache.usergrid.rest.test.resource.model.Collection; +import org.apache.usergrid.rest.test.resource.model.Entity; +import org.apache.usergrid.rest.test.resource.model.QueryParameters; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Iterator; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + + +public class SelectMappingsQueryTest extends QueryTestBase { + private static final Logger logger = LoggerFactory.getLogger(OrderByTest.class); + + + @Test + public void testNestedSelectFieldNames() throws Exception { + + generateTestEntities(20, "things"); + + QueryParameters params = new QueryParameters() + .setQuery("select actor.displayName,sometestprop where sometestprop = 'testprop'"); + Collection things = this.app().collection("things").get(params); + assertEquals( 10, things.getNumOfEntities() ); + + Iterator<Entity> iter = things.iterator(); + while ( iter.hasNext() ) { + + Entity entity = iter.next(); + assertEquals( 5, entity.getDynamicProperties().size() ); + + assertNotNull( entity.getDynamicProperties().get("uuid") ); + assertNotNull( entity.getDynamicProperties().get("type") ); + assertNotNull( entity.getDynamicProperties().get("metadata") ); + assertNotNull( entity.getDynamicProperties().get("sometestprop") ); + + Map<String, Object> actor = (Map<String, Object>)entity.getDynamicProperties().get("actor"); + assertNotNull( actor ); + assertNotNull( actor.get("displayName") ); + + } + } + + + /** + * Shows that field names are case-insensitive. + * If you define two fields with same name but different cases, behavior is undefined. + */ + @Test + public void testFieldNameCaseSensitivity() throws Exception { + + int numberOfEntities = 10; + String collectionName = "things"; + + Entity[] entities = new Entity[numberOfEntities]; + Entity props = new Entity(); + + for (int i = 0; i < numberOfEntities; i++) { + props.put("testProp", "a"); + props.put("testprop", "b"); + entities[i] = app().collection(collectionName).post(props); + } + refreshIndex(); + + { + QueryParameters params = new QueryParameters() + .setQuery( "select * where testProp = 'b'" ); + Collection things = this.app().collection( "things" ).get( params ); + + // if field names were case sensitive, this would fail + assertEquals( numberOfEntities, things.getNumOfEntities() ); + } + + { + QueryParameters params = new QueryParameters() + .setQuery( "select * where testprop='b'" ); + Collection things = this.app().collection( "things" ).get( params ); + + assertEquals( numberOfEntities, things.getNumOfEntities() ); + } + + } + +}
