Skip to content

Commit

Permalink
add user tags filter and sort
Browse files Browse the repository at this point in the history
  • Loading branch information
meetulr committed Oct 31, 2024
1 parent e1403ef commit d4858a3
Show file tree
Hide file tree
Showing 16 changed files with 633 additions and 65 deletions.
38 changes: 34 additions & 4 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1221,7 +1221,7 @@ type Organization {
posts(after: String, before: String, first: PositiveInt, last: PositiveInt): PostsConnection
updatedAt: DateTime!
userRegistrationRequired: Boolean!
userTags(after: String, before: String, first: PositiveInt, last: PositiveInt): UserTagsConnection
userTags(after: String, before: String, first: PositiveInt, last: PositiveInt, sortedBy: UserTagSortedByInput, where: UserTagWhereInput): UserTagsConnection
venues: [Venue]
visibleInSearch: Boolean!
}
Expand Down Expand Up @@ -1866,6 +1866,10 @@ input UserInput {
selectedOrganization: ID!
}

input UserNameWhereInput {
starts_with: String!
}

type UserNotAuthorizedAdminError implements Error {
message: String!
}
Expand Down Expand Up @@ -1914,7 +1918,7 @@ type UserTag {
A connection field to traverse a list of UserTag this UserTag is a
parent to.
"""
childTags(after: String, before: String, first: PositiveInt, last: PositiveInt): UserTagsConnection
childTags(after: String, before: String, first: PositiveInt, last: PositiveInt, sortedBy: UserTagSortedByInput, where: UserTagWhereInput): UserTagsConnection

"""A field to get the name of this UserTag."""
name: String!
Expand All @@ -1929,13 +1933,39 @@ type UserTag {
A connection field to traverse a list of User this UserTag is assigned
to.
"""
usersAssignedTo(after: String, before: String, first: PositiveInt, last: PositiveInt): UsersConnection
usersAssignedTo(after: String, before: String, first: PositiveInt, last: PositiveInt, sortedBy: UserTagUsersAssignedToSortedByInput, where: UserTagUsersAssignedToWhereInput): UsersConnection

"""
A connection field to traverse a list of Users this UserTag is not assigned
to, to see and select among them and assign this tag.
"""
usersToAssignTo(after: String, before: String, first: PositiveInt, last: PositiveInt): UsersConnection
usersToAssignTo(after: String, before: String, first: PositiveInt, last: PositiveInt, where: UserTagUsersToAssignToWhereInput): UsersConnection
}

input UserTagNameWhereInput {
starts_with: String!
}

input UserTagSortedByInput {
id: SortedByOrder!
}

input UserTagUsersAssignedToSortedByInput {
id: SortedByOrder!
}

input UserTagUsersAssignedToWhereInput {
firstName: UserNameWhereInput
lastName: UserNameWhereInput
}

input UserTagUsersToAssignToWhereInput {
firstName: UserNameWhereInput
lastName: UserNameWhereInput
}

input UserTagWhereInput {
name: UserTagNameWhereInput!
}

