From 98f590d52d5e435c05b58b725e7e31abadd1203f Mon Sep 17 00:00:00 2001 From: Yingjian Wu Date: Sat, 15 Jun 2024 14:34:54 -0700 Subject: [PATCH] add isParent field + address comments --- .../server/model/BaseRelEntityInfo.java | 22 +---- .../ParentChildRelMetadataConstants.java | 35 +++++--- .../netflix/metacat/MetacatSmokeSpec.groovy | 58 +++++++++----- .../main/api/v1/ParentChildRelController.java | 2 +- .../main/services/impl/TableServiceImpl.java | 80 ++++++++++--------- .../services/impl/TableServiceImplSpec.groovy | 16 +++- 6 files changed, 122 insertions(+), 91 deletions(-) diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/model/BaseRelEntityInfo.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/model/BaseRelEntityInfo.java index b070d7bfc..41a4b940c 100644 --- a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/model/BaseRelEntityInfo.java +++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/model/BaseRelEntityInfo.java @@ -1,6 +1,8 @@ package com.netflix.metacat.common.server.model; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import java.io.Serializable; @@ -8,28 +10,12 @@ * Base class to represent relation entity. */ @Data +@AllArgsConstructor +@NoArgsConstructor public abstract class BaseRelEntityInfo implements Serializable { private static final long serialVersionUID = 9121109874202888889L; private String name; private String relationType; private String uuid; - /** - Empty Constructor. - */ - public BaseRelEntityInfo() { - - } - - /** - Constructor with all params. - @param name name of the entity - @param relationType type of the relation - @param uuid uuid of the entity - */ - public BaseRelEntityInfo(final String name, final String relationType, final String uuid) { - this.name = name; - this.relationType = relationType; - this.uuid = uuid; - } } diff --git a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/usermetadata/ParentChildRelMetadataConstants.java b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/usermetadata/ParentChildRelMetadataConstants.java index a0c825d35..f2f7dd666 100644 --- a/metacat-common-server/src/main/java/com/netflix/metacat/common/server/usermetadata/ParentChildRelMetadataConstants.java +++ b/metacat-common-server/src/main/java/com/netflix/metacat/common/server/usermetadata/ParentChildRelMetadataConstants.java @@ -7,37 +7,46 @@ */ public final class ParentChildRelMetadataConstants { /** - * During create, top level key specified in DefinitionMetadata that indicate the parent table name. + * During get and create, top level key specified in DefinitionMetadata that indicates the parent child infos. */ - public static final String PARENTNAME = "root_table_name"; + public static final String PARENT_CHILD_RELINFO = "parentChildRelationInfo"; /** - * During create, top level key specified in DefinitionMetadata that indicates the parent table uuid. + * During create, nested level key specified in DefinitionMetadata['parentChildRelationInfo'] + * that indicate the parent table name. */ - public static final String PARENTUUID = "root_table_uuid"; + public static final String PARENT_NAME = "root_table_name"; /** - * During create, top level key specified in DefinitionMetadata that indicates the child table uuid. + * During create, nested level key specified in DefinitionMetadata['parentChildRelationInfo'] + * that indicates the parent table uuid. */ - public static final String CHILDUUID = "child_table_uuid"; - + public static final String PARENT_UUID = "root_table_uuid"; /** - * During create, top level key specified in DefinitionMetadata that indicates relationType. + * During create, nested level key specified in DefinitionMetadata['parentChildRelationInfo'] + * that indicates the child table uuid. */ - public static final String RELATIONTYPE = "relationType"; + public static final String CHILD_UUID = "child_table_uuid"; /** - * During get, top level key specified in DefinitionMetadata that indicates the parent child infos. + * During create, nested level key specified in DefinitionMetadata['parentChildRelationInfo'] + * that indicates relationType. */ - public static final String PARENTCHILDRELINFO = "parentChildRelationInfo"; + public static final String RELATION_TYPE = "relationType"; /** * During get, the nested key specified in DefinitionMetadata[PARENTCHILDRELINFO] that indicates parent infos. */ - public static final String PARENTINFOS = "parentInfos"; + public static final String PARENT_INFOS = "parentInfos"; /** * During get, the nested key specified in DefinitionMetadata[PARENTCHILDRELINFO] that indicates child infos. */ - public static final String CHILDINFOS = "childInfos"; + public static final String CHILD_INFOS = "childInfos"; + + /** + * During get, the nested key specified in DefinitionMetadata[PARENTCHILDRELINFO] + * that indicates if a table is parent. + */ + public static final String IS_PARENT = "isParent"; private ParentChildRelMetadataConstants() { diff --git a/metacat-functional-tests/src/functionalTest/groovy/com/netflix/metacat/MetacatSmokeSpec.groovy b/metacat-functional-tests/src/functionalTest/groovy/com/netflix/metacat/MetacatSmokeSpec.groovy index 60ec49f09..0c01ae194 100644 --- a/metacat-functional-tests/src/functionalTest/groovy/com/netflix/metacat/MetacatSmokeSpec.groovy +++ b/metacat-functional-tests/src/functionalTest/groovy/com/netflix/metacat/MetacatSmokeSpec.groovy @@ -15,6 +15,8 @@ */ package com.netflix.metacat +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper import com.netflix.metacat.client.Client import com.netflix.metacat.client.api.MetacatV1 import com.netflix.metacat.client.api.MetadataV1 @@ -33,6 +35,7 @@ import com.netflix.metacat.common.exception.MetacatUnAuthorizedException import com.netflix.metacat.common.json.MetacatJson import com.netflix.metacat.common.json.MetacatJsonLocator import com.netflix.metacat.common.server.connectors.exception.InvalidMetaException +import com.netflix.metacat.common.server.usermetadata.ParentChildRelMetadataConstants import com.netflix.metacat.connector.hive.util.PartitionUtil import com.netflix.metacat.testdata.provider.PigDataDtoProvider import feign.Logger @@ -141,6 +144,19 @@ class MetacatSmokeSpec extends Specification { } } + static void initializeParentChildRelDefinitionMetadata(TableDto tableDto, + String parent, + String parent_uuid, + String child_uuid) { + def mapper = new ObjectMapper() + def innerNode = mapper.createObjectNode() + innerNode.put(ParentChildRelMetadataConstants.PARENT_NAME, parent) + innerNode.put(ParentChildRelMetadataConstants.PARENT_UUID, parent_uuid) + innerNode.put(ParentChildRelMetadataConstants.CHILD_UUID, child_uuid) + + tableDto.definitionMetadata.put(ParentChildRelMetadataConstants.PARENT_CHILD_RELINFO, innerNode) + } + def createAllTypesTable() { when: createTable('embedded-hive-metastore', 'smoke_db', 'metacat_all_types') @@ -1977,7 +1993,7 @@ class MetacatSmokeSpec extends Specification { def parent1UUID = "p1_uuid" def renameParent1 = "rename_parent1" def parent1Uri = isLocalEnv ? String.format('file:/tmp/%s/%s', databaseName, parent1) : null - def parent1FullName = catalogName + "." + databaseName + "." + parent1 + def parent1FullName = catalogName + "/" + databaseName + "/" + parent1 def child11 = "child11" def child11UUID = "c11_uuid" @@ -1997,7 +2013,7 @@ class MetacatSmokeSpec extends Specification { def parent2 = "parent2" def parent2UUID = "p2_uuid" def parent2Uri = isLocalEnv ? String.format('file:/tmp/%s/%s', databaseName, parent2) : null - def parent2FullName = catalogName + "." + databaseName + "." + parent2 + def parent2FullName = catalogName + "/" + databaseName + "/" + parent2 def child21 = "child21" def child21UUID = "c21_uuid" def child21Uri = isLocalEnv ? String.format('file:/tmp/%s/%s', databaseName, child21) : null @@ -2017,9 +2033,7 @@ class MetacatSmokeSpec extends Specification { // Create child11 Table with parent = parent1 def child11TableDto = PigDataDtoProvider.getTable(catalogName, databaseName, child11, 'amajumdar', child11Uri) - child11TableDto.definitionMetadata.put("root_table_name", parent1FullName) - child11TableDto.definitionMetadata.put("root_table_uuid", parent1UUID) - child11TableDto.definitionMetadata.put("child_table_uuid", child11UUID) + initializeParentChildRelDefinitionMetadata(child11TableDto, parent1FullName, parent1UUID, child11UUID) api.createTable(catalogName, databaseName, child11, child11TableDto) def parent1Table = api.getTable(catalogName, databaseName, parent1, true, true, false) @@ -2027,10 +2041,11 @@ class MetacatSmokeSpec extends Specification { def child11ParentChildRelationInfo = child11Table.definitionMetadata.get("parentChildRelationInfo") then: // Test Parent 1 parentChildInfo - assert !parent1Table.definitionMetadata.has("parentChildRelationInfo") + assert parent1Table.definitionMetadata.get("parentChildRelationInfo").get("isParent").booleanValue() assert parentChildRelV1.getChildren(catalogName, databaseName, parent1) == [new ChildInfoDto("embedded-fast-hive-metastore/iceberg_db/child11", "CLONE", "c11_uuid")] as Set // Test Child11 parentChildInfo + assert !child11Table.definitionMetadata.get("parentChildRelationInfo").has("isParent") JSONAssert.assertEquals(child11ParentChildRelationInfo.toString(), '{"parentInfos":[{"name":"embedded-fast-hive-metastore/iceberg_db/parent1","relationType":"CLONE", "uuid":"p1_uuid"}]}', false) @@ -2042,9 +2057,7 @@ class MetacatSmokeSpec extends Specification { when: // Create Child2 Table def child12TableDto = PigDataDtoProvider.getTable(catalogName, databaseName, child12, 'amajumdar', child12Uri) - child12TableDto.definitionMetadata.put("root_table_name", parent1FullName) - child12TableDto.definitionMetadata.put("root_table_uuid", parent1UUID) - child12TableDto.definitionMetadata.put("child_table_uuid", child12UUID) + initializeParentChildRelDefinitionMetadata(child12TableDto, parent1FullName, parent1UUID, child12UUID) api.createTable(catalogName, databaseName, child12, child12TableDto) parent1Table = api.getTable(catalogName, databaseName, parent1, true, true, false) def child12Table = api.getTable(catalogName, databaseName, child12, true, true, false) @@ -2052,13 +2065,14 @@ class MetacatSmokeSpec extends Specification { then: // Test Parent 1 parentChildInfo - assert !parent1Table.definitionMetadata.get("parentChildRelationInfo") + assert parent1Table.definitionMetadata.get("parentChildRelationInfo").get("isParent").booleanValue() assert parentChildRelV1.getChildren(catalogName, databaseName, parent1) == [ new ChildInfoDto("embedded-fast-hive-metastore/iceberg_db/child11", "CLONE", "c11_uuid"), new ChildInfoDto("embedded-fast-hive-metastore/iceberg_db/child12", "CLONE", "c12_uuid") ] as Set // Test Child12 parentChildInfo + assert !child12Table.definitionMetadata.get("parentChildRelationInfo").has("isParent") JSONAssert.assertEquals(child12ParentChildRelationInfo.toString(), '{"parentInfos":[{"name":"embedded-fast-hive-metastore/iceberg_db/parent1","relationType":"CLONE","uuid":"p1_uuid"}]}', false) @@ -2088,9 +2102,7 @@ class MetacatSmokeSpec extends Specification { // Create child21 Table with parent = parent2 def child21TableDto = PigDataDtoProvider.getTable(catalogName, databaseName, child21, 'amajumdar', child21Uri) - child21TableDto.definitionMetadata.put("root_table_name", parent2FullName) - child21TableDto.definitionMetadata.put("root_table_uuid", parent2UUID) - child21TableDto.definitionMetadata.put("child_table_uuid", child21UUID) + initializeParentChildRelDefinitionMetadata(child21TableDto, parent2FullName, parent2UUID, child21UUID) api.createTable(catalogName, databaseName, child21, child21TableDto) def parent2Table = api.getTable(catalogName, databaseName, parent2, true, true, false) def child21Table = api.getTable(catalogName, databaseName, child21, true, true, false) @@ -2098,7 +2110,7 @@ class MetacatSmokeSpec extends Specification { then: // Test Parent 2 parentChildInfo - assert !parent2Table.definitionMetadata.has("parentChildRelationInfo") + assert parent2Table.definitionMetadata.get("parentChildRelationInfo").get("isParent").booleanValue() assert parentChildRelV1.getChildren(catalogName, databaseName, parent2) == [ new ChildInfoDto("embedded-fast-hive-metastore/iceberg_db/child21", "CLONE", "c21_uuid") ] as Set @@ -2122,19 +2134,21 @@ class MetacatSmokeSpec extends Specification { then: // Test Parent 1 parentChildInfo newName - assert !parent1Table.definitionMetadata.has("parentChildRelationInfo") + assert parent1Table.definitionMetadata.get("parentChildRelationInfo").get("isParent").booleanValue() assert parentChildRelV1.getChildren(catalogName, databaseName, renameParent1) == [ new ChildInfoDto("embedded-fast-hive-metastore/iceberg_db/child11", "CLONE", "c11_uuid"), new ChildInfoDto("embedded-fast-hive-metastore/iceberg_db/child12", "CLONE", "c12_uuid") ] as Set // Test Child11 parentChildInfo + assert !child11Table.definitionMetadata.get("parentChildRelationInfo").has("isParent") JSONAssert.assertEquals(child11ParentChildRelationInfo.toString(), '{"parentInfos":[{"name":"embedded-fast-hive-metastore/iceberg_db/rename_parent1","relationType":"CLONE","uuid":"p1_uuid"}]}', false) assert parentChildRelV1.getChildren(catalogName, databaseName, child11).isEmpty() // Test Child12 parentChildInfo + assert !child12Table.definitionMetadata.get("parentChildRelationInfo").has("isParent") JSONAssert.assertEquals(child12ParentChildRelationInfo.toString(), '{"parentInfos":[{"name":"embedded-fast-hive-metastore/iceberg_db/rename_parent1","relationType":"CLONE","uuid":"p1_uuid"}]}', false) @@ -2149,12 +2163,13 @@ class MetacatSmokeSpec extends Specification { child11Table = api.getTable(catalogName, databaseName, renameChild11, true, true, false) child11ParentChildRelationInfo = child11Table.definitionMetadata.get("parentChildRelationInfo") then: - assert !parent1Table.definitionMetadata.has("parentChildRelationInfo") + assert parent1Table.definitionMetadata.get("parentChildRelationInfo").get("isParent").booleanValue() assert parentChildRelV1.getChildren(catalogName, databaseName, renameParent1) == [ new ChildInfoDto("embedded-fast-hive-metastore/iceberg_db/rename_child11", "CLONE", "c11_uuid"), new ChildInfoDto("embedded-fast-hive-metastore/iceberg_db/child12", "CLONE", "c12_uuid") ] as Set // Test Child11 parentChildInfo with newName + assert !child11Table.definitionMetadata.get("parentChildRelationInfo").has("isParent") JSONAssert.assertEquals(child11ParentChildRelationInfo.toString(), '{"parentInfos":[{"name":"embedded-fast-hive-metastore/iceberg_db/rename_parent1","relationType":"CLONE","uuid":"p1_uuid"}]}', false) @@ -2179,7 +2194,7 @@ class MetacatSmokeSpec extends Specification { then: // Test parent1 Table - assert !parent1Table.definitionMetadata.has("parentChildRelationInfo") + assert parent1Table.definitionMetadata.get("parentChildRelationInfo").get("isParent").booleanValue() assert parentChildRelV1.getChildren(catalogName, databaseName, renameParent1) == [ new ChildInfoDto("embedded-fast-hive-metastore/iceberg_db/child12", "CLONE", "c12_uuid") ] as Set @@ -2206,12 +2221,13 @@ class MetacatSmokeSpec extends Specification { // Since all the operations above are on the first connected relationship, the second connected relationship // should remain the same // Test Parent 2 parentChildInfo - assert !parent2Table.definitionMetadata.has("parentChildRelationInfo") + assert parent2Table.definitionMetadata.get("parentChildRelationInfo").get("isParent").booleanValue() assert parentChildRelV1.getChildren(catalogName, databaseName, parent2) == [ new ChildInfoDto("embedded-fast-hive-metastore/iceberg_db/child21", "CLONE", "c21_uuid") ] as Set // Test Child21 parentChildInfo + assert !child21Table.definitionMetadata.get("parentChildRelationInfo").has("isParent") JSONAssert.assertEquals(child21ParentChildRelationInfo.toString(), '{"parentInfos":[{"name":"embedded-fast-hive-metastore/iceberg_db/parent2","relationType":"CLONE","uuid":"p2_uuid"}]}', false) @@ -2230,12 +2246,13 @@ class MetacatSmokeSpec extends Specification { child21Table = api.getTable(catalogName, databaseName, child21, true, true, false) child21ParentChildRelationInfo = child21Table.definitionMetadata.get("parentChildRelationInfo") then: - assert !parent2Table.definitionMetadata.has("parentChildRelationInfo") + assert parent2Table.definitionMetadata.get("parentChildRelationInfo").get("isParent").booleanValue() assert parentChildRelV1.getChildren(catalogName, databaseName, parent2) == [ new ChildInfoDto("embedded-fast-hive-metastore/iceberg_db/child21", "CLONE", "c21_uuid") ] as Set // Test Child21 parentChildInfo + assert !child21Table.definitionMetadata.get("parentChildRelationInfo").has("isParent") JSONAssert.assertEquals(child21ParentChildRelationInfo.toString(), '{"parentInfos":[{"name":"embedded-fast-hive-metastore/iceberg_db/parent2","relationType":"CLONE","uuid":"p2_uuid"}]}', false) @@ -2255,12 +2272,13 @@ class MetacatSmokeSpec extends Specification { child21ParentChildRelationInfo = child21Table.definitionMetadata.get("parentChildRelationInfo") then: // Test Parent 2 parentChildInfo - assert !parent2Table.definitionMetadata.has("parentChildRelationInfo") + assert parent2Table.definitionMetadata.get("parentChildRelationInfo").get("isParent").booleanValue() assert parentChildRelV1.getChildren(catalogName, databaseName, parent2) == [ new ChildInfoDto("embedded-fast-hive-metastore/iceberg_db/child21", "CLONE", "c21_uuid") ] as Set // Test Child21 parentChildInfo + assert !child21Table.definitionMetadata.get("parentChildRelationInfo").has("isParent") JSONAssert.assertEquals(child21ParentChildRelationInfo.toString(), '{"parentInfos":[{"name":"embedded-fast-hive-metastore/iceberg_db/parent2","relationType":"CLONE","uuid":"p2_uuid"}]}', false) diff --git a/metacat-main/src/main/java/com/netflix/metacat/main/api/v1/ParentChildRelController.java b/metacat-main/src/main/java/com/netflix/metacat/main/api/v1/ParentChildRelController.java index 65ce6572c..6a43a70d2 100644 --- a/metacat-main/src/main/java/com/netflix/metacat/main/api/v1/ParentChildRelController.java +++ b/metacat-main/src/main/java/com/netflix/metacat/main/api/v1/ParentChildRelController.java @@ -22,7 +22,7 @@ /** * Parent Child Relation V1 API implementation. * - * @author amajumdar + * @author Yingjian */ @RestController diff --git a/metacat-main/src/main/java/com/netflix/metacat/main/services/impl/TableServiceImpl.java b/metacat-main/src/main/java/com/netflix/metacat/main/services/impl/TableServiceImpl.java index 1f1c021ef..e2136c65f 100644 --- a/metacat-main/src/main/java/com/netflix/metacat/main/services/impl/TableServiceImpl.java +++ b/metacat-main/src/main/java/com/netflix/metacat/main/services/impl/TableServiceImpl.java @@ -13,6 +13,7 @@ package com.netflix.metacat.main.services.impl; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -114,9 +115,9 @@ public TableDto create(final QualifiedName name, final TableDto tableDto) { log.info("Creating table {}", name); eventBus.post(new MetacatCreateTablePreEvent(name, metacatRequestContext, this, tableDto)); - final Optional unSaveOpOpt = saveParentChildRelationship(name, tableDto); //suceed + final Optional unSaveOpOpt = saveParentChildRelationship(name, tableDto); try { - connectorTableServiceProxy.create(name, converterUtil.fromTableDto(tableDto)); //failed + connectorTableServiceProxy.create(name, converterUtil.fromTableDto(tableDto)); } catch (Exception e) { unSaveOpOpt.ifPresent(Runnable::run); throw e; @@ -153,11 +154,12 @@ public TableDto create(final QualifiedName name, final TableDto tableDto) { return dto; } - private ObjectNode createParentChildObjectNode(@Nullable final Set parentInfos) { + private ObjectNode createParentChildObjectNode(@Nullable final Set parentInfos, + @Nullable final Set childInfos) { final ObjectMapper objectMapper = new ObjectMapper(); final ObjectNode rootNode = objectMapper.createObjectNode(); - // For now, we only populate parent information for a child table. + // For childTable, we will always populate the parent infos if (parentInfos != null && !parentInfos.isEmpty()) { final ArrayNode parentArrayNode = objectMapper.createArrayNode(); for (ParentInfo parentInfo : parentInfos) { @@ -167,7 +169,12 @@ private ObjectNode createParentChildObjectNode(@Nullable final Set p parentNode.put("uuid", parentInfo.getUuid()); parentArrayNode.add(parentNode); } - rootNode.set(ParentChildRelMetadataConstants.PARENTINFOS, parentArrayNode); + rootNode.set(ParentChildRelMetadataConstants.PARENT_INFOS, parentArrayNode); + } + + // For parent table, if it has a child, we will put a field to indicate that the table is a parent table. + if (childInfos != null && !childInfos.isEmpty()) { + rootNode.put(ParentChildRelMetadataConstants.IS_PARENT, true); } return rootNode; } @@ -176,42 +183,42 @@ private ObjectNode createParentChildObjectNode(@Nullable final Set p private Optional saveParentChildRelationship(final QualifiedName child, final TableDto tableDto) { if (tableDto.getDefinitionMetadata() != null) { final ObjectNode definitionMetadata = tableDto.getDefinitionMetadata(); - if (definitionMetadata.has(ParentChildRelMetadataConstants.PARENTNAME)) { - // fetch parent name - final String parentFullName = definitionMetadata.path(ParentChildRelMetadataConstants.PARENTNAME) + if (definitionMetadata.has(ParentChildRelMetadataConstants.PARENT_CHILD_RELINFO)) { + final JsonNode parentChildRelInfo = + definitionMetadata.get(ParentChildRelMetadataConstants.PARENT_CHILD_RELINFO); + + String parentName; + if (!parentChildRelInfo.has(ParentChildRelMetadataConstants.PARENT_NAME)) { + throw new RuntimeException("parent name is not specified"); + } + parentName = parentChildRelInfo.path(ParentChildRelMetadataConstants.PARENT_NAME) .asText(); + final QualifiedName parent = QualifiedName.fromString(parentName); + validate(parent); + + // fetch parent and child uuid String parentUUID; String childUUID; - - if (!definitionMetadata.has(ParentChildRelMetadataConstants.PARENTUUID)) { - throw new RuntimeException("root_table_uuid is not specified for parent table=" + parentFullName); + if (!parentChildRelInfo.has(ParentChildRelMetadataConstants.PARENT_UUID)) { + throw new RuntimeException("root_table_uuid is not specified for parent table=" + + parentName); } - if (!definitionMetadata.has(ParentChildRelMetadataConstants.CHILDUUID)) { + if (!parentChildRelInfo.has(ParentChildRelMetadataConstants.CHILD_UUID)) { throw new RuntimeException("child_table_uuid is not specified for child table=" + child); } - parentUUID = definitionMetadata.path(ParentChildRelMetadataConstants.PARENTUUID).asText(); - childUUID = definitionMetadata.path(ParentChildRelMetadataConstants.CHILDUUID).asText(); - - final String[] splits = parentFullName.split("\\."); - if (splits.length != 3) { - throw new RuntimeException("Parent table identifier should pass in the following format " - + "{catalog}.{db}.{parentTable}"); - } - final QualifiedName parent = QualifiedName.ofTable( - splits[0], - splits[1], - splits[2] - ); - validate(parent); + parentUUID = parentChildRelInfo.path(ParentChildRelMetadataConstants.PARENT_UUID).asText(); + childUUID = parentChildRelInfo.path(ParentChildRelMetadataConstants.CHILD_UUID).asText(); // fetch relationshipType String relationType; - if (definitionMetadata.has(ParentChildRelMetadataConstants.RELATIONTYPE)) { - relationType = definitionMetadata.path(ParentChildRelMetadataConstants.RELATIONTYPE).asText(); + if (parentChildRelInfo.has(ParentChildRelMetadataConstants.RELATION_TYPE)) { + relationType = parentChildRelInfo.path(ParentChildRelMetadataConstants.RELATION_TYPE).asText(); } else { relationType = "CLONE"; } + + // Create parent child relationship parentChildRelMetadataService.createParentChildRelation(parent, parentUUID, child, childUUID, relationType); @@ -221,10 +228,10 @@ private Optional saveParentChildRelationship(final QualifiedName child parentChildRelMetadataService.deleteParentChildRelation(parent, parentUUID, child, childUUID, relationType); } catch (Exception e) { - log.error("parentChildRelMetadataService: Fail to delete parent child relationship " - + "after failing to create the table={}" - + "with the following parameters: " - + "parent={}, parentUUID={}, child={}, childUUID={}, relationType={}", + log.error("parentChildRelMetadataService: Failed to delete parent child relationship " + + "after failing to create the table={}" + + "with the following parameters: " + + "parent={}, parentUUID={}, child={}, childUUID={}, relationType={}", child, parent, parentUUID, child, childUUID, relationType, e); } }); @@ -386,7 +393,7 @@ public TableDto deleteAndReturn(final QualifiedName name, final boolean isMView) try { parentChildRelMetadataService.drop(name); } catch (Exception e) { - log.error("parentChildRelMetadataService: Fail to drop relation for table={}", name, e); + log.error("parentChildRelMetadataService: Failed to drop relation for table={}", name, e); } if (canDeleteMetadata(name)) { @@ -481,10 +488,11 @@ public Optional get(final QualifiedName name, final GetTableServicePar GetMetadataInterceptorParameters.builder().hasMetadata(tableInternal).build()); // Always get the source of truth for parent child relation from the parentChildRelMetadataService final Set parentInfo = parentChildRelMetadataService.getParents(name); - final ObjectNode parentChildRelObjectNode = createParentChildObjectNode(parentInfo); + final Set childInfos = parentChildRelMetadataService.getChildren(name); + final ObjectNode parentChildRelObjectNode = createParentChildObjectNode(parentInfo, childInfos); if (definitionMetadata.isPresent()) { if (!parentChildRelObjectNode.isEmpty()) { - definitionMetadata.get().set(ParentChildRelMetadataConstants.PARENTCHILDRELINFO, + definitionMetadata.get().set(ParentChildRelMetadataConstants.PARENT_CHILD_RELINFO, parentChildRelObjectNode); } } else { @@ -562,7 +570,7 @@ public void rename( // if rename operation fail, rename back the parent child relation parentChildRelMetadataService.rename(newName, oldName); } catch (Exception renameException) { - log.error("parentChildRelMetadataService: Fail to rename parent child relation " + log.error("parentChildRelMetadataService: Failed to rename parent child relation " + "after table fail to rename from {} to {} " + "with the following parameters oldName={} to newName={}", oldName, newName, oldName, newName, renameException); diff --git a/metacat-main/src/test/groovy/com/netflix/metacat/main/services/impl/TableServiceImplSpec.groovy b/metacat-main/src/test/groovy/com/netflix/metacat/main/services/impl/TableServiceImplSpec.groovy index 340f9890b..be3366222 100644 --- a/metacat-main/src/test/groovy/com/netflix/metacat/main/services/impl/TableServiceImplSpec.groovy +++ b/metacat-main/src/test/groovy/com/netflix/metacat/main/services/impl/TableServiceImplSpec.groovy @@ -40,6 +40,7 @@ import com.netflix.metacat.common.server.model.ParentInfo import com.netflix.metacat.common.server.properties.Config import com.netflix.metacat.common.server.spi.MetacatCatalogConfig import com.netflix.metacat.common.server.usermetadata.DefaultAuthorizationService +import com.netflix.metacat.common.server.usermetadata.ParentChildRelMetadataConstants import com.netflix.metacat.common.server.usermetadata.TagService import com.netflix.metacat.common.server.usermetadata.UserMetadataService import com.netflix.metacat.common.server.util.MetacatContextManager @@ -277,9 +278,18 @@ class TableServiceImplSpec extends Specification { given: def childTableName = QualifiedName.ofTable("clone", "clone", "c") def parentTableName = QualifiedName.ofTable("clone", "clone", "p") + def mapper = new ObjectMapper() + + def innerNode = mapper.createObjectNode() + innerNode.put("root_table_name", "clone/clone/p") + innerNode.put("root_table_uuid", "p_uuid") + innerNode.put("child_table_uuid", "child_uuid") + + def outerNode = mapper.createObjectNode() + outerNode.set(ParentChildRelMetadataConstants.PARENT_CHILD_RELINFO, innerNode) def createTableDto = new TableDto( name: childTableName, - definitionMetadata: toObjectNode('{\"root_table_name\":\"clone.clone.p\", \"root_table_uuid\":\"p_uuid\", \"child_table_uuid\":\"child_uuid\"}'), + definitionMetadata: outerNode, serde: new StorageDto(uri: 's3:/clone/clone/c') ) when: @@ -319,7 +329,7 @@ class TableServiceImplSpec extends Specification { service.delete(name) then: 1 * parentChildRelSvc.getParents(name) >> {[new ParentInfo("parent", "clone", "parent_uuid")] as Set} - 1 * parentChildRelSvc.getChildren(name) >> {[new ChildInfo("child", "clone", "child_uuid")] as Set} + 2 * parentChildRelSvc.getChildren(name) >> {[new ChildInfo("child", "clone", "child_uuid")] as Set} 1 * config.getNoTableDeleteOnTags() >> [] thrown(RuntimeException) @@ -327,7 +337,7 @@ class TableServiceImplSpec extends Specification { service.delete(name) then: 1 * parentChildRelSvc.getParents(name) - 1 * parentChildRelSvc.getChildren(name) + 2 * parentChildRelSvc.getChildren(name) 1 * config.getNoTableDeleteOnTags() >> [] 1 * connectorTableServiceProxy.delete(_) >> {throw new RuntimeException("Fail to drop")} 0 * parentChildRelSvc.drop(_, _)