This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 882b2546639adb474a17795b70d9cea4bdf0f517
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Fri Sep 29 15:55:31 2023 +0200

    Modification of the fix about the property name of a link.
    The check for instance of `ValueReference` should be merged with the 
existing check done 20 lines below.
---
 .../main/org/apache/sis/storage/FeatureQuery.java  | 42 ++++++++-------
 .../org/apache/sis/storage/FeatureQueryTest.java   | 60 +++++++++++++++-------
 2 files changed, 61 insertions(+), 41 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/FeatureQuery.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/FeatureQuery.java
index d0d8f9c218..172b87705a 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/FeatureQuery.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/FeatureQuery.java
@@ -738,7 +738,7 @@ public class FeatureQuery extends Query implements 
Cloneable, Serializable {
             final NamedExpression item = projection[column];
             /*
              * For each property, get the expected type (mandatory) and its 
name (optional).
-             * A default name will be computed if no alias were explicitly 
given by user.
+             * A default name will be computed if no alias was explicitly 
given by the user.
              */
             final Expression<? super Feature,?> expression = item.expression;
             final FeatureExpression<?,?> fex = 
FeatureExpression.castOrCopy(expression);
@@ -748,14 +748,6 @@ public class FeatureQuery extends Query implements 
Cloneable, Serializable {
                             
expression.getFunctionName().toInternationalString(), column));
             }
             GenericName name = item.alias;
