renalreg/radar

View on GitHub
radar/exporter/exporters.py

Summary

Maintainability
F
2 wks
Test Coverage
import re

from radar.exporter import queries
from radar.exporter.utils import (
    format_date,
    format_user,
    get_months,
    get_years,
    identity_getter,
    none_getter,
    path_getter,
    stringify_list,
)
from radar.models.results import Observation
from radar.models.rituximab import SUPPORTIVE_MEDICATIONS
from radar.permissions import has_permission_for_patient
from radar.roles import PERMISSION
from radar.utils import get_attrs


ILLEGAL_CHARACTERS_RE = re.compile(r"[\000-\010]|[\013-\014]|[\016-\037]")

exporter_map = {}

INS_STATE = {
    0: 'INS Baseline visit',
    1: 'INS Follow Up visit',
    2: 'INS Relapse',
    3: 'INS Remission',
    4: 'INS Transplant',
    5: '2nd INS Baseline visit',
    6: 'INS Pre-transplant',
    7: 'INS 1 week post-transplant',
    8: 'INS 12 months post-transplant',
    9: 'INS 18 months post-transplant',
}


def none_to_empty(value):
    return "" if value is None else value


def formatters(value):
    val = format_date(value)
    val = none_to_empty(val)
    return val


def register(name):
    """Add an exporter."""

    def decorator(cls):
        exporter_map[name] = cls
        return cls

    return decorator


def column(name, getter=None):
    if getter is None:
        getter = path_getter(name)
    elif isinstance(getter, str):
        getter = path_getter(getter)

    return name, getter


def demographics_column_factory(config):
    """Returns a column based on the config."""

    if config["anonymised"]:

        def column(name, getter=None, anonymised_getter=None, patient_getter=None):
            if anonymised_getter is None:
                anonymised_getter = none_getter
            elif isinstance(anonymised_getter, str):
                anonymised_getter = path_getter(anonymised_getter)

            return name, anonymised_getter

    elif config["user"] is not None:

        def column(name, getter=None, anonymised_getter=None, patient_getter=None):
            if getter is None:
                getter = path_getter(name)
            elif isinstance(getter, str):
                getter = path_getter(getter)

            if anonymised_getter is None:
                anonymised_getter = none_getter
            elif isinstance(anonymised_getter, str):
                anonymised_getter = path_getter(anonymised_getter)

            if patient_getter is None:
                patient_getter = path_getter("patient")
            elif isinstance(anonymised_getter, str):
                patient_getter = path_getter(patient_getter)

            def f(value):
                patient = patient_getter(value)

                if has_permission_for_patient(
                    config["user"], patient, PERMISSION.VIEW_DEMOGRAPHICS
                ):
                    return getter(value)
                else:
                    return anonymised_getter(value)

            return name, f

    else:

        def column(name, getter=None, anonymised_getter=None, patient_getter=None):
            if getter is None:
                getter = path_getter(name)
            elif isinstance(getter, str):
                getter = path_getter(getter)

            return name, getter

    return column


def get_meta_columns(config):
    def created_user(x):
        if config["anonymised"]:
            return ""
        return format_user(x.created_user)

    def modified_user(x):
        if config["anonymised"]:
            return ""
        return format_user(x.modified_user)

    return [
        column("created_date", lambda x: format_date(x.created_date)),
        column("created_user_id"),
        column("created_user", created_user),
        column("modified_date", lambda x: format_date(x.modified_date)),
        column("modified_user_id"),
        column("modified_user", modified_user),
    ]


class Exporter(object):
    def __init__(self, config):
        self.config = config
        self._query = []
        self._columns = []

    def get_rows(self):

        headers = [col[0] for col in self._columns]
        yield headers
        for result in self._query:
            yield [col[1](result) for col in self._columns]


@register("patients")
class PatientExporter(Exporter):
    def setup(self):
        demographics_column = demographics_column_factory(self.config)

        def d(name, getter=None, anonymised_getter=None):
            return demographics_column(name, getter, anonymised_getter, identity_getter)

        group = self.config["patient_group"]

        def recruited_user(x):
            if self.config["anonymised"]:
                return ""
            return format_user(x.recruited_user(group))

        self._columns = [
            column("patient_id", "id"),
            d("patient_number", "primary_patient_number.number"),
            d("first_name"),
            d("last_name"),
            d("date_of_birth", lambda x: format_date(x.date_of_birth)),
            column("year_of_birth"),
            d("date_of_death", lambda x: format_date(x.date_of_death)),
            column("year_of_death"),
            column("available_gender"),
            column("available_gender_label"),
            column("available_ethnicity"),
            column("patient_view", "ukrdc"),
            column("control"),
            column("signed_off_state"),
            column(
                "recruited_date", lambda x: format_date(x.recruited_date(group))
            ),  # 13
            column(
                "recruited_group_id",
                lambda x: get_attrs(x.recruited_group(group), "id"),
            ),
            column(
                "recruited_group", lambda x: get_attrs(x.recruited_group(group), "name")
            ),
            column(
                "recruited_user_id", lambda x: get_attrs(x.recruited_user(group), "id")
            ),
            column("recruited_user", recruited_user),
        ]

        q = queries.get_patients(self.config)
        self._query = q


@register("patient_numbers")
class PatientNumberExporter(Exporter):
    def setup(self):
        d = demographics_column_factory(self.config)

        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("number_group_id"),
            column("number_group", "number_group.name"),
            d("number"),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_patient_numbers(self.config)
        self._query = q


@register("patient_addresses")
class PatientAddressExporter(Exporter):
    def setup(self):
        d = demographics_column_factory(self.config)

        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("from_date", lambda x: format_date(x.from_date)),
            column("to_date", lambda x: format_date(x.to_date)),
            d("address1"),
            d("address2"),
            d("address3"),
            d("address4"),
            d("postcode", anonymised_getter="anonymised_postcode"),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_patient_addresses(self.config)
        self._query = q


