This is an automated email from the ASF dual-hosted git repository. mchades pushed a commit to branch udf-poc in repository https://gitbox.apache.org/repos/asf/gravitino.git
commit ae25f2e2fd124c85cf9814680f8e4a39e430b58a Author: mchades <[email protected]> AuthorDate: Wed Dec 17 20:22:48 2025 +0800 implement RESTful API for function operations --- .../apache/gravitino/dto/function/FunctionDTO.java | 11 ++++- .../gravitino/dto/function/FunctionImplDTO.java | 55 +++++++++++++++++----- .../gravitino/dto/function/FunctionParamDTO.java | 8 ++-- .../dto/requests/FunctionUpdateRequest.java | 3 ++ .../apache/gravitino/dto/util/DTOConverters.java | 13 ++++- rfc/Design of Functions Management in Gravitino.md | 19 ++++++++ .../server/web/rest/FunctionOperations.java | 16 +++---- 7 files changed, 100 insertions(+), 25 deletions(-) diff --git a/common/src/main/java/org/apache/gravitino/dto/function/FunctionDTO.java b/common/src/main/java/org/apache/gravitino/dto/function/FunctionDTO.java index b43043e4a8..cca538d29d 100644 --- a/common/src/main/java/org/apache/gravitino/dto/function/FunctionDTO.java +++ b/common/src/main/java/org/apache/gravitino/dto/function/FunctionDTO.java @@ -18,6 +18,8 @@ */ package org.apache.gravitino.dto.function; +import static org.apache.gravitino.dto.util.DTOConverters.toFunctionArg; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -33,6 +35,7 @@ import org.apache.gravitino.function.FunctionImpl; import org.apache.gravitino.function.FunctionSignature; import org.apache.gravitino.function.FunctionType; import org.apache.gravitino.json.JsonUtils; +import org.apache.gravitino.rel.Column; import org.apache.gravitino.rel.types.Type; /** DTO for {@link Function}. */ @@ -133,7 +136,12 @@ public class FunctionDTO implements Function { param.name(), param.dataType(), param.comment(), - param.defaultValue())) + (param.defaultValue() == null + || param + .defaultValue() + .equals(Column.DEFAULT_VALUE_NOT_SET)) + ? Column.DEFAULT_VALUE_NOT_SET + : toFunctionArg(param.defaultValue()))) .toArray(FunctionParamDTO[]::new))) .withFunctionType(function.functionType()) .withDeterministic(function.deterministic()) @@ -216,6 +224,7 @@ public class FunctionDTO implements Function { return version; } + /** Builder for {@link FunctionDTO}. */ public static class Builder { private FunctionSignatureDTO signature; private FunctionType functionType; diff --git a/common/src/main/java/org/apache/gravitino/dto/function/FunctionImplDTO.java b/common/src/main/java/org/apache/gravitino/dto/function/FunctionImplDTO.java index 0542582d25..5f87e3b858 100644 --- a/common/src/main/java/org/apache/gravitino/dto/function/FunctionImplDTO.java +++ b/common/src/main/java/org/apache/gravitino/dto/function/FunctionImplDTO.java @@ -43,6 +43,11 @@ import org.apache.gravitino.rest.RESTRequest; }) public interface FunctionImplDTO extends RESTRequest { + /** + * Converts this DTO to a {@link FunctionImpl}. + * + * @return The converted function implementation. + */ FunctionImpl toFunctionImpl(); /** DTO for SQL implementation. */ @@ -51,8 +56,8 @@ public interface FunctionImplDTO extends RESTRequest { @ToString class SqlImplDTO implements FunctionImplDTO { - @JsonProperty("dialect") - private String dialect; + @JsonProperty("runtime") + private String runtime; @JsonProperty("sql") private String sql; @@ -70,17 +75,17 @@ public interface FunctionImplDTO extends RESTRequest { /** * Creates a SQL implementation DTO. * - * @param dialect SQL dialect. + * @param runtime Target runtime. * @param sql SQL text. * @param resources Optional resources. * @param properties Implementation properties. */ public SqlImplDTO( - String dialect, + String runtime, String sql, FunctionResourcesDTO resources, Map<String, String> properties) { - this.dialect = dialect; + this.runtime = runtime; this.sql = sql; this.resources = resources; this.properties = properties; @@ -90,13 +95,16 @@ public interface FunctionImplDTO extends RESTRequest { @Override public FunctionImpl toFunctionImpl() { return FunctionImpl.ofSql( - dialect, sql, resources == null ? null : resources.toResources(), properties); + FunctionImpl.RuntimeType.fromString(runtime), + sql, + resources == null ? null : resources.toResources(), + properties); } /** {@inheritDoc} */ @Override public void validate() throws IllegalArgumentException { - Preconditions.checkArgument(StringUtils.isNotBlank(dialect), "\"dialect\" is required"); + Preconditions.checkArgument(StringUtils.isNotBlank(runtime), "\"runtime\" is required"); Preconditions.checkArgument(StringUtils.isNotBlank(sql), "\"sql\" is required"); if (resources != null) { resources.toResources(); @@ -111,6 +119,9 @@ public interface FunctionImplDTO extends RESTRequest { @NoArgsConstructor(access = AccessLevel.PRIVATE) class JavaImplDTO implements FunctionImplDTO { + @JsonProperty("runtime") + private String runtime; + @JsonProperty("className") private String className; @@ -123,12 +134,17 @@ public interface FunctionImplDTO extends RESTRequest { /** * Creates a Java implementation DTO. * + * @param runtime Target runtime. * @param className Fully qualified class name. * @param resources Optional resources. * @param properties Implementation properties. */ public JavaImplDTO( - String className, FunctionResourcesDTO resources, Map<String, String> properties) { + String runtime, + String className, + FunctionResourcesDTO resources, + Map<String, String> properties) { + this.runtime = runtime; this.className = className; this.resources = resources; this.properties = properties; @@ -138,12 +154,16 @@ public interface FunctionImplDTO extends RESTRequest { @Override public FunctionImpl toFunctionImpl() { return FunctionImpl.ofJava( - className, resources == null ? null : resources.toResources(), properties); + FunctionImpl.RuntimeType.fromString(runtime), + className, + resources == null ? null : resources.toResources(), + properties); } /** {@inheritDoc} */ @Override public void validate() throws IllegalArgumentException { + Preconditions.checkArgument(StringUtils.isNotBlank(runtime), "\"runtime\" is required"); Preconditions.checkArgument(StringUtils.isNotBlank(className), "\"className\" is required"); if (resources != null) { resources.toResources(); @@ -158,6 +178,9 @@ public interface FunctionImplDTO extends RESTRequest { @NoArgsConstructor(access = AccessLevel.PRIVATE) class PythonImplDTO implements FunctionImplDTO { + @JsonProperty("runtime") + private String runtime; + @JsonProperty("handler") private String handler; @@ -173,16 +196,19 @@ public interface FunctionImplDTO extends RESTRequest { /** * Creates a Python implementation DTO. * + * @param runtime Target runtime. * @param handler Python handler entry. * @param codeBlock Inline code block. * @param resources Optional resources. * @param properties Implementation properties. */ public PythonImplDTO( + String runtime, String handler, String codeBlock, FunctionResourcesDTO resources, Map<String, String> properties) { + this.runtime = runtime; this.handler = handler; this.codeBlock = codeBlock; this.resources = resources; @@ -193,12 +219,17 @@ public interface FunctionImplDTO extends RESTRequest { @Override public FunctionImpl toFunctionImpl() { return FunctionImpl.ofPython( - handler, codeBlock, resources == null ? null : resources.toResources(), properties); + FunctionImpl.RuntimeType.fromString(runtime), + handler, + codeBlock, + resources == null ? null : resources.toResources(), + properties); } /** {@inheritDoc} */ @Override public void validate() throws IllegalArgumentException { + Preconditions.checkArgument(StringUtils.isNotBlank(runtime), "\"runtime\" is required"); Preconditions.checkArgument(StringUtils.isNotBlank(handler), "\"handler\" is required"); if (resources != null) { resources.toResources(); @@ -216,7 +247,7 @@ public interface FunctionImplDTO extends RESTRequest { if (impl instanceof org.apache.gravitino.function.SQLImpl) { org.apache.gravitino.function.SQLImpl sqlImpl = (org.apache.gravitino.function.SQLImpl) impl; return new SqlImplDTO( - sqlImpl.dialect(), + sqlImpl.runtime().name(), sqlImpl.sql(), new FunctionResourcesDTO(sqlImpl.resources()), sqlImpl.properties()); @@ -224,6 +255,7 @@ public interface FunctionImplDTO extends RESTRequest { org.apache.gravitino.function.JavaImpl javaImpl = (org.apache.gravitino.function.JavaImpl) impl; return new JavaImplDTO( + javaImpl.runtime().name(), javaImpl.className(), new FunctionResourcesDTO(javaImpl.resources()), javaImpl.properties()); @@ -231,6 +263,7 @@ public interface FunctionImplDTO extends RESTRequest { org.apache.gravitino.function.PythonImpl pythonImpl = (org.apache.gravitino.function.PythonImpl) impl; return new PythonImplDTO( + pythonImpl.runtime().name(), pythonImpl.handler(), pythonImpl.codeBlock(), new FunctionResourcesDTO(pythonImpl.resources()), diff --git a/common/src/main/java/org/apache/gravitino/dto/function/FunctionParamDTO.java b/common/src/main/java/org/apache/gravitino/dto/function/FunctionParamDTO.java index 44a5ee6769..86f9b6cd05 100644 --- a/common/src/main/java/org/apache/gravitino/dto/function/FunctionParamDTO.java +++ b/common/src/main/java/org/apache/gravitino/dto/function/FunctionParamDTO.java @@ -28,6 +28,7 @@ import lombok.ToString; import org.apache.commons.lang3.StringUtils; import org.apache.gravitino.function.FunctionParam; import org.apache.gravitino.json.JsonUtils; +import org.apache.gravitino.rel.Column; import org.apache.gravitino.rel.expressions.Expression; import org.apache.gravitino.rel.types.Type; import org.apache.gravitino.rest.RESTRequest; @@ -52,7 +53,7 @@ public class FunctionParamDTO implements FunctionParam, RESTRequest { @JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonSerialize(using = JsonUtils.ColumnDefaultValueSerializer.class) @JsonDeserialize(using = JsonUtils.ColumnDefaultValueDeserializer.class) - private Expression defaultValue = FunctionParam.DEFAULT_VALUE_NOT_SET; + private Expression defaultValue = Column.DEFAULT_VALUE_NOT_SET; /** Default constructor for Jackson. */ private FunctionParamDTO() {} @@ -63,14 +64,13 @@ public class FunctionParamDTO implements FunctionParam, RESTRequest { * @param name Parameter name. * @param dataType Parameter data type. * @param comment Optional parameter comment. - * @param defaultValue Default value; if null, {@link FunctionParam#DEFAULT_VALUE_NOT_SET} is - * used. + * @param defaultValue Default value; if null, {@link Column#DEFAULT_VALUE_NOT_SET} is used. */ public FunctionParamDTO(String name, Type dataType, String comment, Expression defaultValue) { this.name = name; this.dataType = dataType; this.comment = comment; - this.defaultValue = defaultValue == null ? FunctionParam.DEFAULT_VALUE_NOT_SET : defaultValue; + this.defaultValue = defaultValue == null ? Column.DEFAULT_VALUE_NOT_SET : defaultValue; } /** {@inheritDoc} */ diff --git a/common/src/main/java/org/apache/gravitino/dto/requests/FunctionUpdateRequest.java b/common/src/main/java/org/apache/gravitino/dto/requests/FunctionUpdateRequest.java index eb25afb5bc..9f877c777a 100644 --- a/common/src/main/java/org/apache/gravitino/dto/requests/FunctionUpdateRequest.java +++ b/common/src/main/java/org/apache/gravitino/dto/requests/FunctionUpdateRequest.java @@ -56,6 +56,7 @@ public interface FunctionUpdateRequest extends RESTRequest { */ FunctionChange functionChange(); + /** Request to update a function comment. */ @Getter @EqualsAndHashCode @ToString @@ -100,6 +101,7 @@ public interface FunctionUpdateRequest extends RESTRequest { } } + /** Request to replace all implementations of a function. */ @Getter @EqualsAndHashCode @ToString @@ -137,6 +139,7 @@ public interface FunctionUpdateRequest extends RESTRequest { } } + /** Request to add an implementation to a function. */ @Getter @EqualsAndHashCode @ToString diff --git a/common/src/main/java/org/apache/gravitino/dto/util/DTOConverters.java b/common/src/main/java/org/apache/gravitino/dto/util/DTOConverters.java index 625f01fa99..79c111a561 100644 --- a/common/src/main/java/org/apache/gravitino/dto/util/DTOConverters.java +++ b/common/src/main/java/org/apache/gravitino/dto/util/DTOConverters.java @@ -97,6 +97,7 @@ import org.apache.gravitino.function.Function; import org.apache.gravitino.function.FunctionColumn; import org.apache.gravitino.function.FunctionImpl; import org.apache.gravitino.function.FunctionParam; +import org.apache.gravitino.function.FunctionParams; import org.apache.gravitino.function.FunctionSignature; import org.apache.gravitino.job.JobTemplate; import org.apache.gravitino.job.ShellJobTemplate; @@ -1217,7 +1218,17 @@ public class DTOConverters { if (ArrayUtils.isEmpty(paramDTOs)) { return new FunctionParam[0]; } - return Arrays.stream(paramDTOs).map(FunctionParam.class::cast).toArray(FunctionParam[]::new); + return Arrays.stream(paramDTOs) + .map( + p -> + p.defaultValue().equals(Column.DEFAULT_VALUE_NOT_SET) + ? p + : FunctionParams.of( + p.name(), + p.dataType(), + p.comment(), + fromFunctionArg((FunctionArg) p.defaultValue()))) + .toArray(FunctionParam[]::new); } /** diff --git a/rfc/Design of Functions Management in Gravitino.md b/rfc/Design of Functions Management in Gravitino.md index fd8be858fb..291cffb55c 100644 --- a/rfc/Design of Functions Management in Gravitino.md +++ b/rfc/Design of Functions Management in Gravitino.md @@ -1,3 +1,22 @@ +<!-- + 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. +--> + # Design of Functions Management in Gravitino # Background diff --git a/server/src/main/java/org/apache/gravitino/server/web/rest/FunctionOperations.java b/server/src/main/java/org/apache/gravitino/server/web/rest/FunctionOperations.java index 897b53dbd1..afcef10710 100644 --- a/server/src/main/java/org/apache/gravitino/server/web/rest/FunctionOperations.java +++ b/server/src/main/java/org/apache/gravitino/server/web/rest/FunctionOperations.java @@ -21,9 +21,9 @@ package org.apache.gravitino.server.web.rest; import com.codahale.metrics.annotation.ResponseMetered; import com.codahale.metrics.annotation.Timed; import com.google.common.base.Preconditions; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.DELETE; @@ -104,13 +104,13 @@ public class FunctionOperations { return Utils.ok(new EntityListResponse(identifiers)); } - List<FunctionDTO> functionDTOs = new ArrayList<>(); - for (NameIdentifier ident : identifiers) { - Function[] functions = functionDispatcher.getFunction(ident); - if (functions != null) { - functionDTOs.addAll(Arrays.stream(functions).map(DTOConverters::toDTO).toList()); - } - } + Function[] functions = functionDispatcher.listFunctionInfos(namespace); + functions = functions == null ? new Function[0] : functions; + List<FunctionDTO> functionDTOs = + Arrays.stream(functions) + .filter(Objects::nonNull) + .map(DTOConverters::toDTO) + .toList(); LOG.info( "List {} function definitions under schema: {}.{}.{}", functionDTOs.size(),
