This is an automated email from the ASF dual-hosted git repository.

jshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new a9e93e256e [#6704] feat(authz): Support model hook dispatcher (#6844)
a9e93e256e is described below

commit a9e93e256ef7b397af11b45ad858f771d0c6fdb7
Author: roryqi <h...@datastrato.com>
AuthorDate: Wed Apr 9 12:30:42 2025 +0800

    [#6704] feat(authz): Support model hook dispatcher (#6844)
    
    ### What changes were proposed in this pull request?
    
    Support model hook dispatcher
    
    ### Why are the changes needed?
    
    Fix: #6704
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    Add IT.
---
 .../integration/test/authorization/OwnerIT.java    |  56 +++++++
 .../java/org/apache/gravitino/GravitinoEnv.java    |   5 +-
 .../apache/gravitino/hook/ModelHookDispatcher.java | 176 +++++++++++++++++++++
 .../mapper/OwnerMetaSQLProviderFactory.java        |   2 +-
 .../provider/base/OwnerMetaBaseSQLProvider.java    |  13 +-
 .../base/SecurableObjectBaseSQLProvider.java       |  11 ++
 .../base/TagMetadataObjectRelBaseSQLProvider.java  |  11 ++
 .../postgresql/OwnerMetaPostgreSQLProvider.java    |  13 +-
 .../SecurableObjectPostgreSQLProvider.java         |  11 ++
 .../TagMetadataObjectRelPostgreSQLProvider.java    |  11 ++
 .../relational/service/ModelMetaService.java       |  26 ++-
 .../relational/service/TestOwnerMetaService.java   |  79 +++++++--
 .../relational/service/TestSecurableObjects.java   |  65 ++++++--
 .../relational/service/TestTagMetaService.java     |  70 +++++++-
 14 files changed, 515 insertions(+), 34 deletions(-)

diff --git 
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/OwnerIT.java
 
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/OwnerIT.java
index daac8002ab..32ca7bd778 100644
--- 
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/OwnerIT.java
+++ 
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/authorization/OwnerIT.java
@@ -324,6 +324,62 @@ public class OwnerIT extends BaseIT {
     client.dropMetalake(metalakeNameD, true);
   }
 
+  @Test
+  public void testCreateModel() {
+    String metalakeNameF = RandomNameUtils.genRandomName("metalakeF");
+    GravitinoMetalake metalake =
+        client.createMetalake(metalakeNameF, "metalake F comment", 
Collections.emptyMap());
+    String catalogNameF = RandomNameUtils.genRandomName("catalogF");
+    Map<String, String> properties = Maps.newHashMap();
+    Catalog catalog =
+        metalake.createCatalog(catalogNameF, Catalog.Type.MODEL, "catalog 
comment", properties);
+
+    NameIdentifier modelIdent = NameIdentifier.of("schema_owner", 
"model_owner");
+    catalog.asSchemas().createSchema("schema_owner", "comment", 
Collections.emptyMap());
+    catalog.asModelCatalog().registerModel(modelIdent, "comment", 
Collections.emptyMap());
+
+    MetadataObject metalakeObject =
+        MetadataObjects.of(null, metalakeNameF, MetadataObject.Type.METALAKE);
+    Owner owner = metalake.getOwner(metalakeObject).get();
+    Assertions.assertEquals(AuthConstants.ANONYMOUS_USER, owner.name());
+    Assertions.assertEquals(Owner.Type.USER, owner.type());
+
+    MetadataObject catalogObject =
+        MetadataObjects.of(Lists.newArrayList(catalogNameF), 
MetadataObject.Type.CATALOG);
+    owner = metalake.getOwner(catalogObject).get();
+    Assertions.assertEquals(AuthConstants.ANONYMOUS_USER, owner.name());
+    Assertions.assertEquals(Owner.Type.USER, owner.type());
+
+    MetadataObject schemaObject =
+        MetadataObjects.of(
+            Lists.newArrayList(catalogNameF, "schema_owner"), 
MetadataObject.Type.SCHEMA);
+    owner = metalake.getOwner(schemaObject).get();
+    Assertions.assertEquals(AuthConstants.ANONYMOUS_USER, owner.name());
+    Assertions.assertEquals(Owner.Type.USER, owner.type());
+
+    MetadataObject modelObject =
+        MetadataObjects.of(
+            Lists.newArrayList(catalogNameF, "schema_owner", "model_owner"),
+            MetadataObject.Type.MODEL);
+    owner = metalake.getOwner(modelObject).get();
+    Assertions.assertEquals(AuthConstants.ANONYMOUS_USER, owner.name());
+    Assertions.assertEquals(Owner.Type.USER, owner.type());
+
+    // Set another owner
+    String anotherUser = "another";
+    metalake.addUser(anotherUser);
+    metalake.setOwner(modelObject, anotherUser, Owner.Type.USER);
+    owner = metalake.getOwner(modelObject).get();
+    Assertions.assertEquals(anotherUser, owner.name());
+    Assertions.assertEquals(Owner.Type.USER, owner.type());
+
+    // Clean up
+    catalog.asModelCatalog().deleteModel(modelIdent);
+    catalog.asSchemas().dropSchema("schema_owner", true);
+    metalake.dropCatalog(catalogNameF, true);
+    client.dropMetalake(metalakeNameF, true);
+  }
+
   @Test
   public void testOwnerWithException() {
     String metalakeNameE = RandomNameUtils.genRandomName("metalakeE");
diff --git a/core/src/main/java/org/apache/gravitino/GravitinoEnv.java 
b/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
index 4e9fc02b49..b33f2525a2 100644
--- a/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
+++ b/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
@@ -51,6 +51,7 @@ import org.apache.gravitino.hook.AccessControlHookDispatcher;
 import org.apache.gravitino.hook.CatalogHookDispatcher;
 import org.apache.gravitino.hook.FilesetHookDispatcher;
 import org.apache.gravitino.hook.MetalakeHookDispatcher;
+import org.apache.gravitino.hook.ModelHookDispatcher;
 import org.apache.gravitino.hook.SchemaHookDispatcher;
 import org.apache.gravitino.hook.TableHookDispatcher;
 import org.apache.gravitino.hook.TopicHookDispatcher;
@@ -483,11 +484,11 @@ public class GravitinoEnv {
         new TopicNormalizeDispatcher(topicHookDispatcher, catalogManager);
     this.topicDispatcher = new TopicEventDispatcher(eventBus, 
topicNormalizeDispatcher);
 
-    // TODO(jerryshao). Add Hook support for Model.
     ModelOperationDispatcher modelOperationDispatcher =
         new ModelOperationDispatcher(catalogManager, entityStore, idGenerator);
+    ModelHookDispatcher modelHookDispatcher = new 
ModelHookDispatcher(modelOperationDispatcher);
     ModelNormalizeDispatcher modelNormalizeDispatcher =
-        new ModelNormalizeDispatcher(modelOperationDispatcher, catalogManager);
+        new ModelNormalizeDispatcher(modelHookDispatcher, catalogManager);
     this.modelDispatcher = new ModelEventDispatcher(eventBus, 
modelNormalizeDispatcher);
 
     // Create and initialize access control related modules
diff --git 
a/core/src/main/java/org/apache/gravitino/hook/ModelHookDispatcher.java 
b/core/src/main/java/org/apache/gravitino/hook/ModelHookDispatcher.java
new file mode 100644
index 0000000000..af6723e844
--- /dev/null
+++ b/core/src/main/java/org/apache/gravitino/hook/ModelHookDispatcher.java
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.hook;
+
+import java.util.Map;
+import org.apache.gravitino.Entity;
+import org.apache.gravitino.GravitinoEnv;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.authorization.AuthorizationUtils;
+import org.apache.gravitino.authorization.Owner;
+import org.apache.gravitino.authorization.OwnerManager;
+import org.apache.gravitino.catalog.ModelDispatcher;
+import org.apache.gravitino.exceptions.ModelAlreadyExistsException;
+import 
org.apache.gravitino.exceptions.ModelVersionAliasesAlreadyExistException;
+import org.apache.gravitino.exceptions.NoSuchModelException;
+import org.apache.gravitino.exceptions.NoSuchModelVersionException;
+import org.apache.gravitino.exceptions.NoSuchSchemaException;
+import org.apache.gravitino.model.Model;
+import org.apache.gravitino.model.ModelChange;
+import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+import org.apache.gravitino.utils.PrincipalUtils;
+
+/**
+ * {@code ModelHookDispatcher} is a decorator for {@link ModelDispatcher} that 
not only delegates
+ * model operations to the underlying model dispatcher but also executes some 
hook operations before
+ * or after the underlying operations.
+ */
+public class ModelHookDispatcher implements ModelDispatcher {
+
+  private final ModelDispatcher dispatcher;
+
+  public ModelHookDispatcher(ModelDispatcher dispatcher) {
+    this.dispatcher = dispatcher;
+  }
+
+  @Override
+  public NameIdentifier[] listModels(Namespace namespace) throws 
NoSuchSchemaException {
+    return dispatcher.listModels(namespace);
+  }
+
+  @Override
+  public Model getModel(NameIdentifier ident) throws NoSuchModelException {
+    return dispatcher.getModel(ident);
+  }
+
+  @Override
+  public Model registerModel(NameIdentifier ident, String comment, Map<String, 
String> properties)
+      throws NoSuchSchemaException, ModelAlreadyExistsException {
+    // Check whether the current user exists or not
+    AuthorizationUtils.checkCurrentUser(
+        ident.namespace().level(0), PrincipalUtils.getCurrentUserName());
+
+    Model model = dispatcher.registerModel(ident, comment, properties);
+
+    // Set the creator as owner of the model.
+    OwnerManager ownerManager = GravitinoEnv.getInstance().ownerManager();
+    if (ownerManager != null) {
+      ownerManager.setOwner(
+          ident.namespace().level(0),
+          NameIdentifierUtil.toMetadataObject(ident, Entity.EntityType.MODEL),
+          PrincipalUtils.getCurrentUserName(),
+          Owner.Type.USER);
+    }
+    return model;
+  }
+
+  @Override
+  public boolean deleteModel(NameIdentifier ident) {
+    return dispatcher.deleteModel(ident);
+  }
+
+  @Override
+  public int[] listModelVersions(NameIdentifier ident) throws 
NoSuchModelException {
+    return dispatcher.listModelVersions(ident);
+  }
+
+  @Override
+  public ModelVersion getModelVersion(NameIdentifier ident, int version)
+      throws NoSuchModelVersionException {
+    return dispatcher.getModelVersion(ident, version);
+  }
+
+  @Override
+  public ModelVersion getModelVersion(NameIdentifier ident, String alias)
+      throws NoSuchModelVersionException {
+    return dispatcher.getModelVersion(ident, alias);
+  }
+
+  @Override
+  public void linkModelVersion(
+      NameIdentifier ident,
+      String uri,
+      String[] aliases,
+      String comment,
+      Map<String, String> properties)
+      throws NoSuchModelException, ModelVersionAliasesAlreadyExistException {
+    dispatcher.linkModelVersion(ident, uri, aliases, comment, properties);
+  }
+
+  @Override
+  public boolean deleteModelVersion(NameIdentifier ident, int version) {
+    return dispatcher.deleteModelVersion(ident, version);
+  }
+
+  @Override
+  public boolean deleteModelVersion(NameIdentifier ident, String alias) {
+    return dispatcher.deleteModelVersion(ident, alias);
+  }
+
+  @Override
+  public boolean modelExists(NameIdentifier ident) {
+    return dispatcher.modelExists(ident);
+  }
+
+  @Override
+  public Model registerModel(
+      NameIdentifier ident,
+      String uri,
+      String[] aliases,
+      String comment,
+      Map<String, String> properties)
+      throws NoSuchSchemaException, ModelAlreadyExistsException,
+          ModelVersionAliasesAlreadyExistException {
+    // Check whether the current user exists or not
+    AuthorizationUtils.checkCurrentUser(
+        ident.namespace().level(0), PrincipalUtils.getCurrentUserName());
+
+    Model model = dispatcher.registerModel(ident, uri, aliases, comment, 
properties);
+
+    // Set the creator as owner of the model.
+    OwnerManager ownerManager = GravitinoEnv.getInstance().ownerManager();
+    if (ownerManager != null) {
+      ownerManager.setOwner(
+          ident.name(),
+          NameIdentifierUtil.toMetadataObject(ident, Entity.EntityType.MODEL),
+          PrincipalUtils.getCurrentUserName(),
+          Owner.Type.USER);
+    }
+    return model;
+  }
+
+  @Override
+  public boolean modelVersionExists(NameIdentifier ident, int version) {
+    return dispatcher.modelVersionExists(ident, version);
+  }
+
+  @Override
+  public boolean modelVersionExists(NameIdentifier ident, String alias) {
+    return dispatcher.modelVersionExists(ident, alias);
+  }
+
+  @Override
+  public Model alterModel(NameIdentifier ident, ModelChange... changes)
+      throws NoSuchModelException, IllegalArgumentException {
+    return dispatcher.alterModel(ident, changes);
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/OwnerMetaSQLProviderFactory.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/OwnerMetaSQLProviderFactory.java
index 193c3e881a..b7b528a300 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/OwnerMetaSQLProviderFactory.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/OwnerMetaSQLProviderFactory.java
@@ -89,7 +89,7 @@ public class OwnerMetaSQLProviderFactory {
   }
 
   public static String softDeleteOwnerRelBySchemaId(@Param("schemaId") Long 
schemaId) {
-    return getProvider().sotDeleteOwnerRelBySchemaId(schemaId);
+    return getProvider().softDeleteOwnerRelBySchemaId(schemaId);
   }
 
   public static String deleteOwnerMetasByLegacyTimeline(
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/OwnerMetaBaseSQLProvider.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/OwnerMetaBaseSQLProvider.java
index ab89ddcd47..6e3f69e4db 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/OwnerMetaBaseSQLProvider.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/OwnerMetaBaseSQLProvider.java
@@ -23,6 +23,7 @@ import static 
org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper.OWN
 import org.apache.gravitino.storage.relational.mapper.CatalogMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.FilesetMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.GroupMetaMapper;
+import org.apache.gravitino.storage.relational.mapper.ModelMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.SchemaMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.TableMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.TopicMetaMapper;
@@ -148,10 +149,15 @@ public class OwnerMetaBaseSQLProvider {
         + FilesetMetaMapper.META_TABLE_NAME
         + " ft WHERE ft.catalog_id = #{catalogId} AND"
         + " ft.fileset_id = ot.metadata_object_id AND ot.metadata_object_type 
= 'FILESET'"
+        + " UNION "
+        + " SELECT mt.catalog_id FROM "
+        + ModelMetaMapper.TABLE_NAME
+        + " mt WHERE mt.catalog_id = #{catalogId} AND"
+        + " mt.model_id = ot.metadata_object_id AND ot.metadata_object_type = 
'MODEL'"
         + ")";
   }
 
-  public String sotDeleteOwnerRelBySchemaId(@Param("schemaId") Long schemaId) {
+  public String softDeleteOwnerRelBySchemaId(@Param("schemaId") Long schemaId) 
{
     return "UPDATE  "
         + OWNER_TABLE_NAME
         + " ot SET ot.deleted_at = (UNIX_TIMESTAMP() * 1000.0)"
@@ -176,6 +182,11 @@ public class OwnerMetaBaseSQLProvider {
         + FilesetMetaMapper.META_TABLE_NAME
         + " ft WHERE ft.schema_id = #{schemaId} AND "
         + " ft.fileset_id = ot.metadata_object_id AND ot.metadata_object_type 
= 'FILESET'"
+        + " UNION "
+        + " SELECT mt.schema_id FROM "
+        + ModelMetaMapper.TABLE_NAME
+        + " mt WHERE mt.schema_id = #{schemaId} AND "
+        + " mt.model_id = ot.metadata_object_id AND ot.metadata_object_type = 
'MODEL'"
         + ")";
   }
 
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/SecurableObjectBaseSQLProvider.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/SecurableObjectBaseSQLProvider.java
index 42e9026193..6f6407a81a 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/SecurableObjectBaseSQLProvider.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/SecurableObjectBaseSQLProvider.java
@@ -24,6 +24,7 @@ import static 
org.apache.gravitino.storage.relational.mapper.SecurableObjectMapp
 import java.util.List;
 import org.apache.gravitino.storage.relational.mapper.CatalogMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.FilesetMetaMapper;
+import org.apache.gravitino.storage.relational.mapper.ModelMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.SchemaMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.TableMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.TopicMetaMapper;
@@ -128,6 +129,11 @@ public class SecurableObjectBaseSQLProvider {
         + FilesetMetaMapper.META_TABLE_NAME
         + " ft WHERE ft.catalog_id = #{catalogId} AND"
         + " ft.fileset_id = sect.metadata_object_id AND sect.type = 'FILESET'"
+        + " UNION "
+        + " SELECT mt.catalog_id FROM "
+        + ModelMetaMapper.TABLE_NAME
+        + " mt WHERE mt.catalog_id = #{catalogId} AND"
+        + " mt.model_id = sect.metadata_object_id AND sect.type = 'MODEL'"
         + ")";
   }
 
@@ -156,6 +162,11 @@ public class SecurableObjectBaseSQLProvider {
         + FilesetMetaMapper.META_TABLE_NAME
         + " ft WHERE ft.schema_id = #{schemaId} AND "
         + " ft.fileset_id = sect.metadata_object_id AND sect.type = 'FILESET'"
+        + " UNION "
+        + " SELECT mt.schema_id FROM "
+        + ModelMetaMapper.TABLE_NAME
+        + " mt WHERE mt.schema_id = #{schemaId} AND "
+        + " mt.model_id = sect.metadata_object_id AND sect.type = 'MODEL'"
         + ")";
   }
 
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/TagMetadataObjectRelBaseSQLProvider.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/TagMetadataObjectRelBaseSQLProvider.java
index 6c1c7eb5fc..778a026a20 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/TagMetadataObjectRelBaseSQLProvider.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/TagMetadataObjectRelBaseSQLProvider.java
@@ -22,6 +22,7 @@ import java.util.List;
 import org.apache.gravitino.storage.relational.mapper.CatalogMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.FilesetMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.MetalakeMetaMapper;
+import org.apache.gravitino.storage.relational.mapper.ModelMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.SchemaMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.TableColumnMapper;
 import org.apache.gravitino.storage.relational.mapper.TableMetaMapper;
@@ -198,6 +199,11 @@ public class TagMetadataObjectRelBaseSQLProvider {
         + TableColumnMapper.COLUMN_TABLE_NAME
         + " cot WHERE cot.catalog_id = #{catalogId} AND"
         + " cot.column_id = tmt.metadata_object_id AND 
tmt.metadata_object_type = 'COLUMN'"
+        + " UNION "
+        + " SELECT mt.catalog_id FROM "
+        + ModelMetaMapper.TABLE_NAME
+        + " mt WHERE mt.catalog_id = #{catalogId} AND"
+        + " mt.model_id = tmt.metadata_object_id AND tmt.metadata_object_type 
= 'MODEL'"
         + ")";
   }
 
@@ -231,6 +237,11 @@ public class TagMetadataObjectRelBaseSQLProvider {
         + TableColumnMapper.COLUMN_TABLE_NAME
         + " cot WHERE cot.schema_id = #{schemaId} AND "
         + " cot.column_id = tmt.metadata_object_id AND 
tmt.metadata_object_type = 'COLUMN'"
+        + " UNION "
+        + " SELECT mt.schema_id FROM "
+        + ModelMetaMapper.TABLE_NAME
+        + " mt WHERE mt.schema_id = #{schemaId} AND "
+        + " mt.model_id = tmt.metadata_object_id AND tmt.metadata_object_type 
= 'MODEL'"
         + ")";
   }
 
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/OwnerMetaPostgreSQLProvider.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/OwnerMetaPostgreSQLProvider.java
index c0f5d73d8e..c88f292ae4 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/OwnerMetaPostgreSQLProvider.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/OwnerMetaPostgreSQLProvider.java
@@ -22,6 +22,7 @@ import static 
org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper.OWN
 
 import org.apache.gravitino.storage.relational.mapper.CatalogMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.FilesetMetaMapper;
+import org.apache.gravitino.storage.relational.mapper.ModelMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.SchemaMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.TableMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.TopicMetaMapper;
@@ -88,11 +89,16 @@ public class OwnerMetaPostgreSQLProvider extends 
OwnerMetaBaseSQLProvider {
         + FilesetMetaMapper.META_TABLE_NAME
         + " ft WHERE ft.catalog_id = #{catalogId} AND"
         + " ft.fileset_id = ot.metadata_object_id AND ot.metadata_object_type 
= 'FILESET'"
+        + " UNION "
+        + " SELECT mt.catalog_id FROM "
+        + ModelMetaMapper.TABLE_NAME
+        + " mt WHERE mt.catalog_id = #{catalogId} AND"
+        + " mt.model_id = ot.metadata_object_id AND ot.metadata_object_type = 
'MODEL'"
         + ")";
   }
 
   @Override
-  public String sotDeleteOwnerRelBySchemaId(Long schemaId) {
+  public String softDeleteOwnerRelBySchemaId(Long schemaId) {
     return "UPDATE  "
         + OWNER_TABLE_NAME
         + " ot SET deleted_at = floor(extract(epoch from((current_timestamp - 
timestamp '1970-01-01 00:00:00')*1000))) "
@@ -116,6 +122,11 @@ public class OwnerMetaPostgreSQLProvider extends 
OwnerMetaBaseSQLProvider {
         + FilesetMetaMapper.META_TABLE_NAME
         + " ft WHERE ft.schema_id = #{schemaId} AND "
         + "ft.fileset_id = ot.metadata_object_id AND ot.metadata_object_type = 
'FILESET'"
+        + " UNION "
+        + " SELECT mt.schema_id FROM "
+        + ModelMetaMapper.TABLE_NAME
+        + " mt WHERE mt.schema_id = #{schemaId} AND "
+        + "mt.model_id = ot.metadata_object_id AND ot.metadata_object_type = 
'MODEL'"
         + ")";
   }
 
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/SecurableObjectPostgreSQLProvider.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/SecurableObjectPostgreSQLProvider.java
index c67324f9a7..027f4fb720 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/SecurableObjectPostgreSQLProvider.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/SecurableObjectPostgreSQLProvider.java
@@ -24,6 +24,7 @@ import static 
org.apache.gravitino.storage.relational.mapper.SecurableObjectMapp
 import java.util.List;
 import org.apache.gravitino.storage.relational.mapper.CatalogMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.FilesetMetaMapper;
+import org.apache.gravitino.storage.relational.mapper.ModelMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.SchemaMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.TableMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.TopicMetaMapper;
@@ -113,6 +114,11 @@ public class SecurableObjectPostgreSQLProvider extends 
SecurableObjectBaseSQLPro
         + FilesetMetaMapper.META_TABLE_NAME
         + " ft WHERE ft.catalog_id = #{catalogId}  AND"
         + " ft.fileset_id = sect.metadata_object_id AND sect.type = 'FILESET'"
+        + " UNION "
+        + " SELECT mt.catalog_id FROM "
+        + ModelMetaMapper.TABLE_NAME
+        + " mt WHERE mt.catalog_id = #{catalogId} AND"
+        + " mt.model_id = sect.metadata_object_id AND sect.type = 'MODEL'"
         + ")";
   }
 
@@ -142,6 +148,11 @@ public class SecurableObjectPostgreSQLProvider extends 
SecurableObjectBaseSQLPro
         + FilesetMetaMapper.META_TABLE_NAME
         + " ft WHERE ft.schema_id = #{schemaId} AND "
         + "ft.fileset_id = sect.metadata_object_id AND sect.type = 'FILESET'"
+        + " UNION "
+        + " SELECT mt.schema_id FROM "
+        + ModelMetaMapper.TABLE_NAME
+        + " mt WHERE mt.schema_id = #{schemaId} AND "
+        + " mt.model_id = sect.metadata_object_id AND sect.type = 'MODEL'"
         + ")";
   }
 
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/TagMetadataObjectRelPostgreSQLProvider.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/TagMetadataObjectRelPostgreSQLProvider.java
index 9045ead8ea..be008deca5 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/TagMetadataObjectRelPostgreSQLProvider.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/postgresql/TagMetadataObjectRelPostgreSQLProvider.java
@@ -24,6 +24,7 @@ import java.util.List;
 import org.apache.gravitino.storage.relational.mapper.CatalogMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.FilesetMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.MetalakeMetaMapper;
+import org.apache.gravitino.storage.relational.mapper.ModelMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.SchemaMetaMapper;
 import org.apache.gravitino.storage.relational.mapper.TableColumnMapper;
 import org.apache.gravitino.storage.relational.mapper.TableMetaMapper;
@@ -109,6 +110,11 @@ public class TagMetadataObjectRelPostgreSQLProvider 
extends TagMetadataObjectRel
         + TableColumnMapper.COLUMN_TABLE_NAME
         + " cot WHERE cot.catalog_id = #{catalogId} AND"
         + " cot.column_id = tmt.metadata_object_id AND 
tmt.metadata_object_type = 'COLUMN'"
+        + " UNION "
+        + " SELECT mt.catalog_id FROM "
+        + ModelMetaMapper.TABLE_NAME
+        + " mt WHERE mt.catalog_id = #{catalogId} AND"
+        + " mt.model_id = tmt.metadata_object_id AND tmt.metadata_object_type 
= 'MODEL'"
         + ")";
   }
 
@@ -143,6 +149,11 @@ public class TagMetadataObjectRelPostgreSQLProvider 
extends TagMetadataObjectRel
         + TableColumnMapper.COLUMN_TABLE_NAME
         + " cot WHERE cot.schema_id = #{schemaId} AND"
         + " cot.column_id = tmt.metadata_object_id AND 
tmt.metadata_object_type = 'COLUMN'"
+        + " UNION "
+        + " SELECT mt.schema_id FROM "
+        + ModelMetaMapper.TABLE_NAME
+        + " mt WHERE mt.schema_id = #{schemaId} AND "
+        + " mt.model_id = tmt.metadata_object_id AND tmt.metadata_object_type 
= 'MODEL'"
         + ")";
   }
 
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/service/ModelMetaService.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/service/ModelMetaService.java
index 7e32af2f4b..79ca6fc1b0 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/service/ModelMetaService.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/service/ModelMetaService.java
@@ -29,6 +29,7 @@ import java.util.function.Function;
 import java.util.stream.Collectors;
 import org.apache.gravitino.Entity;
 import org.apache.gravitino.HasIdentifier;
+import org.apache.gravitino.MetadataObject;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
 import org.apache.gravitino.exceptions.NoSuchEntityException;
@@ -36,6 +37,9 @@ import org.apache.gravitino.meta.ModelEntity;
 import org.apache.gravitino.storage.relational.mapper.ModelMetaMapper;
 import 
org.apache.gravitino.storage.relational.mapper.ModelVersionAliasRelMapper;
 import org.apache.gravitino.storage.relational.mapper.ModelVersionMetaMapper;
+import org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper;
+import org.apache.gravitino.storage.relational.mapper.SecurableObjectMapper;
+import 
org.apache.gravitino.storage.relational.mapper.TagMetadataObjectRelMapper;
 import org.apache.gravitino.storage.relational.po.ModelPO;
 import org.apache.gravitino.storage.relational.utils.ExceptionUtils;
 import org.apache.gravitino.storage.relational.utils.POConverters;
@@ -102,8 +106,10 @@ public class ModelMetaService {
     NameIdentifierUtil.checkModel(ident);
 
     Long schemaId;
+    Long modelId;
     try {
       schemaId = 
CommonMetaService.getInstance().getParentEntityIdByNamespace(ident.namespace());
+      modelId = getModelIdBySchemaIdAndModelName(schemaId, ident.name());
     } catch (NoSuchEntityException e) {
       LOG.warn("Failed to delete model: {}", ident, e);
       return false;
@@ -132,7 +138,25 @@ public class ModelMetaService {
                 SessionUtils.doWithoutCommitAndFetchResult(
                     ModelMetaMapper.class,
                     mapper ->
-                        
mapper.softDeleteModelMetaBySchemaIdAndModelName(schemaId, ident.name()))));
+                        
mapper.softDeleteModelMetaBySchemaIdAndModelName(schemaId, ident.name()))),
+        () ->
+            SessionUtils.doWithoutCommit(
+                OwnerMetaMapper.class,
+                mapper ->
+                    mapper.softDeleteOwnerRelByMetadataObjectIdAndType(
+                        modelId, MetadataObject.Type.MODEL.name())),
+        () ->
+            SessionUtils.doWithoutCommit(
+                SecurableObjectMapper.class,
+                mapper ->
+                    mapper.softDeleteObjectRelsByMetadataObject(
+                        modelId, MetadataObject.Type.MODEL.name())),
+        () ->
+            SessionUtils.doWithoutCommit(
+                TagMetadataObjectRelMapper.class,
+                mapper ->
+                    mapper.softDeleteTagMetadataObjectRelsByMetadataObject(
+                        modelId, MetadataObject.Type.MODEL.name())));
 
     return modelDeletedCount.get() > 0;
   }
diff --git 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestOwnerMetaService.java
 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestOwnerMetaService.java
index 89dea63a59..908022f667 100644
--- 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestOwnerMetaService.java
+++ 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestOwnerMetaService.java
@@ -28,6 +28,7 @@ import org.apache.gravitino.meta.BaseMetalake;
 import org.apache.gravitino.meta.CatalogEntity;
 import org.apache.gravitino.meta.FilesetEntity;
 import org.apache.gravitino.meta.GroupEntity;
+import org.apache.gravitino.meta.ModelEntity;
 import org.apache.gravitino.meta.RoleEntity;
 import org.apache.gravitino.meta.SchemaEntity;
 import org.apache.gravitino.meta.TableEntity;
@@ -260,6 +261,16 @@ class TestOwnerMetaService extends TestJDBCBackend {
             "topic",
             auditInfo);
     backend.insert(topic, false);
+    ModelEntity model =
+        createModelEntity(
+            RandomIdGenerator.INSTANCE.nextId(),
+            Namespace.of("metalake", "catalog", "schema"),
+            "model",
+            "comment",
+            1,
+            null,
+            auditInfo);
+    backend.insert(model, false);
 
     UserEntity user =
         createUserEntity(
@@ -279,33 +290,40 @@ class TestOwnerMetaService extends TestJDBCBackend {
         .setOwner(fileset.nameIdentifier(), fileset.type(), 
user.nameIdentifier(), user.type());
     OwnerMetaService.getInstance()
         .setOwner(topic.nameIdentifier(), topic.type(), user.nameIdentifier(), 
user.type());
+    OwnerMetaService.getInstance()
+        .setOwner(model.nameIdentifier(), model.type(), user.nameIdentifier(), 
user.type());
+
+    Assertions.assertEquals(6, countAllOwnerRel(user.id()));
+    Assertions.assertEquals(6, countActiveOwnerRel(user.id()));
 
-    Assertions.assertEquals(5, countAllOwnerRel(user.id()));
+    // Test to delete model
+    ModelMetaService.getInstance().deleteModel(model.nameIdentifier());
+    Assertions.assertEquals(6, countAllOwnerRel(user.id()));
     Assertions.assertEquals(5, countActiveOwnerRel(user.id()));
 
     // Test to delete table
     TableMetaService.getInstance().deleteTable(table.nameIdentifier());
-    Assertions.assertEquals(5, countAllOwnerRel(user.id()));
+    Assertions.assertEquals(6, countAllOwnerRel(user.id()));
     Assertions.assertEquals(4, countActiveOwnerRel(user.id()));
 
     // Test to delete topic
     TopicMetaService.getInstance().deleteTopic(topic.nameIdentifier());
-    Assertions.assertEquals(5, countAllOwnerRel(user.id()));
+    Assertions.assertEquals(6, countAllOwnerRel(user.id()));
     Assertions.assertEquals(3, countActiveOwnerRel(user.id()));
 
     // Test to delete fileset
     FilesetMetaService.getInstance().deleteFileset(fileset.nameIdentifier());
-    Assertions.assertEquals(5, countAllOwnerRel(user.id()));
+    Assertions.assertEquals(6, countAllOwnerRel(user.id()));
     Assertions.assertEquals(2, countActiveOwnerRel(user.id()));
 
     // Test to delete schema
     SchemaMetaService.getInstance().deleteSchema(schema.nameIdentifier(), 
false);
-    Assertions.assertEquals(5, countAllOwnerRel(user.id()));
+    Assertions.assertEquals(6, countAllOwnerRel(user.id()));
     Assertions.assertEquals(1, countActiveOwnerRel(user.id()));
 
     // Test to delete catalog
     CatalogMetaService.getInstance().deleteCatalog(catalog.nameIdentifier(), 
false);
-    Assertions.assertEquals(5, countAllOwnerRel(user.id()));
+    Assertions.assertEquals(6, countAllOwnerRel(user.id()));
     Assertions.assertEquals(0, countActiveOwnerRel(user.id()));
 
     // Test to delete catalog with cascade mode
@@ -343,6 +361,16 @@ class TestOwnerMetaService extends TestJDBCBackend {
             "topic",
             auditInfo);
     backend.insert(topic, false);
+    model =
+        createModelEntity(
+            RandomIdGenerator.INSTANCE.nextId(),
+            Namespace.of("metalake", "catalog", "schema"),
+            "model",
+            "comment",
+            1,
+            null,
+            auditInfo);
+    backend.insert(model, false);
 
     OwnerMetaService.getInstance()
         .setOwner(catalog.nameIdentifier(), catalog.type(), 
user.nameIdentifier(), user.type());
@@ -354,9 +382,11 @@ class TestOwnerMetaService extends TestJDBCBackend {
         .setOwner(fileset.nameIdentifier(), fileset.type(), 
user.nameIdentifier(), user.type());
     OwnerMetaService.getInstance()
         .setOwner(topic.nameIdentifier(), topic.type(), user.nameIdentifier(), 
user.type());
+    OwnerMetaService.getInstance()
+        .setOwner(model.nameIdentifier(), model.type(), user.nameIdentifier(), 
user.type());
 
     CatalogMetaService.getInstance().deleteCatalog(catalog.nameIdentifier(), 
true);
-    Assertions.assertEquals(10, countAllOwnerRel(user.id()));
+    Assertions.assertEquals(12, countAllOwnerRel(user.id()));
     Assertions.assertEquals(0, countActiveOwnerRel(user.id()));
 
     // Test to delete schema with cascade mode
@@ -380,6 +410,7 @@ class TestOwnerMetaService extends TestJDBCBackend {
             "fileset",
             auditInfo);
     backend.insert(fileset, false);
+
     table =
         createTableEntity(
             RandomIdGenerator.INSTANCE.nextId(),
@@ -387,6 +418,7 @@ class TestOwnerMetaService extends TestJDBCBackend {
             "table",
             auditInfo);
     backend.insert(table, false);
+
     topic =
         createTopicEntity(
             RandomIdGenerator.INSTANCE.nextId(),
@@ -395,6 +427,17 @@ class TestOwnerMetaService extends TestJDBCBackend {
             auditInfo);
     backend.insert(topic, false);
 
+    model =
+        createModelEntity(
+            RandomIdGenerator.INSTANCE.nextId(),
+            Namespace.of("metalake", "catalog", "schema"),
+            "model",
+            "comment",
+            1,
+            null,
+            auditInfo);
+    backend.insert(model, false);
+
     OwnerMetaService.getInstance()
         .setOwner(schema.nameIdentifier(), schema.type(), 
user.nameIdentifier(), user.type());
     OwnerMetaService.getInstance()
@@ -405,9 +448,11 @@ class TestOwnerMetaService extends TestJDBCBackend {
         .setOwner(fileset.nameIdentifier(), fileset.type(), 
user.nameIdentifier(), user.type());
     OwnerMetaService.getInstance()
         .setOwner(topic.nameIdentifier(), topic.type(), user.nameIdentifier(), 
user.type());
+    OwnerMetaService.getInstance()
+        .setOwner(model.nameIdentifier(), model.type(), user.nameIdentifier(), 
user.type());
 
     SchemaMetaService.getInstance().deleteSchema(schema.nameIdentifier(), 
true);
-    Assertions.assertEquals(15, countAllOwnerRel(user.id()));
+    Assertions.assertEquals(18, countAllOwnerRel(user.id()));
     Assertions.assertEquals(1, countActiveOwnerRel(user.id()));
 
     // Test to delete user
@@ -439,8 +484,20 @@ class TestOwnerMetaService extends TestJDBCBackend {
             Namespace.of("metalake", "catalog", "schema"),
             "topic",
             auditInfo);
+
     backend.insert(topic, false);
 
+    model =
+        createModelEntity(
+            RandomIdGenerator.INSTANCE.nextId(),
+            Namespace.of("metalake", "catalog", "schema"),
+            "model",
+            "comment",
+            1,
+            null,
+            auditInfo);
+    backend.insert(model, false);
+
     OwnerMetaService.getInstance()
         .setOwner(schema.nameIdentifier(), schema.type(), 
user.nameIdentifier(), user.type());
     OwnerMetaService.getInstance()
@@ -451,9 +508,13 @@ class TestOwnerMetaService extends TestJDBCBackend {
         .setOwner(fileset.nameIdentifier(), fileset.type(), 
user.nameIdentifier(), user.type());
     OwnerMetaService.getInstance()
         .setOwner(topic.nameIdentifier(), topic.type(), user.nameIdentifier(), 
user.type());
+    OwnerMetaService.getInstance()
+        .setOwner(model.nameIdentifier(), model.type(), user.nameIdentifier(), 
user.type());
+    OwnerMetaService.getInstance()
+        .setOwner(model.nameIdentifier(), model.type(), user.nameIdentifier(), 
user.type());
 
     UserMetaService.getInstance().deleteUser(user.nameIdentifier());
-    Assertions.assertEquals(20, countAllOwnerRel(user.id()));
+    Assertions.assertEquals(25, countAllOwnerRel(user.id()));
     Assertions.assertEquals(0, countActiveOwnerRel(user.id()));
   }
 }
diff --git 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestSecurableObjects.java
 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestSecurableObjects.java
index b5cc85112a..950ed6f845 100644
--- 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestSecurableObjects.java
+++ 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestSecurableObjects.java
@@ -34,6 +34,7 @@ import org.apache.gravitino.meta.AuditInfo;
 import org.apache.gravitino.meta.BaseMetalake;
 import org.apache.gravitino.meta.CatalogEntity;
 import org.apache.gravitino.meta.FilesetEntity;
+import org.apache.gravitino.meta.ModelEntity;
 import org.apache.gravitino.meta.RoleEntity;
 import org.apache.gravitino.meta.SchemaEntity;
 import org.apache.gravitino.meta.TableEntity;
@@ -192,6 +193,16 @@ public class TestSecurableObjects extends TestJDBCBackend {
             "topic",
             auditInfo);
     backend.insert(topic, false);
+    ModelEntity model =
+        createModelEntity(
+            RandomIdGenerator.INSTANCE.nextId(),
+            Namespace.of("metalake", "catalog", "schema"),
+            "model",
+            "comment",
+            1,
+            null,
+            auditInfo);
+    backend.insert(model, false);
 
     SecurableObject catalogObject =
         SecurableObjects.ofCatalog(
@@ -210,6 +221,9 @@ public class TestSecurableObjects extends TestJDBCBackend {
     SecurableObject topicObject =
         SecurableObjects.ofTopic(
             schemaObject, "topic", 
Lists.newArrayList(Privileges.ConsumeTopic.deny()));
+    SecurableObject modelObject =
+        SecurableObjects.ofModel(
+            schemaObject, "model", 
Lists.newArrayList(Privileges.UseModel.deny()));
 
     RoleEntity role1 =
         createRoleEntity(
@@ -218,37 +232,42 @@ public class TestSecurableObjects extends TestJDBCBackend 
{
             "role1",
             auditInfo,
             Lists.newArrayList(
-                catalogObject, schemaObject, tableObject, filesetObject, 
topicObject),
+                catalogObject, schemaObject, tableObject, filesetObject, 
topicObject, modelObject),
             ImmutableMap.of("k1", "v1"));
 
     roleMetaService.insertRole(role1, false);
 
-    Assertions.assertEquals(5, countAllObjectRel(role1.id()));
+    Assertions.assertEquals(6, countAllObjectRel(role1.id()));
+    Assertions.assertEquals(6, countActiveObjectRel(role1.id()));
+
+    // Test to delete model
+    ModelMetaService.getInstance().deleteModel(model.nameIdentifier());
+    Assertions.assertEquals(6, countAllObjectRel(role1.id()));
     Assertions.assertEquals(5, countActiveObjectRel(role1.id()));
 
     // Test to delete table
     TableMetaService.getInstance().deleteTable(table.nameIdentifier());
-    Assertions.assertEquals(5, countAllObjectRel(role1.id()));
+    Assertions.assertEquals(6, countAllObjectRel(role1.id()));
     Assertions.assertEquals(4, countActiveObjectRel(role1.id()));
 
     // Test to delete topic
     TopicMetaService.getInstance().deleteTopic(topic.nameIdentifier());
-    Assertions.assertEquals(5, countAllObjectRel(role1.id()));
+    Assertions.assertEquals(6, countAllObjectRel(role1.id()));
     Assertions.assertEquals(3, countActiveObjectRel(role1.id()));
 
     // Test to delete fileset
     FilesetMetaService.getInstance().deleteFileset(fileset.nameIdentifier());
-    Assertions.assertEquals(5, countAllObjectRel(role1.id()));
+    Assertions.assertEquals(6, countAllObjectRel(role1.id()));
     Assertions.assertEquals(2, countActiveObjectRel(role1.id()));
 
     // Test to delete schema
     SchemaMetaService.getInstance().deleteSchema(schema.nameIdentifier(), 
false);
-    Assertions.assertEquals(5, countAllObjectRel(role1.id()));
+    Assertions.assertEquals(6, countAllObjectRel(role1.id()));
     Assertions.assertEquals(1, countActiveObjectRel(role1.id()));
 
     // Test to delete catalog
     CatalogMetaService.getInstance().deleteCatalog(catalog.nameIdentifier(), 
false);
-    Assertions.assertEquals(5, countAllObjectRel(role1.id()));
+    Assertions.assertEquals(6, countAllObjectRel(role1.id()));
     Assertions.assertEquals(0, countActiveObjectRel(role1.id()));
 
     roleMetaService.deleteRole(role1.nameIdentifier());
@@ -281,6 +300,7 @@ public class TestSecurableObjects extends TestJDBCBackend {
             "table",
             auditInfo);
     backend.insert(table, false);
+
     topic =
         createTopicEntity(
             RandomIdGenerator.INSTANCE.nextId(),
@@ -288,6 +308,18 @@ public class TestSecurableObjects extends TestJDBCBackend {
             "topic",
             auditInfo);
     backend.insert(topic, false);
+
+    model =
+        createModelEntity(
+            RandomIdGenerator.INSTANCE.nextId(),
+            Namespace.of("metalake", "catalog", "schema"),
+            "model",
+            "comment",
+            1,
+            null,
+            auditInfo);
+    backend.insert(model, false);
+
     role1 =
         createRoleEntity(
             RandomIdGenerator.INSTANCE.nextId(),
@@ -295,13 +327,13 @@ public class TestSecurableObjects extends TestJDBCBackend 
{
             "role1",
             auditInfo,
             Lists.newArrayList(
-                catalogObject, schemaObject, tableObject, filesetObject, 
topicObject),
+                catalogObject, schemaObject, tableObject, filesetObject, 
topicObject, modelObject),
             ImmutableMap.of("k1", "v1"));
 
     roleMetaService.insertRole(role1, false);
 
     CatalogMetaService.getInstance().deleteCatalog(catalog.nameIdentifier(), 
true);
-    Assertions.assertEquals(5, countAllObjectRel(role1.id()));
+    Assertions.assertEquals(6, countAllObjectRel(role1.id()));
     Assertions.assertEquals(0, countActiveObjectRel(role1.id()));
 
     roleMetaService.deleteRole(role1.nameIdentifier());
@@ -341,6 +373,17 @@ public class TestSecurableObjects extends TestJDBCBackend {
             "topic",
             auditInfo);
     backend.insert(topic, false);
+    model =
+        createModelEntity(
+            RandomIdGenerator.INSTANCE.nextId(),
+            Namespace.of("metalake", "catalog", "schema"),
+            "model",
+            "comment",
+            1,
+            null,
+            auditInfo);
+    backend.insert(model, false);
+
     role1 =
         createRoleEntity(
             RandomIdGenerator.INSTANCE.nextId(),
@@ -348,13 +391,13 @@ public class TestSecurableObjects extends TestJDBCBackend 
{
             "role1",
             auditInfo,
             Lists.newArrayList(
-                catalogObject, schemaObject, tableObject, filesetObject, 
topicObject),
+                catalogObject, schemaObject, tableObject, filesetObject, 
topicObject, modelObject),
             ImmutableMap.of("k1", "v1"));
 
     roleMetaService.insertRole(role1, false);
 
     SchemaMetaService.getInstance().deleteSchema(schema.nameIdentifier(), 
true);
-    Assertions.assertEquals(5, countAllObjectRel(role1.id()));
+    Assertions.assertEquals(6, countAllObjectRel(role1.id()));
     Assertions.assertEquals(1, countActiveObjectRel(role1.id()));
   }
 }
diff --git 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestTagMetaService.java
 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestTagMetaService.java
index a81f222de9..feb4bdb07c 100644
--- 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestTagMetaService.java
+++ 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestTagMetaService.java
@@ -36,6 +36,7 @@ import org.apache.gravitino.meta.BaseMetalake;
 import org.apache.gravitino.meta.CatalogEntity;
 import org.apache.gravitino.meta.ColumnEntity;
 import org.apache.gravitino.meta.FilesetEntity;
+import org.apache.gravitino.meta.ModelEntity;
 import org.apache.gravitino.meta.SchemaEntity;
 import org.apache.gravitino.meta.TableEntity;
 import org.apache.gravitino.meta.TagEntity;
@@ -731,6 +732,17 @@ public class TestTagMetaService extends TestJDBCBackend {
             auditInfo);
     backend.insert(fileset, false);
 
+    ModelEntity model =
+        createModelEntity(
+            RandomIdGenerator.INSTANCE.nextId(),
+            Namespace.of(metalakeName, catalog.name(), schema.name()),
+            "model1",
+            "comment",
+            1,
+            null,
+            auditInfo);
+    backend.insert(model, false);
+
     TagMetaService tagMetaService = TagMetaService.getInstance();
     TagEntity tagEntity1 =
         TagEntity.builder()
@@ -774,34 +786,44 @@ public class TestTagMetaService extends TestJDBCBackend {
         column.type(),
         new NameIdentifier[] {tagEntity1.nameIdentifier()},
         new NameIdentifier[0]);
+    tagMetaService.associateTagsWithMetadataObject(
+        model.nameIdentifier(),
+        model.type(),
+        new NameIdentifier[] {tagEntity1.nameIdentifier()},
+        new NameIdentifier[0]);
+
+    Assertions.assertEquals(7, countActiveTagRel(tagEntity1.id()));
+    Assertions.assertEquals(7, countAllTagRel(tagEntity1.id()));
 
+    // Test to delete a model
+    ModelMetaService.getInstance().deleteModel(model.nameIdentifier());
     Assertions.assertEquals(6, countActiveTagRel(tagEntity1.id()));
-    Assertions.assertEquals(6, countAllTagRel(tagEntity1.id()));
+    Assertions.assertEquals(7, countAllTagRel(tagEntity1.id()));
 
     // Test to drop a table
     TableMetaService.getInstance().deleteTable(table.nameIdentifier());
     Assertions.assertEquals(4, countActiveTagRel(tagEntity1.id()));
-    Assertions.assertEquals(6, countAllTagRel(tagEntity1.id()));
+    Assertions.assertEquals(7, countAllTagRel(tagEntity1.id()));
 
     // Test to drop a topic
     TopicMetaService.getInstance().deleteTopic(topic.nameIdentifier());
     Assertions.assertEquals(3, countActiveTagRel(tagEntity1.id()));
-    Assertions.assertEquals(6, countAllTagRel(tagEntity1.id()));
+    Assertions.assertEquals(7, countAllTagRel(tagEntity1.id()));
 
     // Test to drop a fileset
     FilesetMetaService.getInstance().deleteFileset(fileset.nameIdentifier());
     Assertions.assertEquals(2, countActiveTagRel(tagEntity1.id()));
-    Assertions.assertEquals(6, countAllTagRel(tagEntity1.id()));
+    Assertions.assertEquals(7, countAllTagRel(tagEntity1.id()));
 
     // Test to drop a schema
     SchemaMetaService.getInstance().deleteSchema(schema.nameIdentifier(), 
false);
     Assertions.assertEquals(1, countActiveTagRel(tagEntity1.id()));
-    Assertions.assertEquals(6, countAllTagRel(tagEntity1.id()));
+    Assertions.assertEquals(7, countAllTagRel(tagEntity1.id()));
 
     // Test to drop a catalog
     CatalogMetaService.getInstance().deleteCatalog(catalog.nameIdentifier(), 
false);
     Assertions.assertEquals(0, countActiveTagRel(tagEntity1.id()));
-    Assertions.assertEquals(6, countAllTagRel(tagEntity1.id()));
+    Assertions.assertEquals(7, countAllTagRel(tagEntity1.id()));
 
     // Test to drop a catalog using cascade mode
     catalog =
@@ -858,6 +880,17 @@ public class TestTagMetaService extends TestJDBCBackend {
             auditInfo);
     backend.insert(fileset, false);
 
+    model =
+        createModelEntity(
+            RandomIdGenerator.INSTANCE.nextId(),
+            Namespace.of(metalakeName, catalog.name(), schema.name()),
+            "model1",
+            "comment",
+            1,
+            null,
+            auditInfo);
+    backend.insert(model, false);
+
     tagMetaService.associateTagsWithMetadataObject(
         catalog.nameIdentifier(),
         catalog.type(),
@@ -890,10 +923,15 @@ public class TestTagMetaService extends TestJDBCBackend {
         column.type(),
         new NameIdentifier[] {tagEntity1.nameIdentifier()},
         new NameIdentifier[0]);
+    tagMetaService.associateTagsWithMetadataObject(
+        model.nameIdentifier(),
+        model.type(),
+        new NameIdentifier[] {tagEntity1.nameIdentifier()},
+        new NameIdentifier[0]);
 
     CatalogMetaService.getInstance().deleteCatalog(catalog.nameIdentifier(), 
true);
     Assertions.assertEquals(0, countActiveTagRel(tagEntity1.id()));
-    Assertions.assertEquals(12, countAllTagRel(tagEntity1.id()));
+    Assertions.assertEquals(14, countAllTagRel(tagEntity1.id()));
 
     // Test to drop a schema using cascade mode
     catalog =
@@ -950,6 +988,17 @@ public class TestTagMetaService extends TestJDBCBackend {
             auditInfo);
     backend.insert(fileset, false);
 
+    model =
+        createModelEntity(
+            RandomIdGenerator.INSTANCE.nextId(),
+            Namespace.of(metalakeName, catalog.name(), schema.name()),
+            "model1",
+            "comment",
+            1,
+            null,
+            auditInfo);
+    backend.insert(model, false);
+
     tagMetaService.associateTagsWithMetadataObject(
         catalog.nameIdentifier(),
         catalog.type(),
@@ -982,10 +1031,15 @@ public class TestTagMetaService extends TestJDBCBackend {
         column.type(),
         new NameIdentifier[] {tagEntity1.nameIdentifier()},
         new NameIdentifier[0]);
+    tagMetaService.associateTagsWithMetadataObject(
+        model.nameIdentifier(),
+        model.type(),
+        new NameIdentifier[] {tagEntity1.nameIdentifier()},
+        new NameIdentifier[0]);
 
     // Test to drop a schema
     SchemaMetaService.getInstance().deleteSchema(schema.nameIdentifier(), 
true);
     Assertions.assertEquals(1, countActiveTagRel(tagEntity1.id()));
-    Assertions.assertEquals(18, countAllTagRel(tagEntity1.id()));
+    Assertions.assertEquals(21, countAllTagRel(tagEntity1.id()));
   }
 }

Reply via email to