@register("patient_aliases")
class PatientAliasExporter(Exporter):
    def setup(self):
        d = demographics_column_factory(self.config)

        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            d("first_name"),
            d("last_name"),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_patient_aliases(self.config)
        self._query = q


@register("patient_demographics")
class PatientDemographicsExporter(Exporter):
    def setup(self):
        d = demographics_column_factory(self.config)

        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            d("first_name"),
            d("last_name"),
            d("date_of_birth", lambda x: format_date(x.date_of_birth)),
            column("year_of_birth"),
            d("date_of_death", lambda x: format_date(x.date_of_death)),
            column("year_of_death"),
            column("gender"),
            column("gender_label"),
            column("ethnicity"),
            column("ethnicity_label"),
            d("home_number"),
            d("work_number"),
            d("mobile_number"),
            d("email_address"),
        ]

        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_patient_demographics(self.config)
        self._query = q


@register("medications")
class MedicationExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("from_date", lambda x: format_date(x.from_date)),
            column("to_date", lambda x: format_date(x.to_date)),
            column("drug_id"),
            column("drug", "drug.name"),
            column("drug_text"),
            column("dose_quantity"),
            column("dose_unit"),
            column("dose_unit_label"),
            column("dose_text"),
            column("frequency"),
            column("route"),
            column("route_label"),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_medications(self.config)
        self._query = q


@register("current-medications")
class CurrentMedicationExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date_of_visit", lambda x: format_date(x.date_recorded)),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("drug_id"),
            column("drug", "drug.name"),
            column("drug_text"),
            column("dose_quantity"),
            column("dose_unit"),
            column("dose_unit_label"),
            column("dose_text"),
            column("frequency"),
            column("route"),
            column("route_label"),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_current_medications(self.config)
        self._query = q


class DiagnosisExporter(Exporter):
    def setup(self):
        d = demographics_column_factory(self.config)

        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("era-edta prd"),  #5
            column("icd-10"),  #6
            column("snomed ct"), #7
            column("diagnosis", "diagnosis.name"),
            column("diagnosis_text"),
            column("symptoms_date", lambda x: format_date(x.symptoms_date)),
            column("symptoms_age_years", lambda x: get_years(x.symptoms_age)),
            column("symptoms_age_months", lambda x: get_months(x.symptoms_age)),
            column("from_date", lambda x: format_date(x.from_date)),
            column("from_age_years", lambda x: get_years(x.from_age)),
            column("from_age_months", lambda x: get_months(x.from_age)),
            column("to_date", lambda x: format_date(x.to_date)),
            column("to_age_years", lambda x: get_years(x.to_age)),
            column("to_age_months", lambda x: get_months(x.to_age)),
            column("prenatal"),
            column("gene_test"),
            column("biochemistry"),
            column("clinical_picture"),
            column("biopsy"), #23
            column("biopsy_diagnosis"),
            column("biopsy_diagnosis_label"),
            d("comments", anonymised_getter=None)
            ]

        if self.config['patient_group'].code == 'NURTUREINS':            
            self._columns.extend(
                [
                    column("ins_diagnosis"), #27
                    column('ins_diagnosis_date'),
                    column('ins_biopsy_diagnosis'),
                    column('ins_biopsy_diagnosis_label'),
                    column('ins_diagnosis_comments') #31                                  
                ]
            )
        self._columns.extend(get_meta_columns(self.config))
        self._query = queries.get_patient_diagnoses(self.config)
        self._primary = queries.get_primary_diagnoses(self.config)

