Basic Retrieve View Source
import { z } from 'zod';
import dayjs from 'dayjs';
import { TernaryEnum } from '@cqlab/cqflow-core';
import {
  Library,
  Define,
  Documentation,
  ReturnType,
  MockData,
  FhirLibrary,
  Params,
} from '@cqlab/cqdefine';
import { MockPatientIdEnum } from '../mock-patients';

const makeMockDataItem = (id: MockPatientIdEnum) => ({ id: id, label: id });

// Declare a schema using zod to document and validate a return type
const ageSchema = z.number().int().positive().min(0);
type Age = z.infer<typeof ageSchema>;

// The @Library decorator marks the class as a Library and defines the library name
// The optional @MockData decorator binds mock data items to the library for testing
@Library('BasicRetrieveLibrary')
@MockData([
  makeMockDataItem(MockPatientIdEnum.empty_data),
  makeMockDataItem(MockPatientIdEnum.needs_breast_cancer_screening),
])
export class BasicRetrieveLibrary extends FhirLibrary {
  // The @Define decorator exposes the function as a public interface
  // The @Documentation decorator is used to surface documentation
  // Without a @ReturnType decorator, the expected return type defaults to a TernaryEnum
  @Define('Is female')
  @Documentation('Determines if gender is female')
  async isFemale(): Promise<TernaryEnum> {
    const patient = await this.retriever.getPatient();
    if (!patient.gender) {
      return TernaryEnum.UNKNOWN;
    }

    return patient.gender === 'female' ? TernaryEnum.TRUE : TernaryEnum.FALSE;
  }

  // The @ReturnType allows for arbitrary values to be returned
  // It takes a Zod schema which is used for validation
  // and to return a json schema to calling API services
  @Define("Get patient's age in years")
  @ReturnType(ageSchema)
  async getPatientAgeInYears(): Promise<Age | null> {
    const patient = await this.retriever.getPatient();

    if (!patient.birthDate) {
      return null;
    }

    const birthDate = dayjs(patient.birthDate);
    return dayjs().diff(birthDate, 'years');
  }

  // We use the results of getPatientAgeInYears() to return a TernaryEnum
  // This allows us to expose information at different levels based on the needs
  // of the consuming application
  @Define('Is over 18 years old')
  @Documentation('Determines if patient is over 18')
  async isOver18(): Promise<TernaryEnum> {
    const ageInYears = await this.getPatientAgeInYears();

    if (ageInYears === null) {
      return TernaryEnum.UNKNOWN;
    }

    return ageInYears >= 18 ? TernaryEnum.TRUE : TernaryEnum.FALSE;
  }
}
CHOOSE PATIENT:
Is female [isFemale][evaluate]
Determines if gender is female
Get patient's age in years [getPatientAgeInYears][retrieve]
Is over 18 years old [isOver18][evaluate]
Determines if patient is over 18