Skip to content

Commit

Permalink
add ancestorTags field and resolver on the UserTag schema
Browse files Browse the repository at this point in the history
  • Loading branch information
meetulr committed Oct 28, 2024
1 parent 7148400 commit e1403ef
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 0 deletions.
3 changes: 3 additions & 0 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1907,6 +1907,9 @@ type UserTag {
"""A field to get the mongodb object id identifier for this UserTag."""
_id: ID!

"""A field to traverse the ancestor tags of this UserTag."""
ancestorTags: [UserTag]

"""
A connection field to traverse a list of UserTag this UserTag is a
parent to.
Expand Down
44 changes: 44 additions & 0 deletions src/resolvers/UserTag/ancestorTags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type {
InterfaceOrganizationTagUser} from "../../models";
import {
OrganizationTagUser,
} from "../../models";
import type { UserTagResolvers } from "../../types/generatedGraphQLTypes";

/**
* Resolver function for the `ancestorTags` field of an `OrganizationTagUser`.
*
* This function retrieves the ancestor tags of a specific organization user tag by recursively finding
* each parent tag until the root tag (where parentTagId is null) is reached. It then reverses the order,
* appends the current tag at the end, and returns the final array of tags.
*
* @param parent - The parent object representing the user tag. It contains information about the tag, including its ID and parentTagId.
* @returns A promise that resolves to the ordered array of ancestor tag documents found in the database.
*/
export const ancestorTags: UserTagResolvers["ancestorTags"] = async (
parent,
) => {
// Initialize an array to collect the ancestor tags
const ancestorTags: InterfaceOrganizationTagUser[] = [];

// Start with the current parentTagId
let currentParentId = parent.parentTagId;

// Traverse up the hierarchy to find all ancestorTags
while (currentParentId) {
const tag = await OrganizationTagUser.findById(currentParentId).lean();

if (!tag) break;

// Add the found tag to the ancestorTags array
ancestorTags.push(tag);

// Move up to the next parent
currentParentId = tag.parentTagId;
}

// Reverse the ancestorTags to have the root tag first, then append the current tag
ancestorTags.reverse();

return ancestorTags;
};
2 changes: 2 additions & 0 deletions src/resolvers/UserTag/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import type { UserTagResolvers } from "../../types/generatedGraphQLTypes";
import { childTags } from "./childTags";
import { organization } from "./organization";
import { parentTag } from "./parentTag";
import { ancestorTags } from "./ancestorTags";
import { usersAssignedTo } from "./usersAssignedTo";
import { usersToAssignTo } from "./usersToAssignTo";

export const UserTag: UserTagResolvers = {
childTags,
organization,
parentTag,
ancestorTags,
usersAssignedTo,
usersToAssignTo,
};
4 changes: 4 additions & 0 deletions src/typeDefs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,10 @@ export const types = gql`
"""
parentTag: UserTag
"""
A field to traverse the ancestor tags of this UserTag.
"""
ancestorTags: [UserTag]
"""
A connection field to traverse a list of UserTag this UserTag is a
parent to.
"""
Expand Down
3 changes: 3 additions & 0 deletions src/types/generatedGraphQLTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2995,6 +2995,8 @@ export type UserTag = {
__typename?: 'UserTag';
/** A field to get the mongodb object id identifier for this UserTag. */
_id: Scalars['ID']['output'];
/** A field to traverse the ancestor tags of this UserTag. */
ancestorTags?: Maybe<Array<Maybe<UserTag>>>;
/**
* A connection field to traverse a list of UserTag this UserTag is a
* parent to.
Expand Down Expand Up @@ -4699,6 +4701,7 @@ export type UserPhoneResolvers<ContextType = any, ParentType extends ResolversPa

export type UserTagResolvers<ContextType = any, ParentType extends ResolversParentTypes['UserTag'] = ResolversParentTypes['UserTag']> = {
_id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
ancestorTags?: Resolver<Maybe<Array<Maybe<ResolversTypes['UserTag']>>>, ParentType, ContextType>;
childTags?: Resolver<Maybe<ResolversTypes['UserTagsConnection']>, ParentType, ContextType, Partial<UserTagChildTagsArgs>>;
name?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
organization?: Resolver<Maybe<ResolversTypes['Organization']>, ParentType, ContextType>;
Expand Down
45 changes: 45 additions & 0 deletions tests/resolvers/UserTag/ancestorTags.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import "dotenv/config";
import type mongoose from "mongoose";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import type {
InterfaceOrganizationTagUser} from "../../../src/models";
import {
OrganizationTagUser,
} from "../../../src/models";
import { ancestorTags as ancestorTagsResolver } from "../../../src/resolvers/UserTag/ancestorTags";
import { connect, disconnect } from "../../helpers/db";
import type { TestUserTagType } from "../../helpers/tags";
import { createTwoLevelTagsWithOrg } from "../../helpers/tags";
import type { TestOrganizationType } from "../../helpers/userAndOrg";

let MONGOOSE_INSTANCE: typeof mongoose;
let testRootTag: TestUserTagType,
testSubTagLevel1: TestUserTagType,
testSubTagLevel2: TestUserTagType;
let testOrganization: TestOrganizationType;

beforeAll(async () => {
MONGOOSE_INSTANCE = await connect();
[, testOrganization, [testRootTag, testSubTagLevel1]] =
await createTwoLevelTagsWithOrg();

testSubTagLevel2 = await OrganizationTagUser.create({
name: "testSubTagLevel2",
parentTagId: testSubTagLevel1?._id,
organizationId: testOrganization?._id,
});
});

afterAll(async () => {
await disconnect(MONGOOSE_INSTANCE);
});

describe("resolvers -> Tag -> ancestorTags", () => {
it(`returns the correct ancestorTags array`, async () => {
const parent = testSubTagLevel2 as InterfaceOrganizationTagUser;

const payload = await ancestorTagsResolver?.(parent, {}, {});

expect(payload).toEqual([testRootTag, testSubTagLevel1]);
});
});

0 comments on commit e1403ef

Please sign in to comment.