@register("primary-diagnoses")
class PrimaryDiagnosisExporter(DiagnosisExporter):
    '''
    A class that extends DiagnosisExporter exporter for the 
    purpose of constructing all the relevant data to be 
    written to a CSV file. The CSV file will be conserned with
    all the patients in a cohort and their primary diagnosis.

    The exporter contains extra functionality that enables 
    the combination of nurture INS data and INS data although
    in general it is expected that each export will focus on
    only one cohort. It works by storing the patient ID during
    a search for primary diagnosis and only yielding a row when
    a new patient is found. Before yielding a row it combines
    INS data with Nurture INS data.

    :param DiagnosisExporter: a class that contains all the header
    for the CSV and the results of the relevant queries
    :type DiagnosisExporter: class: DiagnosisExporter   
    '''    

        
    def get_rows(self):
        '''
        Gets all the primary diagnosis data for a specific cohort

        :yield: yields CSV row for writting to file
        :rtype: list
        '''        

        headers = [col[0] for col in self._columns]
        yield headers

        # Differnet process for Nurture INS patients
        if self.config['patient_group'].code == 'NURTUREINS':

            patient_id = 0            
            row = []            
            self.ins_data = {
                'pat_id': '',
                'ins_dia_name': '',
                'ins_dia_date': '',
                'ins_biopsy_dia': '',
                'ins_biopsy_dia_label': '',
                'ins_biopsy_dia_comments': ''                
            }

            for record in self._query:
                diagnosis = record.diagnosis                
                if not diagnosis:                
                    continue

                # New patient identified
                if record.patient_id != patient_id:
                    patient_id = record.patient_id
                    
                    # Primary diagnosis found for previous patient, add INS data to row and yield
                    if row:                        
                        self.insert_ins_data(row)                      
                        yield row

                        if diagnosis in self._primary:
                            row = self.make_row(record, diagnosis)
                        else:
                            row = []

                        ins_data = self.get_ins_data(record, diagnosis) 

                    # No primary diagnosis found for previous patient
                    # Check for INS data                    
                    else:
                        # INS data present create blank row, add INS data and yield
                        if self.ins_data['ins_dia_name'] != '':
                            row = [''] * len(headers)
                            row[1] = self.ins_data['pat_id']
                            self.ins_data['pat_id'] = ''
                            self.insert_ins_data(row)
                            yield row

                            if diagnosis in self._primary:                            
                                row = self.make_row(record, diagnosis)
                            else:
                                row = []

                            ins_data = self.get_ins_data(record, diagnosis)

                        # No data found for previous patient so no yield required
                        else:
                            if diagnosis in self._primary:
                                row = self.make_row(record, diagnosis)
                            else:
                                row = []

                            ins_data = self.get_ins_data(record, diagnosis)
                
                # Not new patient
                else:
                    # Primary diagnosis has been found, continue to check for INS data
                    if row:
                        if not self.ins_data['ins_dia_date'] or self.ins_data['ins_dia_date'] < record.from_date:
                            ins_data = self.get_ins_data(record, diagnosis)

                    # Search for primary diagnosis and INS data
                    else:
                        if diagnosis in self._primary:
                            row = self.make_row(record, diagnosis)
                        else:
                            row = []

                        if not self.ins_data['ins_dia_date'] or self.ins_data['ins_dia_date'] < record.from_date:
                            ins_data = self.get_ins_data(record, diagnosis)
        
        # Not Nurture-ins export
        else:            
            for record in self._query:
                diagnosis = record.diagnosis
                if not diagnosis:
                    continue
                if diagnosis in self._primary:
                    row = self.make_row(record, diagnosis)
                else:
                    row = []
                if row:
                    yield row   

    def make_row(self, record, diagnosis):
        '''
        Returns a list that represents the content of a single row
        in a CSV file that provides data about a patients diagnoses.

        :param record: An object containing a single record from primary diagnoses query
        :type record:  class: queries.get_primary_diagnoses()
        :param diagnosis: A diagnosis object provided by record
        :type diagnosis: class: radar.models.diagnoses.Diagnosis
        :return: returns a CSV row with diagnosis data
        :rtype: list
        '''
        
        row = [col[1](record) for col in self._columns]        
        
        if diagnosis.codes:
            for code in diagnosis.codes:
                if code.system == "ERA-EDTA PRD":
                    row[5] = code.code                        
                if code.system == "ICD-10":
                    row[6] = code.code                        
                if code.system == "SNOMED CT":
                    row[7] = code.code

        return row

    def get_ins_data(self, record, diagnosis):
        '''
        Updates ins_data dictionary with INS data

        :param record: An object containing a single record from primary diagnoses query
        :type record: class: queries.get_primary_diagnoses()
        :param diagnosis: A diagnosis object provided by record
        :type diagnosis: class: radar.models.diagnoses.Diagnosis
        '''        

        for group_diagnosis in diagnosis.group_diagnoses:
            if group_diagnosis.group.code == 'INS' and group_diagnosis.type.value == 'PRIMARY':
                self.ins_data['pat_id'] = record.patient_id
                self.ins_data['ins_dia_name'] = diagnosis.name 
                self.ins_data['ins_dia_date'] = record.from_date
                self.ins_data['ins_biopsy_dia'] = record.biopsy_diagnosis
                self.ins_data['ins_biopsy_dia_label'] = record.biopsy_diagnosis_label
                self.ins_data['ins_biopsy_dia_comments'] = record.comments
        

    def insert_ins_data(self, row):
        '''
        Inserts ins_data into row once a new patient is identified

        :param row: a list containing primary diagnosis data if any
                    otherwise a blank row the same length as headers
        :type row: list
        '''        
        row[27] = self.ins_data['ins_dia_name']
        self.ins_data['ins_dia_name'] = ''
        row[28] = self.ins_data['ins_dia_date']
        self.ins_data['ins_dia_date'] = ''
        row[29] = self.ins_data['ins_biopsy_dia']
        self.ins_data['ins_biopsy_dia'] = ''
        row[30] = self.ins_data['ins_biopsy_dia_label']
        self.ins_data['ins_biopsy_dia_label'] = ''
        row[31] = self.ins_data['ins_biopsy_dia_comments']
        self.ins_data['ins_biopsy_dia_comments'] = ''
        


@register("comorbidities")
class ComorbiditiesExporter(DiagnosisExporter):
    def get_rows(self):
        headers = [col[0] for col in self._columns]
        yield headers

        for result in self._query:
            if result in self._primary:
                continue

            row = [col[1](result) for col in self._columns]
            diagnosis = result.diagnosis

            if diagnosis and diagnosis.codes:
                for code in diagnosis.codes:
                    if code.system == "ERA-EDTA PRD":
                        row[5] = code.code
                    if code.system == "ICD-10":
                        row[6] = code.code
                    if code.system == "SNOMED CT":
                        row[7] = code.code

            yield row


@register("genetics")
class GeneticsExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("group_id"),
            column("group", "group.name"),
            column("date_sent", lambda x: format_date(x.date_sent)),
            column("laboratory"),
            column("reference_number"),
            column("karyotype"),
            column("karyotype_label"),
            column("results"),
            column("summary"),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_genetics(self.config)
        self._query = q


@register("pathology")
class PathologyExporter(Exporter):
    def setup(self):
        d = demographics_column_factory(self.config)
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("date", lambda x: format_date(x.date)),
            column("kidney_type"),
            column("kidney_type_label"),
            column("kidney_side"),
            column("kidney_side_label"),
            column("reference_number"),
            column("image_url"),
            d(
                "histological_summary",
                anonymised_getter=lambda x: x.histological_summary
                if x.histological_summary is None
                else "REDACTED",
            ),
            d("em_findings", anonymised_getter=None),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_pathology(self.config)
        self._query = q


@register("family_histories")
class FamilyHistoryExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("group_id"),
            column("group", "group.name"),
            column("parental_consanguinity"),
            column("family_history"),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_family_histories(self.config)
        self._query = q


