def test_patients_registered_with_one_practice_between():
    session = make_session()

    patient_registered_in_2001 = Patient()
    patient_registered_in_2002 = Patient()
    patient_unregistered_in_2002 = Patient()
    patient_registered_in_2001.RegistrationHistory = [
        RegistrationHistory(StartDate="2001-01-01", EndDate="9999-01-01")
    ]
    patient_registered_in_2002.RegistrationHistory = [
        RegistrationHistory(StartDate="2002-01-01", EndDate="9999-01-01")
    ]
    patient_unregistered_in_2002.RegistrationHistory = [
        RegistrationHistory(StartDate="2001-01-01", EndDate="2002-01-01")
    ]

    session.add(patient_registered_in_2001)
    session.add(patient_registered_in_2002)
    session.add(patient_unregistered_in_2002)
    session.commit()

    study = StudyDefinition(
        population=patients.registered_with_one_practice_between(
            "2001-12-01", "2003-01-01"
        )
    )
    results = study.to_dicts()
    assert [x["patient_id"] for x in results] == [
        str(patient_registered_in_2001.Patient_ID)
    ]
def test_patient_registered_as_of():
    session = make_session()

    patient_registered_in_2001 = Patient()
    patient_registered_in_2002 = Patient()
    patient_unregistered_in_2002 = Patient()
    patient_registered_in_2001.RegistrationHistory = [
        RegistrationHistory(StartDate="2001-01-01", EndDate="9999-01-01")
    ]
    patient_registered_in_2002.RegistrationHistory = [
        RegistrationHistory(StartDate="2002-01-01", EndDate="9999-01-01")
    ]
    patient_unregistered_in_2002.RegistrationHistory = [
        RegistrationHistory(StartDate="2001-01-01", EndDate="2002-01-01")
    ]

    session.add(patient_registered_in_2001)
    session.add(patient_registered_in_2002)
    session.add(patient_unregistered_in_2002)
    session.commit()

    # No date criteria
    study = StudyDefinition(population=patients.registered_as_of("2002-03-02"))
    results = study.to_dicts()
    assert [x["patient_id"] for x in results] == [
        str(patient_registered_in_2001.Patient_ID),
        str(patient_registered_in_2002.Patient_ID),
    ]
def test_patients_with_ages_and_practices_sql():
    session = make_session()
    session.add_all([
        # This patient is too old and should be ignored
        Patient(DateOfBirth="2002-05-04"),
        # This patient is too young and should be ignored
        Patient(DateOfBirth="2019-10-04"),
        Patient(
            DateOfBirth="2018-10-28",
            RegistrationHistory=[
                RegistrationHistory(
                    StartDate="2015-01-01",
                    EndDate="2021-10-01",
                    Organisation=Organisation(Organisation_ID=456),
                ),
            ],
        ),
        Patient(
            DateOfBirth="2014-09-14",
            RegistrationHistory=[
                RegistrationHistory(
                    StartDate="2010-01-01",
                    EndDate="2015-10-01",
                    Organisation=Organisation(Organisation_ID=123),
                ),
                # Deliberately overlapping registration histories
                RegistrationHistory(
                    StartDate="2015-04-01",
                    EndDate="9999-12-31",
                    Organisation=Organisation(Organisation_ID=345),
                ),
            ],
        ),
    ])
    session.commit()
    sql = patients_with_ages_and_practices_sql(
        date_of_birth_range=("2012-01-01", "2019-06-01"),
        age_thresholds=[12, 24, 60],
    )
    results = sql_to_dicts(sql)
    # Note this is rounded to start of month
    assert [x["date_of_birth"]
            for x in results] == ["2018-10-01", "2014-09-01"]
    assert [x["practice_id_at_month_12"] for x in results] == ["456", "345"]
    assert [x["practice_id_at_month_24"] for x in results] == ["456", "345"]
    assert [x["practice_id_at_month_60"] for x in results] == ["0", "345"]
