diff --git a/src/api/graphql/resolvers/volunteers.resolvers.ts b/src/api/graphql/resolvers/volunteers.resolvers.ts index 25fffa6..ef33694 100644 --- a/src/api/graphql/resolvers/volunteers.resolvers.ts +++ b/src/api/graphql/resolvers/volunteers.resolvers.ts @@ -1,38 +1,96 @@ +// src/api/graphql/resolvers/volunteers.resolvers.ts + +import { z } from 'zod'; import { createVolunteer, createVolunteerSchema, deleteVolunteer, - getAllVolunteers, getVolunteerById, updateVolunteer, updateVolunteerSchema, } from '../../../core'; -import { GraphQLError } from 'graphql'; -import { z } from 'zod'; +import { + PrismaClient, + Prisma, + volunteer_status as VStatus, +} from '@prisma/client'; + +const prisma = new PrismaClient(); -// Infer TypeScript types directly from your Zod schemas type CreateVolunteerInput = z.infer; type UpdateVolunteerInput = z.infer; +export interface VolunteerFilterInput { + chapters?: string[]; + roles?: string[]; + statuses?: (import('@prisma/client').volunteer_status | string)[]; +} + export const volunteerResolvers = { Query: { - volunteers: () => getAllVolunteers(), + // GraphQL: + // volunteers(filter, limit, offset): [Volunteer!]! + volunteers: async ( + _parent: unknown, + args: { + filter?: VolunteerFilterInput; + limit?: number; + offset?: number; + } + ) => { + const { filter, limit = 50, offset = 0 } = args; + + const where: Prisma.volunteersWhereInput = {}; + + // status filter + if (filter?.statuses?.length) { + const statuses = filter.statuses + .map((s) => (typeof s === 'string' ? s.toUpperCase() : s)) + .filter((s): s is VStatus => s === 'STUDENT' || s === 'PROFESSIONAL'); + + if (statuses.length) { + where.volunteer_status = { in: statuses }; + } + } + + // chapter filter via related chapters model + if (filter?.chapters?.length) { + where.chapters = { + is: { + name: { in: filter.chapters }, + }, + }; + } + + // role filter via volunteer_assignment → roles + if (filter?.roles?.length) { + where.volunteer_assignment = { + some: { + roles: { + name: { in: filter.roles }, + }, + }, + }; + } + + // Tests expect an array of volunteers here + return prisma.volunteers.findMany({ + where, + skip: offset, + take: limit, + orderBy: [{ last_name: 'asc' }, { first_name: 'asc' }], + }); + }, + + // GraphQL: volunteer(id: ID!): Volunteer volunteer: async (_parent: unknown, { id }: { id: string }) => { + // Let the service throw NotFoundError / DatabaseError as it already does. + // GraphQL will surface the error message in `errors[0].message`. const volunteer = await getVolunteerById(id); - if (!volunteer) { - throw new GraphQLError( - 'Volunteer not found', - undefined, // nodes - undefined, // source - undefined, // positions - undefined, // path - undefined, // originalError - { code: 'NOT_FOUND' } // extensions - ); - } return volunteer; }, }, + Mutation: { createVolunteer: ( _parent: unknown, diff --git a/src/api/graphql/schemas/volunteers.schema.ts b/src/api/graphql/schemas/volunteers.schema.ts index d9c6831..0ba1532 100644 --- a/src/api/graphql/schemas/volunteers.schema.ts +++ b/src/api/graphql/schemas/volunteers.schema.ts @@ -1,5 +1,4 @@ export const volunteerSchemaString = ` - # Using the enum from your Prisma schema enum StatusType { STUDENT PROFESSIONAL @@ -11,6 +10,12 @@ export const volunteerSchemaString = ` BOTH } + input VolunteerFilterInput { + chapters: [String!] + roles: [String!] + statuses: [String!] + } + type Volunteer { volunteer_id: ID! first_name: String! @@ -27,8 +32,18 @@ export const volunteerSchemaString = ` updated_at: String! } + type VolunteerConnection { + nodes: [Volunteer!]! + totalCount: Int! + } + type Query { - volunteers: [Volunteer!]! + volunteers( + filter: VolunteerFilterInput + limit: Int = 50 + offset: Int = 0 + ): [Volunteer!]! + volunteer(id: ID!): Volunteer } diff --git a/tests/setup.ts b/tests/setup.ts index b43f316..8035eff 100644 --- a/tests/setup.ts +++ b/tests/setup.ts @@ -28,12 +28,15 @@ beforeEach(async () => { // Skip cleanup for unit tests since they mock the database if (!isUnitTest) { - // Delete all records in dependency order (children first, then parents) - await prisma.chapters.deleteMany({}); + await prisma.volunteer_assignment.deleteMany({}); + await prisma.volunteer_role_project.deleteMany({}); + await prisma.volunteer_history.deleteMany({}); + + await prisma.nonprofit_chapter_project.deleteMany({}); + await prisma.sponsor_chapter.deleteMany({}); + await prisma.projects.deleteMany({}); - // Add other models as needed: - // await prisma.users.deleteMany({}); - // await prisma.events.deleteMany({}); + await prisma.chapters.deleteMany({}); } } catch (error) { console.error('Failed to clean database between tests:', error);