@register("family_history_relatives")
class FamilyHistoryRelativeExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("family_history_id"),
            column("relationship"),
            column("relationship_label"),
            column("patient_id"),
        ]

        q = queries.get_family_history_relatives(self.config)
        self._query = q


@register("ins_clinical_pictures")
class InsClinicalPictureExporter(Exporter):
    def setup(self):
        d = demographics_column_factory(self.config)
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date_of_picture", lambda x: format_date(x.date_of_picture)),
            column("oedema"),
            column("hypovalaemia"),
            column("fever"),
            column("thrombosis"),
            column("peritonitis"),
            column("pulmonary_odemea"),
            column("hypertension"),
            column("rash"),
            column("rash_details"),
            column("infection"),
            column("infection_details"),
            column("ophthalmoscopy"),
            column("ophthalmoscopy_details"),
            d("comments", anonymised_getter=None),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_ins_clinical_pictures(self.config)
        self._query = q


@register("dialysis")
class DialysisExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("from_date", lambda x: format_date(x.from_date)),
            column("to_date", lambda x: format_date(x.to_date)),
            column("modality"),
            column("modality_label"),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_dialyses(self.config)
        self._query = q


@register("plasmapheresis")
class PlasmapheresisExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("from_date", lambda x: format_date(x.from_date)),
            column("to_date", lambda x: format_date(x.to_date)),
            column("no_of_exchanges"),
            column("no_of_exchanges_label"),
            column("response"),
            column("response_label"),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_plasmapheresis(self.config)
        self._query = q


@register("transplants")
class TransplantExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("transplant_group_id"),
            column("transplant_group", "transplant_group.name"),
            column("date", lambda x: format_date(x.date)),
            column("modality"),
            column("modality_label"),
            column("recipient_hla"),
            column("donor_hla"),
            column(
                "date_of_cmv_infection", lambda x: format_date(x.date_of_cmv_infection)
            ),
            column("date_of_recurrence", lambda x: format_date(x.date_of_recurrence)),
            column("date_of_failure", lambda x: format_date(x.date_of_failure)),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_transplants(self.config)
        self._query = q


@register("transplant_biopsies")
class TransplantBiopsyExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("transplant_id"),
            column("date_of_biopsy", lambda x: format_date(x.date_of_biopsy)),
            column("recurrence"),
        ]

        q = queries.get_transplant_biopsies(self.config)
        self._query = q


@register("transplant_rejections")
class TransplantRejectionExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("transplant_id"),
            column("date_of_rejection", lambda x: format_date(x.date_of_rejection)),
            column("graft_loss_cause"),
        ]

        q = queries.get_transplant_rejections(self.config)
        self._query = q


@register("hospitalisations")
class HospitalisationExporter(Exporter):
    def setup(self):
        d = demographics_column_factory(self.config)
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("date_of_admission", lambda x: format_date(x.date_of_admission)),
            column("date_of_discharge", lambda x: format_date(x.date_of_discharge)),
            column("reason_for_admission"),
            d("comments", anonymised_getter=None),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_hospitalisations(self.config)
        self._query = q


@register("ins_relapses")
class InsRelapseExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date_of_relapse"),
            column("kidney_type"),
            column("kidney_type_label"),
            column("viral_trigger"),
            column("immunisation_trigger"),
            column("other_trigger"),
            column("peak_pcr"),
            column("peak_acr"),
            column("peak_protein_dipstick"),
            column("remission_protein_dipstick"),
            column("high_dose_oral_prednisolone"),
            column("iv_methyl_prednisolone"),
            column("relapse_sample_taken"),
            column("date_of_remission", lambda x: format_date(x.date_of_remission)),
            column("remission_type"),
            column("remission_type_label"),
            column("remission_pcr"),
            column("remission_acr"),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_ins_relapses(self.config)
        self._query = q


@register("mpgn_clinical_pictures")
class MpgnClinicalPicturesExporter(Exporter):
    def setup(self):
        d = demographics_column_factory(self.config)
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date_of_picture", lambda x: format_date(x.date_of_picture)),
            column("oedema"),
            column("hypertension"),
            column("urticaria"),
            column("partial_lipodystrophy"),
            column("infection"),
            column("infection_details"),
            column("ophthalmoscopy"),
            column("ophthalmoscopy_details"),
            d("comments", anonymised_getter=None),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_mpgn_clinical_pictures(self.config)
        self._query = q


@register("group_patients")
class GroupPatientExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("group_id"),
            column("group", "group.name"),
            column("from_date", lambda x: format_date(x.from_date)),
            column("to_date", lambda x: format_date(x.to_date)),
            column("discharged_date", lambda x: format_date(x.discharged_date)),
            column("created_group_id"),
            column("created_group", "created_group.name"),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_group_patients(self.config)
        self._query = q


@register("renal_progressions")
class RenalProgressionExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("onset_date", lambda x: format_date(x.onset_date)),
            column("ckd3a_date", lambda x: format_date(x.ckd3a_date)),
            column("ckd3b_date", lambda x: format_date(x.ckd3b_date)),
            column("ckd4_date", lambda x: format_date(x.ckd4_date)),
            column("ckd5_date", lambda x: format_date(x.ckd5_date)),
            column("esrf_date", lambda x: format_date(x.esrf_date)),
        ]
        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_renal_progressions(self.config)
        self._query = q


