This is an automated email from the ASF dual-hosted git repository.
jshao pushed a commit to branch branch-0.9
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/branch-0.9 by this push:
new c1c3c06fe0 [#6815] feat(server): Support update comment for model
version (#6987)
c1c3c06fe0 is described below
commit c1c3c06fe0408d8c5b4beab0a616b29484b28518
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Thu Apr 17 16:20:52 2025 +0800
[#6815] feat(server): Support update comment for model version (#6987)
### What changes were proposed in this pull request?
Support update comment for model version
- [x] PR1: Add ModelVersionChange API interface, Implement the update
comment logic in model catalog and JDBC backend logic, update related
event.
- [X] PR2: Add REST endpoint to support model version change, add Java
client and Python client for model version comment update.
### Why are the changes needed?
Fix: #6815
### Does this PR introduce _any_ user-facing change?
Add support for updating comments on model versions. Users can now
update a model version's comment via the REST API.
### How was this patch tested?
local test.
original model version comment.
<img width="1055" alt="image"
src="https://github.com/user-attachments/assets/c74c4dd1-f785-4c74-ae17-d666b06950f0"
/>
`bin/gcli.sh model update -m demo_metalake --name
model_catalog.schema.model2 --version 0 --comment 'new comment'`
<img width="1057" alt="image"
src="https://github.com/user-attachments/assets/a866371e-df0b-4999-adb6-8543eaff73a3"
/>
`bin/gcli.sh model update -m demo_metalake --name
model_catalog.schema.model2 --alias test --comment 'new comment by
alias'`
<img width="1070" alt="image"
src="https://github.com/user-attachments/assets/2f838272-21a1-45b7-944d-014e45c7a511"
/>
Co-authored-by: Lord of Abyss
<[email protected]>
---
.../apache/gravitino/model/ModelVersionChange.java | 4 +-
.../catalog/model/ModelCatalogOperations.java | 1 +
.../integration/test/ModelCatalogOperationsIT.java | 65 +++++++++
.../org/apache/gravitino/cli/ErrorMessages.java | 2 +
.../org/apache/gravitino/cli/GravitinoOptions.java | 4 +-
.../apache/gravitino/cli/ModelCommandHandler.java | 28 ++++
.../apache/gravitino/cli/SimpleCommandHandler.java | 2 +-
.../apache/gravitino/cli/TestableCommandLine.java | 14 ++
.../cli/commands/UpdateModelVersionComment.java | 113 ++++++++++++++++
.../apache/gravitino/cli/TestModelCommands.java | 91 +++++++++++++
.../apache/gravitino/cli/TestSimpleCommands.java | 2 +-
.../org/apache/gravitino/client/DTOConverters.java | 19 +++
.../gravitino/client/GenericModelCatalog.java | 49 ++++++-
.../gravitino/client/TestGenericModelCatalog.java | 150 +++++++++++++++++++++
.../gravitino/api/model_version_change.py | 78 +++++++++++
.../gravitino/client/generic_model_catalog.py | 98 ++++++++++++++
.../dto/requests/model_version_update_request.py | 63 +++++++++
.../dto/requests/model_version_updates_request.py | 50 +++++++
.../tests/integration/test_model_catalog.py | 48 +++++++
.../tests/unittests/test_model_catalog_api.py | 39 ++++++
.../dto/requests/ModelVersionUpdateRequest.java | 71 ++++++++++
.../dto/requests/ModelVersionUpdatesRequest.java | 46 +++++++
.../catalog/TestModelOperationDispatcher.java | 5 +-
.../gravitino/connector/TestCatalogOperations.java | 1 +
.../gravitino/server/web/rest/ModelOperations.java | 94 +++++++++++++
.../server/web/rest/TestModelOperations.java | 82 +++++++++++
26 files changed, 1209 insertions(+), 10 deletions(-)
diff --git
a/api/src/main/java/org/apache/gravitino/model/ModelVersionChange.java
b/api/src/main/java/org/apache/gravitino/model/ModelVersionChange.java
index 281d1dcbb7..2b18bccb26 100644
--- a/api/src/main/java/org/apache/gravitino/model/ModelVersionChange.java
+++ b/api/src/main/java/org/apache/gravitino/model/ModelVersionChange.java
@@ -34,13 +34,13 @@ public interface ModelVersionChange {
* Create a ModelVersionChange for updating the comment of a model version.
*
* @param newComment new comment to be set for the model version
- * @return a new ModelVersionChange instance for updating the comment of a
model version
+ * @return A new ModelVersionChange instance for updating the comment of a
model version
*/
static ModelVersionChange updateComment(String newComment) {
return new ModelVersionChange.UpdateComment(newComment);
}
- /** A ModelVersionChange to update the modelve version comment. */
+ /** A ModelVersionChange to update the model version comment. */
final class UpdateComment implements ModelVersionChange {
private final String newComment;
diff --git
a/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
index 21d8612b83..bba059308b 100644
---
a/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
+++
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
@@ -415,6 +415,7 @@ public class ModelCatalogOperations extends
ManagedSchemaOperations
for (ModelVersionChange change : changes) {
if (change instanceof ModelVersionChange.UpdateComment) {
entityComment = ((ModelVersionChange.UpdateComment)
change).newComment();
+
} else {
throw new IllegalArgumentException(
"Unsupported model version change: " +
change.getClass().getSimpleName());
diff --git
a/catalogs/catalog-model/src/test/java/org/apache/gravtitino/catalog/model/integration/test/ModelCatalogOperationsIT.java
b/catalogs/catalog-model/src/test/java/org/apache/gravtitino/catalog/model/integration/test/ModelCatalogOperationsIT.java
index 0cabc1495c..1b582672fb 100644
---
a/catalogs/catalog-model/src/test/java/org/apache/gravtitino/catalog/model/integration/test/ModelCatalogOperationsIT.java
+++
b/catalogs/catalog-model/src/test/java/org/apache/gravtitino/catalog/model/integration/test/ModelCatalogOperationsIT.java
@@ -40,6 +40,7 @@ import org.apache.gravitino.integration.test.util.BaseIT;
import org.apache.gravitino.model.Model;
import org.apache.gravitino.model.ModelChange;
import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.model.ModelVersionChange;
import org.apache.gravitino.utils.RandomNameUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
@@ -329,6 +330,70 @@ public class ModelCatalogOperationsIT extends BaseIT {
Assertions.assertEquals(0, modelVersionsAfterDeleteAll.length);
}
+ @Test
+ void testLinkAndUpdateModelVersionCommentViaVersion() {
+ String modelName = RandomNameUtils.genRandomName("model1");
+ Map<String, String> properties = ImmutableMap.of("key1", "val1", "key2",
"val2");
+ NameIdentifier modelIdent = NameIdentifier.of(schemaName, modelName);
+ String versionNewComment = "new comment";
+
+ gravitinoCatalog.asModelCatalog().registerModel(modelIdent, null, null);
+
+ gravitinoCatalog
+ .asModelCatalog()
+ .linkModelVersion(modelIdent, "uri", new String[] {"alias1"},
"comment", properties);
+
+ ModelVersion modelVersion =
gravitinoCatalog.asModelCatalog().getModelVersion(modelIdent, 0);
+
+ Assertions.assertEquals(0, modelVersion.version());
+ Assertions.assertEquals("uri", modelVersion.uri());
+ Assertions.assertArrayEquals(new String[] {"alias1"},
modelVersion.aliases());
+ Assertions.assertEquals("comment", modelVersion.comment());
+ Assertions.assertEquals(properties, modelVersion.properties());
+
+ ModelVersionChange updateComment =
ModelVersionChange.updateComment(versionNewComment);
+ ModelVersion updatedModelVersion =
+ gravitinoCatalog.asModelCatalog().alterModelVersion(modelIdent, 0,
updateComment);
+
+ Assertions.assertEquals(modelVersion.version(),
updatedModelVersion.version());
+ Assertions.assertEquals(modelVersion.uri(), updatedModelVersion.uri());
+ Assertions.assertArrayEquals(modelVersion.aliases(),
updatedModelVersion.aliases());
+ Assertions.assertEquals(versionNewComment, updatedModelVersion.comment());
+ Assertions.assertEquals(modelVersion.properties(),
updatedModelVersion.properties());
+ }
+
+ @Test
+ void testLinkAndUpdateModelVersionCommentViaAlias() {
+ String modelName = RandomNameUtils.genRandomName("model1");
+ Map<String, String> properties = ImmutableMap.of("key1", "val1", "key2",
"val2");
+ NameIdentifier modelIdent = NameIdentifier.of(schemaName, modelName);
+ String aliasNewComment = "new comment";
+
+ gravitinoCatalog.asModelCatalog().registerModel(modelIdent, null, null);
+
+ gravitinoCatalog
+ .asModelCatalog()
+ .linkModelVersion(modelIdent, "uri", new String[] {"alias1"},
"comment", properties);
+
+ ModelVersion modelVersion =
+ gravitinoCatalog.asModelCatalog().getModelVersion(modelIdent,
"alias1");
+ Assertions.assertEquals(0, modelVersion.version());
+ Assertions.assertEquals("uri", modelVersion.uri());
+ Assertions.assertArrayEquals(new String[] {"alias1"},
modelVersion.aliases());
+ Assertions.assertEquals("comment", modelVersion.comment());
+ Assertions.assertEquals(properties, modelVersion.properties());
+
+ ModelVersionChange updateComment =
ModelVersionChange.updateComment(aliasNewComment);
+ ModelVersion updatedModelVersion =
+ gravitinoCatalog.asModelCatalog().alterModelVersion(modelIdent,
"alias1", updateComment);
+
+ Assertions.assertEquals(modelVersion.version(),
updatedModelVersion.version());
+ Assertions.assertEquals(modelVersion.uri(), updatedModelVersion.uri());
+ Assertions.assertArrayEquals(modelVersion.aliases(),
updatedModelVersion.aliases());
+ Assertions.assertEquals(aliasNewComment, updatedModelVersion.comment());
+ Assertions.assertEquals(modelVersion.properties(),
updatedModelVersion.properties());
+ }
+
@Test
public void testRegisterAndUpdateModel() {
String comment = "comment";
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/ErrorMessages.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/ErrorMessages.java
index 0ba98c0c77..cc36dd66b7 100644
--- a/clients/cli/src/main/java/org/apache/gravitino/cli/ErrorMessages.java
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/ErrorMessages.java
@@ -66,6 +66,8 @@ public class ErrorMessages {
public static final String MISSING_USER = "Missing --user option.";
public static final String MISSING_VALUE = "Missing --value option.";
+ public static final String MULTIPLE_ALIASES_COMMAND_ERROR =
+ "This command only supports one --alias option.";
public static final String MULTIPLE_ROLE_COMMAND_ERROR =
"This command only supports one --role option.";
public static final String MULTIPLE_TAG_COMMAND_ERROR =
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java
index 9d304c8775..52c15ad80b 100644
--- a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java
+++ b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java
@@ -26,6 +26,7 @@ import org.apache.commons.cli.Options;
public class GravitinoOptions {
public static final String AUDIT = "audit";
public static final String AUTO = "auto";
+ public static final String CLIENT = "client";
public static final String COLUMNFILE = "columnfile";
public static final String COMMENT = "comment";
public static final String DATATYPE = "datatype";
@@ -76,7 +77,7 @@ public class GravitinoOptions {
// Add options using helper method to avoid repetition
options.addOption(createSimpleOption("h", HELP, "command help
information"));
- options.addOption(createSimpleOption("v", VERSION, "Gravitino client
version"));
+ options.addOption(createSimpleOption(null, CLIENT, "Gravitino client
version"));
options.addOption(createSimpleOption("s", SERVER, "Gravitino server
version"));
options.addOption(createArgOption("u", URL, "Gravitino URL (default:
http://localhost:8090)"));
options.addOption(createArgOption("n", NAME, "full entity name (dot
separated)"));
@@ -116,6 +117,7 @@ public class GravitinoOptions {
// model options
options.addOption(createArgOption(null, URI, "model version artifact"));
options.addOption(createArgsOption(null, ALIAS, "model aliases"));
+ options.addOption(createArgOption(null, VERSION, "Gravitino client
version"));
// Options that support multiple values
options.addOption(createArgsOption("p", PROPERTIES, "property name/value
pairs"));
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/ModelCommandHandler.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/ModelCommandHandler.java
index 6bbe796dba..28cb743186 100644
---
a/clients/cli/src/main/java/org/apache/gravitino/cli/ModelCommandHandler.java
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/ModelCommandHandler.java
@@ -180,6 +180,26 @@ public class ModelCommandHandler extends CommandHandler {
.validate()
.handle();
}
+
+ if (!line.hasOption(GravitinoOptions.URI)
+ && line.hasOption(GravitinoOptions.COMMENT)
+ && (line.hasOption(GravitinoOptions.ALIAS) ||
line.hasOption(GravitinoOptions.VERSION))) {
+ String comment = line.getOptionValue(GravitinoOptions.COMMENT);
+ Integer version =
+ line.hasOption(GravitinoOptions.VERSION)
+ ? Integer.parseInt(line.getOptionValue(GravitinoOptions.VERSION))
+ : null;
+ String alias =
+ line.hasOption(GravitinoOptions.ALIAS)
+ ? getOneAlias(line.getOptionValues(GravitinoOptions.ALIAS))
+ : null;
+
+ gravitinoCommandLine
+ .newUpdateModelVersionComment(
+ context, metalake, catalog, schema, model, version, alias,
comment)
+ .validate()
+ .handle();
+ }
}
/** Handles the "LIST" command. */
@@ -204,4 +224,12 @@ public class ModelCommandHandler extends CommandHandler {
.validate()
.handle();
}
+
+ private String getOneAlias(String[] aliases) {
+ if (aliases == null || aliases.length > 1) {
+ System.err.println(ErrorMessages.MULTIPLE_ALIASES_COMMAND_ERROR);
+ Main.exit(-1);
+ }
+ return aliases[0];
+ }
}
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/SimpleCommandHandler.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/SimpleCommandHandler.java
index 113be4f20b..b4baf4c223 100644
---
a/clients/cli/src/main/java/org/apache/gravitino/cli/SimpleCommandHandler.java
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/SimpleCommandHandler.java
@@ -44,7 +44,7 @@ public class SimpleCommandHandler extends CommandHandler {
/** Handles the command execution logic based on the provided command. */
@Override
protected void handle() {
- if (line.hasOption(GravitinoOptions.VERSION)) {
+ if (line.hasOption(GravitinoOptions.CLIENT)) {
gravitinoCommandLine.newClientVersion(context).validate().handle();
} else if (line.hasOption(GravitinoOptions.SERVER)) {
gravitinoCommandLine.newServerVersion(context).validate().handle();
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java
index 9bf17aacd5..86acd5b0de 100644
---
a/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java
@@ -135,6 +135,7 @@ import org.apache.gravitino.cli.commands.UpdateFilesetName;
import org.apache.gravitino.cli.commands.UpdateMetalakeComment;
import org.apache.gravitino.cli.commands.UpdateMetalakeName;
import org.apache.gravitino.cli.commands.UpdateModelName;
+import org.apache.gravitino.cli.commands.UpdateModelVersionComment;
import org.apache.gravitino.cli.commands.UpdateTableComment;
import org.apache.gravitino.cli.commands.UpdateTableName;
import org.apache.gravitino.cli.commands.UpdateTagComment;
@@ -885,6 +886,19 @@ public class TestableCommandLine {
return new UpdateModelName(context, metalake, catalog, schema, model,
rename);
}
+ protected UpdateModelVersionComment newUpdateModelVersionComment(
+ CommandContext context,
+ String metalake,
+ String catalog,
+ String schema,
+ String model,
+ Integer version,
+ String alias,
+ String comment) {
+ return new UpdateModelVersionComment(
+ context, metalake, catalog, schema, model, version, alias, comment);
+ }
+
protected SetModelProperty newSetModelProperty(
CommandContext context,
String metalake,
diff --git
a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/UpdateModelVersionComment.java
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/UpdateModelVersionComment.java
new file mode 100644
index 0000000000..bb280b189e
--- /dev/null
+++
b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/UpdateModelVersionComment.java
@@ -0,0 +1,113 @@
+/*
+ * 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.gravitino.cli.commands;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.cli.CommandContext;
+import org.apache.gravitino.cli.ErrorMessages;
+import org.apache.gravitino.client.GravitinoClient;
+import org.apache.gravitino.exceptions.NoSuchCatalogException;
+import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NoSuchSchemaException;
+import org.apache.gravitino.exceptions.NoSuchTableException;
+import org.apache.gravitino.model.ModelVersionChange;
+
+/** Update the comment of a model version. */
+public class UpdateModelVersionComment extends Command {
+ protected final String metalake;
+ protected final String catalog;
+ protected final String schema;
+ protected final String model;
+ protected final Integer version;
+ private final String alias;
+ private final String comment;
+
+ /**
+ * Constructs a new {@link UpdateModelVersionComment} instance.
+ *
+ * @param context The command context.
+ * @param metalake The name of the metalake.
+ * @param catalog The name of the catalog.
+ * @param schema The name of the schema.
+ * @param model The name of the model.
+ * @param version The version of the model.
+ * @param alias The alias of the model version.
+ * @param comment The new comment for the model version.
+ */
+ public UpdateModelVersionComment(
+ CommandContext context,
+ String metalake,
+ String catalog,
+ String schema,
+ String model,
+ Integer version,
+ String alias,
+ String comment) {
+ super(context);
+ this.metalake = metalake;
+ this.catalog = catalog;
+ this.schema = schema;
+ this.model = model;
+ this.version = version;
+ this.alias = alias;
+ this.comment = comment;
+ }
+
+ /** Update the comment of a model version. */
+ @Override
+ public void handle() {
+ try {
+ NameIdentifier modelIdent = NameIdentifier.of(schema, model);
+ GravitinoClient client = buildClient(metalake);
+ ModelVersionChange change = ModelVersionChange.updateComment(comment);
+ if (alias != null) {
+
client.loadCatalog(catalog).asModelCatalog().alterModelVersion(modelIdent,
alias, change);
+ } else {
+
client.loadCatalog(catalog).asModelCatalog().alterModelVersion(modelIdent,
version, change);
+ }
+ } catch (NoSuchMetalakeException err) {
+ exitWithError(ErrorMessages.UNKNOWN_METALAKE);
+ } catch (NoSuchCatalogException err) {
+ exitWithError(ErrorMessages.UNKNOWN_CATALOG);
+ } catch (NoSuchSchemaException err) {
+ exitWithError(ErrorMessages.UNKNOWN_SCHEMA);
+ } catch (NoSuchTableException err) {
+ exitWithError(ErrorMessages.UNKNOWN_TABLE);
+ } catch (Exception exp) {
+ exitWithError(exp.getMessage());
+ }
+
+ if (alias != null) {
+ printInformation(model + " version " + alias + " comment changed.");
+ } else {
+ printInformation(model + " version " + version + " comment changed.");
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Command validate() {
+ if (alias != null && version != null) {
+ exitWithError("Cannot specify both alias and version");
+ }
+
+ return this;
+ }
+}
diff --git
a/clients/cli/src/test/java/org/apache/gravitino/cli/TestModelCommands.java
b/clients/cli/src/test/java/org/apache/gravitino/cli/TestModelCommands.java
index 9f03769093..35b9f62698 100644
--- a/clients/cli/src/test/java/org/apache/gravitino/cli/TestModelCommands.java
+++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestModelCommands.java
@@ -49,7 +49,9 @@ import org.apache.gravitino.cli.commands.RegisterModel;
import org.apache.gravitino.cli.commands.RemoveModelProperty;
import org.apache.gravitino.cli.commands.SetModelProperty;
import org.apache.gravitino.cli.commands.UpdateModelName;
+import org.apache.gravitino.cli.commands.UpdateModelVersionComment;
import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.testcontainers.shaded.com.google.common.base.Joiner;
@@ -661,4 +663,93 @@ public class TestModelCommands {
commandLine.handleCommandLine();
verify(mockRemoveProperty).handle();
}
+
+ @Test
+ void testUpdateModelVersionCommentCommand() {
+ UpdateModelVersionComment mockUpdate =
mock(UpdateModelVersionComment.class);
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.NAME)).thenReturn("catalog.schema.model");
+ when(mockCommandLine.hasOption(GravitinoOptions.VERSION)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.VERSION)).thenReturn("1");
+ when(mockCommandLine.hasOption(GravitinoOptions.COMMENT)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.COMMENT)).thenReturn("comment");
+
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.UPDATE));
+
+ doReturn(mockUpdate)
+ .when(commandLine)
+ .newUpdateModelVersionComment(
+ any(CommandContext.class),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"),
+ eq("model"),
+ any(),
+ any(),
+ eq("comment"));
+ doReturn(mockUpdate).when(mockUpdate).validate();
+ commandLine.handleCommandLine();
+ verify(mockUpdate).handle();
+ }
+
+ @Test
+ void testUpdateModelVersionCommentCommandByAlias() {
+ Main.useExit = false;
+ UpdateModelVersionComment mockUpdate =
mock(UpdateModelVersionComment.class);
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.NAME)).thenReturn("catalog.schema.model");
+ when(mockCommandLine.hasOption(GravitinoOptions.ALIAS)).thenReturn(true);
+ when(mockCommandLine.getOptionValues(GravitinoOptions.ALIAS))
+ .thenReturn(new String[] {"aliasA"});
+ when(mockCommandLine.hasOption(GravitinoOptions.COMMENT)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.COMMENT)).thenReturn("comment");
+
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.UPDATE));
+
+ doReturn(mockUpdate)
+ .when(commandLine)
+ .newUpdateModelVersionComment(
+ any(CommandContext.class),
+ eq("metalake_demo"),
+ eq("catalog"),
+ eq("schema"),
+ eq("model"),
+ any(),
+ any(),
+ eq("comment"));
+ doReturn(mockUpdate).when(mockUpdate).validate();
+ commandLine.handleCommandLine();
+ verify(mockUpdate).handle();
+ }
+
+ @Test
+ void testUpdateModelVersionCommentCommandByAliasAndVersion() {
+ Main.useExit = false;
+
when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo");
+ when(mockCommandLine.hasOption(GravitinoOptions.ALIAS)).thenReturn(true);
+ when(mockCommandLine.getOptionValues(GravitinoOptions.ALIAS))
+ .thenReturn(new String[] {"aliasA"});
+ when(mockCommandLine.hasOption(GravitinoOptions.VERSION)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.VERSION)).thenReturn("1");
+ when(mockCommandLine.hasOption(GravitinoOptions.COMMENT)).thenReturn(true);
+
when(mockCommandLine.getOptionValue(GravitinoOptions.COMMENT)).thenReturn("comment");
+
+ GravitinoCommandLine commandLine =
+ spy(
+ new GravitinoCommandLine(
+ mockCommandLine, mockOptions, CommandEntities.MODEL,
CommandActions.UPDATE));
+
+ Assertions.assertThrows(RuntimeException.class,
commandLine::handleCommandLine);
+ }
}
diff --git
a/clients/cli/src/test/java/org/apache/gravitino/cli/TestSimpleCommands.java
b/clients/cli/src/test/java/org/apache/gravitino/cli/TestSimpleCommands.java
index 8024189112..9342b98cc2 100644
--- a/clients/cli/src/test/java/org/apache/gravitino/cli/TestSimpleCommands.java
+++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestSimpleCommands.java
@@ -60,7 +60,7 @@ public class TestSimpleCommands {
@Test
void testClientVersion() {
ClientVersion mockClientVersion = mock(ClientVersion.class);
- when(mockCommandLine.hasOption(GravitinoOptions.VERSION)).thenReturn(true);
+ when(mockCommandLine.hasOption(GravitinoOptions.CLIENT)).thenReturn(true);
GravitinoCommandLine commandLine =
spy(new GravitinoCommandLine(mockCommandLine, mockOptions, null,
null));
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/DTOConverters.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/DTOConverters.java
index e76b1a0b1d..ceffd38a94 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/DTOConverters.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/DTOConverters.java
@@ -39,6 +39,7 @@ import org.apache.gravitino.dto.requests.CatalogUpdateRequest;
import org.apache.gravitino.dto.requests.FilesetUpdateRequest;
import org.apache.gravitino.dto.requests.MetalakeUpdateRequest;
import org.apache.gravitino.dto.requests.ModelUpdateRequest;
+import org.apache.gravitino.dto.requests.ModelVersionUpdateRequest;
import org.apache.gravitino.dto.requests.SchemaUpdateRequest;
import org.apache.gravitino.dto.requests.TableUpdateRequest;
import org.apache.gravitino.dto.requests.TagUpdateRequest;
@@ -46,6 +47,7 @@ import org.apache.gravitino.dto.requests.TopicUpdateRequest;
import org.apache.gravitino.file.FilesetChange;
import org.apache.gravitino.messaging.TopicChange;
import org.apache.gravitino.model.ModelChange;
+import org.apache.gravitino.model.ModelVersionChange;
import org.apache.gravitino.rel.Column;
import org.apache.gravitino.rel.TableChange;
import org.apache.gravitino.rel.expressions.Expression;
@@ -377,4 +379,21 @@ class DTOConverters {
"Unknown model change type: " + change.getClass().getSimpleName());
}
}
+
+ /**
+ * Converts a {@link ModelVersionChange} to a {@link
ModelVersionUpdateRequest}.
+ *
+ * @param change The change to convert.
+ * @return The converted request.
+ */
+ static ModelVersionUpdateRequest
toModelVersionUpdateRequest(ModelVersionChange change) {
+ if (change instanceof ModelVersionChange.UpdateComment) {
+ return new ModelVersionUpdateRequest.UpdateModelVersionComment(
+ ((ModelVersionChange.UpdateComment) change).newComment());
+
+ } else {
+ throw new IllegalArgumentException(
+ "Unknown model version change type: " +
change.getClass().getSimpleName());
+ }
+ }
}
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModelCatalog.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModelCatalog.java
index 64d6a91b00..520352d9af 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModelCatalog.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModelCatalog.java
@@ -35,6 +35,8 @@ import org.apache.gravitino.dto.requests.ModelRegisterRequest;
import org.apache.gravitino.dto.requests.ModelUpdateRequest;
import org.apache.gravitino.dto.requests.ModelUpdatesRequest;
import org.apache.gravitino.dto.requests.ModelVersionLinkRequest;
+import org.apache.gravitino.dto.requests.ModelVersionUpdateRequest;
+import org.apache.gravitino.dto.requests.ModelVersionUpdatesRequest;
import org.apache.gravitino.dto.responses.BaseResponse;
import org.apache.gravitino.dto.responses.DropResponse;
import org.apache.gravitino.dto.responses.EntityListResponse;
@@ -286,16 +288,55 @@ class GenericModelCatalog extends BaseSchemaCatalog
implements ModelCatalog {
public ModelVersion alterModelVersion(
NameIdentifier ident, int version, ModelVersionChange... changes)
throws NoSuchModelException, NoSuchModelVersionException,
IllegalArgumentException {
- // TODO implement
- return null;
+ checkModelNameIdentifier(ident);
+
+ List<ModelVersionUpdateRequest> updateRequests =
+ Arrays.stream(changes)
+ .map(DTOConverters::toModelVersionUpdateRequest)
+ .collect(Collectors.toList());
+
+ ModelVersionUpdatesRequest req = new
ModelVersionUpdatesRequest(updateRequests);
+ req.validate();
+
+ NameIdentifier modelFullIdent = modelFullNameIdentifier(ident);
+ ModelVersionResponse resp =
+ restClient.put(
+ formatModelVersionRequestPath(modelFullIdent) + "/versions/" +
version,
+ req,
+ ModelVersionResponse.class,
+ Collections.emptyMap(),
+ ErrorHandlers.modelErrorHandler());
+
+ resp.validate();
+ return new GenericModelVersion(resp.getModelVersion());
}
@Override
public ModelVersion alterModelVersion(
NameIdentifier ident, String alias, ModelVersionChange... changes)
throws NoSuchModelException, IllegalArgumentException {
- // TODO implement
- return null;
+ checkModelNameIdentifier(ident);
+ Preconditions.checkArgument(StringUtils.isNotBlank(alias), "Model alias
must be non-empty");
+
+ List<ModelVersionUpdateRequest> updateRequests =
+ Arrays.stream(changes)
+ .map(DTOConverters::toModelVersionUpdateRequest)
+ .collect(Collectors.toList());
+
+ ModelVersionUpdatesRequest req = new
ModelVersionUpdatesRequest(updateRequests);
+ req.validate();
+
+ NameIdentifier modelFullIdent = modelFullNameIdentifier(ident);
+ ModelVersionResponse resp =
+ restClient.put(
+ formatModelVersionRequestPath(modelFullIdent) + "/aliases/" +
alias,
+ req,
+ ModelVersionResponse.class,
+ Collections.emptyMap(),
+ ErrorHandlers.modelErrorHandler());
+
+ resp.validate();
+ return new GenericModelVersion(resp.getModelVersion());
}
/** @return A new builder instance for {@link GenericModelCatalog}. */
diff --git
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestGenericModelCatalog.java
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestGenericModelCatalog.java
index 583ff3a257..1fdea36228 100644
---
a/clients/client-java/src/test/java/org/apache/gravitino/client/TestGenericModelCatalog.java
+++
b/clients/client-java/src/test/java/org/apache/gravitino/client/TestGenericModelCatalog.java
@@ -36,6 +36,8 @@ import org.apache.gravitino.dto.requests.ModelRegisterRequest;
import org.apache.gravitino.dto.requests.ModelUpdateRequest;
import org.apache.gravitino.dto.requests.ModelUpdatesRequest;
import org.apache.gravitino.dto.requests.ModelVersionLinkRequest;
+import org.apache.gravitino.dto.requests.ModelVersionUpdateRequest;
+import org.apache.gravitino.dto.requests.ModelVersionUpdatesRequest;
import org.apache.gravitino.dto.responses.BaseResponse;
import org.apache.gravitino.dto.responses.CatalogResponse;
import org.apache.gravitino.dto.responses.DropResponse;
@@ -570,6 +572,154 @@ public class TestGenericModelCatalog extends TestBase {
"internal error");
}
+ @Test
+ void testUpdateModelVersionComment() throws JsonProcessingException {
+ String newComment = "new comment";
+ String uri = "uri";
+ int version = 0;
+ String[] aliases = new String[] {"alias1", "alias2"};
+
+ NameIdentifier modelId = NameIdentifier.of("schema1", "model1");
+ String modelVersionPath =
+ withSlash(
+ GenericModelCatalog.formatModelVersionRequestPath(
+ NameIdentifier.of(METALAKE_NAME, CATALOG_NAME, "schema1",
"model1"))
+ + "/versions/0");
+
+ ModelVersionDTO mockModelVersion =
+ mockModelVersion(version, uri, aliases, newComment,
Collections.emptyMap());
+ ModelVersionResponse resp = new ModelVersionResponse(mockModelVersion);
+ ModelVersionUpdateRequest.UpdateModelVersionComment updateCommentReq =
+ new ModelVersionUpdateRequest.UpdateModelVersionComment(newComment);
+
+ buildMockResource(
+ Method.PUT,
+ modelVersionPath,
+ new ModelVersionUpdatesRequest(ImmutableList.of(updateCommentReq)),
+ resp,
+ HttpStatus.SC_OK);
+
+ ModelVersion updatedModelVersion =
+ catalog
+ .asModelCatalog()
+ .alterModelVersion(modelId, version,
updateCommentReq.modelVersionChange());
+ compareModelVersion(mockModelVersion, updatedModelVersion);
+
+ Assertions.assertEquals(uri, updatedModelVersion.uri());
+ Assertions.assertEquals(newComment, updatedModelVersion.comment());
+ Assertions.assertEquals(Collections.emptyMap(),
updatedModelVersion.properties());
+ Assertions.assertEquals(version, updatedModelVersion.version());
+ Assertions.assertArrayEquals(aliases, updatedModelVersion.aliases());
+
+ // Test NoSuchModelException
+ ErrorResponse notFoundResp =
+ ErrorResponse.notFound(
+ NoSuchModelVersionException.class.getSimpleName(), "model version
not found");
+ buildMockResource(
+ Method.PUT,
+ modelVersionPath,
+ new ModelVersionUpdatesRequest(ImmutableList.of(updateCommentReq)),
+ notFoundResp,
+ HttpStatus.SC_NOT_FOUND);
+ Assertions.assertThrows(
+ NoSuchModelVersionException.class,
+ () ->
+ catalog
+ .asModelCatalog()
+ .alterModelVersion(modelId, version,
updateCommentReq.modelVersionChange()),
+ "model not found");
+
+ // Test RuntimeException
+ ErrorResponse internalErrorResp = ErrorResponse.internalError("internal
error");
+ buildMockResource(
+ Method.PUT,
+ modelVersionPath,
+ new ModelVersionUpdatesRequest(ImmutableList.of(updateCommentReq)),
+ internalErrorResp,
+ HttpStatus.SC_INTERNAL_SERVER_ERROR);
+ Assertions.assertThrows(
+ RuntimeException.class,
+ () ->
+ catalog
+ .asModelCatalog()
+ .alterModelVersion(modelId, version,
updateCommentReq.modelVersionChange()),
+ "internal error");
+ }
+
+ @Test
+ void testUpdateModelVersionCommentByAlias() throws JsonProcessingException {
+ String newComment = "new comment";
+ String uri = "uri";
+ int version = 0;
+ String[] aliases = new String[] {"alias1", "alias2"};
+
+ NameIdentifier modelId = NameIdentifier.of("schema1", "model1");
+ String modelVersionPath =
+ withSlash(
+ GenericModelCatalog.formatModelVersionRequestPath(
+ NameIdentifier.of(METALAKE_NAME, CATALOG_NAME, "schema1",
"model1"))
+ + "/aliases/alias1");
+
+ ModelVersionDTO mockModelVersion =
+ mockModelVersion(version, uri, aliases, newComment,
Collections.emptyMap());
+ ModelVersionResponse resp = new ModelVersionResponse(mockModelVersion);
+ ModelVersionUpdateRequest.UpdateModelVersionComment updateCommentReq =
+ new ModelVersionUpdateRequest.UpdateModelVersionComment(newComment);
+
+ buildMockResource(
+ Method.PUT,
+ modelVersionPath,
+ new ModelVersionUpdatesRequest(ImmutableList.of(updateCommentReq)),
+ resp,
+ HttpStatus.SC_OK);
+
+ ModelVersion updatedModelVersion =
+ catalog
+ .asModelCatalog()
+ .alterModelVersion(modelId, aliases[0],
updateCommentReq.modelVersionChange());
+ compareModelVersion(mockModelVersion, updatedModelVersion);
+
+ Assertions.assertEquals(uri, updatedModelVersion.uri());
+ Assertions.assertEquals(newComment, updatedModelVersion.comment());
+ Assertions.assertEquals(Collections.emptyMap(),
updatedModelVersion.properties());
+ Assertions.assertEquals(version, updatedModelVersion.version());
+ Assertions.assertArrayEquals(aliases, updatedModelVersion.aliases());
+
+ // Test NoSuchModelException
+ ErrorResponse notFoundResp =
+ ErrorResponse.notFound(
+ NoSuchModelVersionException.class.getSimpleName(), "model version
not found");
+ buildMockResource(
+ Method.PUT,
+ modelVersionPath,
+ new ModelVersionUpdatesRequest(ImmutableList.of(updateCommentReq)),
+ notFoundResp,
+ HttpStatus.SC_NOT_FOUND);
+ Assertions.assertThrows(
+ NoSuchModelVersionException.class,
+ () ->
+ catalog
+ .asModelCatalog()
+ .alterModelVersion(modelId, aliases[0],
updateCommentReq.modelVersionChange()),
+ "model not found");
+
+ // Test RuntimeException
+ ErrorResponse internalErrorResp = ErrorResponse.internalError("internal
error");
+ buildMockResource(
+ Method.PUT,
+ modelVersionPath,
+ new ModelVersionUpdatesRequest(ImmutableList.of(updateCommentReq)),
+ internalErrorResp,
+ HttpStatus.SC_INTERNAL_SERVER_ERROR);
+ Assertions.assertThrows(
+ RuntimeException.class,
+ () ->
+ catalog
+ .asModelCatalog()
+ .alterModelVersion(modelId, aliases[0],
updateCommentReq.modelVersionChange()),
+ "internal error");
+ }
+
private ModelDTO mockModelDTO(
String modelName, int latestVersion, String comment, Map<String, String>
properties) {
return ModelDTO.builder()
diff --git a/clients/client-python/gravitino/api/model_version_change.py
b/clients/client-python/gravitino/api/model_version_change.py
new file mode 100644
index 0000000000..0c555e983b
--- /dev/null
+++ b/clients/client-python/gravitino/api/model_version_change.py
@@ -0,0 +1,78 @@
+# 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.
+
+from abc import ABC
+
+
+class ModelVersionChange(ABC):
+ """
+ A model version change is a change to a model version. It can be used to
update the comment
+ of a model version, set a property and value pair for a model version, or
remove a property from a model.
+ """
+
+ @staticmethod
+ def update_comment(comment: str):
+ """Creates a new model version change to update the comment of the
model version.
+ Args:
+ comment: The new comment of the model version.
+ Returns:
+ The model version change.
+ """
+ return ModelVersionChange.UpdateComment(comment)
+
+ class UpdateComment:
+ """A model version change to update the comment of the model
version."""
+
+ def __init__(self, new_comment: str):
+ self._new_comment = new_comment
+
+ def new_comment(self) -> str:
+ """Retrieves the new comment of the model version.
+ Returns:
+ The new comment of the model version.
+ """
+ return self._new_comment
+
+ def __eq__(self, other):
+ """Compares this UpdateComment instance with another object for
equality. Two instances are
+ considered equal if they designate the same new comment for the
model version.
+ Args:
+ other: The object to compare with this instance.
+ Returns:
+ true if the given object represents an identical model version
comment update operation;
+ false otherwise.
+ """
+ if not isinstance(other, ModelVersionChange.UpdateComment):
+ return False
+
+ return self.new_comment() == other.new_comment()
+
+ def __hash__(self):
+ """Generates a hash code for this UpdateComment instance. The hash
code is primarily based on
+ the new comment for the model version.
+ Returns:
+ A hash code value for this comment update operation.
+ """
+ return hash(self.new_comment())
+
+ def __str__(self):
+ """Provides a string representation of the UpdateComment instance.
This string includes the
+ class name followed by the new comment of the model version.
+ Returns:
+ A string summary of this comment update operation.
+ """
+ return f"UpdateComment {self._new_comment}"
diff --git a/clients/client-python/gravitino/client/generic_model_catalog.py
b/clients/client-python/gravitino/client/generic_model_catalog.py
index 79cfcdb2e9..554b788e54 100644
--- a/clients/client-python/gravitino/client/generic_model_catalog.py
+++ b/clients/client-python/gravitino/client/generic_model_catalog.py
@@ -21,6 +21,7 @@ from gravitino.api.catalog import Catalog
from gravitino.api.model.model import Model
from gravitino.api.model.model_version import ModelVersion
from gravitino.api.model_change import ModelChange
+from gravitino.api.model_version_change import ModelVersionChange
from gravitino.client.base_schema_catalog import BaseSchemaCatalog
from gravitino.client.generic_model import GenericModel
from gravitino.client.generic_model_version import GenericModelVersion
@@ -29,6 +30,12 @@ from gravitino.dto.requests.model_register_request import
ModelRegisterRequest
from gravitino.dto.requests.model_update_request import ModelUpdateRequest
from gravitino.dto.requests.model_updates_request import ModelUpdatesRequest
from gravitino.dto.requests.model_version_link_request import
ModelVersionLinkRequest
+from gravitino.dto.requests.model_version_update_request import (
+ ModelVersionUpdateRequest,
+)
+from gravitino.dto.requests.model_version_updates_request import (
+ ModelVersionUpdatesRequest,
+)
from gravitino.dto.responses.base_response import BaseResponse
from gravitino.dto.responses.drop_response import DropResponse
from gravitino.dto.responses.entity_list_response import EntityListResponse
@@ -302,6 +309,85 @@ class GenericModelCatalog(BaseSchemaCatalog):
model_response.validate()
return GenericModel(model_response.model())
+ def alter_model_version(
+ self, model_ident: NameIdentifier, version: int, *changes:
ModelVersionChange
+ ):
+ """
+ Alter the model version by applying the changes.
+ Args:
+ model_ident: The identifier of the model.
+ version: The version of the model version.
+ changes: The changes to apply to the model version.
+ Raises:
+ NoSuchModelVersionException: If the model version does not exist.
+ IllegalArgumentException: If the changes are invalid.
+ Returns:
+ The updated model version object.
+ """
+ self._check_model_ident(model_ident)
+
+ model_full_ident = self._model_full_identifier(model_ident)
+
+ update_requests = [
+ GenericModelCatalog.to_model_version_update_request(change)
+ for change in changes
+ ]
+
+ req = ModelVersionUpdatesRequest(update_requests)
+ req.validate()
+
+ resp = self.rest_client.put(
+
f"{self._format_model_version_request_path(model_full_ident)}/versions/{version}",
+ req,
+ error_handler=MODEL_ERROR_HANDLER,
+ )
+
+ model_version_response = ModelVersionResponse.from_json(
+ resp.body, infer_missing=True
+ )
+ model_version_response.validate()
+ return GenericModelVersion(model_version_response.model_version())
+
+ def alter_model_version_by_alias(
+ self, model_ident: NameIdentifier, alias: str, *changes:
ModelVersionChange
+ ):
+ """
+ Alter the model version by applying the changes.
+ Args:
+ model_ident: The identifier of the model.
+ alias: The alias of the model version.
+ changes: The changes to apply to the model version.
+ Raises:
+ NoSuchModelVersionException: If the model version does not exist.
+ IllegalArgumentException: If the changes are invalid.
+ Returns:
+ The updated model version object.
+ """
+ self._check_model_ident(model_ident)
+
+ model_full_ident = self._model_full_identifier(model_ident)
+
+ update_requests = [
+ GenericModelCatalog.to_model_version_update_request(change)
+ for change in changes
+ ]
+
+ req = ModelVersionUpdatesRequest(update_requests)
+ req.validate()
+
+ resp = self.rest_client.put(
+
f"{self._format_model_version_request_path(model_full_ident)}/aliases/"
+ f"{encode_string(alias)}",
+ req,
+ error_handler=MODEL_ERROR_HANDLER,
+ )
+
+ model_version_response = ModelVersionResponse.from_json(
+ resp.body, infer_missing=True
+ )
+ model_version_response.validate()
+ return GenericModelVersion(model_version_response.model_version())
+
def link_model_version(
self,
model_ident: NameIdentifier,
@@ -439,6 +525,18 @@ class GenericModelCatalog(BaseSchemaCatalog):
raise ValueError(f"Unknown change type: {type(change).__name__}")
+ @staticmethod
+ def to_model_version_update_request(change: ModelVersionChange):
+ if isinstance(change, ModelVersionChange.UpdateComment):
+ return ModelVersionUpdateRequest.UpdateModelVersionComment(
+ change.new_comment()
+ )
+
+ if isinstance(change, ModelVersionChange.RemoveComment):
+ return ModelVersionUpdateRequest.RemoveModelVersionComment()
+
+ raise ValueError(f"Unknown change type: {type(change).__name__}")
+
def _check_model_namespace(self, namespace: Namespace):
"""Check the validity of the model namespace.
diff --git
a/clients/client-python/gravitino/dto/requests/model_version_update_request.py
b/clients/client-python/gravitino/dto/requests/model_version_update_request.py
new file mode 100644
index 0000000000..a9a5b9c1c4
--- /dev/null
+++
b/clients/client-python/gravitino/dto/requests/model_version_update_request.py
@@ -0,0 +1,63 @@
+# 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.
+
+
+from abc import abstractmethod
+from dataclasses import dataclass, field
+from typing import Optional
+
+from dataclasses_json import config
+
+from gravitino.api.model_version_change import ModelVersionChange
+from gravitino.rest.rest_message import RESTRequest
+
+
+@dataclass
+class ModelVersionUpdateRequestBase(RESTRequest):
+ """Base class for all model version update requests."""
+
+ _type: str = field(metadata=config(field_name="@type"))
+
+ def __init__(self, action_type: str):
+ self._type = action_type
+
+ @abstractmethod
+ def model_version_change(self) -> ModelVersionChange:
+ """Convert to model version change operation"""
+ pass
+
+
+class ModelVersionUpdateRequest:
+ """Namespace for all model version update request types."""
+
+ @dataclass
+ class UpdateModelVersionComment(ModelVersionUpdateRequestBase):
+ """Request to update model version comment"""
+
+ _new_comment: Optional[str] =
field(metadata=config(field_name="newComment"))
+ """Represents a request to update the comment on a Metalake."""
+
+ def __init__(self, new_comment: str):
+ super().__init__("updateComment")
+ self._new_comment = new_comment
+
+ def validate(self):
+ """Validates the fields of the request. Always pass."""
+ pass
+
+ def model_version_change(self):
+ return ModelVersionChange.update_comment(self._new_comment)
diff --git
a/clients/client-python/gravitino/dto/requests/model_version_updates_request.py
b/clients/client-python/gravitino/dto/requests/model_version_updates_request.py
new file mode 100644
index 0000000000..6695a6e106
--- /dev/null
+++
b/clients/client-python/gravitino/dto/requests/model_version_updates_request.py
@@ -0,0 +1,50 @@
+# 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.
+
+
+from dataclasses import dataclass, field
+from typing import List
+
+from dataclasses_json import config
+
+from gravitino.dto.requests.model_version_update_request import (
+ ModelVersionUpdateRequest,
+)
+from gravitino.rest.rest_message import RESTRequest
+
+
+@dataclass
+class ModelVersionUpdatesRequest(RESTRequest):
+ """Represents a collection of model Version update operations to be
applied atomically."""
+
+ _updates: List[ModelVersionUpdateRequest] = field(
+ metadata=config(field_name="updates"), default_factory=list
+ )
+
+ def __init__(self, updates: List[ModelVersionUpdateRequest] = None):
+ self._updates = updates
+
+ def validate(self):
+ """Validates the update requests.
+ Raises:
+ ValueError: If the updates list is empty or contains invalid
requests.
+ """
+ if not self._updates:
+ raise ValueError("At least one model update must be specified")
+
+ for update in self._updates:
+ update.validate()
diff --git a/clients/client-python/tests/integration/test_model_catalog.py
b/clients/client-python/tests/integration/test_model_catalog.py
index 88ef813bd5..85211ccd65 100644
--- a/clients/client-python/tests/integration/test_model_catalog.py
+++ b/clients/client-python/tests/integration/test_model_catalog.py
@@ -18,6 +18,7 @@ from random import randint
from gravitino import Catalog, GravitinoAdminClient, GravitinoClient,
NameIdentifier
from gravitino.api.model_change import ModelChange
+from gravitino.api.model_version_change import ModelVersionChange
from gravitino.exceptions.base import (
ModelAlreadyExistsException,
ModelVersionAliasesAlreadyExistException,
@@ -280,6 +281,53 @@ class TestModelCatalog(IntegrationTestEnv):
self.assertEqual(update_property_model.latest_version(), 0)
self.assertEqual(update_property_model.properties(), {"k2": "v2"})
+ def test_register_alter_model_with_update_comment(self):
+ model_name = f"model_it_model{str(randint(0, 1000))}"
+ model_ident = NameIdentifier.of(self._schema_name, model_name)
+ self._catalog.as_model_catalog().register_model(model_ident,
"comment", {})
+
+ # Test link model version
+ self._catalog.as_model_catalog().link_model_version(
+ model_ident,
+ uri="uri",
+ aliases=["alias1", "alias2"],
+ comment="comment",
+ properties={"k1": "v1", "k2": "v2"},
+ )
+
+ model_version = self._catalog.as_model_catalog().get_model_version(
+ model_ident, 0
+ )
+ self.assertEqual(0, model_version.version())
+ self.assertEqual("uri", model_version.uri())
+ self.assertEqual(["alias1", "alias2"], model_version.aliases())
+ self.assertEqual("comment", model_version.comment())
+ self.assertEqual({"k1": "v1", "k2": "v2"}, model_version.properties())
+
+ model_version =
self._catalog.as_model_catalog().get_model_version_by_alias(
+ model_ident, "alias1"
+ )
+ self.assertEqual(0, model_version.version())
+ self.assertEqual("uri", model_version.uri())
+
+ model_version =
self._catalog.as_model_catalog().get_model_version_by_alias(
+ model_ident, "alias2"
+ )
+ self.assertEqual(0, model_version.version())
+ self.assertEqual("uri", model_version.uri())
+
+ changes = [ModelVersionChange.update_comment("new comment")]
+ self._catalog.as_model_catalog().alter_model_version(model_ident, 0,
*changes)
+ updated_model_version =
self._catalog.as_model_catalog().get_model_version(
+ model_ident, 0
+ )
+
+ self.assertEqual(0, updated_model_version.version())
+ self.assertEqual("new comment", updated_model_version.comment())
+ self.assertEqual(["alias1", "alias2"], updated_model_version.aliases())
+ self.assertEqual({"k1": "v1", "k2": "v2"},
updated_model_version.properties())
+ self.assertEqual("uri", updated_model_version.uri())
+
def test_link_get_model_version(self):
model_name = "model_it_model" + str(randint(0, 1000))
model_ident = NameIdentifier.of(self._schema_name, model_name)
diff --git a/clients/client-python/tests/unittests/test_model_catalog_api.py
b/clients/client-python/tests/unittests/test_model_catalog_api.py
index 721cc6756a..19b95ae4ee 100644
--- a/clients/client-python/tests/unittests/test_model_catalog_api.py
+++ b/clients/client-python/tests/unittests/test_model_catalog_api.py
@@ -23,6 +23,7 @@ from gravitino import GravitinoClient, NameIdentifier
from gravitino.api.model.model import Model
from gravitino.api.model.model_version import ModelVersion
from gravitino.api.model_change import ModelChange
+from gravitino.api.model_version_change import ModelVersionChange
from gravitino.dto.audit_dto import AuditDTO
from gravitino.dto.model_dto import ModelDTO
from gravitino.dto.model_version_dto import ModelVersionDTO
@@ -259,6 +260,44 @@ class TestModelCatalogApi(unittest.TestCase):
model_versions =
catalog.as_model_catalog().list_model_versions(model_ident)
self.assertEqual([], model_versions)
+ def test_alter_model_version_comment(self, *mock_method):
+ gravitino_client = GravitinoClient(
+ uri="http://localhost:8090", metalake_name=self._metalake_name
+ )
+ catalog = gravitino_client.load_catalog(self._catalog_name)
+
+ model_ident = NameIdentifier.of("schema", "model1")
+ version = 1
+ alias = "alias1"
+ new_comment = "new comment"
+
+ model_version_dto = ModelVersionDTO(
+ _version=1,
+ _uri="http://localhost:8090",
+ _aliases=["alias1", "alias2"],
+ _comment="new comment",
+ _properties={"k": "v"},
+ _audit=AuditDTO(_creator="test",
_create_time="2022-01-01T00:00:00Z"),
+ )
+
+ model_resp = ModelVersionResponse(_model_version=model_version_dto,
_code=0)
+ json_str = model_resp.to_json()
+ mock_resp = self._mock_http_response(json_str)
+
+ with patch(
+ "gravitino.utils.http_client.HTTPClient.put",
+ return_value=mock_resp,
+ ):
+ model_version = catalog.as_model_catalog().alter_model_version(
+ model_ident, version,
ModelVersionChange.update_comment(new_comment)
+ )
+ self._compare_model_versions(model_version_dto, model_version)
+
+ model_version = catalog.as_model_catalog().alter_model_version(
+ model_ident, alias,
ModelVersionChange.update_comment(new_comment)
+ )
+ self._compare_model_versions(model_version_dto, model_version)
+
def test_get_model_version(self, *mock_method):
gravitino_client = GravitinoClient(
uri="http://localhost:8090", metalake_name=self._metalake_name
diff --git
a/common/src/main/java/org/apache/gravitino/dto/requests/ModelVersionUpdateRequest.java
b/common/src/main/java/org/apache/gravitino/dto/requests/ModelVersionUpdateRequest.java
new file mode 100644
index 0000000000..1026bd82ae
--- /dev/null
+++
b/common/src/main/java/org/apache/gravitino/dto/requests/ModelVersionUpdateRequest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.gravitino.dto.requests;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import org.apache.gravitino.model.ModelVersionChange;
+import org.apache.gravitino.rest.RESTRequest;
+
+/** Request to update a model version. */
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
+@JsonSubTypes({
+ @JsonSubTypes.Type(
+ value = ModelVersionUpdateRequest.UpdateModelVersionComment.class,
+ name = "updateComment")
+})
+public interface ModelVersionUpdateRequest extends RESTRequest {
+
+ /**
+ * Returns the model version change.
+ *
+ * @return the model version change.
+ */
+ ModelVersionChange modelVersionChange();
+
+ /** Request to update comment of a model version */
+ @EqualsAndHashCode
+ @AllArgsConstructor
+ @NoArgsConstructor(force = true)
+ @ToString
+ @Getter
+ class UpdateModelVersionComment implements ModelVersionUpdateRequest {
+ @JsonProperty("newComment")
+ private final String newComment;
+
+ /** {@inheritDoc} */
+ @Override
+ public ModelVersionChange modelVersionChange() {
+ return ModelVersionChange.updateComment(newComment);
+ }
+
+ /** Validates the fields of the request. Always pass. */
+ @Override
+ public void validate() throws IllegalArgumentException {}
+ }
+}
diff --git
a/common/src/main/java/org/apache/gravitino/dto/requests/ModelVersionUpdatesRequest.java
b/common/src/main/java/org/apache/gravitino/dto/requests/ModelVersionUpdatesRequest.java
new file mode 100644
index 0000000000..14e2675041
--- /dev/null
+++
b/common/src/main/java/org/apache/gravitino/dto/requests/ModelVersionUpdatesRequest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.gravitino.dto.requests;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import org.apache.gravitino.rest.RESTRequest;
+
+/** Represents a several request to update a model version. */
+@Getter
+@EqualsAndHashCode
+@AllArgsConstructor
+@NoArgsConstructor(force = true)
+@ToString
+public class ModelVersionUpdatesRequest implements RESTRequest {
+ @JsonProperty("updates")
+ private final List<ModelVersionUpdateRequest> updates;
+
+ /** {@inheritDoc} */
+ @Override
+ public void validate() throws IllegalArgumentException {
+ updates.forEach(ModelVersionUpdateRequest::validate);
+ }
+}
diff --git
a/core/src/test/java/org/apache/gravitino/catalog/TestModelOperationDispatcher.java
b/core/src/test/java/org/apache/gravitino/catalog/TestModelOperationDispatcher.java
index 40c3520bc5..115350dbcc 100644
---
a/core/src/test/java/org/apache/gravitino/catalog/TestModelOperationDispatcher.java
+++
b/core/src/test/java/org/apache/gravitino/catalog/TestModelOperationDispatcher.java
@@ -365,7 +365,7 @@ public class TestModelOperationDispatcher extends
TestOperationDispatcher {
}
@Test
- void testUpdateModelComment() {
+ void testUpdateModelVersionComment() {
String schemaName = randomSchemaName();
String schemaComment = "schema which tests update";
@@ -393,6 +393,9 @@ public class TestModelOperationDispatcher extends
TestOperationDispatcher {
modelOperationDispatcher.alterModelVersion(modelIdent, "alias1",
changeComment);
Assertions.assertEquals(modelVersion.uri(), alteredModelVersion.uri());
+ Assertions.assertEquals(modelVersion.aliases(),
alteredModelVersion.aliases());
+ Assertions.assertEquals(versionNewComment, alteredModelVersion.comment());
+ Assertions.assertEquals(modelVersion.properties(),
alteredModelVersion.properties());
}
private String randomSchemaName() {
diff --git
a/core/src/test/java/org/apache/gravitino/connector/TestCatalogOperations.java
b/core/src/test/java/org/apache/gravitino/connector/TestCatalogOperations.java
index cb4b55833a..1588ba0e27 100644
---
a/core/src/test/java/org/apache/gravitino/connector/TestCatalogOperations.java
+++
b/core/src/test/java/org/apache/gravitino/connector/TestCatalogOperations.java
@@ -1045,6 +1045,7 @@ public class TestCatalogOperations
for (ModelVersionChange change : changes) {
if (change instanceof ModelVersionChange.UpdateComment) {
newComment = ((ModelVersionChange.UpdateComment) change).newComment();
+
} else {
throw new IllegalArgumentException("Unsupported model change: " +
change);
}
diff --git
a/server/src/main/java/org/apache/gravitino/server/web/rest/ModelOperations.java
b/server/src/main/java/org/apache/gravitino/server/web/rest/ModelOperations.java
index 7c4ff37c58..e2ebc58302 100644
---
a/server/src/main/java/org/apache/gravitino/server/web/rest/ModelOperations.java
+++
b/server/src/main/java/org/apache/gravitino/server/web/rest/ModelOperations.java
@@ -38,6 +38,8 @@ import org.apache.gravitino.dto.requests.ModelRegisterRequest;
import org.apache.gravitino.dto.requests.ModelUpdateRequest;
import org.apache.gravitino.dto.requests.ModelUpdatesRequest;
import org.apache.gravitino.dto.requests.ModelVersionLinkRequest;
+import org.apache.gravitino.dto.requests.ModelVersionUpdateRequest;
+import org.apache.gravitino.dto.requests.ModelVersionUpdatesRequest;
import org.apache.gravitino.dto.responses.BaseResponse;
import org.apache.gravitino.dto.responses.DropResponse;
import org.apache.gravitino.dto.responses.EntityListResponse;
@@ -49,6 +51,7 @@ import org.apache.gravitino.metrics.MetricNames;
import org.apache.gravitino.model.Model;
import org.apache.gravitino.model.ModelChange;
import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.model.ModelVersionChange;
import org.apache.gravitino.server.web.Utils;
import org.apache.gravitino.utils.NameIdentifierUtil;
import org.apache.gravitino.utils.NamespaceUtil;
@@ -405,6 +408,97 @@ public class ModelOperations {
}
}
+ @PUT
+ @Path("{model}/versions/{version}")
+ @Produces("application/vnd.gravitino.v1+json")
+ @Timed(name = "alter-model-version." + MetricNames.HTTP_PROCESS_DURATION,
absolute = true)
+ @ResponseMetered(name = "alter-model-version", absolute = true)
+ public Response alterModelVersion(
+ @PathParam("metalake") String metalake,
+ @PathParam("catalog") String catalog,
+ @PathParam("schema") String schema,
+ @PathParam("model") String model,
+ @PathParam("version") int version,
+ ModelVersionUpdatesRequest request) {
+ LOG.info(
+ "Received alter model version request: {}.{}.{}.{}.{}",
+ metalake,
+ catalog,
+ schema,
+ model,
+ version);
+ request.validate();
+
+ try {
+ NameIdentifier modelId = NameIdentifierUtil.ofModel(metalake, catalog,
schema, model);
+
+ return Utils.doAs(
+ httpRequest,
+ () -> {
+ request.validate();
+ ModelVersionChange[] changes =
+ request.getUpdates().stream()
+ .map(ModelVersionUpdateRequest::modelVersionChange)
+ .toArray(ModelVersionChange[]::new);
+
+ ModelVersion modelVersion =
+ modelDispatcher.alterModelVersion(modelId, version, changes);
+ Response response =
+ Utils.ok(new
ModelVersionResponse(DTOConverters.toDTO(modelVersion)));
+ LOG.info("Model version altered: {}.{}", modelId, version);
+ return response;
+ });
+ } catch (Exception e) {
+ return ExceptionHandlers.handleModelException(
+ OperationType.ALTER, versionString(model, version), schema, e);
+ }
+ }
+
+ @PUT
+ @Path("{model}/aliases/{alias}")
+ @Produces("application/vnd.gravitino.v1+json")
+ @Timed(name = "alter-model-alias." + MetricNames.HTTP_PROCESS_DURATION,
absolute = true)
+ @ResponseMetered(name = "alter-model-alias", absolute = true)
+ public Response alterModelVersionByAlias(
+ @PathParam("metalake") String metalake,
+ @PathParam("catalog") String catalog,
+ @PathParam("schema") String schema,
+ @PathParam("model") String model,
+ @PathParam("alias") String alias,
+ ModelVersionUpdatesRequest request) {
+ LOG.info(
+ "Received alter model version request: {}.{}.{}.{}.{}",
+ metalake,
+ catalog,
+ schema,
+ model,
+ alias);
+ request.validate();
+
+ try {
+ NameIdentifier modelId = NameIdentifierUtil.ofModel(metalake, catalog,
schema, model);
+ return Utils.doAs(
+ httpRequest,
+ () -> {
+ request.validate();
+ ModelVersionChange[] changes =
+ request.getUpdates().stream()
+ .map(ModelVersionUpdateRequest::modelVersionChange)
+ .toArray(ModelVersionChange[]::new);
+
+ ModelVersion modelVersion =
modelDispatcher.alterModelVersion(modelId, alias, changes);
+ Response response =
+ Utils.ok(new
ModelVersionResponse(DTOConverters.toDTO(modelVersion)));
+ LOG.info("Model version altered: {}.{}", modelId, alias);
+ return response;
+ });
+
+ } catch (Exception e) {
+ return ExceptionHandlers.handleModelException(
+ OperationType.ALTER, aliasString(model, alias), schema, e);
+ }
+ }
+
@PUT
@Path("{model}")
@Produces("application/vnd.gravitino.v1+json")
diff --git
a/server/src/test/java/org/apache/gravitino/server/web/rest/TestModelOperations.java
b/server/src/test/java/org/apache/gravitino/server/web/rest/TestModelOperations.java
index c3040a5acc..ebb852cc99 100644
---
a/server/src/test/java/org/apache/gravitino/server/web/rest/TestModelOperations.java
+++
b/server/src/test/java/org/apache/gravitino/server/web/rest/TestModelOperations.java
@@ -36,10 +36,13 @@ import javax.ws.rs.core.Response;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.catalog.ModelDispatcher;
+import org.apache.gravitino.dto.model.ModelVersionDTO;
import org.apache.gravitino.dto.requests.ModelRegisterRequest;
import org.apache.gravitino.dto.requests.ModelUpdateRequest;
import org.apache.gravitino.dto.requests.ModelUpdatesRequest;
import org.apache.gravitino.dto.requests.ModelVersionLinkRequest;
+import org.apache.gravitino.dto.requests.ModelVersionUpdateRequest;
+import org.apache.gravitino.dto.requests.ModelVersionUpdatesRequest;
import org.apache.gravitino.dto.responses.BaseResponse;
import org.apache.gravitino.dto.responses.DropResponse;
import org.apache.gravitino.dto.responses.EntityListResponse;
@@ -55,6 +58,7 @@ import org.apache.gravitino.meta.AuditInfo;
import org.apache.gravitino.model.Model;
import org.apache.gravitino.model.ModelChange;
import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.model.ModelVersionChange;
import org.apache.gravitino.rest.RESTUtils;
import org.apache.gravitino.utils.NameIdentifierUtil;
import org.apache.gravitino.utils.NamespaceUtil;
@@ -967,6 +971,84 @@ public class TestModelOperations extends JerseyTest {
Assertions.assertFalse(modelResp.getModel().properties().containsKey("key1"));
}
+ @Test
+ void testUpdateModelVersionComment() {
+ String modelName = "model1";
+ String newComment = "new comment";
+ String uri = "uri1";
+ int version = 0;
+ String[] alias = new String[] {"alias1"};
+
+ NameIdentifier modelId = NameIdentifierUtil.ofModel(metalake, catalog,
schema, modelName);
+ ModelVersion mockModelVersion = mockModelVersion(version, uri, alias,
newComment);
+
+ when(modelDispatcher.alterModelVersion(
+ modelId, version, ModelVersionChange.updateComment(newComment)))
+ .thenReturn(mockModelVersion);
+
+ ModelVersionUpdatesRequest req =
+ new ModelVersionUpdatesRequest(
+ Collections.singletonList(
+ new
ModelVersionUpdateRequest.UpdateModelVersionComment(newComment)));
+
+ Response resp =
+ target(modelPath())
+ .path("model1")
+ .path("versions")
+ .path("0")
+ .request(MediaType.APPLICATION_JSON_TYPE)
+ .accept("application/vnd.gravitino.v1+json")
+ .put(Entity.entity(req, MediaType.APPLICATION_JSON_TYPE));
+
+ Assertions.assertEquals(Response.Status.OK.getStatusCode(),
resp.getStatus());
+ ModelVersionResponse modelVersionResponse =
resp.readEntity(ModelVersionResponse.class);
+ ModelVersionDTO modelVersion = modelVersionResponse.getModelVersion();
+
+ Assertions.assertEquals(newComment, modelVersion.comment());
+ Assertions.assertArrayEquals(alias, modelVersion.aliases());
+ Assertions.assertEquals(version, modelVersion.version());
+ Assertions.assertEquals(uri, modelVersion.uri());
+ }
+
+ @Test
+ void testUpdateModelVersionCommentByAlias() {
+ String modelName = "model1";
+ String newComment = "new comment";
+ String uri = "uri1";
+ int version = 0;
+ String[] alias = new String[] {"alias1"};
+
+ NameIdentifier modelId = NameIdentifierUtil.ofModel(metalake, catalog,
schema, modelName);
+ ModelVersion mockModelVersion = mockModelVersion(version, uri, alias,
newComment);
+
+ when(modelDispatcher.alterModelVersion(
+ modelId, alias[0], ModelVersionChange.updateComment(newComment)))
+ .thenReturn(mockModelVersion);
+
+ ModelVersionUpdatesRequest req =
+ new ModelVersionUpdatesRequest(
+ Collections.singletonList(
+ new
ModelVersionUpdateRequest.UpdateModelVersionComment(newComment)));
+
+ Response resp =
+ target(modelPath())
+ .path("model1")
+ .path("aliases")
+ .path(alias[0])
+ .request(MediaType.APPLICATION_JSON_TYPE)
+ .accept("application/vnd.gravitino.v1+json")
+ .put(Entity.entity(req, MediaType.APPLICATION_JSON_TYPE));
+
+ Assertions.assertEquals(Response.Status.OK.getStatusCode(),
resp.getStatus());
+ ModelVersionResponse modelVersionResponse =
resp.readEntity(ModelVersionResponse.class);
+ ModelVersionDTO modelVersion = modelVersionResponse.getModelVersion();
+
+ Assertions.assertEquals(newComment, modelVersion.comment());
+ Assertions.assertArrayEquals(alias, modelVersion.aliases());
+ Assertions.assertEquals(version, modelVersion.version());
+ Assertions.assertEquals(uri, modelVersion.uri());
+ }
+
private String modelPath() {
return "/metalakes/" + metalake + "/catalogs/" + catalog + "/schemas/" +
schema + "/models";
}