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 39309d5f1fcff561f08f43fbb850cca69e511a4f
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu Nov 6 10:36:03 2025 +0100

    Add aliases for some mathematical functions.
    For example, `CEIL` also known as `CEILING`.
    Note that this commit add the aliases in the Java code only.
    It does not check which spelling the database actually use.
---
 .../main/org/apache/sis/filter/math/Function.java  | 36 ++++++++++
 .../main/org/apache/sis/filter/math/Registry.java  |  8 +--
 .../main/org/apache/sis/filter/sqlmm/Registry.java |  4 +-
 .../apache/sis/filter/visitor/FunctionNames.java   | 14 ----
 .../org/apache/sis/storage/sql/SQLStoreTest.java   | 12 ++--
 .../org/apache/sis/util/collection/Containers.java | 79 +++++++++++++---------
 .../sis/util/internal/shared/CollectionsExt.java   |  2 +-
 7 files changed, 97 insertions(+), 58 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/Function.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/Function.java
index d96bfab94c..9beeb396b6 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/Function.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/Function.java
@@ -19,6 +19,7 @@ package org.apache.sis.filter.math;
 import java.util.Map;
 import java.util.List;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.function.DoubleUnaryOperator;
 import java.util.function.DoubleBinaryOperator;
 import java.util.function.DoublePredicate;
@@ -31,6 +32,7 @@ import org.apache.sis.parameter.DefaultParameterDescriptor;
 import org.apache.sis.feature.internal.shared.FeatureExpression;
 import org.apache.sis.filter.visitor.FunctionIdentifier;
 import org.apache.sis.filter.base.Node;
+import org.apache.sis.util.collection.Containers;
 import org.apache.sis.util.iso.Names;
 
 // Specific to the geoapi-3.1 and geoapi-4.0 branches:
@@ -86,6 +88,7 @@ public enum Function implements FunctionIdentifier, 
AvailableFunction {
 
     /**
      * The logarithm in base {@linkplain Math#E e} of <var>x</var>.
+     * This is named {@code LN} in some databases.
      */
     LOG(Math::log),
 
@@ -165,6 +168,16 @@ public enum Function implements FunctionIdentifier, 
AvailableFunction {
      */
     IS_NAN(Double::isNaN, null, null);
 
+    /**
+     * Synonymous of some function.
+     */
+    private static final Map<String, Function> ALIASES = Map.of(
+            "CEILING",    CEIL,
+            "LN",         LOG,
+            "isFinite",   IS_FINITE,
+            "isInfinite", IS_INFINITE,
+            "isNaN",      IS_NAN);
+
     /**
      * The mathematical function to invoke if this operation is a predicate, 
or {@code null}.
      */
@@ -325,4 +338,27 @@ public enum Function implements FunctionIdentifier, 
AvailableFunction {
         }
         return dataTypes;
     }
+
+    /**
+     * Returns the names and aliases of all functions.
+     */
+    static List<String> namesAndAliases() {
+        final var names = new 
ArrayList<String>(Containers.namesOf(Function.class));
+        names.addAll(ALIASES.keySet());
+        return names;
+    }
+
+    /**
+     * Returns the enumeration value for the given name.
+     * This method accepts synonymous.
+     *
+     * @param  name  the name or alias of the function.
+     * @return function for the given name or alias.
+     * @throws IllegalArgumentException if the given name or alias is unknown.
+     */
+    public static Function of(final String name) {
+        Function f = ALIASES.get(name);
+        if (f == null) f = valueOf(name);
+        return f;
+    }
 }
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/Registry.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/Registry.java
index 94ad94e5aa..0bb2ede9a3 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/Registry.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/Registry.java
@@ -18,8 +18,8 @@ package org.apache.sis.filter.math;
 
 import java.util.Set;
 import org.apache.sis.filter.FunctionRegister;
-import org.apache.sis.filter.visitor.FunctionNames;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.internal.shared.CollectionsExt;
 import org.apache.sis.util.internal.shared.Constants;
 
 // Specific to the geoapi-3.1 and geoapi-4.0 branches:
@@ -56,7 +56,7 @@ public final class Registry implements FunctionRegister {
      */
     @Override
     public Set<String> getNames() {
-        return FunctionNames.of(Function.class);
+        return CollectionsExt.viewAsSet(Function.namesAndAliases());
     }
 
     /**
@@ -68,7 +68,7 @@ public final class Registry implements FunctionRegister {
      */
     @Override
     public AvailableFunction describe(String name) {
-        return Function.valueOf(name);
+        return Function.of(name);
     }
 
     /**
@@ -82,7 +82,7 @@ public final class Registry implements FunctionRegister {
      */
     @Override
     public <R> Expression<R,?> create(final String name, final 
Expression<R,?>[] parameters) {
-        final Function function = Function.valueOf(name);
+        final Function function = Function.of(name);
         ArgumentChecks.ensureCountBetween("parameters", false,
                                           function.getMinParameterCount(),
                                           function.getMaxParameterCount(),
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/sqlmm/Registry.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/sqlmm/Registry.java
index 545e902304..6d479a0eee 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/sqlmm/Registry.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/sqlmm/Registry.java
@@ -17,9 +17,9 @@
 package org.apache.sis.filter.sqlmm;
 
 import java.util.Set;
+import org.apache.sis.util.collection.Containers;
 import org.apache.sis.geometry.wrapper.Geometries;
 import org.apache.sis.filter.FunctionRegister;
-import org.apache.sis.filter.visitor.FunctionNames;
 
 // Specific to the geoapi-3.1 and geoapi-4.0 branches:
 import org.opengis.filter.Expression;
@@ -61,7 +61,7 @@ public final class Registry implements FunctionRegister {
      */
     @Override
     public Set<String> getNames() {
-        return FunctionNames.of(SQLMM.class);
+        return Containers.namesOf(SQLMM.class);
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/visitor/FunctionNames.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/visitor/FunctionNames.java
index d974cd1fd4..74d073f832 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/visitor/FunctionNames.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/visitor/FunctionNames.java
@@ -16,13 +16,9 @@
  */
 package org.apache.sis.filter.visitor;
 
-import java.util.Arrays;
-import java.util.Set;
 import org.opengis.util.CodeList;
 import org.apache.sis.filter.DefaultFilterFactory;
 import org.apache.sis.filter.sqlmm.SQLMM;
-import org.apache.sis.util.collection.Containers;
-import org.apache.sis.util.internal.shared.CollectionsExt;
 
 
 /**
@@ -102,14 +98,4 @@ public final class FunctionNames {
     public static CodeList<?> resourceId() {
         return 
DefaultFilterFactory.forFeatures().resourceId("resourceId").getOperatorType();
     }
-
-    /**
-     * Returns the names of all enumeration values, to be interpreted as 
function names.
-     *
-     * @param  type  type of the enumeration for which to get the names.
-     * @return the names viewed as a collection.
-     */
-    public static Set<String> of(final Class<? extends Enum<?>> type) {
-        return 
CollectionsExt.viewAsSet(Containers.derivedList(Arrays.asList(type.getEnumConstants()),
 Enum::name));
-    }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/SQLStoreTest.java
 
b/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/SQLStoreTest.java
index 71b460e328..bf3cc4110e 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/SQLStoreTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/SQLStoreTest.java
@@ -389,7 +389,7 @@ public final class SQLStoreTest extends TestOnAllDatabases {
     }
 
     /**
-     * Requests features with a mathematical operation.
+     * Requests features with some mathematical operations.
      *
      * @param  dataset  the store on which to query the features.
      * @throws DataStoreException if an error occurred during query execution.
@@ -401,9 +401,9 @@ public final class SQLStoreTest extends TestOnAllDatabases {
                             new 
FeatureQuery.NamedExpression(FF.function("SQRT", FF.property("population")), 
"value"));
         final FeatureSet subset = cities.subset(query);
         final var values = new HashMap<Object, Object>();
-        subset.features(false).forEach(
-                (feature) -> 
assertNull(values.put(feature.getPropertyValue("english_name"),
-                                                   
feature.getPropertyValue("value"))));
+        subset.features(false).forEach((feature) ->
+                assertNull(values.put(feature.getPropertyValue("english_name"),
+                                      feature.getPropertyValue("value"))));
         final String[] expected = {"Montreal", "Quebec", "Paris", "Tōkyō"};
         final int[]  population = {  1704694,   531902, 2206488, 13622267};
         for (int i=0; i<expected.length; i++) {
@@ -411,8 +411,8 @@ public final class SQLStoreTest extends TestOnAllDatabases {
             final double value = assertInstanceOf(Double.class, 
values.remove(city), city);
             assertEquals(population[i], value * value, 0.1, city);
         }
-        // Try again with a function returning a boolean value.
-        query.setProjection(new 
FeatureQuery.NamedExpression(FF.function("IS_NAN", FF.property("population")), 
"flag"));
+        // Try again with a function returning a boolean value and with a 
function name which is an alias.
+        query.setProjection(new 
FeatureQuery.NamedExpression(FF.function("isNaN", FF.property("population")), 
"flag"));
         cities.subset(query).features(false).forEach((feature) -> 
assertEquals(Boolean.FALSE, feature.getPropertyValue("flag")));
     }
 
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/Containers.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/Containers.java
index a8110729ba..c5798ef7b7 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/Containers.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/Containers.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.util.collection;
 
+import java.util.Arrays;
 import java.util.Map;
 import java.util.Set;
 import java.util.List;
@@ -26,13 +27,13 @@ import java.util.function.Function;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.ObjectConverter;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.internal.shared.CollectionsExt;
 import org.apache.sis.util.internal.shared.UnmodifiableArrayList;
 
 
 /**
- * Static methods working on {@link Collection} or {@link CheckedContainer} 
objects.
- * Unless otherwise noted in the javadoc, every collections returned by the 
methods
- * in this class implement the {@code CheckedContainer} interface.
+ * Static methods working on various types of objects that can be viewed as 
collections.
+ * The types include {@link Collection}, {@link CheckedContainer} or {@code 
Class<Enum>}.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @version 1.6
@@ -123,6 +124,36 @@ public final class Containers {
         return UnmodifiableArrayList.wrap(array, lower, upper);
     }
 
+    /**
+     * Returns a list whose elements are derived <i>on-the-fly</i> from the 
given list.
+     * Conversions from the original elements to the derived elements are 
performed when needed
+     * by invoking the {@link Function#apply(Object)} method on the given 
converter.
+     * Those conversions are repeated every time that a {@code List} method 
needs to access values.
+     * Consequently, any change in the original list is immediately visible in 
the derived list.
+     *
+     * <p>The returned list can be serialized if the given list and converter 
are serializable.
+     * The returned list is not synchronized by itself, but is nevertheless 
thread-safe if the
+     * given list (including its iterator) and converter are thread-safe.</p>
+     *
+     * <p>The returned list does <em>not</em> implement {@link 
CheckedContainer}.</p>
+     *
+     * @param  <S>        the type of elements in the storage (original) list.
+     * @param  <E>        the type of elements in the derived list.
+     * @param  storage    the storage list containing the original elements, 
or {@code null}.
+     * @param  converter  the converter from the elements in the storage list 
to the elements in the derived list.
+     * @return a view over the {@code storage} list containing all elements 
converted by the given converter,
+     *         or {@code null} if {@code storage} was null.
+     *
+     * @since 1.6
+     */
+    public static <S,E> List<E> derivedList(final List<S> storage, final 
Function<S,E> converter) {
+        ArgumentChecks.ensureNonNull("converter", converter);
+        if (storage == null) {
+            return null;
+        }
+        return new DerivedList<>(storage, converter);
+    }
+
     /**
      * Returns a set whose elements are derived <i>on-the-fly</i> from the 
given set.
      * Conversions from the original elements to the derived elements are 
performed when needed
@@ -163,34 +194,6 @@ public final class Containers {
         return DerivedSet.create(storage, converter);
     }
 
-    /**
-     * Returns a list whose elements are derived <i>on-the-fly</i> from the 
given list.
-     * Conversions from the original elements to the derived elements are 
performed when needed
-     * by invoking the {@link Function#apply(Object)} method on the given 
converter.
-     * Those conversions are repeated every time that a {@code List} method 
needs to access values.
-     * Consequently, any change in the original list is immediately visible in 
the derived list.
-     *
-     * <p>The returned list can be serialized if the given list and converter 
are serializable.
-     * The returned list is not synchronized by itself, but is nevertheless 
thread-safe if the
-     * given list (including its iterator) and converter are thread-safe.</p>
-     *
-     * @param  <S>        the type of elements in the storage (original) list.
-     * @param  <E>        the type of elements in the derived list.
-     * @param  storage    the storage list containing the original elements, 
or {@code null}.
-     * @param  converter  the converter from the elements in the storage list 
to the elements in the derived list.
-     * @return a view over the {@code storage} list containing all elements 
converted by the given converter,
-     *         or {@code null} if {@code storage} was null.
-     *
-     * @since 1.6
-     */
-    public static <S,E> List<E> derivedList(final List<S> storage, final 
Function<S,E> converter) {
-        ArgumentChecks.ensureNonNull("converter", converter);
-        if (storage == null) {
-            return null;
-        }
-        return new DerivedList<>(storage, converter);
-    }
-
     /**
      * Returns a map whose keys and values are derived <i>on-the-fly</i> from 
the given map.
      * Conversions from the original entries to the derived entries are 
performed when needed
@@ -242,6 +245,20 @@ public final class Containers {
         return DerivedMap.create(storage, keyConverter, valueConverter);
     }
 
+    /**
+     * Returns in an unmodifiable set the names of all enumeration values of 
the given type.
+     * The names are obtained by {@link Enum#name()}, which guarantees that 
there is no duplicated values.
+     * The iteration order is the declaration order of the enumeration values.
+     *
+     * @param  type  type of the enumeration for which to get the names.
+     * @return the names viewed as an unmodifiable set.
+     *
+     * @since 1.6
+     */
+    public static Set<String> namesOf(final Class<? extends Enum<?>> type) {
+        return 
CollectionsExt.viewAsSet(derivedList(Arrays.asList(type.getEnumConstants()), 
Enum::name));
+    }
+
     /**
      * Returns the value mapped to the given key cast to the given type,
      * or {@code null} if the map is null or does not contain a value for the 
key.
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/CollectionsExt.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/CollectionsExt.java
index fcff2d39c4..d4e1cdb20b 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/CollectionsExt.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/CollectionsExt.java
@@ -394,7 +394,7 @@ public final class CollectionsExt {
             }
             default: {
                 @SuppressWarnings("varargs")
-                final Set<E> set = new LinkedHashSet<>(Arrays.asList(array));
+                final var set = new LinkedHashSet<E>(Arrays.asList(array));
                 if (excludeNull) {
                     set.remove(null);
                 }

Reply via email to