@register("results")
class ResultExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("date"),
            column("observation_name", "observation.name"),
            column("value"),
            column("value_label"),
            column("sent_value"),
        ]
        self._columns.extend(get_meta_columns(self.config))

    def get_rows(self):
        headers = [col[0] for col in self._columns]
        yield headers

        q = queries.get_results(self.config)
        for result in q.yield_per(1000):
            yield [col[1](result) for col in self._columns]
            value = result.calculate_z_score_height
            if value:
                row = [col[1](result) for col in self._columns]
                row[6] = "RADAR Z Score Height"
                row[7] = row[9] = value
                yield row
            value = result.calculate_z_score_weight
            if value:
                row = [col[1](result) for col in self._columns]
                row[6] = "RADAR Z Score Weight"
                row[7] = row[9] = value
                yield row
            value = result.egfr_calculated
            if value:
                row = [col[1](result) for col in self._columns]
                row[6] = "RADAR Calculated eGFR"
                row[7] = row[9] = value
                yield row
            value = result.ckd_epi_egfr_calculated_with_ethnicity
            if value:
                row = [col[1](result) for col in self._columns]
                row[6] = "RADAR Calculated eGFR with ethnicity"
                row[7] = row[9] = value
                yield row
            value = result.ckd_epi_egfr_calculated_without_ethnicity
            if value:
                row = [col[1](result) for col in self._columns]
                row[6] = "RADAR Calculated eGFR without ethnicity"
                row[7] = row[9] = value
                yield row


@register("results-pivot")
class PivotedResultExporter(Exporter):
    def setup(self):
        self._columns = [
            column("patient_id"),
            column("source_group"),
            column("source_type"),
            column("date"),
        ]

    def get_rows(self):
        observations = queries.get_observations()
        for observation in observations:
            self._columns.append(column(observation.short_name))

        headers = [col[0] for col in self._columns]
        yield headers

        for patient in queries.get_patients(self.config):
            data = {}
            for result in patient.results:
                try:
                    date_str = result.date.strftime("%Y-%m-%dT%H:%M:%S")
                except ValueError:
                    date_str = "bad_date"
                key = (result.source_group.name, result.source_type, date_str)
                if key not in data:
                    data[key] = {}
                data[key][result.observation.short_name] = result.sent_value

            for key, items in sorted(data.items(), key=lambda x: x[0][2]):
                row = [patient.id, key[0], key[1], key[2]]
                for observation in headers[4:]:
                    row.append(items.get(observation, None))

                yield row


#     def run(self):
#         q = queries.get_results(self.config)
#         self._query = q

#     @property
#     def dataset(self):
#         egfr_calculated = 'Estimated GFR Calculated'
#         extra = {row.observation.name for row in self._query}
#         extra.add(egfr_calculated)
#         extra = sorted(extra, key=lambda val: val.lower())

#         self._columns.extend(column(name) for name in extra)

#         data = OrderedDict()

#         for row in self._query:
#             key = (row.patient_id, row.source_group.name, row.source_type, row.date)
#             if key not in data:
#                 data[key] = {egfr_calculated: ''}

#             data[key][row.observation.name] = row.value_label_or_value

#             if data[key][egfr_calculated] == '':
#                 data[key][egfr_calculated] = row.egfr_calculated

#         dataset = make_dataset(self._columns, results=True)

#         for key, results in data.items():
#             row = list(key)
#             try:
#                 row[3] = row[3].strftime('%d/%m/%Y %H:%M:%S')
#             except ValueError:
#                 year, month, day, hour, minute, second = row[3].timetuple()[:6]
#                 row[3] = '{}/{}/{} {}:{}:{}'.format(day, month, year, hour, minute, second)

#             for test in extra:
#                 if test in results:
#                     row.append(results[test])
#                 else:
#                     row.append('')
#             dataset.append(row)

#         return dataset


@register("observations")
class ObservationExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("name"),
            column("short_name"),
            column("value_type"),
            column("sample_type"),
            column("pv_code"),
            column("min_value"),
            column("max_value"),
            column("min_length"),
            column("max_length"),
            column("units"),
            column("options"),
        ]

        self._query = Observation.query.order_by(Observation.id)


@register("6cit")
class Cit6Exporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date", "data.date"),
            column("q1", "data.q1"),
            column("q2", "data.q2"),
            column("q4", "data.q4"),
            column("q5", "data.q5"),
            column("q6", "data.q6"),
            column("q7", "data.q7"),
            column("score", "data.score"),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register("chu9d")
class CHU9DExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date", "data.date"),
            column("worried", "data.worried"),
            column("sad", "data.sad"),
            column("pain", "data.pain"),
            column("tired", "data.tired"),
            column("annoyed", "data.annoyed"),
            column("work", "data.work"),
            column("sleep", "data.sleep"),
            column("routine", "data.routine"),
            column("activities", "data.activities"),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register("diabetic-complications")
class DiabeticComplicationExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("laser", "data.laser"),
            column("foot ulcers", "data.footUlcers"),
            column("retinopathy", "data.retinopathy"),
            column("peripheral neuropathy", "data.peripheralNeuropathy"),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register("eq-5d-5l")
class Eq5d5lExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date", "data.date"),
            column("age", "data.age"),
            column("gender", "data.gender"),
            column("mobility", "data.mobility"),
            column("self care", "data.selfCare"),
            column("pain discomfort", "data.painDiscomfort"),
            column("usual activities", "data.usualActivities"),
            column("anxiety depression", "data.anxietyDepression"),
            column("health", "data.health"),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register("eq-5d-y")
class Eq5dyExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date", "data.date"),
            column("age", "data.age"),
            column("gender", "data.gender"),
            column("mobility", "data.mobility"),
            column("self care", "data.selfCare"),
            column("pain discomfort", "data.painDiscomfort"),
            column("usual activities", "data.usualActivities"),
            column("anxiety depression", "data.anxietyDepression"),
            column("health", "data.health"),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register("hads")
class HadsExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date", "data.date"),
            column("a1", "data.a1"),
            column("a2", "data.a2"),
            column("a3", "data.a3"),
            column("a4", "data.a4"),
            column("a5", "data.a5"),
            column("a6", "data.a6"),
            column("a7", "data.a7"),
            column("d1", "data.d1"),
            column("d2", "data.d2"),
            column("d3", "data.d3"),
            column("d4", "data.d4"),
            column("d5", "data.d5"),
            column("d6", "data.d6"),
            column("d7", "data.d7"),
            column("anxiety score", "data.anxietyScore"),
            column("depression score", "data.depressionScore"),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register("family-history")
class FamilyDiseasesHistoryExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("chd", "data.chd"),
            column("eskd", "data.eskd"),
            column("diabetes", "data.diabetes"),
            column("chdRelative1", "data.chdRelative1"),
            column("chdRelative2", "data.chdRelative2"),
            column("chdRelative3", "data.chdRelative3"),
            column("eskdRelative1", "data.eskdRelative1"),
            column("eskdRelative2", "data.eskdRelative2"),
            column("eskdRelative3", "data.eskdRelative3"),
            column("diabetesRelative1", "data.diabetesRelative1"),
            column("diabetesRelative2", "data.diabetesRelative2"),
            column("diabetesRelative3", "data.diabetesRelative3"),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register("ipos")
class IposExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date", "data.date"),
            column("score1", "data.score1"),
            column("score2", "data.score2"),
            column("score3", "data.score3"),
            column("score4", "data.score4"),
            column("score5", "data.score5"),
            column("score6", "data.score6"),
            column("score7", "data.score7"),
            column("score8", "data.score8"),
            column("score9", "data.score9"),
            column("score10", "data.score10"),
            column("score11", "data.score11"),
            column("score12", "data.score12"),
            column("score13", "data.score13"),
            column("score14", "data.score14"),
            column("score15", "data.score15"),
            column("score16", "data.score16"),
            column("score17", "data.score17"),
            column("question1", "data.question1"),
            column("score18", "data.score18"),
            column("question2", "data.question2"),
            column("score19", "data.score19"),
            column("question3", "data.question3"),
            column("score20", "data.score20"),
            column("question4", "data.question4"),
            column("question5", "data.question5"),
            column("score", "data.score"),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register("samples")
class SamplesExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date", "data.date"),
            column("barcode", "data.barcode"),
            column("ins_state", "data.insstate")
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q

    def get_rows(self):

        headers = [col[0] for col in self._columns]
        headers[4] = 'sample_type'
        yield headers
        for data in self._query:
            row = [col[1](data) for col in self._columns]

            if row[4] is not None:
                row[4] = INS_STATE[row[4]]

            yield row


@register("anthropometrics")
class AnthropometricsExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date", "data.date"),
            column("height", "data.height"),
            column("weight", "data.weight"),
            column("hip", "data.hip"),
            column("waist", "data.waist"),
            column("arm", "data.arm"),
            column("up", "data.up"),
            column("gripDominant", "data.gripDominant"),
            column("gripNonDominant", "data.gripNonDominant"),
            column("karnofsky", "data.karnofsky"),
            column("systolic1", "data.systolic1"),
            column("systolic2", "data.systolic2"),
            column("systolic3", "data.systolic3"),
            column("systolic", "data.systolic"),
            column("diastolic1", "data.diastolic1"),
            column("diastolic2", "data.diastolic2"),
            column("diastolic3", "data.diastolic3"),
            column("diastolic", "data.diastolic"),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register("socio-economic")
class SocioEconomicExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date", "data.date"),
            column("maritalStatus", "data.maritalStatus"),
            column("education", "data.education"),
            column("employmentStatus", "data.employmentStatus"),
            column("firstLanguage", "data.firstLanguage"),
            column("literacy", "data.literacy"),
            column("literacyHelp", "data.literacyHelp"),
            column("smoking", "data.smoking"),
            column("cigarettesPerDay", "data.cigarettesPerDay"),
            column("alcohol", "data.alcohol"),
            column("unitsPerWeek", "data.unitsPerWeek"),
            column("diet", "data.diet"),
            column("otherDiet", "data.otherDiet"),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register("nurtureckd")
class NurtureCKDExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date", "data.date"),
            column("visit", "data.visit"),
            column("comorbidities", "data.comorbities"),
            column("vaccinationFlu", "data.vaccinationFlu"),
            column("vaccinationPneumonia", "data.vaccinationPneumonia"),
            column("admission", "data.admission"),
            column("admissionNumber", "data.admissionNumber"),
            column("admissionEmergency", "data.admissionEmergency"),
            column("admissionPlanned", "data.admissionPlanned"),
            column("admissionDays", "data.admissionDays"),
            column("admissionAntibiotics", "data.admissionAntibiotics"),
            column("medicine1", "data.medicine1"),
            column("tabletsParacetamol", "data.tabletsParacetamol"),
            column("yearsParacetamol", "data.yearsParacetamol"),
            column("medicine2", "data.medicine2"),
            column("tabletsCocodamol", "data.tabletsCocodamol"),
            column("yearsCocodamol", "data.yearsCocodamol"),
            column("medicine3", "data.medicine3"),
            column("tabletsIbuprofen", "data.tabletsIbuprofen"),
            column("yearsIbuprofen", "data.yearsIbuprofen"),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register("renal_imaging")
class RenalImagingExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("date", lambda x: format_date(x.date)),
            column("imaging_type"),
            column("right_present"),
            column("right_type"),
            column("right_length"),
            column("right_volume"),
            column("right_cysts"),
            column("right_stones"),
            column("right_calcification"),
            column("right_nephrocalcinosis"),
            column("right_nephrolithiasis"),
            column("right_other_malformation"),
            column("left_present"),
            column("left_type"),
            column("left_length"),
            column("left_volume"),
            column("left_cysts"),
            column("left_stones"),
            column("left_calcification"),
            column("left_nephrocalcinosis"),
            column("left_nephrolithiasis"),
            column("left_other_malformation"),
        ]

        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_renal_imaging(self.config)
        self._query = q