"""A default connection on the UserTag type."""
Expand Down
48 changes: 40 additions & 8 deletions src/resolvers/Organization/userTags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import type { OrganizationResolvers } from "../../types/generatedGraphQLTypes";
import type { InterfaceOrganizationTagUser } from "../../models";
import { OrganizationTagUser } from "../../models";
import {
getCommonGraphQLConnectionFilter,
getCommonGraphQLConnectionSort,
parseGraphQLConnectionArguments,
getUserTagGraphQLConnectionFilter,
getUserTagGraphQLConnectionSort,
parseGraphQLConnectionArgumentsWithSortedByAndWhere,
transformToDefaultGraphQLConnection,
type DefaultGraphQLArgumentError,
type ParseGraphQLConnectionCursorArguments,
Expand All @@ -13,6 +13,10 @@ import {
import { GraphQLError } from "graphql";
import { MAXIMUM_FETCH_LIMIT } from "../../constants";
import type { Types } from "mongoose";
import {
parseUserTagSortedBy,
parseUserTagWhere,
} from "../../utilities/userTagsUtils";

/**
* Resolver function for the `userTags` field of an `Organization`.
Expand All @@ -37,9 +41,20 @@ export const userTags: OrganizationResolvers["userTags"] = async (
parent,
args,
) => {
const parsedWhere = parseUserTagWhere(args.where);
const parsedSortedBy = parseUserTagSortedBy(args.sortedBy);

const parseGraphQLConnectionArgumentsResult =
await parseGraphQLConnectionArguments({
await parseGraphQLConnectionArgumentsWithSortedByAndWhere({
args,
parseSortedByResult: {
isSuccessful: true,
parsedSortedBy,
},
parseWhereResult: {
isSuccessful: true,
parsedWhere,
},
parseCursor: (args) =>
parseCursor({
...args,
Expand All @@ -59,26 +74,43 @@ export const userTags: OrganizationResolvers["userTags"] = async (

const { parsedArgs } = parseGraphQLConnectionArgumentsResult;

const filter = getCommonGraphQLConnectionFilter({
const objectListFilter = getUserTagGraphQLConnectionFilter({
cursor: parsedArgs.cursor,
direction: parsedArgs.direction,
sortById: parsedArgs.sort.sortById,
nameStartsWith: parsedArgs.filter.nameStartsWith,
});

const sort = getCommonGraphQLConnectionSort({
// don't use _id as a filter in while counting the documents
// _id is only used for pagination
const totalCountFilter = Object.fromEntries(
Object.entries(objectListFilter).filter(([key]) => key !== "_id"),
);

const sort = getUserTagGraphQLConnectionSort({
direction: parsedArgs.direction,
sortById: parsedArgs.sort.sortById,
});

// if there's no search input, we'll list all the root tag
// otherwise we'll also list the subtags matching the filter
const parentTagIdFilter = parsedWhere.nameStartsWith
? {}
: { parentTagId: null };

const [objectList, totalCount] = await Promise.all([
OrganizationTagUser.find({
...filter,
...objectListFilter,
...parentTagIdFilter,
organizationId: parent._id,
parentTagId: null,
})
.sort(sort)
.limit(parsedArgs.limit)
.lean()
.exec(),
OrganizationTagUser.find({
...totalCountFilter,
...parentTagIdFilter,
organizationId: parent._id,
})
.countDocuments()
Expand Down
43 changes: 34 additions & 9 deletions src/resolvers/UserTag/childTags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import type { UserTagResolvers } from "../../types/generatedGraphQLTypes";
import type { InterfaceOrganizationTagUser } from "../../models";
import { OrganizationTagUser } from "../../models";
import {
getCommonGraphQLConnectionFilter,
getCommonGraphQLConnectionSort,
parseGraphQLConnectionArguments,
getUserTagGraphQLConnectionFilter,
getUserTagGraphQLConnectionSort,
parseGraphQLConnectionArgumentsWithSortedByAndWhere,
transformToDefaultGraphQLConnection,
type DefaultGraphQLArgumentError,
type ParseGraphQLConnectionCursorArguments,
Expand All @@ -13,6 +13,10 @@ import {
import { GraphQLError } from "graphql";
import { MAXIMUM_FETCH_LIMIT } from "../../constants";
import type { Types } from "mongoose";
import {
parseUserTagSortedBy,
parseUserTagWhere,
} from "../../utilities/userTagsUtils";

/**
* Resolver function for the `childTags` field of a `UserTag`.
Expand All @@ -26,8 +30,8 @@ import type { Types } from "mongoose";
* @see OrganizationTagUser - The OrganizationTagUser model used to interact with the organization tag users collection in the database.
* @see parseGraphQLConnectionArguments - The function used to parse the GraphQL connection arguments (filter, sort, pagination).
* @see transformToDefaultGraphQLConnection - The function used to transform the list of child tags into a connection object.
* @see getCommonGraphQLConnectionFilter - The function used to get the common filter object for the GraphQL connection.
* @see getCommonGraphQLConnectionSort - The function used to get the common sort object for the GraphQL connection.
* @see getGraphQLConnectionFilter - The function used to get the common filter object for the GraphQL connection.
* @see getGraphQLConnectionSort - The function used to get the common sort object for the GraphQL connection.
* @see MAXIMUM_FETCH_LIMIT - The maximum number of child tags that can be fetched in a single request.
* @see GraphQLError - The error class used to throw GraphQL errors.
* @see UserTagResolvers - The type definition for the resolvers of the UserTag fields.
Expand All @@ -37,9 +41,20 @@ export const childTags: UserTagResolvers["childTags"] = async (
parent,
args,
) => {
const parsedWhere = parseUserTagWhere(args.where);
const parsedSortedBy = parseUserTagSortedBy(args.sortedBy);

const parseGraphQLConnectionArgumentsResult =
await parseGraphQLConnectionArguments({
await parseGraphQLConnectionArgumentsWithSortedByAndWhere({
args,
parseSortedByResult: {
isSuccessful: true,
parsedSortedBy,
},
parseWhereResult: {
isSuccessful: true,
parsedWhere,
},
parseCursor: (args) =>
parseCursor({
...args,
Expand All @@ -59,25 +74,35 @@ export const childTags: UserTagResolvers["childTags"] = async (

const { parsedArgs } = parseGraphQLConnectionArgumentsResult;

const filter = getCommonGraphQLConnectionFilter({
const objectListFilter = getUserTagGraphQLConnectionFilter({
cursor: parsedArgs.cursor,
direction: parsedArgs.direction,
sortById: parsedArgs.sort.sortById,
nameStartsWith: parsedArgs.filter.nameStartsWith,
});

const sort = getCommonGraphQLConnectionSort({
// don't use _id as a filter in while counting the documents
// _id is only used for pagination
const totalCountFilter = Object.fromEntries(
Object.entries(objectListFilter).filter(([key]) => key !== "_id"),
);

const sort = getUserTagGraphQLConnectionSort({
direction: parsedArgs.direction,
sortById: parsedArgs.sort.sortById,
});

const [objectList, totalCount] = await Promise.all([
OrganizationTagUser.find({
...filter,
...objectListFilter,
parentTagId: parent._id,
})
.sort(sort)
.limit(parsedArgs.limit)
.lean()
.exec(),
OrganizationTagUser.find({
...totalCountFilter,
parentTagId: parent._id,
})
.countDocuments()
Expand Down
Loading

0 comments on commit d4858a3

Please sign in to comment.