Fix #16046 : modify glossaryTerms api endpoint to support querying immediate children with childrenCount (#16056)

* Fix #16046 : modify glossaryTerms api endpoint to support querying immediate children with childrenCount

* childrenCount added in glossary_term_index_mapping.json

* childrenCount added in glossary_term_index_mapping.json
This commit is contained in:
sonika-shah 2024-04-30 00:01:07 +05:30 committed by GitHub
parent 58992c2e24
commit 432820d929
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 105 additions and 3 deletions

View File

@ -1765,6 +1765,51 @@ public interface CollectionDAO {
default String getNameHashColumn() {
return "fqnHash";
}
@Override
default int listCount(ListFilter filter) {
String condition = filter.getCondition();
String directChildrenOf = filter.getQueryParam("directChildrenOf");
if (!nullOrEmpty(directChildrenOf)) {
condition =
String.format(
" %s AND fqnHash = CONCAT('%s', '.', MD5( IF(name LIKE '%%.%%', CONCAT('\"', name, '\"'), name))) ",
condition, FullyQualifiedName.buildHash(directChildrenOf));
}
return listCount(getTableName(), getNameHashColumn(), condition);
}
@Override
default List<String> listBefore(ListFilter filter, int limit, String before) {
String condition = filter.getCondition();
String directChildrenOf = filter.getQueryParam("directChildrenOf");
if (!nullOrEmpty(directChildrenOf)) {
condition =
String.format(
" %s AND fqnHash = CONCAT('%s', '.', MD5( IF(name LIKE '%%.%%', CONCAT('\"', name, '\"'), name))) ",
condition, FullyQualifiedName.buildHash(directChildrenOf));
}
return listBefore(getTableName(), condition, limit, before);
}
@Override
default List<String> listAfter(ListFilter filter, int limit, String after) {
String condition = filter.getCondition();
String directChildrenOf = filter.getQueryParam("directChildrenOf");
if (!nullOrEmpty(directChildrenOf)) {
condition =
String.format(
" %s AND fqnHash = CONCAT('%s', '.', MD5( IF(name LIKE '%%.%%', CONCAT('\"', name, '\"'), name))) ",
condition, FullyQualifiedName.buildHash(directChildrenOf));
}
return listAfter(getTableName(), condition, limit, after);
}
}
interface IngestionPipelineDAO extends EntityDAO<IngestionPipeline> {

View File

@ -118,12 +118,15 @@ public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> {
fields.contains("relatedTerms") ? getRelatedTerms(entity) : entity.getRelatedTerms());
entity.withUsageCount(
fields.contains("usageCount") ? getUsageCount(entity) : entity.getUsageCount());
entity.withChildrenCount(
fields.contains("childrenCount") ? getChildrenCount(entity) : entity.getChildrenCount());
}
@Override
public void clearFields(GlossaryTerm entity, Fields fields) {
entity.setRelatedTerms(fields.contains("relatedTerms") ? entity.getRelatedTerms() : null);
entity.withUsageCount(fields.contains("usageCount") ? entity.getUsageCount() : null);
entity.withChildrenCount(fields.contains("childrenCount") ? entity.getChildrenCount() : null);
}
@Override
@ -140,6 +143,13 @@ public class GlossaryTermRepository extends EntityRepository<GlossaryTerm> {
.getTagCount(TagSource.GLOSSARY.ordinal(), term.getFullyQualifiedName());
}
private Integer getChildrenCount(GlossaryTerm term) {
return daoCollection
.relationshipDAO()
.findTo(term.getId(), GLOSSARY_TERM, Relationship.CONTAINS.ordinal(), GLOSSARY_TERM)
.size();
}
private List<EntityReference> getRelatedTerms(GlossaryTerm entity) {
return findBoth(entity.getId(), GLOSSARY_TERM, Relationship.RELATED_TO, GLOSSARY_TERM);
}

View File

