mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-10-31 18:48:35 +00:00 
			
		
		
		
	
							parent
							
								
									bf25787709
								
							
						
					
					
						commit
						c56e78f3f2
					
				| @ -408,6 +408,7 @@ public abstract class EntityRepository<T> { | ||||
|     T original = setFields(dao.findEntityById(id), patchFields); | ||||
| 
 | ||||
|     // Apply JSON patch to the original entity to get the updated entity | ||||
|     System.out.println("XXX patch is " + patch); | ||||
|     T updated = JsonUtils.applyPatch(original, patch, entityClass); | ||||
|     EntityInterface<T> updatedEntity = getEntityInterface(updated); | ||||
|     updatedEntity.setUpdateDetails(user, System.currentTimeMillis()); | ||||
| @ -861,6 +862,14 @@ public abstract class EntityRepository<T> { | ||||
|     return daoCollection.relationshipDAO().insert(fromId, toId, fromEntity, toEntity, relationship.ordinal()); | ||||
|   } | ||||
| 
 | ||||
|   public int addBidirectionalRelationship( | ||||
|       UUID fromId, UUID toId, String fromEntity, String toEntity, Relationship relationship) { | ||||
|     if (fromId.compareTo(toId) < 0) { | ||||
|       return daoCollection.relationshipDAO().insert(fromId, toId, fromEntity, toEntity, relationship.ordinal()); | ||||
|     } | ||||
|     return daoCollection.relationshipDAO().insert(toId, fromId, toEntity, fromEntity, relationship.ordinal()); | ||||
|   } | ||||
| 
 | ||||
|   public void setOwner(UUID ownedEntityId, String ownedEntityType, EntityReference owner) { | ||||
|     // Add relationship owner --- owns ---> ownedEntity | ||||
|     if (owner != null) { | ||||
| @ -891,6 +900,26 @@ public abstract class EntityRepository<T> { | ||||
|         .findTo(fromId.toString(), fromEntity, relationship.ordinal(), toEntity, deleted); | ||||
|   } | ||||
| 
 | ||||
|   public void validateUsers(List<EntityReference> entityReferences) throws IOException { | ||||
|     if (entityReferences != null) { | ||||
|       entityReferences.sort(EntityUtil.compareEntityReference); | ||||
|       for (EntityReference entityReference : entityReferences) { | ||||
|         EntityReference ref = daoCollection.userDAO().findEntityReferenceById(entityReference.getId()); | ||||
|         entityReference.withType(ref.getType()).withName(ref.getName()).withDisplayName(ref.getDisplayName()); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public void validateRoles(List<EntityReference> entityReferences) throws IOException { | ||||
|     if (entityReferences != null) { | ||||
|       entityReferences.sort(EntityUtil.compareEntityReference); | ||||
|       for (EntityReference entityReference : entityReferences) { | ||||
|         EntityReference ref = daoCollection.roleDAO().findEntityReferenceById(entityReference.getId()); | ||||
|         entityReference.withType(ref.getType()).withName(ref.getName()).withDisplayName(ref.getDisplayName()); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   enum Operation { | ||||
|     PUT, | ||||
|     PATCH, | ||||
| @ -1135,6 +1164,77 @@ public abstract class EntityRepository<T> { | ||||
|       return !addedItems.isEmpty() || !deletedItems.isEmpty(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Remove `fromEntityType:fromId` -- `relationType` ---> `toEntityType:origToRefs` Add `fromEntityType:fromId` -- | ||||
|      * `relationType` ---> `toEntityType:updatedToRefs` and record it as change for entity field `field`. | ||||
|      */ | ||||
|     public final void updateToRelationships( | ||||
|         String field, | ||||
|         String fromEntityType, | ||||
|         UUID fromId, | ||||
|         Relationship relationshipType, | ||||
|         String toEntityType, | ||||
|         List<EntityReference> origToRefs, | ||||
|         List<EntityReference> updatedToRefs) | ||||
|         throws JsonProcessingException { | ||||
|       List<EntityReference> added = new ArrayList<>(); | ||||
|       List<EntityReference> deleted = new ArrayList<>(); | ||||
|       if (!recordListChange(field, origToRefs, updatedToRefs, added, deleted, entityReferenceMatch)) { | ||||
|         // No changes between original and updated. | ||||
|         return; | ||||
|       } | ||||
|       // Remove relationships from original | ||||
|       daoCollection | ||||
|           .relationshipDAO() | ||||
|           .deleteFrom(fromId.toString(), fromEntityType, relationshipType.ordinal(), toEntityType); | ||||
|       // Add relationships from updated | ||||
|       for (EntityReference ref : updatedToRefs) { | ||||
|         System.out.println( | ||||
|             String.format( | ||||
|                 "XXX relationship %s:%s to %s:%s of type %s", | ||||
|                 fromEntityType, fromId, toEntityType, ref.getId(), relationshipType)); | ||||
|         addRelationship(fromId, ref.getId(), fromEntityType, toEntityType, relationshipType); | ||||
|       } | ||||
|       updatedToRefs.sort(EntityUtil.compareEntityReference); | ||||
|       origToRefs.sort(EntityUtil.compareEntityReference); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Remove `fromEntityType:origFromRefs` -- `relationType` ---> `toEntityType:toId` Add | ||||
|      * `fromEntityType:updatedFromRefs` -- `relationType` ---> `toEntityType:toId` and record it as change for entity | ||||
|      * field `field`. | ||||
|      */ | ||||
|     public final void updateFromRelationships( | ||||
|         String field, | ||||
|         String fromEntityType, | ||||
|         List<EntityReference> originFromRefs, | ||||
|         List<EntityReference> updatedFromRefs, | ||||
|         Relationship relationshipType, | ||||
|         String toEntityType, | ||||
|         UUID toId) | ||||
|         throws JsonProcessingException { | ||||
|       List<EntityReference> added = new ArrayList<>(); | ||||
|       List<EntityReference> deleted = new ArrayList<>(); | ||||
|       if (!recordListChange(field, originFromRefs, updatedFromRefs, added, deleted, entityReferenceMatch)) { | ||||
|         // No changes between original and updated. | ||||
|         return; | ||||
|       } | ||||
|       // Remove relationships from original | ||||
|       daoCollection | ||||
|           .relationshipDAO() | ||||
|           .deleteTo(toId.toString(), fromEntityType, relationshipType.ordinal(), toEntityType); | ||||
|       // Add relationships from updated | ||||
|       for (EntityReference ref : updatedFromRefs) { | ||||
|         System.out.println( | ||||
|             String.format( | ||||
|                 "XXX relationship %s:%s to %s:%s of type %s", | ||||
|                 fromEntityType, ref, toEntityType, toId, relationshipType)); | ||||
|         addRelationship(ref.getId(), toId, fromEntityType, toEntityType, relationshipType); | ||||
|       } | ||||
|       updatedFromRefs.sort(EntityUtil.compareEntityReference); | ||||
|       originFromRefs.sort(EntityUtil.compareEntityReference); | ||||
|     } | ||||
| 
 | ||||
|     public final void storeUpdate() throws IOException { | ||||
|       if (updateVersion(original.getVersion())) { // Update changed the entity version | ||||
|         storeOldVersion(); // Store old version for listing previous versions of the entity | ||||
|  | ||||
| @ -19,10 +19,13 @@ package org.openmetadata.catalog.jdbi3; | ||||
| import static org.openmetadata.catalog.Entity.FIELD_OWNER; | ||||
| import static org.openmetadata.catalog.Entity.helper; | ||||
| 
 | ||||
| import com.fasterxml.jackson.core.JsonProcessingException; | ||||
| import java.io.IOException; | ||||
| import java.net.URI; | ||||
| import java.text.ParseException; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
| import java.util.UUID; | ||||
| import org.jdbi.v3.sqlobject.transaction.Transaction; | ||||
| import org.openmetadata.catalog.Entity; | ||||
| @ -30,6 +33,7 @@ import org.openmetadata.catalog.entity.data.Glossary; | ||||
| import org.openmetadata.catalog.resources.glossary.GlossaryResource; | ||||
| import org.openmetadata.catalog.type.ChangeDescription; | ||||
| import org.openmetadata.catalog.type.EntityReference; | ||||
| import org.openmetadata.catalog.type.Relationship; | ||||
| import org.openmetadata.catalog.type.TagLabel; | ||||
| import org.openmetadata.catalog.util.EntityInterface; | ||||
| import org.openmetadata.catalog.util.EntityUtil; | ||||
| @ -37,8 +41,8 @@ import org.openmetadata.catalog.util.EntityUtil.Fields; | ||||
| import org.openmetadata.catalog.util.JsonUtils; | ||||
| 
 | ||||
| public class GlossaryRepository extends EntityRepository<Glossary> { | ||||
|   private static final Fields GLOSSARY_UPDATE_FIELDS = new Fields(GlossaryResource.ALLOWED_FIELDS, "owner,tags"); | ||||
|   private static final Fields GLOSSARY_PATCH_FIELDS = new Fields(GlossaryResource.ALLOWED_FIELDS, "owner,tags"); | ||||
|   private static final Fields UPDATE_FIELDS = new Fields(GlossaryResource.ALLOWED_FIELDS, "owner,tags,reviewers"); | ||||
|   private static final Fields PATCH_FIELDS = new Fields(GlossaryResource.ALLOWED_FIELDS, "owner,tags,reviewers"); | ||||
| 
 | ||||
|   public GlossaryRepository(CollectionDAO dao) { | ||||
|     super( | ||||
| @ -47,8 +51,8 @@ public class GlossaryRepository extends EntityRepository<Glossary> { | ||||
|         Glossary.class, | ||||
|         dao.glossaryDAO(), | ||||
|         dao, | ||||
|         GLOSSARY_PATCH_FIELDS, | ||||
|         GLOSSARY_UPDATE_FIELDS, | ||||
|         PATCH_FIELDS, | ||||
|         UPDATE_FIELDS, | ||||
|         true, | ||||
|         true, | ||||
|         false); | ||||
| @ -63,13 +67,14 @@ public class GlossaryRepository extends EntityRepository<Glossary> { | ||||
|   public Glossary setFields(Glossary glossary, Fields fields) throws IOException, ParseException { | ||||
|     glossary.setOwner(fields.contains(FIELD_OWNER) ? getOwner(glossary) : null); | ||||
|     glossary.setTags(fields.contains("tags") ? getTags(glossary.getName()) : null); | ||||
|     glossary.setReviewers(fields.contains("reviewers") ? getReviewers(glossary) : null); | ||||
|     return glossary; | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void prepare(Glossary glossary) throws IOException, ParseException { | ||||
|     glossary.setOwner(helper(glossary).validateOwnerOrNull()); | ||||
|     // TODO validate reviewers | ||||
|     validateUsers(glossary.getReviewers()); | ||||
|     glossary.setTags(EntityUtil.addDerivedTags(daoCollection.tagDAO(), glossary.getTags())); | ||||
|   } | ||||
| 
 | ||||
| @ -78,7 +83,7 @@ public class GlossaryRepository extends EntityRepository<Glossary> { | ||||
|     // Relationships and fields such as href are derived and not stored as part of json | ||||
|     EntityReference owner = glossary.getOwner(); | ||||
|     List<TagLabel> tags = glossary.getTags(); | ||||
|     // TODO Add relationships for reviewers | ||||
|     List<EntityReference> reviewers = glossary.getReviewers(); | ||||
| 
 | ||||
|     // Don't store owner, href and tags as JSON. Build it on the fly based on relationships | ||||
|     glossary.withOwner(null).withHref(null).withTags(null); | ||||
| @ -90,14 +95,16 @@ public class GlossaryRepository extends EntityRepository<Glossary> { | ||||
|     } | ||||
| 
 | ||||
|     // Restore the relationships | ||||
|     glossary.withOwner(owner).withTags(tags); | ||||
|     glossary.withOwner(owner).withTags(tags).withReviewers(reviewers); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void storeRelationships(Glossary glossary) { | ||||
|     // TODO Add relationships for  related terms, and reviewers | ||||
|     setOwner(glossary, glossary.getOwner()); | ||||
|     applyTags(glossary); | ||||
|     for (EntityReference reviewer : Optional.ofNullable(glossary.getReviewers()).orElse(Collections.emptyList())) { | ||||
|       addRelationship(reviewer.getId(), glossary.getId(), Entity.USER, Entity.GLOSSARY, Relationship.REVIEWS); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
| @ -110,6 +117,13 @@ public class GlossaryRepository extends EntityRepository<Glossary> { | ||||
|     return new GlossaryUpdater(original, updated, operation); | ||||
|   } | ||||
| 
 | ||||
|   private List<EntityReference> getReviewers(Glossary entity) throws IOException { | ||||
|     List<String> ids = | ||||
|         findFrom(entity.getId(), Entity.GLOSSARY, Relationship.REVIEWS, Entity.USER, entity.getDeleted()); | ||||
|     System.out.println("XXX reviewers for " + entity.getId() + " " + ids); | ||||
|     return EntityUtil.populateEntityReferences(ids, Entity.USER); | ||||
|   } | ||||
| 
 | ||||
|   public static class GlossaryEntityInterface implements EntityInterface<Glossary> { | ||||
|     private final Glossary entity; | ||||
| 
 | ||||
| @ -260,5 +274,25 @@ public class GlossaryRepository extends EntityRepository<Glossary> { | ||||
|     public GlossaryUpdater(Glossary original, Glossary updated, Operation operation) { | ||||
|       super(original, updated, operation); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void entitySpecificUpdate() throws IOException, ParseException { | ||||
|       updateReviewers(original.getEntity(), updated.getEntity()); | ||||
|     } | ||||
| 
 | ||||
|     private void updateReviewers(Glossary origGlossary, Glossary updatedGlossary) throws JsonProcessingException { | ||||
|       List<EntityReference> origUsers = | ||||
|           Optional.ofNullable(origGlossary.getReviewers()).orElse(Collections.emptyList()); | ||||
|       List<EntityReference> updatedUsers = | ||||
|           Optional.ofNullable(updatedGlossary.getReviewers()).orElse(Collections.emptyList()); | ||||
|       updateFromRelationships( | ||||
|           "reviewers", | ||||
|           Entity.USER, | ||||
|           origUsers, | ||||
|           updatedUsers, | ||||
|           Relationship.REVIEWS, | ||||
|           Entity.GLOSSARY, | ||||
|           origGlossary.getId()); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -16,9 +16,13 @@ | ||||
| 
 | ||||
| package org.openmetadata.catalog.jdbi3; | ||||
| 
 | ||||
| import static org.openmetadata.catalog.util.EntityUtil.stringMatch; | ||||
| 
 | ||||
| import com.fasterxml.jackson.core.JsonProcessingException; | ||||
| import java.io.IOException; | ||||
| import java.net.URI; | ||||
| import java.text.ParseException; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
| @ -39,8 +43,8 @@ import org.openmetadata.catalog.util.JsonUtils; | ||||
| 
 | ||||
| @Slf4j | ||||
| public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> { | ||||
|   private static final Fields UPDATE_FIELDS = new Fields(GlossaryResource.ALLOWED_FIELDS, "tags"); | ||||
|   private static final Fields PATCH_FIELDS = new Fields(GlossaryResource.ALLOWED_FIELDS, "tags"); | ||||
|   private static final Fields UPDATE_FIELDS = new Fields(GlossaryResource.ALLOWED_FIELDS, "tags,reviewers"); | ||||
|   private static final Fields PATCH_FIELDS = new Fields(GlossaryResource.ALLOWED_FIELDS, "tags,reviewers"); | ||||
| 
 | ||||
|   public GlossaryTermRepository(CollectionDAO dao) { | ||||
|     super( | ||||
| @ -166,11 +170,10 @@ public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> { | ||||
|     } | ||||
|     for (EntityReference relTerm : Optional.ofNullable(entity.getRelatedTerms()).orElse(Collections.emptyList())) { | ||||
|       // Make this bidirectional relationship | ||||
|       addRelationship( | ||||
|       addBidirectionalRelationship( | ||||
|           entity.getId(), relTerm.getId(), Entity.GLOSSARY_TERM, Entity.GLOSSARY_TERM, Relationship.RELATED_TO); | ||||
|     } | ||||
|     for (EntityReference reviewer : Optional.ofNullable(entity.getReviewers()).orElse(Collections.emptyList())) { | ||||
|       // Make this bidirectional relationship | ||||
|       addRelationship(reviewer.getId(), entity.getId(), Entity.USER, Entity.GLOSSARY_TERM, Relationship.REVIEWS); | ||||
|     } | ||||
| 
 | ||||
| @ -349,7 +352,31 @@ public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> { | ||||
| 
 | ||||
|     @Override | ||||
|     public void entitySpecificUpdate() throws IOException { | ||||
|       // TODO | ||||
|       updateSynonyms(original.getEntity(), updated.getEntity()); | ||||
|       updateReviewers(original.getEntity(), updated.getEntity()); | ||||
|     } | ||||
| 
 | ||||
|     private void updateSynonyms(GlossaryTerm origTerm, GlossaryTerm updatedTerm) throws JsonProcessingException { | ||||
|       List<String> origSynonyms = Optional.ofNullable(origTerm.getSynonyms()).orElse(Collections.emptyList()); | ||||
|       List<String> updatedSynonyms = Optional.ofNullable(updatedTerm.getSynonyms()).orElse(Collections.emptyList()); | ||||
| 
 | ||||
|       List<String> added = new ArrayList<>(); | ||||
|       List<String> deleted = new ArrayList<>(); | ||||
|       recordListChange("synonyms", origSynonyms, updatedSynonyms, added, deleted, stringMatch); | ||||
|     } | ||||
| 
 | ||||
|     private void updateReviewers(GlossaryTerm origTerm, GlossaryTerm updatedTerm) throws JsonProcessingException { | ||||
|       List<EntityReference> origUsers = Optional.ofNullable(origTerm.getReviewers()).orElse(Collections.emptyList()); | ||||
|       List<EntityReference> updatedUsers = | ||||
|           Optional.ofNullable(updatedTerm.getReviewers()).orElse(Collections.emptyList()); | ||||
|       updateFromRelationships( | ||||
|           "reviewers", | ||||
|           Entity.USER, | ||||
|           origUsers, | ||||
|           updatedUsers, | ||||
|           Relationship.REVIEWS, | ||||
|           Entity.GLOSSARY_TERM, | ||||
|           origTerm.getId()); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -13,7 +13,6 @@ | ||||
| 
 | ||||
| package org.openmetadata.catalog.jdbi3; | ||||
| 
 | ||||
| import static org.openmetadata.catalog.util.EntityUtil.entityReferenceMatch; | ||||
| import static org.openmetadata.catalog.util.EntityUtil.toBoolean; | ||||
| 
 | ||||
| import com.fasterxml.jackson.core.JsonProcessingException; | ||||
| @ -63,26 +62,6 @@ public class TeamRepository extends EntityRepository<Team> { | ||||
|     return entityReferences; | ||||
|   } | ||||
| 
 | ||||
|   public void validateEntityReferences(List<EntityReference> entityReferences, String entityType) throws IOException { | ||||
|     if (entityReferences != null) { | ||||
|       entityReferences.sort(EntityUtil.compareEntityReference); | ||||
|       for (EntityReference entityReference : entityReferences) { | ||||
|         EntityReference ref; | ||||
|         switch (entityType) { | ||||
|           case Entity.USER: | ||||
|             ref = daoCollection.userDAO().findEntityReferenceById(entityReference.getId()); | ||||
|             break; | ||||
|           case Entity.ROLE: | ||||
|             ref = daoCollection.roleDAO().findEntityReferenceById(entityReference.getId()); | ||||
|             break; | ||||
|           default: | ||||
|             throw new IllegalArgumentException("Unsupported entity reference for validation"); | ||||
|         } | ||||
|         entityReference.withType(ref.getType()).withName(ref.getName()).withDisplayName(ref.getDisplayName()); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public Team setFields(Team team, Fields fields) throws IOException { | ||||
|     if (!fields.contains("profile")) { | ||||
| @ -107,8 +86,8 @@ public class TeamRepository extends EntityRepository<Team> { | ||||
| 
 | ||||
|   @Override | ||||
|   public void prepare(Team team) throws IOException { | ||||
|     validateEntityReferences(team.getUsers(), Entity.USER); | ||||
|     validateEntityReferences(team.getDefaultRoles(), Entity.ROLE); | ||||
|     validateUsers(team.getUsers()); | ||||
|     validateRoles(team.getDefaultRoles()); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
| @ -297,8 +276,8 @@ public class TeamRepository extends EntityRepository<Team> { | ||||
|     private void updateUsers(Team origTeam, Team updatedTeam) throws JsonProcessingException { | ||||
|       List<EntityReference> origUsers = Optional.ofNullable(origTeam.getUsers()).orElse(Collections.emptyList()); | ||||
|       List<EntityReference> updatedUsers = Optional.ofNullable(updatedTeam.getUsers()).orElse(Collections.emptyList()); | ||||
|       updateEntityRelationships( | ||||
|           "users", origTeam.getId(), updatedTeam.getId(), Relationship.HAS, Entity.USER, origUsers, updatedUsers); | ||||
|       updateToRelationships( | ||||
|           "users", Entity.TEAM, origTeam.getId(), Relationship.HAS, Entity.USER, origUsers, updatedUsers); | ||||
|     } | ||||
| 
 | ||||
|     private void updateDefaultRoles(Team origTeam, Team updatedTeam) throws JsonProcessingException { | ||||
| @ -306,41 +285,14 @@ public class TeamRepository extends EntityRepository<Team> { | ||||
|           Optional.ofNullable(origTeam.getDefaultRoles()).orElse(Collections.emptyList()); | ||||
|       List<EntityReference> updatedDefaultRoles = | ||||
|           Optional.ofNullable(updatedTeam.getDefaultRoles()).orElse(Collections.emptyList()); | ||||
|       updateEntityRelationships( | ||||
|       updateToRelationships( | ||||
|           "defaultRoles", | ||||
|           Entity.TEAM, | ||||
|           origTeam.getId(), | ||||
|           updatedTeam.getId(), | ||||
|           Relationship.HAS, | ||||
|           Entity.ROLE, | ||||
|           origDefaultRoles, | ||||
|           updatedDefaultRoles); | ||||
|     } | ||||
| 
 | ||||
|     private void updateEntityRelationships( | ||||
|         String field, | ||||
|         UUID origId, | ||||
|         UUID updatedId, | ||||
|         Relationship relationshipType, | ||||
|         String toEntityType, | ||||
|         List<EntityReference> origRefs, | ||||
|         List<EntityReference> updatedRefs) | ||||
|         throws JsonProcessingException { | ||||
|       List<EntityReference> added = new ArrayList<>(); | ||||
|       List<EntityReference> deleted = new ArrayList<>(); | ||||
|       if (!recordListChange(field, origRefs, updatedRefs, added, deleted, entityReferenceMatch)) { | ||||
|         // No changes between original and updated. | ||||
|         return; | ||||
|       } | ||||
|       // Remove relationships from original | ||||
|       daoCollection | ||||
|           .relationshipDAO() | ||||
|           .deleteFrom(origId.toString(), Entity.TEAM, relationshipType.ordinal(), toEntityType); | ||||
|       // Add relationships from updated | ||||
|       for (EntityReference ref : updatedRefs) { | ||||
|         addRelationship(updatedId, ref.getId(), Entity.TEAM, toEntityType, relationshipType); | ||||
|       } | ||||
|       updatedRefs.sort(EntityUtil.compareEntityReference); | ||||
|       origRefs.sort(EntityUtil.compareEntityReference); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -172,7 +172,7 @@ public class UserRepository extends EntityRepository<User> { | ||||
|             .findTo(user.getId().toString(), Entity.USER, Relationship.FOLLOWS.ordinal(), toBoolean(toInclude(user)))); | ||||
|   } | ||||
| 
 | ||||
|   public List<EntityReference> validateRoles(List<UUID> roleIds) throws IOException { | ||||
|   public List<EntityReference> validateRolesByIds(List<UUID> roleIds) throws IOException { | ||||
|     if (roleIds == null) { | ||||
|       return Collections.emptyList(); // Return an empty roles list | ||||
|     } | ||||
|  | ||||
| @ -88,6 +88,7 @@ public class GlossaryResource { | ||||
|   public static Glossary addHref(UriInfo uriInfo, Glossary glossary) { | ||||
|     glossary.setHref(RestUtil.getHref(uriInfo, COLLECTION_PATH, glossary.getId())); | ||||
|     Entity.withHref(uriInfo, glossary.getOwner()); | ||||
|     Entity.withHref(uriInfo, glossary.getReviewers()); | ||||
|     return glossary; | ||||
|   } | ||||
| 
 | ||||
| @ -110,7 +111,7 @@ public class GlossaryResource { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   static final String FIELDS = "owner,tags"; | ||||
|   static final String FIELDS = "owner,tags,reviewers"; | ||||
|   public static final List<String> ALLOWED_FIELDS = Entity.getEntityFields(Glossary.class); | ||||
| 
 | ||||
|   @GET | ||||
|  | ||||
| @ -434,6 +434,6 @@ public class UserResource { | ||||
|         .withUpdatedBy(securityContext.getUserPrincipal().getName()) | ||||
|         .withUpdatedAt(System.currentTimeMillis()) | ||||
|         .withTeams(dao.validateTeams(create.getTeams())) | ||||
|         .withRoles(dao.validateRoles(create.getRoles())); | ||||
|         .withRoles(dao.validateRolesByIds(create.getRoles())); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -18,10 +18,10 @@ | ||||
|       "type": "string" | ||||
|     }, | ||||
|     "reviewers": { | ||||
|       "description": "User names of the reviewers for this glossary.", | ||||
|       "description": "User references of the reviewers for this glossary.", | ||||
|       "type": "array", | ||||
|       "items": { | ||||
|         "type": "string" | ||||
|         "$ref": "../../type/entityReference.json" | ||||
|       } | ||||
|     }, | ||||
|     "owner": { | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
|   "$id": "https://open-metadata.org/schema/entity/data/glossary.json", | ||||
|   "$schema": "http://json-schema.org/draft-07/schema#", | ||||
|   "title": "Glossary", | ||||
|   "description": "This schema defines the Glossary entity based on SKOS.", | ||||
|   "description": "This schema defines the Glossary entity. A Glossary is collection of hierarchical GlossaryTerms.", | ||||
|   "type": "object", | ||||
|   "definitions": { | ||||
|     "name": { | ||||
| @ -47,10 +47,10 @@ | ||||
|       "$ref": "../../type/basic.json#/definitions/href" | ||||
|     }, | ||||
|     "reviewers": { | ||||
|       "description": "User names of the reviewers for this glossary.", | ||||
|       "description": "User references of the reviewers for this glossary.", | ||||
|       "type": "array", | ||||
|       "items": { | ||||
|         "type": "string" | ||||
|         "$ref": "../../type/entityReference.json" | ||||
|       } | ||||
|     }, | ||||
|     "owner": { | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
|   "$id": "https://open-metadata.org/schema/entity/data/glossaryTerm.json", | ||||
|   "$schema": "http://json-schema.org/draft-07/schema#", | ||||
|   "title": "GlossaryTerm", | ||||
|   "description": "This schema defines the Glossary term entities.", | ||||
|   "description": "This schema defines te Glossary term entities.", | ||||
|   "type": "object", | ||||
|   "definitions": { | ||||
|     "name": { | ||||
| @ -94,10 +94,6 @@ | ||||
|       "description": "User who made the update.", | ||||
|       "type": "string" | ||||
|     }, | ||||
|     "skos": { | ||||
|       "description": "SKOS data in JSON-LD format", | ||||
|       "type": "string" | ||||
|     }, | ||||
|     "href": { | ||||
|       "description": "Link to the resource corresponding to this entity.", | ||||
|       "$ref": "../../type/basic.json#/definitions/href" | ||||
|  | ||||
| @ -1952,7 +1952,14 @@ public abstract class EntityResourceTest<T, K> extends CatalogApplicationTest { | ||||
|     for (EntityReference expected : expectedList) { | ||||
|       EntityReference actual = | ||||
|           actualList.stream().filter(a -> EntityUtil.entityReferenceMatch.test(a, expected)).findAny().orElse(null); | ||||
|       assertNotNull(actual, "Expected entity " + expected.getId() + " not found"); | ||||
|       assertNotNull(actual, "Expected entity reference " + expected.getId() + " not found"); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   protected void assertStrings(List<String> expectedList, List<String> actualList) { | ||||
|     for (String expected : expectedList) { | ||||
|       String actual = actualList.stream().filter(a -> EntityUtil.stringMatch.test(a, expected)).findAny().orElse(null); | ||||
|       assertNotNull(actual, "Expected string " + expected + " not found"); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -22,10 +22,12 @@ import static org.openmetadata.catalog.util.TestUtils.assertListNull; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.net.URISyntaxException; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import org.apache.http.client.HttpResponseException; | ||||
| import org.junit.jupiter.api.BeforeAll; | ||||
| import org.junit.jupiter.api.MethodOrderer; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.junit.jupiter.api.TestInfo; | ||||
| import org.junit.jupiter.api.TestMethodOrder; | ||||
| import org.openmetadata.catalog.Entity; | ||||
| @ -33,8 +35,12 @@ import org.openmetadata.catalog.api.data.CreateGlossary; | ||||
| import org.openmetadata.catalog.entity.data.Glossary; | ||||
| import org.openmetadata.catalog.jdbi3.GlossaryRepository.GlossaryEntityInterface; | ||||
| import org.openmetadata.catalog.resources.EntityResourceTest; | ||||
| import org.openmetadata.catalog.type.ChangeDescription; | ||||
| import org.openmetadata.catalog.type.EntityReference; | ||||
| import org.openmetadata.catalog.type.FieldChange; | ||||
| import org.openmetadata.catalog.util.JsonUtils; | ||||
| import org.openmetadata.catalog.util.TestUtils; | ||||
| import org.openmetadata.catalog.util.TestUtils.UpdateType; | ||||
| 
 | ||||
| @TestMethodOrder(MethodOrderer.OrderAnnotation.class) | ||||
| public class GlossaryResourceTest extends EntityResourceTest<Glossary, CreateGlossary> { | ||||
| @ -57,6 +63,26 @@ public class GlossaryResourceTest extends EntityResourceTest<Glossary, CreateGlo | ||||
|     super.setup(test); | ||||
|   } | ||||
| 
 | ||||
|   @Test | ||||
|   void patch_addDeleteReviewers(TestInfo test) throws IOException { | ||||
|     CreateGlossary create = createRequest(getEntityName(test), "", "", null); | ||||
|     Glossary glossary = createEntity(create, ADMIN_AUTH_HEADERS); | ||||
| 
 | ||||
|     // Add reviewer USER1 in PATCH request | ||||
|     String origJson = JsonUtils.pojoToJson(glossary); | ||||
|     glossary.withReviewers(List.of(USER_OWNER1)); | ||||
|     ChangeDescription change = getChangeDescription(glossary.getVersion()); | ||||
|     change.getFieldsAdded().add(new FieldChange().withName("reviewers").withNewValue(List.of(USER_OWNER1))); | ||||
|     glossary = patchEntityAndCheck(glossary, origJson, ADMIN_AUTH_HEADERS, UpdateType.MINOR_UPDATE, change); | ||||
| 
 | ||||
|     // Remove a reviewer in PATCH request | ||||
|     origJson = JsonUtils.pojoToJson(glossary); | ||||
|     glossary.withReviewers(null); | ||||
|     change = getChangeDescription(glossary.getVersion()); | ||||
|     change.getFieldsDeleted().add(new FieldChange().withName("reviewers").withOldValue(List.of(USER_OWNER1))); | ||||
|     patchEntityAndCheck(glossary, origJson, ADMIN_AUTH_HEADERS, UpdateType.MINOR_UPDATE, change); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public CreateGlossary createRequest(String name, String description, String displayName, EntityReference owner) { | ||||
|     return new CreateGlossary() | ||||
| @ -91,6 +117,7 @@ public class GlossaryResourceTest extends EntityResourceTest<Glossary, CreateGlo | ||||
| 
 | ||||
|     // Entity specific validation | ||||
|     TestUtils.validateTags(expected.getTags(), patched.getTags()); | ||||
|     TestUtils.assertEntityReferenceList(expected.getReviewers(), patched.getReviewers()); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
| @ -120,6 +147,13 @@ public class GlossaryResourceTest extends EntityResourceTest<Glossary, CreateGlo | ||||
|     if (expected == actual) { | ||||
|       return; | ||||
|     } | ||||
|     if (fieldName.equals("reviewers")) { | ||||
|       @SuppressWarnings("unchecked") | ||||
|       List<EntityReference> expectedRefs = (List<EntityReference>) expected; | ||||
|       List<EntityReference> actualRefs = JsonUtils.readObjects(actual.toString(), EntityReference.class); | ||||
|       assertEntityReferencesFieldChange(expectedRefs, actualRefs); | ||||
|     } else { | ||||
|       assertCommonFieldChange(fieldName, expected, actual); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -50,10 +50,14 @@ import org.openmetadata.catalog.entity.data.GlossaryTerm; | ||||
| import org.openmetadata.catalog.jdbi3.GlossaryRepository.GlossaryEntityInterface; | ||||
| import org.openmetadata.catalog.jdbi3.GlossaryTermRepository.GlossaryTermEntityInterface; | ||||
| import org.openmetadata.catalog.resources.EntityResourceTest; | ||||
| import org.openmetadata.catalog.type.ChangeDescription; | ||||
| import org.openmetadata.catalog.type.EntityReference; | ||||
| import org.openmetadata.catalog.type.FieldChange; | ||||
| import org.openmetadata.catalog.util.EntityUtil; | ||||
| import org.openmetadata.catalog.util.JsonUtils; | ||||
| import org.openmetadata.catalog.util.ResultList; | ||||
| import org.openmetadata.catalog.util.TestUtils; | ||||
| import org.openmetadata.catalog.util.TestUtils.UpdateType; | ||||
| 
 | ||||
| @TestMethodOrder(MethodOrderer.OrderAnnotation.class) | ||||
| public class GlossaryTermResourceTest extends EntityResourceTest<GlossaryTerm, CreateGlossaryTerm> { | ||||
| @ -178,6 +182,28 @@ public class GlossaryTermResourceTest extends EntityResourceTest<GlossaryTerm, C | ||||
|         glossaryTermMismatch(term1.getId().toString(), glossary2.getId().toString())); | ||||
|   } | ||||
| 
 | ||||
|   @Test | ||||
|   void patch_addDeleteReviewers(TestInfo test) throws IOException { | ||||
|     CreateGlossaryTerm create = createRequest(getEntityName(test), "", "", null).withReviewers(null).withSynonyms(null); | ||||
|     GlossaryTerm term = createEntity(create, ADMIN_AUTH_HEADERS); | ||||
| 
 | ||||
|     // Add reviewer USER1 in PATCH request | ||||
|     String origJson = JsonUtils.pojoToJson(term); | ||||
|     term.withReviewers(List.of(USER_OWNER1)).withSynonyms(List.of("synonym1")); | ||||
|     ChangeDescription change = getChangeDescription(term.getVersion()); | ||||
|     change.getFieldsAdded().add(new FieldChange().withName("reviewers").withNewValue(List.of(USER_OWNER1))); | ||||
|     change.getFieldsAdded().add(new FieldChange().withName("synonyms").withNewValue(List.of("synonym1"))); | ||||
|     term = patchEntityAndCheck(term, origJson, ADMIN_AUTH_HEADERS, UpdateType.MINOR_UPDATE, change); | ||||
| 
 | ||||
|     // Remove a reviewer in PATCH request | ||||
|     origJson = JsonUtils.pojoToJson(term); | ||||
|     term.withReviewers(null).withSynonyms(null); | ||||
|     change = getChangeDescription(term.getVersion()); | ||||
|     change.getFieldsDeleted().add(new FieldChange().withName("reviewers").withOldValue(List.of(USER_OWNER1))); | ||||
|     change.getFieldsDeleted().add(new FieldChange().withName("synonyms").withOldValue(List.of("synonym1"))); | ||||
|     patchEntityAndCheck(term, origJson, ADMIN_AUTH_HEADERS, UpdateType.MINOR_UPDATE, change); | ||||
|   } | ||||
| 
 | ||||
|   public GlossaryTerm createTerm(Glossary glossary, GlossaryTerm parent, String termName) throws HttpResponseException { | ||||
|     EntityReference glossaryRef = new GlossaryEntityInterface(glossary).getEntityReference(); | ||||
|     EntityReference parentRef = parent != null ? new GlossaryTermEntityInterface(parent).getEntityReference() : null; | ||||
| @ -281,6 +307,18 @@ public class GlossaryTermResourceTest extends EntityResourceTest<GlossaryTerm, C | ||||
|     if (expected == actual) { | ||||
|       return; | ||||
|     } | ||||
|     if (fieldName.equals("reviewers")) { | ||||
|       @SuppressWarnings("unchecked") | ||||
|       List<EntityReference> expectedRefs = (List<EntityReference>) expected; | ||||
|       List<EntityReference> actualRefs = JsonUtils.readObjects(actual.toString(), EntityReference.class); | ||||
|       assertEntityReferencesFieldChange(expectedRefs, actualRefs); | ||||
|     } else if (fieldName.equals("synonyms")) { | ||||
|       @SuppressWarnings("unchecked") | ||||
|       List<String> expectedRefs = (List<String>) expected; | ||||
|       List<String> actualRefs = JsonUtils.readObjects(actual.toString(), String.class); | ||||
|       assertStrings(expectedRefs, actualRefs); | ||||
|     } else { | ||||
|       assertCommonFieldChange(fieldName, expected, actual); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Suresh Srinivas
						Suresh Srinivas