@register("consultants")
class ConsultantsExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("first_name"),
            column("last_name"),
            column("email"),
            column("telephone_number"),
            column("gmc_number"),
            column("specialty", "specialty.name"),
        ]
        q = queries.get_consultants(self.config)
        self._query = q


@register("pregnancies")
class PregnanciesExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("pregnancy_number"),
            column("date_of_lmp", lambda x: format_date(x.date_of_lmp)),
            column("gravidity"),
            column("parity1"),
            column("parity2"),
            column("outcome"),
            column("weight"),
            column("weight_centile"),
            column("gestational_age"),
            column("delivery_method"),
            column("neonatal_intensive_care"),
            column("pre_eclampsia"),
        ]

        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_pregnancies(self.config)
        self._query = q


@register("fetal_ultrasounds")
class FetalUltrasoundsExporter(Exporter):
    def setup(self):
        d = demographics_column_factory(self.config)
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("date_of_scan", lambda x: format_date(x.date_of_scan)),
            column("fetal_identifier"),
            column("gestational_age"),
            column("head_centile"),
            column("abdomen_centile"),
            column("uterine_artery_notched"),
            column("liquor_volume"),
            d("comments", anonymised_getter=None),
        ]

        self._columns.extend(get_meta_columns(self.config))

        q = queries.get_fetal_ultrasounds(self.config)
        self._query = q


@register("clinical_features")
class ClinicalFeaturesExporter(Exporter):
    def setup(self):
        d = demographics_column_factory(self.config)
        self._columns = [
            column("id"),
            column("patient_id"),
            column("normal_pregnancy"),
            d("abnormal_pregnancy_text", anonymised_getter=None),
            column("neurological_problems"),
            column("seizures"),
            column("abnormal_gait"),
            column("deafness"),
            column("other_neurological_problem"),
            d("other_neurological_problem_text", anonymised_getter=None),
            column("joint_problems"),
            column("joint_problems_age"),
            column("x_ray_abnormalities"),
            column("chondrocalcinosis"),
            column("other_x_ray_abnormality"),
            d("other_x_ray_abnormality_text", anonymised_getter=None),
        ]

        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_clinical_features(self.config)
        self._query = q


@register("liver-imaging")
class LiverImagingExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("date", lambda x: format_date(x.date)),
            column("imaging_type"),
            column("size"),
            column("hepatic_fibrosis"),
            column("hepatic_cysts"),
            column("bile_duct_cysts"),
            column("dilated_bile_ducts"),
            column("cholangitis"),
        ]
        q = queries.get_liver_imaging(self.config)
        self._query = q


@register("liver-diseases")
class LiverDiseasesExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("portal_hypertension"),
            column("portal_hypertension_date"),
            column("ascites"),
            column("ascites_date", lambda x: format_date(x.ascites_date)),
            column("oesophageal"),
            column("oesophageal_date", lambda x: format_date(x.oesophageal_date)),
            column("oesophageal_bleeding"),
            column(
                "oesophageal_bleeding_date",
                lambda x: format_date(x.oesophageal_bleeding_date),
            ),
            column("gastric"),
            column("gastric_date", lambda x: format_date(x.gastric_date)),
            column("gastric_bleeding"),
            column(
                "gastric_bleeding_date", lambda x: format_date(x.gastric_bleeding_date)
            ),
            column("anorectal"),
            column("anorectal_date", lambda x: format_date(x.anorectal_date)),
            column("anorectal_bleeding"),
            column(
                "anorectal_bleeding_date",
                lambda x: format_date(x.anorectal_bleeding_date),
            ),
            column("cholangitis_acute"),
            column(
                "cholangitis_acute_date",
                lambda x: format_date(x.cholangitis_acute_date),
            ),
            column("cholangitis_recurrent"),
            column(
                "cholangitis_recurrent_date",
                lambda x: format_date(x.cholangitis_recurrent_date),
            ),
            column("spleen_palpable"),
            column(
                "spleen_palpable_date", lambda x: format_date(x.spleen_palpable_date)
            ),
        ]
        q = queries.get_liver_diseases(self.config)
        self._query = q


@register("liver-transplants")
class LiverTransplantsExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("transplant_group", "transplant_group.name"),
            column("registration_date", lambda x: format_date(x.registration_date)),
            column("transplant_date", lambda x: format_date(x.transplant_date)),
            column("indications"),
            column("other_indications"),
            column("first_graft_source"),
            column("loss_reason"),
            column("other_loss_reason"),
        ]
        q = queries.get_liver_transplants(self.config)
        self._query = q


@register("nephrectomies")
class NephrectomiesExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("date", lambda x: format_date(x.date)),
            column("kidney_side"),
            column("kidney_type"),
            column("entry_type"),
        ]
        q = queries.get_nephrectomies(self.config)
        self._query = q


@register("nutrition")
class NutritionExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group", "source_group.name"),
            column("source_type"),
            column("feeding_type"),
            column("from_date", lambda x: format_date(x.from_date)),
            column("to_date", lambda x: format_date(x.to_date)),
        ]
        q = queries.get_nutrition(self.config)
        self._query = q


@register("consents")
class ConsentsExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("consent", "consent.label"),
            column("signed_on_date", lambda x: format_date(x.signed_on_date)),
            column(
                "reconsent_letter_sent_date",
                lambda x: format_date(x.reconsent_letter_sent_date),
            ),
            column(
                "reconsent_letter_returned_date",
                lambda x: format_date(x.reconsent_letter_returned_date),
            ),
        ]
        q = queries.get_consents(self.config)
        self._query = q


