This is an automated email from the ASF dual-hosted git repository. roryqi pushed a commit to branch ISSUE-6353 in repository https://gitbox.apache.org/repos/asf/gravitino.git
commit 97adf259872044c46c0f957b87b6515647ab301c Author: Lord of Abyss <103809695+abyss-l...@users.noreply.github.com> AuthorDate: Thu Jan 16 13:13:24 2025 +0800 [#6242] improve(CLI): Add tag support to Models in Gravtitino CLI. (#6284) ### What changes were proposed in this pull request? Add tag support to Models in Gravtitino CLI. currently, the CLI support following actions: 1. `UntagEntity`, 2. `TagEntity`, 3. `ListEntityTags` ### Why are the changes needed? Fix: #6242 ### Does this PR introduce _any_ user-facing change? No ### How was this patch tested? local test. --- .../java/org/apache/gravitino/cli/FullName.java | 14 ++++ .../gravitino/cli/commands/ListEntityTags.java | 42 +++++++++--- .../apache/gravitino/cli/commands/TagEntity.java | 51 ++++++++++---- .../apache/gravitino/cli/commands/UntagEntity.java | 51 ++++++++++---- .../apache/gravitino/cli/utils/FullNameUtil.java | 79 +++++++++++++++++++++ .../org/apache/gravitino/cli/TestFullNameUtil.java | 80 ++++++++++++++++++++++ .../org/apache/gravitino/cli/TestFulllName.java | 36 ++++++++++ 7 files changed, 318 insertions(+), 35 deletions(-) diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/FullName.java b/clients/cli/src/main/java/org/apache/gravitino/cli/FullName.java index 7a9481cb95..f6de0213ed 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/FullName.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/FullName.java @@ -41,6 +41,20 @@ public class FullName { this.line = line; } + /** + * Retrieves the level of the full name. + * + * @return The level of the full name, or -1 if line does not contain a {@code --name} option. + */ + public int getLevel() { + if (line.hasOption(GravitinoOptions.NAME)) { + String[] names = line.getOptionValue(GravitinoOptions.NAME).split("\\."); + return names.length; + } + + return -1; + } + /** * Retrieves the metalake name from the command line options, the GRAVITINO_METALAKE environment * variable or the Gravitino config file. diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListEntityTags.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListEntityTags.java index c0dc501732..90b1000fa0 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListEntityTags.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListEntityTags.java @@ -20,15 +20,18 @@ package org.apache.gravitino.cli.commands; import org.apache.gravitino.Catalog; -import org.apache.gravitino.NameIdentifier; import org.apache.gravitino.Schema; import org.apache.gravitino.cli.ErrorMessages; import org.apache.gravitino.cli.FullName; +import org.apache.gravitino.cli.utils.FullNameUtil; 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.file.Fileset; +import org.apache.gravitino.messaging.Topic; +import org.apache.gravitino.model.Model; import org.apache.gravitino.rel.Table; /* Lists all tags in a metalake. */ @@ -58,17 +61,34 @@ public class ListEntityTags extends Command { try { GravitinoClient client = buildClient(metalake); - // TODO fileset and topic - if (name.hasTableName()) { + if (name.getLevel() == 3) { String catalog = name.getCatalogName(); - String schema = name.getSchemaName(); - String table = name.getTableName(); - Table gTable = - client - .loadCatalog(catalog) - .asTableCatalog() - .loadTable(NameIdentifier.of(schema, table)); - tags = gTable.supportsTags().listTags(); + Catalog catalogObject = client.loadCatalog(catalog); + switch (catalogObject.type()) { + case RELATIONAL: + Table gTable = catalogObject.asTableCatalog().loadTable(FullNameUtil.toTable(name)); + tags = gTable.supportsTags().listTags(); + break; + + case MODEL: + Model gModel = catalogObject.asModelCatalog().getModel(FullNameUtil.toModel(name)); + tags = gModel.supportsTags().listTags(); + break; + + case FILESET: + Fileset fileset = + catalogObject.asFilesetCatalog().loadFileset(FullNameUtil.toFileset(name)); + tags = fileset.supportsTags().listTags(); + break; + + case MESSAGING: + Topic topic = catalogObject.asTopicCatalog().loadTopic(FullNameUtil.toTopic(name)); + tags = topic.supportsTags().listTags(); + break; + + default: + break; + } } else if (name.hasSchemaName()) { String catalog = name.getCatalogName(); String schema = name.getSchemaName(); diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/TagEntity.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/TagEntity.java index 4a06918850..3b97778818 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/TagEntity.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/TagEntity.java @@ -20,16 +20,19 @@ package org.apache.gravitino.cli.commands; import org.apache.gravitino.Catalog; -import org.apache.gravitino.NameIdentifier; import org.apache.gravitino.Schema; import org.apache.gravitino.cli.ErrorMessages; import org.apache.gravitino.cli.FullName; +import org.apache.gravitino.cli.utils.FullNameUtil; 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.exceptions.TagAlreadyAssociatedException; +import org.apache.gravitino.file.Fileset; +import org.apache.gravitino.messaging.Topic; +import org.apache.gravitino.model.Model; import org.apache.gravitino.rel.Table; public class TagEntity extends Command { @@ -63,18 +66,42 @@ public class TagEntity extends Command { try { GravitinoClient client = buildClient(metalake); - // TODO fileset and topic - if (name.hasTableName()) { + if (name.getLevel() == 3) { String catalog = name.getCatalogName(); - String schema = name.getSchemaName(); - String table = name.getTableName(); - Table gTable = - client - .loadCatalog(catalog) - .asTableCatalog() - .loadTable(NameIdentifier.of(schema, table)); - tagsToAdd = gTable.supportsTags().associateTags(tags, null); - entity = table; + Catalog catalogObject = client.loadCatalog(catalog); + switch (catalogObject.type()) { + case RELATIONAL: + String table = name.getTableName(); + entity = table; + Table gTable = catalogObject.asTableCatalog().loadTable(FullNameUtil.toTable(name)); + tagsToAdd = gTable.supportsTags().associateTags(tags, null); + break; + + case MODEL: + String model = name.getModelName(); + entity = model; + Model gModel = catalogObject.asModelCatalog().getModel(FullNameUtil.toModel(name)); + tagsToAdd = gModel.supportsTags().associateTags(tags, null); + break; + + case FILESET: + String fileset = name.getFilesetName(); + entity = fileset; + Fileset gFileset = + catalogObject.asFilesetCatalog().loadFileset(FullNameUtil.toFileset(name)); + gFileset.supportsTags().associateTags(tags, null); + break; + + case MESSAGING: + String topic = name.getTopicName(); + entity = topic; + Topic gTopic = catalogObject.asTopicCatalog().loadTopic(FullNameUtil.toTopic(name)); + gTopic.supportsTags().associateTags(tags, null); + break; + + default: + break; + } } else if (name.hasSchemaName()) { String catalog = name.getCatalogName(); String schema = name.getSchemaName(); diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/UntagEntity.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/UntagEntity.java index e82d0da470..205242135b 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/UntagEntity.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/UntagEntity.java @@ -20,15 +20,18 @@ package org.apache.gravitino.cli.commands; import org.apache.gravitino.Catalog; -import org.apache.gravitino.NameIdentifier; import org.apache.gravitino.Schema; import org.apache.gravitino.cli.ErrorMessages; import org.apache.gravitino.cli.FullName; +import org.apache.gravitino.cli.utils.FullNameUtil; 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.file.Fileset; +import org.apache.gravitino.messaging.Topic; +import org.apache.gravitino.model.Model; import org.apache.gravitino.rel.Table; public class UntagEntity extends Command { @@ -62,18 +65,42 @@ public class UntagEntity extends Command { try { GravitinoClient client = buildClient(metalake); - // TODO fileset and topic - if (name.hasTableName()) { + if (name.getLevel() == 3) { String catalog = name.getCatalogName(); - String schema = name.getSchemaName(); - String table = name.getTableName(); - Table gTable = - client - .loadCatalog(catalog) - .asTableCatalog() - .loadTable(NameIdentifier.of(schema, table)); - removeTags = gTable.supportsTags().associateTags(null, tags); - entity = table; + Catalog catalogObject = client.loadCatalog(catalog); + switch (catalogObject.type()) { + case RELATIONAL: + String table = name.getTableName(); + entity = table; + Table gTable = catalogObject.asTableCatalog().loadTable(FullNameUtil.toTable(name)); + removeTags = gTable.supportsTags().associateTags(null, tags); + break; + + case MODEL: + String model = name.getModelName(); + entity = model; + Model gModel = catalogObject.asModelCatalog().getModel(FullNameUtil.toModel(name)); + removeTags = gModel.supportsTags().associateTags(null, tags); + break; + + case FILESET: + String fileset = name.getFilesetName(); + entity = fileset; + Fileset gFileset = + catalogObject.asFilesetCatalog().loadFileset(FullNameUtil.toFileset(name)); + removeTags = gFileset.supportsTags().associateTags(null, tags); + break; + + case MESSAGING: + String topic = name.getTopicName(); + entity = topic; + Topic gTopic = catalogObject.asTopicCatalog().loadTopic(FullNameUtil.toTopic(name)); + removeTags = gTopic.supportsTags().associateTags(null, tags); + break; + + default: + break; + } } else if (name.hasSchemaName()) { String catalog = name.getCatalogName(); String schema = name.getSchemaName(); diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/utils/FullNameUtil.java b/clients/cli/src/main/java/org/apache/gravitino/cli/utils/FullNameUtil.java new file mode 100644 index 0000000000..6017b4246d --- /dev/null +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/utils/FullNameUtil.java @@ -0,0 +1,79 @@ +/* + * 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.utils; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.cli.FullName; + +/** Utility class for helping with creating NameIdentifiers from {@link FullName}. */ +public class FullNameUtil { + + /** + * Returns a NameIdentifier for a model. + * + * @param fullName the {@link FullName} of the model. + * @return a NameIdentifier for the model. + */ + public static NameIdentifier toModel(FullName fullName) { + String schema = fullName.getSchemaName(); + String model = fullName.getModelName(); + + return NameIdentifier.of(schema, model); + } + + /** + * Returns a NameIdentifier for a table. + * + * @param fullName the {@link FullName} of the table. + * @return a NameIdentifier for the table. + */ + public static NameIdentifier toTable(FullName fullName) { + String schema = fullName.getSchemaName(); + String table = fullName.getTableName(); + + return NameIdentifier.of(schema, table); + } + + /** + * Returns a NameIdentifier for a fileset. + * + * @param fullName the {@link FullName} of the fileset. + * @return a NameIdentifier for the fileset. + */ + public static NameIdentifier toFileset(FullName fullName) { + String schema = fullName.getSchemaName(); + String fileset = fullName.getFilesetName(); + + return NameIdentifier.of(schema, fileset); + } + + /** + * Returns a NameIdentifier for a topic. + * + * @param fullName the {@link FullName} of the topic. + * @return a NameIdentifier for the topic. + */ + public static NameIdentifier toTopic(FullName fullName) { + String schema = fullName.getSchemaName(); + String topic = fullName.getTopicName(); + + return NameIdentifier.of(schema, topic); + } +} diff --git a/clients/cli/src/test/java/org/apache/gravitino/cli/TestFullNameUtil.java b/clients/cli/src/test/java/org/apache/gravitino/cli/TestFullNameUtil.java new file mode 100644 index 0000000000..8123bb3342 --- /dev/null +++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestFullNameUtil.java @@ -0,0 +1,80 @@ +/* + * 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; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.cli.utils.FullNameUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class TestFullNameUtil { + private Options options; + + @BeforeEach + public void setUp() { + Main.useExit = false; + options = new GravitinoOptions().options(); + } + + @Test + void testToModel() throws ParseException { + String[] args = {"table", "list", "-i", "--name", "Model_catalog.schema.model"}; + CommandLine commandLine = new DefaultParser().parse(options, args); + FullName fullName = new FullName(commandLine); + NameIdentifier modelIdent = FullNameUtil.toModel(fullName); + Assertions.assertEquals("model", modelIdent.name()); + Assertions.assertArrayEquals(new String[] {"schema"}, modelIdent.namespace().levels()); + } + + @Test + void testToTable() throws ParseException { + String[] args = {"table", "list", "-i", "--name", "Table_catalog.schema.table"}; + CommandLine commandLine = new DefaultParser().parse(options, args); + FullName fullName = new FullName(commandLine); + NameIdentifier tableIdent = FullNameUtil.toTable(fullName); + Assertions.assertEquals("table", tableIdent.name()); + Assertions.assertArrayEquals(new String[] {"schema"}, tableIdent.namespace().levels()); + } + + @Test + void testToFileset() throws ParseException { + String[] args = {"fileset", "list", "-i", "--name", "Fileset_catalog.schema.fileset"}; + CommandLine commandLine = new DefaultParser().parse(options, args); + FullName fullName = new FullName(commandLine); + NameIdentifier filesetIdent = FullNameUtil.toFileset(fullName); + Assertions.assertEquals("fileset", filesetIdent.name()); + Assertions.assertArrayEquals(new String[] {"schema"}, filesetIdent.namespace().levels()); + } + + @Test + void testToTopic() throws ParseException { + String[] args = {"topic", "list", "-i", "--name", "Topic_catalog.schema.topic"}; + CommandLine commandLine = new DefaultParser().parse(options, args); + FullName fullName = new FullName(commandLine); + NameIdentifier topicIdent = FullNameUtil.toTopic(fullName); + Assertions.assertEquals("topic", topicIdent.name()); + Assertions.assertArrayEquals(new String[] {"schema"}, topicIdent.namespace().levels()); + } +} diff --git a/clients/cli/src/test/java/org/apache/gravitino/cli/TestFulllName.java b/clients/cli/src/test/java/org/apache/gravitino/cli/TestFulllName.java index f13d6e0920..c2e54c81d5 100644 --- a/clients/cli/src/test/java/org/apache/gravitino/cli/TestFulllName.java +++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestFulllName.java @@ -235,4 +235,40 @@ public class TestFulllName { String errOutput = new String(errContent.toByteArray(), StandardCharsets.UTF_8).trim(); assertEquals(errOutput, ErrorMessages.MISSING_METALAKE); } + + @Test + @SuppressWarnings("DefaultCharset") + void testGetLevelFromCatalog() throws ParseException { + String[] args = {"table", "list", "-i", "--name", "Hive_catalog"}; + CommandLine commandLine = new DefaultParser().parse(options, args); + FullName fullName = new FullName(commandLine); + assertEquals(1, fullName.getLevel()); + } + + @Test + @SuppressWarnings("DefaultCharset") + void testGetLevelFromSchema() throws ParseException { + String[] args = {"table", "list", "-i", "--name", "Hive_catalog.default"}; + CommandLine commandLine = new DefaultParser().parse(options, args); + FullName fullName = new FullName(commandLine); + assertEquals(2, fullName.getLevel()); + } + + @Test + @SuppressWarnings("DefaultCharset") + void testGetLevelFromTable() throws ParseException { + String[] args = {"table", "list", "-i", "--name", "Hive_catalog.default.sales"}; + CommandLine commandLine = new DefaultParser().parse(options, args); + FullName fullName = new FullName(commandLine); + assertEquals(3, fullName.getLevel()); + } + + @Test + @SuppressWarnings("DefaultCharset") + void testGetLevelFromColumn() throws ParseException { + String[] args = {"table", "list", "-i", "--name", "Hive_catalog.default.sales.columns"}; + CommandLine commandLine = new DefaultParser().parse(options, args); + FullName fullName = new FullName(commandLine); + assertEquals(4, fullName.getLevel()); + } }