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); }