-            if (name == null && expression instanceof ValueReference<?,?>) {
-                /*
-                 * If we do not have an alias, use the original property name.
-                 * This name may be different from the resultType name because 
of links or functions.
-                 */
-                name = valueType.getProperty(((ValueReference<?, ?>) 
expression).getXPath()).getName();
-            }
-
             if (name == null) {
                 /*
                  * Build a list of aliases declared by the user, for making 
sure that we do not collide with them.
@@ -777,14 +769,20 @@ public class FeatureQuery extends Query implements 
Cloneable, Serializable {
                  */
                 CharSequence text = null;
                 if (expression instanceof ValueReference<?,?>) {
-                    final GenericName current = resultType.getName();
-                    if (current != null && names.add(current.toString())) {
-                        continue;
-                    }
                     String xpath = ((ValueReference<?,?>) 
expression).getXPath().trim();
-                    xpath = xpath.substring(xpath.lastIndexOf(XPath.SEPARATOR) 
+ 1);  // Works also if '/' is not found.
-                    if (!(xpath.isEmpty() || names.contains(xpath))) {
-                        text = xpath;
+                    /*
+                     * Before to take the tip, take the existing `GenericName` 
instance from the property.
+                     * It should be equivalent, except that it may be a 
`ScopedName` instead of `LocalName`.
+                     * We do not take `resultType.getName()` because the 
latter is different if the property
+                     * is itself a link to another property (in which case 
`resultType` is the final target).
+                     */
+                    name = valueType.getProperty(xpath).getName();
+                    if (name == null || !names.add(name.toString())) {
+                        name = null;
+                        xpath = 
xpath.substring(xpath.lastIndexOf(XPath.SEPARATOR) + 1);  // Works also if '/' 
is not found.
+                        if (!(xpath.isEmpty() || names.contains(xpath))) {
+                            text = xpath;
+                        }
                     }
                 }
                 /*
@@ -793,15 +791,15 @@ public class FeatureQuery extends Query implements 
Cloneable, Serializable {
                  * (for easier programmatic use) because `GenericName` 
implementation is designed for
                  * providing localized names only if explicitly requested.
                  */
-                if (text == null) do {
-                    text = 
Vocabulary.formatInternational(Vocabulary.Keys.Unnamed_1, ++unnamedNumber);
-                } while (!names.add(text.toString()));
-                name = Names.createLocalName(null, null, text);
+                if (name == null) {
+                    if (text == null) do {
+                        text = 
Vocabulary.formatInternational(Vocabulary.Keys.Unnamed_1, ++unnamedNumber);
+                    } while (!names.add(text.toString()));
+                    name = Names.createLocalName(null, null, text);
+                }
             }
             /*
              * If the attribute that we just added should be virtual, replace 
the attribute by an operation.
-             * We need to keep the property name computed by 
`fex.expectedType(…)` for the operation result,
-             * because that name is the name of the link to create if the 
operation is `ValueReference`.
              */
             if (item.type == ProjectionType.COMPUTING && resultType instanceof 
AttributeTypeBuilder<?>) {
                 final var ab = (AttributeTypeBuilder<?>) resultType;
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureQueryTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureQueryTest.java
index 4dea8a07ca..a165f2bc7d 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureQueryTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureQueryTest.java
@@ -63,12 +63,12 @@ public final class FeatureQueryTest extends TestCase {
     /**
      * An arbitrary number of features, all of the same type.
      */
-    private final Feature[] features;
+    private Feature[] features;
 
     /**
      * The {@link #features} array wrapped in a in-memory feature set.
      */
-    private final FeatureSet featureSet;
+    private FeatureSet featureSet;
 
     /**
      * The query to be executed.
@@ -76,9 +76,31 @@ public final class FeatureQueryTest extends TestCase {
     private final FeatureQuery query;
 
     /**
-     * Creates a new test with a feature type composed of two attributes and 
one association.
+     * Creates a new test case.
      */
     public FeatureQueryTest() {
+        query = new FeatureQuery();
+    }
+
+    /**
+     * Creates a simple feature with a property flagged as an identifier.
+     */
+    private void createFeatureWithIdentifier() {
+        final FeatureTypeBuilder ftb = new 
FeatureTypeBuilder().setName("Test");
+        
ftb.addAttribute(String.class).setName("id").addRole(AttributeRole.IDENTIFIER_COMPONENT);
+        final FeatureType type = ftb.build();
+        features = new Feature[] {
+            type.newInstance()
+        };
+        features[0].setPropertyValue("id", "id-0");
+        featureSet = new MemoryFeatureSet(null, type, Arrays.asList(features));
+    }
+
+    /**
+     * Creates a set of features common to most tests.
+     * The feature type is composed of two attributes and one association.
+     */
+    private void createFeaturesWithAssociation() {
         FeatureTypeBuilder ftb;
 
         // A dependency of the test feature type.
@@ -100,7 +122,6 @@ public final class FeatureQueryTest extends TestCase {
             feature(type, null,       4, 1,  0)
         };
         featureSet = new MemoryFeatureSet(null, type, Arrays.asList(features));
-        query      = new FeatureQuery();
     }
 
     /**
@@ -158,6 +179,7 @@ public final class FeatureQueryTest extends TestCase {
      */
     @Test
     public void testLimit() throws DataStoreException {
+        createFeaturesWithAssociation();
         query.setLimit(2);
         verifyQueryResult(0, 1);
     }
@@ -169,6 +191,7 @@ public final class FeatureQueryTest extends TestCase {
      */
     @Test
     public void testOffset() throws DataStoreException {
+        createFeaturesWithAssociation();
         query.setOffset(2);
         verifyQueryResult(2, 3, 4);
     }
@@ -180,6 +203,7 @@ public final class FeatureQueryTest extends TestCase {
      */
     @Test
     public void testSortBy() throws DataStoreException {
+        createFeaturesWithAssociation();
         final FilterFactory<Feature,?,?> ff = 
DefaultFilterFactory.forFeatures();
         query.setSortBy(ff.sort(ff.property("value1", Integer.class), 
SortOrder.ASCENDING),
                         ff.sort(ff.property("value2", Integer.class), 
SortOrder.DESCENDING));
@@ -193,6 +217,7 @@ public final class FeatureQueryTest extends TestCase {
      */
     @Test
     public void testSelection() throws DataStoreException {
+        createFeaturesWithAssociation();
         final FilterFactory<Feature,?,?> ff = 
DefaultFilterFactory.forFeatures();
         query.setSelection(ff.equal(ff.property("value1", Integer.class),
                                     ff.literal(2), true, MatchAction.ALL));
@@ -207,6 +232,7 @@ public final class FeatureQueryTest extends TestCase {
      */
     @Test
     public void testSelectionThroughAssociation() throws DataStoreException {
+        createFeaturesWithAssociation();
         final FilterFactory<Feature,?,?> ff = 
DefaultFilterFactory.forFeatures();
         query.setSelection(ff.equal(ff.property("dependency/value3"), 
ff.literal(18)));
         verifyQueryResult(3);
@@ -219,6 +245,7 @@ public final class FeatureQueryTest extends TestCase {
      */
     @Test
     public void testProjection() throws DataStoreException {
+        createFeaturesWithAssociation();
         final FilterFactory<Feature,?,?> ff = 
DefaultFilterFactory.forFeatures();
         query.setProjection(new 
FeatureQuery.NamedExpression(ff.property("value1", Integer.class), (String) 
null),
                             new 
FeatureQuery.NamedExpression(ff.property("value1", Integer.class), "renamed1"),
@@ -252,6 +279,7 @@ public final class FeatureQueryTest extends TestCase {
      */
     @Test
     public void testProjectionByNames() throws DataStoreException {
+        createFeaturesWithAssociation();
         query.setProjection("value2");
         final Feature instance = executeAndGetFirst();
         final PropertyType p = 
TestUtilities.getSingleton(instance.getType().getProperties(true));
@@ -266,6 +294,7 @@ public final class FeatureQueryTest extends TestCase {
      */
     @Test
     public void testDefaultColumnName() throws DataStoreException {
+        createFeaturesWithAssociation();
         final FilterFactory<Feature,?,?> ff = 
DefaultFilterFactory.forFeatures();
         query.setLimit(1);
         query.setProjection(
@@ -291,6 +320,7 @@ public final class FeatureQueryTest extends TestCase {
      */
     @Test
     public void testProjectionOfAbstractType() throws DataStoreException {
+        createFeaturesWithAssociation();
         final FilterFactory<Feature,?,?> ff = 
DefaultFilterFactory.forFeatures();
         query.setProjection(new 
FeatureQuery.NamedExpression(ff.property("value1"),  (String) null),
                             new 
FeatureQuery.NamedExpression(ff.property("/*/unknown"), "unexpected"));
@@ -320,6 +350,7 @@ public final class FeatureQueryTest extends TestCase {
      */
     @Test
     public void testProjectionThroughAssociation() throws DataStoreException {
+        createFeaturesWithAssociation();
         final FilterFactory<Feature,?,?> ff = 
DefaultFilterFactory.forFeatures();
         query.setProjection(new 
FeatureQuery.NamedExpression(ff.property("value1"),  (String) null),
                             new 
FeatureQuery.NamedExpression(ff.property("dependency/value3"), "value3"));
@@ -331,27 +362,16 @@ public final class FeatureQueryTest extends TestCase {
 
     /**
      * Tests {@link 
FeatureQuery#setProjection(FeatureQuery.NamedExpression...)} on a field
-     * which is a link, ensure the link name is preserved.
+     * which is a link, ensuring that the link name is preserved.
      *
      * @throws DataStoreException if an error occurred while executing the 
query.
      */
     @Test
     public void testProjectionOfLink() throws DataStoreException {
-
-        final FeatureTypeBuilder ftb = new FeatureTypeBuilder();
-        ftb.setName("test");
-        
ftb.addAttribute(String.class).setName("id").addRole(AttributeRole.IDENTIFIER_COMPONENT);
-        FeatureType ft = ftb.build();
-
-        Feature feature = ft.newInstance();
-        feature.setPropertyValue("id", "id-0");
-
-        final FeatureQuery query = new FeatureQuery();
+        createFeatureWithIdentifier();
         query.setProjection(AttributeConvention.IDENTIFIER);
-
-        final FeatureSet fs = new MemoryFeatureSet(null, ft, List.of(feature));
-        Feature r = fs.subset(query).features(true).iterator().next();
-        assertEquals("id-0", 
r.getPropertyValue(AttributeConvention.IDENTIFIER));
+        final Feature instance = executeAndGetFirst();
+        assertEquals("id-0", 
instance.getPropertyValue(AttributeConvention.IDENTIFIER));
     }
 
     /**
@@ -368,6 +388,7 @@ public final class FeatureQueryTest extends TestCase {
      */
     @Test
     public void testVirtualProjection() throws DataStoreException {
+        createFeaturesWithAssociation();
         final FilterFactory<Feature,?,?> ff = 
DefaultFilterFactory.forFeatures();
         query.setProjection(
                 new FeatureQuery.NamedExpression(ff.property("value1", 
Integer.class), (String) null),
@@ -411,6 +432,7 @@ public final class FeatureQueryTest extends TestCase {
      */
     @Test
     public void testIncorrectVirtualProjection() throws DataStoreException {
+        createFeaturesWithAssociation();
         final FilterFactory<Feature,?,?> ff = 
DefaultFilterFactory.forFeatures();
         query.setProjection(new 
FeatureQuery.NamedExpression(ff.property("value1", Integer.class), (String) 
null),
                             virtualProjection(ff.property("valueMissing", 
Integer.class), "renamed1"));

Reply via email to