@ -89,7 +89,7 @@ import org.openmetadata.service.util.ResultList;
public class GlossaryTermResource extends EntityResource<GlossaryTerm, GlossaryTermRepository> {
public static final String COLLECTION_PATH = "v1/glossaryTerms/";
static final String FIELDS =
"children,relatedTerms,reviewers,owner,tags,usageCount,domain,extension";
"children,relatedTerms,reviewers,owner,tags,usageCount,domain,extension,childrenCount";
@Override
public GlossaryTerm addHref(UriInfo uriInfo, GlossaryTerm term) {
@ -210,7 +210,14 @@ public class GlossaryTermResource extends EntityResource<GlossaryTerm, GlossaryT
schema = @Schema(implementation = Include.class))
@QueryParam("include")
@DefaultValue("non-deleted")
Include include) {
Include include,
@Parameter(
description =
"List glossary terms filtered to retrieve the first level/immediate children of the glossary term "
+ "`directChildrenOf` parameter.",
schema = @Schema(type = "string"))
@QueryParam("directChildrenOf")
String parentTermFQNParam) {
RestUtil.validateCursors(before, after);
Fields fields = getFields(fieldsParam);
@ -234,7 +241,10 @@ public class GlossaryTermResource extends EntityResource<GlossaryTerm, GlossaryT
parentTermParam.toString(), glossaryIdParam));
}
}
ListFilter filter = new ListFilter(include).addQueryParam("parent", fqn);
ListFilter filter =
new ListFilter(include)
.addQueryParam("parent", fqn)
.addQueryParam("directChildrenOf", parentTermFQNParam);
ResultList<GlossaryTerm> terms;
if (before != null) { // Reverse paging

View File

@ -416,6 +416,9 @@
},
"descriptionStatus": {
"type": "keyword"
},
"childrenCount": {
"type": "integer"
}
}
}

View File

@ -411,6 +411,9 @@
},
"descriptionStatus": {
"type": "keyword"
},
"childrenCount": {
"type": "integer"
}
}
}

View File

@ -985,6 +985,33 @@ public class GlossaryTermResourceTest extends EntityResourceTest<GlossaryTerm, C
}
}
@Test
public void test_getImmediateChildrenGlossaryTermsWithParentFQN() throws IOException {
Glossary glossary1 = createGlossary("glossary1", null, null);
GlossaryTerm term1 = createTerm(glossary1, null, "term1");
GlossaryTerm term11 = createTerm(glossary1, term1, "term11");
GlossaryTerm term12 = createTerm(glossary1, term1, "term12");
GlossaryTerm term111 = createTerm(glossary1, term11, "term111");
term1.setChildren(List.of(term11.getEntityReference(), term12.getEntityReference()));
// List children glossary terms with term1 as the parent and getting immediate children only
Map<String, String> queryParams = new HashMap<>();
queryParams.put("directChildrenOf", term1.getFullyQualifiedName());
List<GlossaryTerm> children = listEntities(queryParams, ADMIN_AUTH_HEADERS).getData();
assertEquals(term1.getChildren().size(), children.size());
for (int i = 0; i < children.size(); i++) {
GlossaryTerm responseChild = children.get(i);
GlossaryTerm child = children.get(i);
assertTrue(child.getFullyQualifiedName().startsWith(responseChild.getFullyQualifiedName()));
}
GlossaryTerm response = getEntity(term1.getId(), "childrenCount", ADMIN_AUTH_HEADERS);
assertEquals(term1.getChildren().size(), response.getChildrenCount());
}
public Glossary createGlossary(
TestInfo test, List<EntityReference> reviewers, EntityReference owner) throws IOException {
return createGlossary(glossaryTest.getEntityName(test), reviewers, owner);

View File

@ -153,6 +153,10 @@
},
"votes" : {
"$ref": "../../type/votes.json"
},
"childrenCount": {
"description": "Count of immediate children glossary terms.",
"type": "integer"
}
},
"required": ["id", "name", "description", "glossary"],