def set_up_patients(event_data):
    organisations = [Organisation(Organisation_ID=ix) for ix in range(5)]

    # This patient is in the target population, because they're still registered at the
    # practice.
    current_patient = Patient()
    current_patient.RegistrationHistory = [
        RegistrationHistory(
            StartDate="2000-01-01",
            EndDate="2001-01-01",
            Organisation=organisations[0],
        ),
        RegistrationHistory(
            StartDate="2001-01-01",
            EndDate="9999-01-01",
            Organisation=organisations[1],
        ),
    ]
    current_patient.CodedEventsSnomed = [
        CodedEventSnomed(ConsultationDate=date, ConceptID=code)
        for date, code in event_data
    ]

    # This patient is in the target population, because they're still registered at the
    # practice, but they have no events.
    current_patient_no_events = Patient()
    current_patient_no_events.RegistrationHistory = [
        RegistrationHistory(
            StartDate="2001-01-01",
            EndDate="9999-01-01",
            Organisation=organisations[1],
        ),
    ]

    # This patient is in the target population, because they died during the timeframe
    # we're interested in.
    dead_patient = Patient(DateOfDeath="2022-01-15")
    dead_patient.RegistrationHistory = [
        RegistrationHistory(
            StartDate="2001-01-01",
            EndDate="2022-01-15",
            Organisation=organisations[2],
        )
    ]
    dead_patient.CodedEventsSnomed = [
        CodedEventSnomed(ConsultationDate=date, ConceptID=code)
        for date, code in event_data
    ]

    # This patient is not in the target population, because they were not registered by
    # the end of the timeframe we're interested in.
    former_patient = Patient()
    former_patient.RegistrationHistory = [
        RegistrationHistory(
            StartDate="2001-01-01",
            EndDate="2022-01-15",
            Organisation=organisations[3],
        )
    ]
    former_patient.CodedEventsSnomed = [
        CodedEventSnomed(ConsultationDate=date, ConceptID=code)
        for date, code in event_data
    ]

    # This patient is not in the target population, because they died before the
    # timeframe we're interested in.
    long_dead_patient = Patient(DateOfDeath="2011-12-31")
    long_dead_patient.RegistrationHistory = [
        RegistrationHistory(
            StartDate="2001-01-01",
            EndDate="2011-12-31",
            Organisation=organisations[4],
        )
    ]
    long_dead_patient.CodedEventsSnomed = [
        CodedEventSnomed(ConsultationDate=date, ConceptID=code)
        for date, code in event_data
    ]

    session = make_session()
    session.add(current_patient)
    session.add(current_patient_no_events)
    session.add(dead_patient)
    session.add(former_patient)
    session.add(long_dead_patient)
    session.commit()
def test_study_definition(tmp_path):
    session = make_session()
    session.add_all([
        # This patient is too old and should be ignored
        Patient(Patient_ID=1, DateOfBirth="2002-05-04"),
        Patient(
            Patient_ID=2,
            DateOfBirth="2019-01-01",
            RegistrationHistory=[
                RegistrationHistory(
                    StartDate="2019-01-10",
                    EndDate="9999-12-31",
                    Organisation=Organisation(Organisation_ID=678),
                ),
            ],
        ),
        Patient(
            Patient_ID=3,
            DateOfBirth="2018-10-28",
            RegistrationHistory=[
                RegistrationHistory(
                    StartDate="2010-01-01",
                    EndDate="2015-10-01",
                    Organisation=Organisation(Organisation_ID=123),
                ),
                # Deliberately overlapping registration histories
                RegistrationHistory(
                    StartDate="2015-04-01",
                    EndDate="9999-12-31",
                    Organisation=Organisation(Organisation_ID=345),
                ),
            ],
            Vaccinations=[
                Vaccination(
                    VaccinationName="Infanrix Hexa",
                    VaccinationDate="2018-11-01",
                )
            ],
            MedicationIssues=[
                MedicationIssue(
                    MedicationDictionary=MedicationDictionary(
                        DMD_ID="123", MultilexDrug_ID="123"),
                    ConsultationDate="2019-01-01",
                ),
            ],
            CodedEvents=[
                CodedEvent(CTV3Code="abc", ConsultationDate="2019-06-01")
            ],
        ),
    ])
    session.commit()
    study = VaccinationsStudyDefinition(
        start_date="2017-06-01",
        get_registered_practice_at_months=[12, 24, 60],
        tpp_vaccine_codelist=codelist(
            [
                ("Infanrix Hexa", "dtap_hex"),
                ("Bexsero", "menb"),
                ("Rotarix", "rotavirus"),
                ("Prevenar", "pcv"),
                ("Prevenar - 13", "pcv"),
                ("Menitorix", "hib_menc"),
                ("Repevax", "dtap_ipv"),
                ("Boostrix-IPV", "dtap_ipv"),
                ("MMRvaxPRO", "mmr"),
                ("Priorix", "mmr"),
            ],
            system="tpp_vaccines",
        ),
        ctv3_vaccine_codelist=codelist([("abc", "menb")], system="ctv3"),
        snomed_vaccine_codelist=codelist([("123", "rotavirus")],
                                         system="snomed"),
        event_washout_period=14,
        vaccination_schedule=[
            "dtap_hex_1",
            "menb_1",
            "rotavirus_1",
            "dtap_hex_2",
            "pcv_1",
            "rotavirus_2",
            "dtap_hex_3",
            "menb_2",
            "hib_menc_1",
            "pcv_2",
            "mmr_1",
            "menb_3",
            "dtap_ipv_1",
            "mmr_2",
        ],
    )
    study.to_csv(tmp_path / "test.csv")
    with open(tmp_path / "test.csv", newline="") as f:
        reader = csv.DictReader(f)
        results = list(reader)
    assert results == [
        {
            "patient_id": "2",
            "date_of_birth": "2019-01-01",
            "practice_id_at_month_12": "678",
            "practice_id_at_month_24": "678",
            "practice_id_at_month_60": "678",
            "dtap_hex_1": "",
            "menb_1": "",
            "rotavirus_1": "",
            "dtap_hex_2": "",
            "pcv_1": "",
            "rotavirus_2": "",
            "dtap_hex_3": "",
            "menb_2": "",
            "hib_menc_1": "",
            "pcv_2": "",
            "mmr_1": "",
            "menb_3": "",
            "dtap_ipv_1": "",
            "mmr_2": "",
        },
        {
            "patient_id": "3",
            "date_of_birth": "2018-10-01",
            "practice_id_at_month_12": "345",
            "practice_id_at_month_24": "345",
            "practice_id_at_month_60": "345",
            "dtap_hex_1": "2018-11-01",
            "menb_1": "2019-06-01",
            "rotavirus_1": "2019-01-01",
            "dtap_hex_2": "",
            "pcv_1": "",
            "rotavirus_2": "",
            "dtap_hex_3": "",
            "menb_2": "",
            "hib_menc_1": "",
            "pcv_2": "",
            "mmr_1": "",
            "menb_3": "",
            "dtap_ipv_1": "",
            "mmr_2": "",
        },
    ]
