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 968260ebad0013fc75b60e6ef8a65c92c058d8de Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Wed Aug 2 18:11:02 2023 +0200 Add a `FunctionRegister.describe(String)` method. --- .../sis/internal/filter/FunctionRegister.java | 12 +- .../internal/filter/sqlmm/FunctionDescription.java | 176 +++++++++++++++++++++ .../apache/sis/internal/filter/sqlmm/Registry.java | 13 ++ .../apache/sis/internal/filter/sqlmm/SQLMM.java | 31 +++- .../internal/filter/sqlmm/RegistryTestCase.java | 18 +++ 5 files changed, 246 insertions(+), 4 deletions(-) diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/FunctionRegister.java b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/FunctionRegister.java index 109a55da51..0a147fcae7 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/FunctionRegister.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/FunctionRegister.java @@ -18,6 +18,7 @@ package org.apache.sis.internal.filter; import java.util.Collection; import org.opengis.filter.Expression; +import org.opengis.filter.capability.AvailableFunction; /** @@ -57,7 +58,16 @@ public interface FunctionRegister { Collection<String> getNames(); /** - * Create a new function of the given name with given parameters. + * Describes the parameters of a function. + * + * @param name name of the function to describe (not null). + * @return description of the function parameters. + * @throws IllegalArgumentException if function name is unknown.. + */ + AvailableFunction describe(String name) throws IllegalArgumentException; + + /** + * Creates a new function of the given name with given parameters. * * @param <R> the type of resources (e.g. {@link org.opengis.feature.Feature}) used as inputs. * @param name name of the function to create (not null). diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/FunctionDescription.java b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/FunctionDescription.java new file mode 100644 index 0000000000..d3b8407ef9 --- /dev/null +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/FunctionDescription.java @@ -0,0 +1,176 @@ +/* + * 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.sis.internal.filter.sqlmm; + +import java.util.List; +import org.opengis.util.LocalName; +import org.opengis.util.TypeName; +import org.apache.sis.util.iso.Names; +import org.apache.sis.internal.feature.Geometries; +import org.apache.sis.internal.feature.GeometryType; + +// Branch-dependent imports +import org.opengis.filter.capability.Argument; +import org.opengis.filter.capability.AvailableFunction; + + +/** + * Description of a SQLMM function with its parameters. + * + * @todo Argument descriptions are incomplete. They have no good names, + * and the types are missing (null) except for geometry types. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.4 + * + * @see SQLMM#description(Geometries) + * + * @since 1.4 + */ +final class FunctionDescription implements AvailableFunction { + /** + * The function name in SQLMM namespace. + * + * @see #getName() + */ + private final LocalName name; + + /** + * The name and type of each argument expected by this function. + * This list is unmodifiable. + * + * @see #getArguments() + */ + private final List<Argument> arguments; + + /** + * The type of return value. + * + * @see #getReturnType() + */ + private final TypeName result; + + /** + * Creates a new description for the given SQLMM function. + * + * @param function the SQLMM function for which to create a description. + * @param library the geometry library implementation in use. + */ + FunctionDescription(final SQLMM function, final Geometries<?> library) { + name = createLocalName(function.name()); + final Arg[] args = new Arg[function.maxParamCount]; + for (int i=0; i<args.length; i++) { + final GeometryType type; + switch (i) { + case 0: type = function.geometryType1; break; + case 1: type = function.geometryType2; break; + default: type = null; break; + } + args[i] = new Arg(i, (type != null) ? type.getTypeName(library) : null); + } + arguments = List.of(args); + result = function.getGeometryType().map((t) -> t.getTypeName(library)) + .orElseGet(() -> Names.createTypeName(function.getReturnType(library))); + } + + /** + * Creates a name which is local in SQLMM namespace. + * + * @param name text of the name to create. + * @return name which is local in SQLMM namespace. + */ + private static LocalName createLocalName(final String name) { + return Names.createLocalName("SQLMM", null, name); + } + + /** + * Returns the function name in SQLMM namespace. This is the {@linkplain SQLMM#name() name} + * of the enumeration value, but wrapped in a {@link LocalName} with the "SQLMM" namespace. + * + * @return the function name. + */ + @Override + public LocalName getName() { + return name; + } + + /** + * Returns the name and type of each argument expected by this function. + * + * @return arguments that the function accepts. + */ + @Override + @SuppressWarnings("ReturnOfCollectionOrArrayField") + public List<Argument> getArguments() { + return arguments; + } + + /** + * Returns the type of return value. + * + * @return the type of return value. + */ + @Override + public TypeName getReturnType() { + return result; + } + + /** + * Description of an argument of a SQLMM function. + * + * @todo Argument names are not informative. + * @todo Argument types are unknown if not geometric. + */ + private static final class Arg implements Argument { + /** + * The argument name. + */ + private final LocalName name; + + /** + * The value type, or {@code null} if unknown. + */ + private final TypeName type; + + /** + * Creates a new argument description. + * + * @param i index of the argument being created. + * @param type the argument type, or {@code null} if unknown. + */ + Arg(final int i, final TypeName type) { + this.name = createLocalName("arg" + (i+1)); + this.type = type; + } + + /** + * {@return the name of the argument}. + */ + @Override + public LocalName getName() { + return name; + } + + /** + * {@return the name of the type of the argument}. + */ + @Override + public TypeName getValueType() { + return type; + } + } +} diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/Registry.java b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/Registry.java index 37371d0870..b71a9e5148 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/Registry.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/Registry.java @@ -24,6 +24,7 @@ import org.apache.sis.internal.jdk17.JDK17; // Branch-dependent imports import org.opengis.filter.Expression; +import org.opengis.filter.capability.AvailableFunction; /** @@ -66,6 +67,18 @@ public final class Registry implements FunctionRegister { return JDK17.toList(Arrays.stream(SQLMM.values()).map(SQLMM::name)); } + /** + * Describes the parameters of a function. + * + * @param name name of the function to describe. + * @return description of the function parameters. + * @throws IllegalArgumentException if function name is unknown.. + */ + @Override + public AvailableFunction describe(final String name) { + return SQLMM.valueOf(name).description(library); + } + /** * Create a new function of the given name with given parameters. * It is caller's responsibility to ensure that the given array is non-null, diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/SQLMM.java b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/SQLMM.java index c8c3615032..f43e86f6e8 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/SQLMM.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/filter/sqlmm/SQLMM.java @@ -16,9 +16,11 @@ */ package org.apache.sis.internal.filter.sqlmm; +import java.util.EnumMap; import java.util.Optional; import javax.measure.Quantity; import org.opengis.geometry.Envelope; +import org.apache.sis.setup.GeometryLibrary; import org.apache.sis.internal.feature.Geometries; import org.apache.sis.internal.feature.GeometryType; @@ -26,6 +28,7 @@ import static org.apache.sis.internal.feature.GeometryType.*; // Branch-dependent imports import org.opengis.filter.SpatialOperatorName; +import org.opengis.filter.capability.AvailableFunction; /** @@ -34,7 +37,7 @@ import org.opengis.filter.SpatialOperatorName; * Enumeration values order is the approximated declaration order in SQLMM standard. * * @author Martin Desruisseaux (Geomatys) - * @version 1.1 + * @version 1.4 * * @see <a href="https://www.iso.org/standard/60343.html">ISO 13249-3 - SQLMM</a> * @@ -783,10 +786,18 @@ public enum SQLMM { /** * Type of value returned by the method as a {@link Class} or a {@link GeometryType}. * - * @see #getReturnType() + * @see #getReturnType(Geometries) */ private final Object returnType; + /** + * Description of this SQLMM function, created when first needed. + * The associated Java type depends on the geometry library. + * + * @see #description(Geometries) + */ + private transient EnumMap<GeometryLibrary,AvailableFunction> descriptions; + /** * Creates a new enumeration value for an operation expecting exactly one geometry object * and no other argument. @@ -827,13 +838,27 @@ public enum SQLMM { this.returnType = returnType; } + /** + * Returns a description of this SQLMM function. + * The Java types associated to arguments and return value depend on which geometry library is used. + * + * @param library the geometry ilibrary implementation to use. + * @return description of this SQLMM function. + */ + public final synchronized AvailableFunction description(final Geometries<?> library) { + if (descriptions == null) { + descriptions = new EnumMap<>(GeometryLibrary.class); + } + return descriptions.computeIfAbsent(library.library, (key) -> new FunctionDescription(this, library)); + } + /** * Returns the number of parameters that are geometry objects. Those parameters shall be first. * This value shall be between {@link #minParamCount} and {@link #maxParamCount}. * * @return number of parameters that are geometry objects. */ - public int geometryCount() { + public final int geometryCount() { return (geometryType1 == null) ? 0 : (geometryType2 == null) ? 1 : 2; } diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/filter/sqlmm/RegistryTestCase.java b/core/sis-feature/src/test/java/org/apache/sis/internal/filter/sqlmm/RegistryTestCase.java index 11fa836c57..4aac037849 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/internal/filter/sqlmm/RegistryTestCase.java +++ b/core/sis-feature/src/test/java/org/apache/sis/internal/filter/sqlmm/RegistryTestCase.java @@ -50,6 +50,7 @@ import org.opengis.filter.Literal; import org.opengis.filter.Expression; import org.opengis.filter.FilterFactory; import org.opengis.filter.ValueReference; +import org.opengis.filter.capability.AvailableFunction; /** @@ -127,6 +128,23 @@ public abstract class RegistryTestCase<G> extends TestCase { this.supportCRS = supportCRS; } + /** + * Tests {@link Registry#describe(String)}. + */ + @Test + public void testDescribe() { + final Registry r = new Registry(library); + AvailableFunction desc = r.describe("ST_Transform"); + assertEquals("SQLMM:ST_Transform", desc.getName().toFullyQualifiedName().toString()); + assertEquals("OGC:Geometry", desc.getReturnType().toFullyQualifiedName().toString()); + assertEquals(library.rootClass, desc.getReturnType().toJavaType().get()); + + desc = r.describe("ST_PointFromText"); + assertEquals("ST_PointFromText", desc.getName().toString()); + assertEquals("OGC:Point", desc.getReturnType().toFullyQualifiedName().toString()); + assertEquals(library.pointClass, desc.getReturnType().toJavaType().get()); + } + /** * Verifies that attempts to create a function of the given name fail if no argument is provided. */