@register("alport-clinical-pictures")
class AlportPicturesExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date_of_picture", lambda x: format_date(x.date_of_picture)),
            column("deafness"),
            column("deafness_date", lambda x: format_date(x.deafness_date)),
            column("hearing_aid_date", lambda x: format_date(x.hearing_aid_date)),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_alport_clinical_pictures(self.config)
        self._query = q


@register("rituximab-criteria")
class RituximabConsentsExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date", lambda x: format_date(x.date)),
            column("ongoing_severe_disease"),
            column("hypersensitivity"),
            column("drug_associated_toxicity"),
            column("alkylating_complication"),
            column("alkylating_failure_monitoring_requirements"),
            column("cancer"),
            column("threatened_fertility"),
            column("fall_in_egfr"),
            column("cni_therapy_complication"),
            column("cni_failure_monitoring_requirements"),
            column("diabetes"),
            column("risk_factors"),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_rituximab_consents(self.config)
        self._query = q


@register("rituximab-baseline-assessment")
class RituximabBaselineAssessmentExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("source_group", "source_group.name"),
            column("date"),
            column("nephropathy"),
            column("comorbidities"),
        ]
        q = queries.get_rituximab_baseline_assessment_data(self.config)
        self._query = q

    def get_rows(self):
        self._columns.extend(
            column(item.lower()) for item in SUPPORTIVE_MEDICATIONS.keys()
        )

        previous = (
            "chlorambucil",
            "cyclophosphamide",
            "rituximab",
            "tacrolimus",
            "cyclosporine",
        )
        with_dose = ("chlorambucil", "cyclophosphamide", "rituximab")

        for item in previous:
            items = (item, "{}_start_date".format(item), "{}_end_date".format(item))
            self._columns.extend(column(item) for item in items)
            if item in with_dose:
                self._columns.append(column("{}_dose".format(item)))
        self._columns.append(column("steroids"))
        self._columns.append(column("other_previous_treatment"))
        self._columns.append(column("past_remission"))
        self._columns.append(column("performance_status"))
        self._columns.extend(get_meta_columns(self.config))
        headers = [col[0] for col in self._columns]

        yield headers

        for data in self._query:
            row = [data.id, data.patient.id, data.source_group.name, data.date]
            row.append(data.nephropathy)
            row.append(data.comorbidities)
            for supportive in SUPPORTIVE_MEDICATIONS:
                row.append(supportive in data.supportive_medication)

            for item in previous:
                treatment = None
                if data.previous_treatment:
                    treatment = data.previous_treatment.get(item, {})
                if treatment:
                    row.append(treatment.get(item))
                    row.append(treatment.get("start_date"))
                    row.append(treatment.get("end_date"))
                else:
                    row.append(False)
                    row.append("")
                    row.append("")

                if item in with_dose:
                    if treatment:
                        row.append(treatment.get("total_dose"))
                    else:
                        row.append("")

            row.append(data.steroids)
            row.append(data.other_previous_treatment)
            row.append(data.past_remission)
            row.append(data.performance_status)
            for col in self._columns[-6:]:
                row.append(col[1](data))

            yield row


@register("rituximab-administration")
class RituximabAdministrationExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date", "data.date"),
            column("drug_name", "data.drugName"),
            column("other_drug", "data.otherDrug"),
            column("dose", "data.dose"),
            column("retreatment", "data.retreatment"),
            column("toxicity", stringify_list("toxicity")),
            column("other_toxicity", "data.otherToxicity"),
        ]

        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register("rituximab-assessment")
class RituximabFollowupAssessmentExporter(Exporter):
    def setup(self):
        self._columns = [
            column("id"),
            column("patient_id"),
            column("date", "data.date"),
            column("visit", "data.visit"),
            column("performance", "data.performance"),
            column("transplant", "data.transplant"),
            column("haemodialysis", "data.haemodialysis"),
            column("peritoneal_dialysis", "data.peritonealDialysis"),
            column("supportive_medication", stringify_list("medication")),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register('rituximab-adverse-events')
class RituximabAdverseEventsExporter(Exporter):
    def setup(self):
        d = demographics_column_factory(self.config)
        self._columns = [
            column('id'),
            column('patient_id'),
            column('date', 'data.date'),
            column('hospitalisation', 'data.hospitalisation'),
            column('adverse_events', 'data.adverseEvents'),
            column('onset_cancer', 'data.newOnsetCancer'),
            column('caused_cancer', 'data.causedCancer'),
            column('thromboembolism', 'data.thromboembolism'),
            column('caused_thromboembolism', 'data.causedVenousThromboEmbolism'),
            column('myocardial_infarction', 'data.myocardialInfarction'),
            column('caused_infarction', 'data.causedAcuteMyocardialInfarction'),
            column('stroke', 'data.stroke'),
            column('caused_stroke', 'data.causedStroke'),
            column('ischaemic_attack', 'data.ischaemicAttack'),
            column('caused_attack', 'data.causedIschaemicAttack'),
            column('other_adverse_event', 'data.otherAdverseEvent'),
            column('other_toxicity', 'data.otherTox'),
            column('caused_other', 'data.causedOther'),
            column('date_of_death', 'data.dod'),
            d('cause_of_death', 'data.dodCause', anonymised_getter=None)
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_form_data(self.config)
        self._query = q


@register("adtkd-clinical-pictures")
class ADTKDClinicalPicturesExporter(Exporter):
    def setup(self):
        d = demographics_column_factory(self.config)
        self._columns = [
            column("id"),
            column("patient_id"),
            column("picture_date"),
            column("gout"),
            column("gout_date"),
            column("family_gout"),
            column("family_gout_relatives"),
            column("thp"),
            column("uti"),
            d("comments", anonymised_getter=None),
        ]
        self._columns.extend(get_meta_columns(self.config))
        q = queries.get_adtkd_clinical_pictures(self.config)
        self._query = q