Skip to main content
Glama
patientUtils.ts7.24 kB
import { medplum, ensureAuthenticated } from '../config/medplumClient'; import { Patient, HumanName, Identifier, ContactPoint, Address, Coding } from '@medplum/fhirtypes'; /** * Interface for the data needed to create a new patient. * This helps ensure that at least the minimum required fields are considered. * Based on common requirements for a Patient resource. */ export interface CreatePatientArgs { firstName: string; lastName: string; birthDate: string; // YYYY-MM-DD gender?: 'male' | 'female' | 'other' | 'unknown'; // Made optional for test compatibility mrn?: string; // Medical Record Number telecom?: string; // Phone number email?: string; address?: { line1: string; city: string; state: string; postalCode: string; country?: string; }; } /** * Interface for the arguments accepted by the searchPatients function. * All parameters are optional, but at least one should be provided for a meaningful search. */ export interface PatientSearchArgs { firstName?: string; lastName?: string; birthDate?: string; mrn?: string; email?: string; telecom?: string; familyName?: string; // Added for more specific name search givenName?: string; // Added for more specific name search identifier?: string; // General identifier search (e.g. system|value or just value) _lastUpdated?: string; // Add fields that tests expect family?: string; given?: string; birthdate?: string; // Alternative spelling used in tests } /** * Creates a new Patient resource in Medplum. * Ensures Medplum client is authenticated before performing the creation. * @param args - The arguments for creating the patient. * @returns A promise that resolves to the created Patient resource, or null if an error occurs. */ export async function createPatient(args: CreatePatientArgs): Promise<Patient> { await ensureAuthenticated(); if (!args.firstName || !args.lastName || !args.birthDate) { throw new Error('First name, last name, and birth date are required to create a patient.'); } const patientResource: Patient = { resourceType: 'Patient', name: [{ given: [args.firstName], family: args.lastName } as HumanName], birthDate: args.birthDate, }; // Only set gender if provided if (args.gender) { patientResource.gender = args.gender; } if (args.mrn) { patientResource.identifier = [ { type: { coding: [ { system: 'http://terminology.hl7.org/CodeSystem/v2-0203', code: 'MR', display: 'Medical Record Number', } as Coding, ], text: 'Medical Record Number', }, value: args.mrn, } as Identifier, ]; } const telecoms: ContactPoint[] = []; if (args.telecom) { telecoms.push({ system: 'phone', value: args.telecom, use: 'home' } as ContactPoint); } if (args.email) { telecoms.push({ system: 'email', value: args.email, use: 'home' } as ContactPoint); } if (telecoms.length > 0) { patientResource.telecom = telecoms; } if (args.address) { patientResource.address = [ { line: [args.address.line1], city: args.address.city, state: args.address.state, postalCode: args.address.postalCode, country: args.address.country || 'US', // Default to US if not specified } as Address, ]; } return medplum.createResource<Patient>(patientResource); } /** * Retrieves a Patient resource by its ID. * @param args - Arguments containing the patientId. * @returns A promise that resolves to the Patient resource, or null if not found or an error occurs. */ export async function getPatientById(args: { patientId: string } | string): Promise<Patient | null> { await ensureAuthenticated(); // Handle both string and object parameter formats const patientId = typeof args === 'string' ? args : args.patientId; if (!patientId) { throw new Error('Patient ID is required to fetch a patient.'); } try { // No generic type needed, Medplum infers it from 'Patient' string return await medplum.readResource('Patient', patientId); } catch (error: any) { if (error.outcome?.issue?.[0]?.code === 'not-found') { return null; } throw error; } } /** * Updates an existing Patient resource. * @param patientId - The ID of the patient to update. * @param updates - An object containing the fields to update. * @returns A promise that resolves to the updated Patient resource, or null if an error occurs. */ export async function updatePatient(patientId: string, updates: Omit<Partial<Patient>, 'resourceType' | 'id'>): Promise<Patient> { await ensureAuthenticated(); if (!patientId) { throw new Error('Patient ID is required to update a patient.'); } if (!updates || Object.keys(updates).length === 0) { throw new Error('Updates object cannot be empty for updating a patient.'); } const existingPatient = await medplum.readResource('Patient', patientId); if (!existingPatient) { throw new Error(`Patient with ID ${patientId} not found.`); } const { resourceType, id, ...safeUpdates } = updates as any; const patientToUpdate: Patient = { ...(existingPatient as Patient), ...(safeUpdates as Partial<Patient>), resourceType: 'Patient', id: patientId, }; return medplum.updateResource(patientToUpdate); } /** * Searches for Patient resources based on specified criteria. * @param args - The search criteria. * @returns A promise that resolves to an array of Patient resources, or an empty array if none found or an error occurs. */ export async function searchPatients(args: PatientSearchArgs): Promise<Patient[]> { await ensureAuthenticated(); const searchCriteria: string[] = []; if (args.firstName) searchCriteria.push(`given:contains=${args.firstName}`); if (args.lastName) searchCriteria.push(`family:contains=${args.lastName}`); if (args.givenName) searchCriteria.push(`given:contains=${args.givenName}`); if (args.familyName) searchCriteria.push(`family:contains=${args.familyName}`); if (args.birthDate) searchCriteria.push(`birthdate=${args.birthDate}`); if (args.mrn) searchCriteria.push(`identifier=${args.mrn}`); // Assumes MRN is a primary identifier if (args.email) searchCriteria.push(`email=${args.email}`); if (args.telecom) searchCriteria.push(`telecom=${args.telecom}`); if (args.identifier) searchCriteria.push(`identifier=${args.identifier}`); if (args._lastUpdated) searchCriteria.push(`_lastUpdated=${args._lastUpdated}`); // Handle additional test fields if (args.family) searchCriteria.push(`family:contains=${args.family}`); if (args.given) searchCriteria.push(`given:contains=${args.given}`); if (args.birthdate) searchCriteria.push(`birthdate=${args.birthdate}`); if (searchCriteria.length === 0) { // Consider if this should throw an error, return all, or return empty. // Returning empty for now if no specific criteria are provided. return []; } const queryString = searchCriteria.join('&'); return medplum.searchResources('Patient', queryString); } // Example Usage has been migrated to tests/integration/patient.integration.test.ts

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rkirkendall/medplum-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server