class Outcome(db.Model, Base): """ Outcome entity. :param kf_id: Unique id given by the Kid's First DCC :param created_at: Time of object creation :param modified_at: Last time of object modification :param external_id: Name given to outcome by contributor :param vital_status: Vital status of the participant :param disease_related: true if Deceased and cause of death was disease related , false if Deceasedand cause of death was disease related, Not Reported :param age_at_event_days: Age at the time of outcome occured in number of days since birth. """ __tablename__ = 'outcome' __prefix__ = 'OC' external_id = db.Column(db.Text(), doc='external id used by contributor') vital_status = db.Column(db.Text(), doc='The vital status reported') disease_related = db.Column(db.Text()) age_at_event_days = db.Column(db.Integer(), doc='Age at the time of event occurred in ' 'number of days since birth.') participant_id = db.Column(KfId(), db.ForeignKey('participant.kf_id'), nullable=False, doc='kf_id of the participant this outcome was ' 'reported for')
class Investigator(db.Model, Base): """ Study entity representing the Investigator. :param kf_id: Unique id given by the Kid's First DCC :param created_at: Time of object creation :param modified_at: Last time of object modification :param external_id: Name given to investigator by contributor :param name: Name of the investigator :param institution: institution of the investigator """ __tablename__ = 'investigator' __prefix__ = 'IG' external_id = db.Column(db.Text(), doc='external id used by contributor') name = db.Column(db.Text(), doc='The name of the investigator') institution = db.Column(db.Text(), doc='The name of the investigator\'s institution') studies = db.relationship(Study, backref=db.backref('investigator', lazy=True), doc='kf_id of the studies belonging to this ' 'investigator') def __repr__(self): return '<Investigator {}>'.format(self.kf_id)
class ReadGroup(db.Model, Base): """ ReadGroup entity. :param kf_id: Unique id given by the Kid's First DCC :param external_id: Name given to sequencing experiment by contributor :param paired_end: The direction of the read :param flow_cell: The identifier for the group's flow cell :param lane_number: The group's lane :param quality_scale: The quality score encoding of the fastq file """ __tablename__ = 'read_group' __prefix__ = 'RG' external_id = db.Column(db.Text(), nullable=True, doc='Name given to read group by the contributor') flow_cell = db.Column(db.Text(), doc='The identifier of the group\'s flow cell') lane_number = db.Column(db.Float(), doc='The group\'s lane') quality_scale = db.Column(db.Text(), doc='The scale used to encode quality scores') genomic_files = association_proxy( 'read_group_genomic_files', 'genomic_file', creator=lambda gf: ReadGroupGenomicFile(genomic_file=gf)) read_group_genomic_files = db.relationship('ReadGroupGenomicFile', backref='read_group', cascade='all, delete-orphan')
class Family(db.Model, Base): """ Family entity. :param kf_id: Unique id given by the Kid's First DCC :param external_id: Name given to the family by contributor :param family_type: Denotes type of family examples: duo, trio etc. :param created_at: Time of object creation :param modified_at: Last time of object modification """ __tablename__ = "family" __prefix__ = 'FM' external_id = db.Column(db.Text(), doc='ID used by external study') family_type = db.Column(db.Text(), doc='Denotes type of family') participants = db.relationship(Participant, backref='family')
class BiospecimenDiagnosis(db.Model, Base): """ Represents association table between biospecimen table and diagnosis table. Contains all biospecimen, diagnosis combiniations. :param kf_id: Unique id given by the Kid's First DCC :param created_at: Time of object creation :param modified_at: Last time of object modification """ __tablename__ = 'biospecimen_diagnosis' __prefix__ = 'BD' __table_args__ = (db.UniqueConstraint('diagnosis_id', 'biospecimen_id'), ) diagnosis_id = db.Column(KfId(), db.ForeignKey('diagnosis.kf_id'), nullable=False) biospecimen_id = db.Column(KfId(), db.ForeignKey('biospecimen.kf_id'), nullable=False) external_id = db.Column(db.Text(), doc='external id used by contributor') biospecimen = db.relationship(Biospecimen, backref=db.backref( 'biospecimen_diagnoses', cascade='all, delete-orphan')) diagnosis = db.relationship(Diagnosis, backref=db.backref( 'biospecimen_diagnoses', cascade='all, delete-orphan'))
class CavaticaTask(db.Model, Base): """ CavaticaTask entity represents an executed Cavatica task :param kf_id: Unique id given by the Kid's First DCC :param created_at: Time of object creation :param modified_at: Last time of object modification :param name: Name of cavatica_task :param external_cavatica_task_id: Id of executed task assigned by Cavatica """ __tablename__ = 'cavatica_task' __prefix__ = 'CT' external_cavatica_task_id = db.Column(UUID(as_uuid=True), doc='Id assigned to Cavatica task' 'by Cavatica') name = db.Column(db.Text(), doc='Name given to Cavatica task by user') cavatica_app_id = db.Column(KfId(), db.ForeignKey('cavatica_app.kf_id'), doc='Id for the Cavatica app to which this ' 'task belongs') genomic_files = association_proxy( 'cavatica_task_genomic_files', 'genomic_file', creator=lambda genomic_file: CavaticaTaskGenomicFile( genomic_file=genomic_file, is_input=genomic_file.is_harmonized)) cavatica_task_genomic_files = db.relationship('CavaticaTaskGenomicFile', backref='cavatica_task', cascade='all, delete-orphan')
class SequencingCenter(db.Model, Base): """ SequencingExperiment entity. :param kf_id: Unique id given by the Kid's First DCC :param external_id: Name given to sequencing center by contributor :param name: Name given to sequencing center by contributor """ __tablename__ = 'sequencing_center' __prefix__ = 'SC' external_id = db.Column(db.Text(), doc='external id used by contributor') name = db.Column(db.Text(), nullable=False, unique=True, doc='Name given to sequencing center by contributor') sequencing_experiments = db.relationship(SequencingExperiment, backref=db.backref( 'sequencing_center', lazy=True)) biospecimens = db.relationship(Biospecimen, backref=db.backref('sequencing_center', lazy=True))
class Phenotype(db.Model, Base): """ Phenotype entity. :param kf_id: Unique id given by the Kid's First DCC :param created_at: Time of object creation :param modified_at: Last time of object modification :param external_id: Name given to phenotype by contributor :param source_text_phenotype: Name given to Phenotype by contributor :param hpo_id_phenotype: The ID of the term from the Human Phenotype Ontology which represents a harmonized phenotype :param snomed_id_phenotype: The ID of the term from Systematized Nomenclature of Medicine -- Clinical Terms which encodes clinical terminology :param observed: whether phenotype is negative or positive :param age_at_event_days: Age at the time phenotype was observed, expressed in number of days since birth """ __tablename__ = 'phenotype' __prefix__ = 'PH' external_id = db.Column(db.Text(), doc='external id used by contributor') source_text_phenotype = db.Column(db.Text(), doc='Name given to Phenotype by ' 'contributor') hpo_id_phenotype = db.Column(db.Text(), doc='The ID of the term from Human Phenotype ' 'Ontology which represents a harmonized' ' phenotype') snomed_id_phenotype = db.Column(db.Text(), doc='The ID of the term from Systematized ' 'Nomenclature of Medicine --Clinical Terms' ' which encodes clinical terminology') observed = db.Column(db.Text(), doc='whether phenotype is negative or positive') age_at_event_days = db.Column(db.Integer(), doc='Age at the time of event occurred in ' 'number of days since birth') participant_id = db.Column(KfId(), db.ForeignKey('participant.kf_id'), nullable=False)
class CavaticaApp(db.Model, Base): """ CavaticaApp entity. :param kf_id: Unique id given by the Kid's First DCC :param external_cavatica_app_id: Id given to Cavatica app by user :param name: Name given to Cavatica app by user :param revision: Revision number of the Cavatica app :param github_commit_url: GitHub URL to the last git commit made for app """ __tablename__ = 'cavatica_app' __prefix__ = 'CA' external_cavatica_app_id = db.Column( db.Text(), doc='Id given to Cavatica app by Cavatica user') name = db.Column(db.Text(), doc='Name given to Cavatica app by Cavatica user') revision = db.Column(db.Integer(), doc='Revision number of the' ' Cavatica app assigned by Cavatica user') github_commit_url = db.Column(db.Text(), doc='Link to git commit on GitHub') tasks = db.relationship(Task, backref='cavatica_app')
class Study(db.Model, Base): """ Study entity representing the dbGaP study. :param kf_id: Unique id given by the Kid's First DCC :param created_at: Time of object creation :param modified_at: Last time of object modification :param data_access_authority: Name of organization which governs data access :param external_id: dbGaP accession number :param version: dbGaP version :param name: Name or title of study :short_name: Short name for study :param attribution: Link to attribution prose provided by dbGaP :param release_status: Release status of the study """ __tablename__ = 'study' __prefix__ = 'SD' data_access_authority = db.Column(db.Text(), nullable=False, default='dbGaP') external_id = db.Column(db.Text(), nullable=False, doc='dbGaP accession number') version = db.Column(db.Text(), doc='dbGaP version') name = db.Column(db.Text(), doc='Name or title of study') short_name = db.Column(db.Text(), doc='Short name for study') attribution = db.Column(db.Text(), doc='Link to attribution prose provided by dbGaP') release_status = db.Column(db.Text(), doc='Release status of the study') participants = db.relationship(Participant, cascade="all, delete-orphan", backref='study') investigator_id = db.Column(KfId(), db.ForeignKey('investigator.kf_id')) study_files = db.relationship(StudyFile, cascade="all, delete-orphan", backref='study') def __repr__(self): return '<Study {}>'.format(self.kf_id)
class ReadGroupGenomicFile(db.Model, Base): """ Represents association table between read_group table and genomic_file table. Contains all read_group, genomic_file combiniations. :param kf_id: Unique id given by the Kid's First DCC :param created_at: Time of object creation :param modified_at: Last time of object modification """ __tablename__ = 'read_group_genomic_file' __prefix__ = 'RF' __table_args__ = (db.UniqueConstraint( 'read_group_id', 'genomic_file_id', ), ) read_group_id = db.Column(KfId(), db.ForeignKey('read_group.kf_id'), nullable=False) genomic_file_id = db.Column(KfId(), db.ForeignKey('genomic_file.kf_id'), nullable=False) external_id = db.Column(db.Text(), doc='external id used by contributor')
class Diagnosis(db.Model, Base): """ Diagnosis entity. :param _id: Unique id assigned by RDBMS :param kf_id: Unique id given by the Kid's First DCC :param created_at: Time of object creation :param modified_at: Last time of object modification :param external_id: Name given to diagnosis by contributor :param source_text_diagnosis: Diagnosis of the participant :param diagnosis_category: High level diagnosis categorization :param source_text_tumor_location: Location of the tumor :param age_at_event_days: Age at the time of diagnosis expressed in number of days since birth :param mondo_id_diagnosis: The ID of the term from the Monary Disease Ontology which represents a harmonized diagnosis :param icd_id_diagnosis: The ID of the term from the International Classification of Diseases which represents a harmonized diagnosis :param uberon_id_tumor_location: The ID of the term from Uber-anatomy ontology which represents harmonized anatomical ontologies :param ncit_id_diagnosis: The ID term from the National Cancer Institute Thesaurus which represents a harmonized diagnosis :param spatial_descriptor: Ontology term that harmonizes the spatial concepts from Biological Spatial Ontology """ __tablename__ = 'diagnosis' __prefix__ = 'DG' external_id = db.Column(db.Text(), doc='external id used by contributor') source_text_diagnosis = db.Column(db.Text(), doc='the pathological diagnosis') diagnosis_category = db.Column(db.Text(), doc='High level diagnosis categorization') source_text_tumor_location = db.Column(db.Text(), doc='location of the tumor') age_at_event_days = db.Column(db.Integer(), doc='Age at the time of event occurred in ' 'number of days since birth') mondo_id_diagnosis = db.Column(db.Text(), doc='The ID of the term from the Monary ' 'Disease Ontology which represents a' ' harmonized diagnosis') icd_id_diagnosis = db.Column(db.Text(), doc='The ID of the term from the' ' International Classification of Diseases' ' which represents harmonized diagnosis') uberon_id_tumor_location = db.Column(db.Text(), doc='The ID of the term from Uber ' 'anatomy ontology which represents' ' harmonized anatomical ontologies') ncit_id_diagnosis = db.Column(db.Text(), doc='The ID term from the National Cancer' ' Institute Thesaurus which represents a' ' harmonized diagnosis') spatial_descriptor = db.Column(db.Text(), doc='Ontology term that harmonizes the' 'spatial concepts from Biological Spatial' ' Ontology') participant_id = db.Column(KfId(), db.ForeignKey('participant.kf_id'), doc='the participant who was diagnosed', nullable=False)
class Participant(db.Model, Base): """ Participant entity. :param kf_id: Unique id given by the Kid's First DCC :param external_id: Name given to participant by contributor :param family_id: Id for the participants grouped by family :param is_proband: Denotes whether participant is proband of study :param race: Race of participant :param ethnicity: Ethnicity of participant :param gender: Self reported gender of participant :param affected_status: Denotes whether participant is affected :param diagnosis_category: High level diagnosis categorization :param created_at: Time of object creation :param modified_at: Last time of object modification """ __tablename__ = 'participant' __prefix__ = 'PT' external_id = db.Column(db.Text(), doc='ID used by external study') family_id = db.Column(KfId(), db.ForeignKey('family.kf_id'), nullable=True, doc='Id for the participants grouped by family') is_proband = db.Column( db.Boolean(), doc='Denotes whether participant is proband of study') race = db.Column(db.Text(), doc='The race of the participant') ethnicity = db.Column(db.Text(), doc='The ethnicity of the participant') gender = db.Column(db.Text(), doc='The gender of the participant') affected_status = db.Column(db.Boolean(), doc='Denotes whether participant is affected') diagnosis_category = db.Column(db.Text(), doc='High level diagnosis categorization') species = db.Column(db.Text(), default='H**o sapiens', doc='The species of the research particpant') diagnoses = db.relationship(Diagnosis, cascade='all, delete-orphan', backref=db.backref('participant', lazy=True)) biospecimens = db.relationship(Biospecimen, backref='participant', cascade='all, delete-orphan') outcomes = db.relationship(Outcome, cascade='all, delete-orphan', backref=db.backref('participant', lazy=True)) phenotypes = db.relationship(Phenotype, cascade='all, delete-orphan', backref=db.backref('participant', lazy=True)) study_id = db.Column(KfId(), db.ForeignKey('study.kf_id'), nullable=False) alias_group_id = db.Column(KfId(), db.ForeignKey('alias_group.kf_id')) def add_alias(self, pt): """ A convenience method to make participant 'pt' an alias of participant 'self'. There are 4 cases to consider: 1) Participant pt and self have not been assigned an alias group. Create a new alias group and add both particpants to it. 2) Participant pt does not have an alias group, but participant self does. Add pt to self's alias group. 3) Participant self does not have an alias group but particpant pt does. Add self to pt's alias group 4) Both participants already have an alias group. Find which particpant has the smaller alias group and merge all particpants in the smaller group into the larger group ** NOTE ** A particpant's aliases can also be created manually by direct manipulation of the particpants in an AliasGroup or the particpant's alias_group_id. However, then it is completely up to the user to ensure all aliases are in the right group and there aren't redundant groups that exist. """ # Neither particpant has an alias group yet if (not pt.alias_group) and (not self.alias_group): g = AliasGroup() g.participants.extend([self, pt]) # Self belongs to alias group, pt does not elif (not pt.alias_group) and (self.alias_group): self.alias_group.particpants.append(pt) # pt belongs to an alias group, self does not elif pt.alias_group and (not self.alias_group): pt.alias_group.particpants.append(self) # Both particpants belong to two different alias groups elif pt.alias_group and self.alias_group: # Find smaller alias group first c1 = (Participant.query.filter_by( alias_group_id=self.alias_group_id).count()) c2 = (Participant.query.filter_by( alias_group_id=pt.alias_group_id).count()) smaller_alias_group = self.alias_group larger_alias_group = pt.alias_group if c2 <= c1: larger_alias_group = self.alias_group smaller_alias_group = pt.alias_group # Merge smaller alias group with larger alias group # aka, change all participants' alias_group_id in the smaller group # to be the alias_group_id of the larger group for p in (db.session.query(Participant).filter( Participant.alias_group_id == smaller_alias_group.kf_id)): p.alias_group = larger_alias_group # Delete old alias group db.session.delete(smaller_alias_group) @property def aliases(self): """ Retrieve aliases of participant Return all participants with same alias group id """ if self.alias_group: return [ pt for pt in Participant.query.filter( and_(Participant.alias_group_id == self.alias_group_id), Participant.kf_id != self.kf_id) ] else: return [] def __repr__(self): return '<Participant {}>'.format(self.kf_id)
class SequencingExperiment(db.Model, Base): """ SequencingExperiment entity. :param kf_id: Unique id given by the Kid's First DCC :param external_id: Name given to sequencing experiment by contributor :param experiment_date : Date of the sequencing experiment conducted :param experiment_strategy: Text term that represents the library strategy :param library_name: Text term that represents the name of the library :param library_strand: Text term that represents the library stranded-ness :param is_paired_end: Boolean term specifies whether reads have paired end :param platform: Name of the platform used to obtain data :param instrument_model: Text term that represents the model of instrument :param max_insert_size: Maximum size of the fragmented DNA :param mean_insert_size: Mean size of the fragmented DNA :param mean_depth: (Coverage)Describes the amount of sequence data that is available per position in the sequenced genome territory :param total_reads: Total reads of the sequencing experiment :param mean_read_length: Mean lenth of the reads """ __tablename__ = 'sequencing_experiment' __prefix__ = 'SE' external_id = db.Column(db.Text(), nullable=False, doc='Name given to sequencing experiment by' ' contributor') experiment_date = db.Column(db.DateTime(), doc='Date of the sequencing experiment' ' conducted') experiment_strategy = db.Column(db.Text(), nullable=False, doc='Text term that represents the' ' Library strategy') library_name = db.Column(db.Text(), doc='Text term that represents the name of the' ' library') library_strand = db.Column(db.Text(), doc='Text term that represents the' ' library stranded-ness') is_paired_end = db.Column(db.Boolean(), nullable=False, doc='Boolean term specifies whether reads have' ' paired end') platform = db.Column(db.Text(), nullable=False, doc='Name of the platform used to obtain data') instrument_model = db.Column(db.Text(), doc='Text term that represents the model of' ' instrument') max_insert_size = db.Column(db.Integer(), doc='Maximum size of the fragmented DNA') mean_insert_size = db.Column(db.Float(), doc='Mean size of the fragmented DNA') mean_depth = db.Column(db.Float(), doc='Mean depth or coverage describes the amount of' ' sequence data that is available per position in' ' the sequenced genome territory') total_reads = db.Column(db.Integer(), doc='Total reads of the sequencing experiment') mean_read_length = db.Column(db.Float(), doc='Mean lenth of the reads') genomic_files = db.relationship(GenomicFile, backref=db.backref( 'sequencing_experiment', lazy=True)) sequencing_center_id = db.Column(KfId(), db.ForeignKey('sequencing_center.kf_id'), nullable=False, doc='The kf_id of the sequencing center')
class Biospecimen(db.Model, Base): """ Biospecimen entity. :param kf_id: Unique id given by the Kid's First DCC :param external_sample_id: Name given to sample by contributor :param external_aliquot_id: Name given to aliquot by contributor :param composition : The cellular composition of the biospecimen. :param source_text_tissue_type: description of the kind of tissue collected with respect to disease status or proximity to tumor tissue :param source_text_anatomical_site : The name of the primary disease site of the submitted tumor biospecimen :param age_at_event_days: Age at the time biospecimen was acquired, expressed in number of days since birth :param source_text_tumor_descriptor: The kind of disease present in the tumor specimen as related to a specific timepoint :param shipment_origin : The origin of the shipment :param analyte_type: Text term that represents the kind of molecular specimen analyte :param concentration_mg_per_ml: The concentration of an analyte or aliquot extracted from the biospecimen or biospecimen portion, measured in milligrams per milliliter :param volume_ul: The volume in microliters (ul) of the aliquots derived from the analyte(s) shipped for sequencing and characterization :param shipment_date: The date item was shipped in YYYY-MM-DD format :param uberon_id_anatomical_site: The ID of the term from Uber-anatomy ontology which represents harmonized anatomical ontologies :param ncit_id_tissue_type: The ID term from the National Cancer Institute Thesaurus which represents a harmonized tissue_type :param ncit_id_anatomical_site: The ID term from the National Cancer Institute Thesaurus which represents a harmonized anatomical_site :param spatial_descriptor: Ontology term that harmonizes the spatial concepts from Biological Spatial Ontology :param consent_type: Short name of consent :param dbgap_consent_code: Consent classification code from dbgap """ __tablename__ = 'biospecimen' __prefix__ = 'BS' external_sample_id = db.Column(db.Text(), doc='Name given to sample by contributor') external_aliquot_id = db.Column(db.Text(), doc='Name given to aliquot by contributor') source_text_tissue_type = db.Column(db.Text(), doc='Description of the kind of ' 'biospecimen collected') composition = db.Column(db.Text(), doc='The cellular composition of the biospecimen') source_text_anatomical_site = db.Column(db.Text(), doc='The anatomical location of ' 'collection') age_at_event_days = db.Column(db.Integer(), doc='Age at the time of event occurred in ' 'number of days since birth.') source_text_tumor_descriptor = db.Column(db.Text(), doc='Disease present in the ' 'biospecimen') shipment_origin = db.Column(db.Text(), doc='The original site of the aliquot') analyte_type = db.Column(db.Text(), nullable=False, doc='The molecular description of the aliquot') concentration_mg_per_ml = db.Column(db.Float(), doc='The concentration of the aliquot') volume_ul = db.Column(db.Float(), doc='The volume of the aliquot') shipment_date = db.Column(db.DateTime(), doc='The date the aliquot was shipped') uberon_id_anatomical_site = db.Column(db.Text(), doc='The ID of the term from ' 'Uber-anatomy ontology which ' 'represents harmonized anatomical' ' ontologies') ncit_id_tissue_type = db.Column(db.Text(), doc='The ID term from the National Cancer' 'Institute Thesaurus which represents a ' 'harmonized tissue_type') ncit_id_anatomical_site = db.Column(db.Text(), doc='The ID term from the National' 'Cancer Institute Thesaurus which ' 'represents a harmonized' ' anatomical_site') spatial_descriptor = db.Column(db.Text(), doc='Ontology term that harmonizes the' 'spatial concepts from Biological Spatial' ' Ontology') method_of_sample_procurement = db.Column(db.Text(), doc='The method used to procure ' 'the sample used to extract ' 'analyte(s)') participant_id = db.Column(KfId(), db.ForeignKey('participant.kf_id'), nullable=False, doc='The kf_id of the biospecimen\'s donor') sequencing_center_id = db.Column(KfId(), db.ForeignKey('sequencing_center.kf_id'), nullable=False, doc='The kf_id of the sequencing center') consent_type = db.Column(db.Text(), doc='Short name of consent') dbgap_consent_code = db.Column( db.Text(), doc='Consent classification code from dbgap') genomic_files = association_proxy( 'biospecimen_genomic_files', 'genomic_file', creator=lambda genomic_file: BiospecimenGenomicFile(genomic_file= genomic_file)) diagnoses = association_proxy( 'biospecimen_diagnoses', 'diagnosis', creator=lambda dg: BiospecimenDiagnosis(diagnosis=dg)) biospecimen_genomic_files = db.relationship(BiospecimenGenomicFile, backref='biospecimen', cascade='all, delete-orphan')
class FamilyRelationship(db.Model, Base): """ Represents a relationship between two family members. The relationship table represents a directed graph. One or more relationships may exist between any two participants. (P1 -> P2 is different than P2 -> P1) :param kf_id: Primary key given by the Kid's First DCC :param created_at: Time of object creation :param modified_at: Last time of object modification :param external_id: Name given to family_relationship by contributor :param participant1_id: Kids first id of the first Participant in the relationship :param participant2_id: Kids first id of the second Participant in the relationship :param relationship_type: Text describing the nature of the relationship (i.e. father, mother, sister, brother) :param _rel_name: an autogenerated parameter used to ensure that the relationships are not duplicated and the graph is undirected :param source_text_notes: Text notes from source describing the relationship """ __tablename__ = 'family_relationship' __prefix__ = 'FR' __table_args__ = (db.UniqueConstraint( 'participant1_id', 'participant2_id', 'participant1_to_participant2_relation', 'participant2_to_participant1_relation'), ) external_id = db.Column(db.Text(), doc='external id used by contributor') participant1_id = db.Column( KfId(), db.ForeignKey('participant.kf_id'), nullable=False, doc='kf_id of one participant in the relationship') participant2_id = db.Column( KfId(), db.ForeignKey('participant.kf_id'), nullable=False, doc='kf_id of the other participant in the relationship') participant1_to_participant2_relation = db.Column(db.Text(), nullable=False) participant2_to_participant1_relation = db.Column(db.Text()) source_text_notes = db.Column(db.Text(), doc='Text notes from source describing ' 'the relationship') participant1 = db.relationship( Participant, primaryjoin=participant1_id == Participant.kf_id, backref=db.backref('outgoing_family_relationships', cascade='all, delete-orphan')) participant2 = db.relationship( Participant, primaryjoin=participant2_id == Participant.kf_id, backref=db.backref('incoming_family_relationships', cascade='all, delete-orphan')) @classmethod def query_all_relationships(cls, participant_kf_id=None, model_filter_params=None): """ Find all family relationships for a participant :param participant_kf_id: Kids First ID of the participant :param model_filter_params: Filter parameters to the query Given a participant's kf_id, return all of the biological family relationships of the participant and the relationships of the participant's family members. If the participant does not have a family defined, then return all of the immediate/direct family relationships of the participant. """ # Apply model property filter params if model_filter_params is None: model_filter_params = {} q = FamilyRelationship.query.filter_by(**model_filter_params) # Get family relationships and join with participants q = q.join( Participant, or_(FamilyRelationship.participant1, FamilyRelationship.participant2)) # Do this bc query.get() errors out if passed None if participant_kf_id: pt = Participant.query.get(participant_kf_id) family_id = pt.family_id if pt else None # Use family to get all family relationships in participants family if family_id: q = q.filter(Participant.family_id == family_id) # No family provided, use just family relationships # to get only immediate family relationships for participant else: q = q.filter( or_( FamilyRelationship.participant1_id == participant_kf_id, FamilyRelationship.participant2_id == participant_kf_id)) # Don't want duplicates - return unique family relationships q = q.group_by(FamilyRelationship.kf_id) return q def __repr__(self): return '<{} is {} of {}>'.format( self.participant1.kf_id, self.participant1_to_participant2_relation, self.participant2.kf_id)