def test_patients_registered_practice_as_of():
    session = make_session()
    org_1 = Organisation(
        STPCode="123", MSOACode="E0201", Region="East of England", Organisation_ID=1
    )
    org_2 = Organisation(
        STPCode="456", MSOACode="E0202", Region="Midlands", Organisation_ID=2
    )
    org_3 = Organisation(
        STPCode="789", MSOACode="E0203", Region="London", Organisation_ID=3
    )
    org_4 = Organisation(
        STPCode="910", MSOACode="E0204", Region="North West", Organisation_ID=4
    )
    patient = Patient()
    patient.RegistrationHistory.append(
        RegistrationHistory(
            StartDate="1990-01-01", EndDate="2018-01-01", Organisation=org_1
        )
    )
    # We deliberately create overlapping registration periods so we can check
    # that we handle these correctly
    patient.RegistrationHistory.append(
        RegistrationHistory(
            StartDate="2018-01-01", EndDate="2022-01-01", Organisation=org_2
        )
    )
    patient.RegistrationHistory.append(
        RegistrationHistory(
            StartDate="2019-09-01", EndDate="2020-05-01", Organisation=org_3
        )
    )
    patient.RegistrationHistory.append(
        RegistrationHistory(
            StartDate="2022-01-01", EndDate="9999-12-31", Organisation=org_4
        )
    )
    patient_2 = Patient()
    patient_2.RegistrationHistory.append(
        RegistrationHistory(
            StartDate="2010-01-01", EndDate="9999-12-31", Organisation=org_1
        )
    )
    patient_3 = Patient()
    patient_3.RegistrationHistory.append(
        RegistrationHistory(StartDate="2010-01-01", EndDate="9999-12-31")
    )
    session.add_all([patient, patient_2, patient_3])
    session.commit()
    study = StudyDefinition(
        population=patients.all(),
        stp=patients.registered_practice_as_of("2020-01-01", returning="stp_code"),
        msoa=patients.registered_practice_as_of("2020-01-01", returning="msoa_code"),
        region=patients.registered_practice_as_of(
            "2020-01-01", returning="nhse_region_name"
        ),
        pseudo_id=patients.registered_practice_as_of(
            "2020-01-01", returning="pseudo_id"
        ),
    )
    results = study.to_dicts()
    assert [i["stp"] for i in results] == ["789", "123", ""]
    assert [i["msoa"] for i in results] == ["E0203", "E0201", ""]
    assert [i["region"] for i in results] == ["London", "East of England", ""]
    assert [i["pseudo_id"] for i in results] == ["3", "1", "0"]