nci-cidc-api-modules 1.2.29__py3-none-any.whl → 1.2.34__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. cidc_api/models/data.py +4 -0
  2. cidc_api/models/db/stage2/additional_treatment_orm.py +4 -3
  3. cidc_api/models/db/stage2/adverse_event_orm.py +1 -0
  4. cidc_api/models/db/stage2/baseline_clinical_assessment_orm.py +1 -0
  5. cidc_api/models/db/stage2/comorbidity_orm.py +1 -0
  6. cidc_api/models/db/stage2/consent_group_orm.py +1 -0
  7. cidc_api/models/db/stage2/demographic_orm.py +8 -5
  8. cidc_api/models/db/stage2/disease_orm.py +9 -10
  9. cidc_api/models/db/stage2/exposure_orm.py +2 -1
  10. cidc_api/models/db/stage2/gvhd_diagnosis_acute_orm.py +1 -0
  11. cidc_api/models/db/stage2/gvhd_diagnosis_chronic_orm.py +1 -0
  12. cidc_api/models/db/stage2/gvhd_organ_acute_orm.py +1 -0
  13. cidc_api/models/db/stage2/gvhd_organ_chronic_orm.py +1 -0
  14. cidc_api/models/db/stage2/medical_history_orm.py +1 -0
  15. cidc_api/models/db/stage2/other_malignancy_orm.py +7 -6
  16. cidc_api/models/db/stage2/participant_orm.py +5 -4
  17. cidc_api/models/db/stage2/prior_treatment_orm.py +12 -10
  18. cidc_api/models/db/stage2/radiotherapy_dose_orm.py +1 -0
  19. cidc_api/models/db/stage2/response_by_system_orm.py +2 -0
  20. cidc_api/models/db/stage2/response_orm.py +3 -2
  21. cidc_api/models/db/stage2/stem_cell_transplant_orm.py +1 -0
  22. cidc_api/models/db/stage2/surgery_orm.py +1 -0
  23. cidc_api/models/db/stage2/therapy_agent_dose_orm.py +1 -0
  24. cidc_api/models/db/stage2/treatment_orm.py +1 -0
  25. cidc_api/models/db/stage2/trial_orm.py +20 -17
  26. cidc_api/models/models.py +1 -0
  27. cidc_api/models/pydantic/stage2/additional_treatment.py +6 -4
  28. cidc_api/models/pydantic/stage2/adverse_event.py +1 -1
  29. cidc_api/models/pydantic/stage2/base.py +19 -1
  30. cidc_api/models/pydantic/stage2/baseline_clinical_assessment.py +1 -1
  31. cidc_api/models/pydantic/stage2/demographic.py +26 -17
  32. cidc_api/models/pydantic/stage2/disease.py +32 -18
  33. cidc_api/models/pydantic/stage2/exposure.py +2 -2
  34. cidc_api/models/pydantic/stage2/gvhd_diagnosis_acute.py +1 -1
  35. cidc_api/models/pydantic/stage2/gvhd_diagnosis_chronic.py +1 -1
  36. cidc_api/models/pydantic/stage2/medical_history.py +1 -1
  37. cidc_api/models/pydantic/stage2/other_malignancy.py +11 -7
  38. cidc_api/models/pydantic/stage2/participant.py +6 -5
  39. cidc_api/models/pydantic/stage2/prior_treatment.py +12 -12
  40. cidc_api/models/pydantic/stage2/radiotherapy_dose.py +1 -1
  41. cidc_api/models/pydantic/stage2/response.py +4 -10
  42. cidc_api/models/pydantic/stage2/response_by_system.py +9 -6
  43. cidc_api/models/pydantic/stage2/specimen.py +2 -2
  44. cidc_api/models/pydantic/stage2/treatment.py +1 -1
  45. cidc_api/models/pydantic/stage2/trial.py +13 -7
  46. cidc_api/models/types.py +18 -29
  47. {nci_cidc_api_modules-1.2.29.dist-info → nci_cidc_api_modules-1.2.34.dist-info}/METADATA +6 -4
  48. {nci_cidc_api_modules-1.2.29.dist-info → nci_cidc_api_modules-1.2.34.dist-info}/RECORD +51 -51
  49. {nci_cidc_api_modules-1.2.29.dist-info → nci_cidc_api_modules-1.2.34.dist-info}/WHEEL +0 -0
  50. {nci_cidc_api_modules-1.2.29.dist-info → nci_cidc_api_modules-1.2.34.dist-info}/licenses/LICENSE +0 -0
  51. {nci_cidc_api_modules-1.2.29.dist-info → nci_cidc_api_modules-1.2.34.dist-info}/top_level.txt +0 -0
cidc_api/models/data.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from cidc_api.models.pydantic.stage2 import all_models
2
+ from cidc_api.models.db.stage2 import all_models as all_db_models
2
3
 
3
4
  standard_data_categories = [model.__data_category__ for model in all_models if hasattr(model, "__data_category__")]
4
5
 
@@ -13,3 +14,6 @@ class Dataset(dict):
13
14
 
14
15
  # Maps data categories like "treatment" to their associated pydantic model
15
16
  data_category_to_model = {model.__data_category__: model for model in all_models if hasattr(model, "__data_category__")}
17
+ data_category_to_db_model = {
18
+ model.__data_category__: model for model in all_db_models if hasattr(model, "__data_category__")
19
+ }
@@ -11,12 +11,13 @@ class AdditionalTreatmentORM(BaseORM):
11
11
  __tablename__ = "additional_treatment"
12
12
  __repr_attrs__ = ["additional_treatment_id", "participant_id", "description"]
13
13
  __table_args__ = {"schema": "stage2"}
14
+ __data_category__ = "additional_treatment"
14
15
 
15
16
  additional_treatment_id: Mapped[int] = mapped_column(primary_key=True)
16
17
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
17
18
 
18
- days_to_start: Mapped[Optional[NonNegativeInt]]
19
- days_to_end: Mapped[Optional[NonNegativeInt]]
20
- description: Mapped[str]
19
+ additional_treatment_days_to_start: Mapped[Optional[NonNegativeInt]]
20
+ additional_treatment_days_to_end: Mapped[Optional[NonNegativeInt]]
21
+ additional_treatment_description: Mapped[str]
21
22
 
22
23
  participant: Mapped["ParticipantORM"] = relationship(back_populates="additional_treatments", cascade="all, delete")
@@ -22,6 +22,7 @@ class AdverseEventORM(BaseORM):
22
22
  __tablename__ = "adverse_event"
23
23
  __repr_attrs__ = ["adverse_event_id", "participant_id", "event_term"]
24
24
  __table_args__ = {"schema": "stage2"}
25
+ __data_category__ = "adverse_event"
25
26
 
26
27
  adverse_event_id: Mapped[int] = mapped_column(primary_key=True)
27
28
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
@@ -11,6 +11,7 @@ class BaselineClinicalAssessmentORM(BaseORM):
11
11
  __tablename__ = "baseline_clinical_assessment"
12
12
  __repr_attrs__ = ["baseline_clinical_assessment_id", "participant_id"]
13
13
  __table_args__ = {"schema": "stage2"}
14
+ __data_category__ = "baseline_clinical_assessment"
14
15
 
15
16
  baseline_clinical_assessment_id: Mapped[int] = mapped_column(primary_key=True)
16
17
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
@@ -11,6 +11,7 @@ class ComorbidityORM(BaseORM):
11
11
  __tablename__ = "comorbidity"
12
12
  __repr_attrs__ = ["comorbidity_id", "comorbidity_term"]
13
13
  __table_args__ = {"schema": "stage2"}
14
+ __data_category__ = "comorbidity"
14
15
 
15
16
  comorbidity_id: Mapped[int] = mapped_column(primary_key=True)
16
17
  medical_history_id: Mapped[int] = mapped_column(
@@ -16,6 +16,7 @@ class ConsentGroupORM(BaseORM):
16
16
  ),
17
17
  {"schema": "stage2"},
18
18
  )
19
+ __data_category__ = "consent_group"
19
20
 
20
21
  consent_group_id: Mapped[int] = mapped_column(primary_key=True)
21
22
  trial_id: Mapped[str]
@@ -1,7 +1,9 @@
1
1
  from pydantic import NonNegativeFloat, PositiveFloat, PositiveInt
2
+ from typing import List
2
3
 
3
4
  from sqlalchemy import ForeignKey
4
5
  from sqlalchemy.orm import Mapped, mapped_column, relationship
6
+ from sqlalchemy.types import JSON
5
7
 
6
8
  from cidc_api.models.db.base_orm import BaseORM
7
9
  from cidc_api.models.types import (
@@ -21,22 +23,23 @@ class DemographicORM(BaseORM):
21
23
  __tablename__ = "demographic"
22
24
  __repr_attrs__ = ["demographic_id", "participant_id", "age_at_enrollment", "sex"]
23
25
  __table_args__ = {"schema": "stage2"}
26
+ __data_category__ = "demographic"
24
27
 
25
28
  demographic_id: Mapped[int] = mapped_column(primary_key=True)
26
29
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
27
30
  age_at_enrollment: Mapped[PositiveInt | None]
28
31
  age_at_enrollment_units: Mapped[AgeAtEnrollmentUnits | None]
29
- age_90_or_older: Mapped[bool]
32
+ age_90_or_over: Mapped[bool]
30
33
  sex: Mapped[Sex]
31
- race: Mapped[Race]
34
+ race: Mapped[List[Race]] = mapped_column(JSON)
32
35
  ethnicity: Mapped[Ethnicity]
33
36
  height: Mapped[PositiveFloat]
34
37
  height_units: Mapped[HeightUnits]
35
38
  weight: Mapped[PositiveFloat]
36
39
  weight_units: Mapped[WeightUnits]
37
- body_mass_index: Mapped[PositiveFloat]
38
- body_surface_area: Mapped[PositiveFloat]
39
- body_surface_area_units: Mapped[BodySurfaceAreaUnits]
40
+ body_mass_index: Mapped[PositiveFloat | None]
41
+ body_surface_area: Mapped[PositiveFloat | None]
42
+ body_surface_area_units: Mapped[BodySurfaceAreaUnits | None]
40
43
  occupation: Mapped[Occupation | None]
41
44
  income: Mapped[NonNegativeFloat | None]
42
45
  highest_level_of_education: Mapped[Education | None]
@@ -7,7 +7,6 @@ from sqlalchemy.types import JSON
7
7
 
8
8
  from cidc_api.models.db.base_orm import BaseORM
9
9
  from cidc_api.models.types import (
10
- PrimaryDiagnosisDiseaseGroup,
11
10
  TumorGrade,
12
11
  CancerStageSystem,
13
12
  CancerStageSystemVersion,
@@ -30,23 +29,23 @@ class DiseaseORM(BaseORM):
30
29
  "participant_id",
31
30
  ]
32
31
  __table_args__ = {"schema": "stage2"}
32
+ __data_category__ = "disease"
33
33
 
34
34
  disease_id: Mapped[int] = mapped_column(primary_key=True)
35
35
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
36
- primary_diagnosis_disease_group: Mapped[PrimaryDiagnosisDiseaseGroup]
37
36
  primary_disease_site: Mapped[UberonAnatomicalTerm]
38
- morphological_code: Mapped[ICDO3MorphologicalCode]
39
- morphological_term: Mapped[ICDO3MorphologicalTerm]
37
+ morphological_code: Mapped[ICDO3MorphologicalCode | None]
38
+ morphological_term: Mapped[ICDO3MorphologicalTerm | None]
40
39
  cancer_type_description: Mapped[str | None]
41
- days_since_original_diagnosis: Mapped[NonPositiveInt]
40
+ days_since_original_diagnosis: Mapped[NonPositiveInt | None]
42
41
  tumor_grade: Mapped[TumorGrade | None]
43
42
  cancer_stage_system: Mapped[CancerStageSystem]
44
43
  cancer_stage_system_version: Mapped[CancerStageSystemVersion | None] = mapped_column(String, nullable=True)
45
- cancer_stage: Mapped[CancerStage] = mapped_column(String)
46
- t_category: Mapped[TCategory]
47
- n_category: Mapped[NCategory]
48
- m_category: Mapped[MCategory]
49
- metastatic_organ: Mapped[List[UberonAnatomicalTerm]] = mapped_column(JSON, nullable=True)
44
+ cancer_stage: Mapped[CancerStage | None] = mapped_column(String)
45
+ t_category: Mapped[TCategory | None]
46
+ n_category: Mapped[NCategory | None]
47
+ m_category: Mapped[MCategory | None]
48
+ metastatic_organ: Mapped[List[UberonAnatomicalTerm] | None] = mapped_column(JSON, nullable=True)
50
49
  solely_extramedullary_disease: Mapped[YNU]
51
50
  extramedullary_organ: Mapped[List[UberonAnatomicalTerm]] = mapped_column(JSON, nullable=True)
52
51
 
@@ -11,11 +11,12 @@ class ExposureORM(BaseORM):
11
11
  __tablename__ = "exposure"
12
12
  __repr_attrs__ = ["exposure_id", "exposure_type", "carcinogen_exposure"]
13
13
  __table_args__ = {"schema": "stage2"}
14
+ __data_category__ = "exposure"
14
15
 
15
16
  exposure_id: Mapped[int] = mapped_column(primary_key=True)
16
17
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
17
18
 
18
19
  carcinogen_exposure: Mapped[YNU]
19
- exposure_type: Mapped[ExposureType]
20
+ exposure_type: Mapped[ExposureType | None]
20
21
 
21
22
  participant: Mapped["ParticipantORM"] = relationship(back_populates="exposures", cascade="all, delete")
@@ -19,6 +19,7 @@ class GVHDDiagnosisAcuteORM(BaseORM):
19
19
  {"schema": "stage2"},
20
20
  )
21
21
  __repr_attrs__ = ["gvhd_diagnosis_acute_id", "pre_or_post_enrollment"]
22
+ __data_category__ = "gvhd_diagnosis_acute"
22
23
 
23
24
  gvhd_diagnosis_acute_id: Mapped[int] = mapped_column(primary_key=True)
24
25
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
@@ -21,6 +21,7 @@ class GVHDDiagnosisChronicORM(BaseORM):
21
21
  {"schema": "stage2"},
22
22
  )
23
23
  __repr_attrs__ = ["gvhd_diagnosis_chronic_id", "pre_or_post_enrollment"]
24
+ __data_category__ = "gvhd_diagnosis_chronic"
24
25
 
25
26
  gvhd_diagnosis_chronic_id: Mapped[int] = mapped_column(primary_key=True)
26
27
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
@@ -9,6 +9,7 @@ class GVHDOrganAcuteORM(BaseORM):
9
9
  __tablename__ = "gvhd_organ_acute"
10
10
  __repr_attrs__ = ["gvhd_organ_acute_id", "organ"]
11
11
  __table_args__ = {"schema": "stage2"}
12
+ __data_category__ = "gvhd_organ_acute"
12
13
 
13
14
  gvhd_organ_acute_id: Mapped[int] = mapped_column(primary_key=True)
14
15
  gvhd_diagnosis_acute_id: Mapped[int] = mapped_column(
@@ -9,6 +9,7 @@ class GVHDOrganChronicORM(BaseORM):
9
9
  __tablename__ = "gvhd_organ_chronic"
10
10
  __repr_attrs__ = ["gvhd_organ_chronic_id", "organ"]
11
11
  __table_args__ = {"schema": "stage2"}
12
+ __data_category__ = "gvhd_organ_chronic"
12
13
 
13
14
  gvhd_organ_chronic_id: Mapped[int] = mapped_column(primary_key=True)
14
15
  gvhd_diagnosis_chronic_id: Mapped[int] = mapped_column(
@@ -12,6 +12,7 @@ class MedicalHistoryORM(BaseORM):
12
12
  __tablename__ = "medical_history"
13
13
  __repr_attrs__ = ["medical_history_id"]
14
14
  __table_args__ = {"schema": "stage2"}
15
+ __data_category__ = "medical_history"
15
16
 
16
17
  medical_history_id: Mapped[int] = mapped_column(primary_key=True)
17
18
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
@@ -12,18 +12,19 @@ class OtherMalignancyORM(BaseORM):
12
12
  __tablename__ = "other_malignancy"
13
13
  __repr_attrs__ = ["other_malignancy_id", "primary_disease_site"]
14
14
  __table_args__ = {"schema": "stage2"}
15
+ __data_category__ = "other_malignancy"
15
16
 
16
17
  other_malignancy_id: Mapped[int] = mapped_column(primary_key=True)
17
18
  medical_history_id: Mapped[int] = mapped_column(
18
19
  ForeignKey("stage2.medical_history.medical_history_id", ondelete="CASCADE")
19
20
  )
20
21
 
21
- primary_disease_site: Mapped[UberonAnatomicalTerm]
22
- morphological_code: Mapped[Optional[ICDO3MorphologicalCode]]
23
- morphological_term: Mapped[Optional[ICDO3MorphologicalTerm]]
24
- malignancy_description: Mapped[Optional[str]]
25
- days_since_diagnosis: Mapped[Optional[NonPositiveInt]]
26
- malignancy_status: Mapped[Optional[MalignancyStatus]]
22
+ other_malignancy_primary_disease_site: Mapped[UberonAnatomicalTerm]
23
+ other_malignancy_morphological_code: Mapped[Optional[ICDO3MorphologicalCode]]
24
+ other_malignancy_morphological_term: Mapped[Optional[ICDO3MorphologicalTerm]]
25
+ other_malignancy_description: Mapped[Optional[str]]
26
+ other_malignancy_days_since_diagnosis: Mapped[Optional[NonPositiveInt]]
27
+ other_malignancy_status: Mapped[Optional[MalignancyStatus]]
27
28
 
28
29
  medical_history: Mapped["MedicalHistoryORM"] = relationship(
29
30
  back_populates="other_malignancies", cascade="all, delete"
@@ -4,7 +4,7 @@ from sqlalchemy import ForeignKey, ForeignKeyConstraint
4
4
  from sqlalchemy.orm import Mapped, mapped_column, relationship
5
5
 
6
6
  from cidc_api.models.db.base_orm import BaseORM
7
- from cidc_api.models.types import OffStudyReason
7
+ from cidc_api.models.types import OffStudyReason, YNU
8
8
 
9
9
 
10
10
  class ParticipantORM(BaseORM):
@@ -16,17 +16,18 @@ class ParticipantORM(BaseORM):
16
16
  ),
17
17
  {"schema": "stage2"},
18
18
  )
19
+ __data_category__ = "participant"
19
20
 
20
21
  participant_id: Mapped[int] = mapped_column(primary_key=True)
21
22
  trial_id: Mapped[str]
22
23
  version: Mapped[str]
23
24
 
24
- native_participant_id: Mapped[str]
25
- cimac_participant_id: Mapped[str] = mapped_column(unique=True)
25
+ native_participant_id: Mapped[str | None]
26
+ cimac_participant_id: Mapped[str | None]
26
27
  consent_group_id: Mapped[Optional[int]] = mapped_column(
27
28
  ForeignKey("stage2.consent_group.consent_group_id", ondelete="CASCADE")
28
29
  )
29
- off_study: Mapped[bool]
30
+ off_study: Mapped[YNU]
30
31
  off_study_reason: Mapped[Optional[OffStudyReason]]
31
32
  off_study_reason_other: Mapped[Optional[str]]
32
33
 
@@ -1,8 +1,9 @@
1
- from typing import Optional
1
+ from typing import Optional, List
2
2
 
3
- from pydantic import NonPositiveInt, NonNegativeInt
3
+ from pydantic import NonPositiveInt, NegativeInt
4
4
  from sqlalchemy import ForeignKey
5
5
  from sqlalchemy.orm import Mapped, mapped_column, relationship
6
+ from sqlalchemy.types import JSON
6
7
 
7
8
  from cidc_api.models.db.base_orm import BaseORM
8
9
  from cidc_api.models.types import PriorTreatmentType, ConditioningRegimenType, StemCellDonorType
@@ -12,17 +13,18 @@ class PriorTreatmentORM(BaseORM):
12
13
  __tablename__ = "prior_treatment"
13
14
  __repr_attrs__ = ["prior_treatment_id", "type"]
14
15
  __table_args__ = {"schema": "stage2"}
16
+ __data_category__ = "prior_treatment"
15
17
 
16
18
  prior_treatment_id: Mapped[int] = mapped_column(primary_key=True)
17
19
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
18
20
 
19
- days_to_start: Mapped[Optional[NonPositiveInt]]
20
- days_to_end: Mapped[Optional[NonPositiveInt]]
21
- type: Mapped[PriorTreatmentType]
22
- description: Mapped[Optional[str]]
23
- best_response: Mapped[Optional[str]]
24
- conditioning_regimen_type: Mapped[Optional[ConditioningRegimenType]]
25
- stem_cell_donor_type: Mapped[Optional[StemCellDonorType]]
26
- days_from_transplant_to_treatment_initiation: Mapped[Optional[NonNegativeInt]]
21
+ prior_treatment_days_to_start: Mapped[Optional[NonPositiveInt]]
22
+ prior_treatment_days_to_end: Mapped[Optional[NonPositiveInt]]
23
+ prior_treatment_type: Mapped[List[PriorTreatmentType]] = mapped_column(JSON, nullable=False)
24
+ prior_treatment_description: Mapped[Optional[str]]
25
+ prior_treatment_best_response: Mapped[Optional[str]]
26
+ prior_treatment_conditioning_regimen_type: Mapped[Optional[ConditioningRegimenType]]
27
+ prior_treatment_stem_cell_donor_type: Mapped[Optional[StemCellDonorType]]
28
+ prior_treatment_days_to_prior_transplant: Mapped[Optional[NegativeInt]]
27
29
 
28
30
  participant: Mapped["ParticipantORM"] = relationship(back_populates="prior_treatments", cascade="all, delete")
@@ -18,6 +18,7 @@ class RadiotherapyDoseORM(BaseORM):
18
18
  __tablename__ = "radiotherapy_dose"
19
19
  __repr_attrs__ = ["radiotherapy_dose_id", "procedure"]
20
20
  __table_args__ = {"schema": "stage2"}
21
+ __data_category__ = "radiotherapy_dose"
21
22
 
22
23
  radiotherapy_dose_id: Mapped[int] = mapped_column(primary_key=True)
23
24
  treatment_id: Mapped[int] = mapped_column(ForeignKey("stage2.treatment.treatment_id", ondelete="CASCADE"))
@@ -10,6 +10,7 @@ class ResponseBySystemORM(BaseORM):
10
10
  __tablename__ = "response_by_system"
11
11
  __repr_attrs__ = ["response_by_system_id", "participant_id"]
12
12
  __table_args__ = {"schema": "stage2"}
13
+ __data_category__ = "response_by_system"
13
14
 
14
15
  response_by_system_id: Mapped[int] = mapped_column(primary_key=True)
15
16
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
@@ -17,6 +18,7 @@ class ResponseBySystemORM(BaseORM):
17
18
  response_system_version: Mapped[ResponseSystemVersion] = mapped_column(String)
18
19
  best_overall_response: Mapped[BestOverallResponse] = mapped_column(String)
19
20
  response_duration: Mapped[PositiveInt | None]
21
+ duration_of_stable_disease: Mapped[PositiveInt | None]
20
22
  durable_clinical_benefit: Mapped[bool | None]
21
23
  days_to_first_response: Mapped[PositiveInt | None]
22
24
  days_to_best_response: Mapped[PositiveInt | None]
@@ -11,17 +11,18 @@ class ResponseORM(BaseORM):
11
11
  __tablename__ = "response"
12
12
  __repr_attrs__ = ["response_id", "participant_id"]
13
13
  __table_args__ = {"schema": "stage2"}
14
+ __data_category__ = "response"
14
15
 
15
16
  response_id: Mapped[int] = mapped_column(primary_key=True)
16
17
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
17
18
  survival_status: Mapped[SurvivalStatus]
18
- overall_survival: Mapped[NonNegativeInt | None]
19
+ overall_survival: Mapped[NonNegativeInt]
19
20
  abscopal_response: Mapped[YNUNA | None]
20
21
  pathological_complete_response: Mapped[YNUNA | None]
21
22
  days_to_death: Mapped[NonNegativeInt | None]
22
23
  cause_of_death: Mapped[CauseOfDeath | None]
23
24
  evaluable_for_toxicity: Mapped[bool]
24
25
  evaluable_for_efficacy: Mapped[bool]
25
- days_to_last_follow_up: Mapped[NonNegativeInt | None]
26
+ days_to_last_vital_status: Mapped[NonNegativeInt | None]
26
27
 
27
28
  participant: Mapped["ParticipantORM"] = relationship(back_populates="response", cascade="all, delete")
@@ -12,6 +12,7 @@ class StemCellTransplantORM(BaseORM):
12
12
  __tablename__ = "stem_cell_transplant"
13
13
  __repr_attrs__ = ["stem_cell_transplant_id"]
14
14
  __table_args__ = {"schema": "stage2"}
15
+ __data_category__ = "stem_cell_transplant"
15
16
 
16
17
  stem_cell_transplant_id: Mapped[int] = mapped_column(primary_key=True)
17
18
  treatment_id: Mapped[int] = mapped_column(ForeignKey("stage2.treatment.treatment_id", ondelete="CASCADE"))
@@ -12,6 +12,7 @@ class SurgeryORM(BaseORM):
12
12
  __tablename__ = "surgery"
13
13
  __repr_attrs__ = ["surgery_id", "procedure"]
14
14
  __table_args__ = {"schema": "stage2"}
15
+ __data_category__ = "surgery"
15
16
 
16
17
  surgery_id: Mapped[int] = mapped_column(primary_key=True)
17
18
  treatment_id: Mapped[int] = mapped_column(ForeignKey("stage2.treatment.treatment_id", ondelete="CASCADE"))
@@ -12,6 +12,7 @@ class TherapyAgentDoseORM(BaseORM):
12
12
  __tablename__ = "therapy_agent_dose"
13
13
  __repr_attrs__ = ["therapy_agent_dose_id", "therapy_agent_name"]
14
14
  __table_args__ = {"schema": "stage2"}
15
+ __data_category__ = "therapy_agent_dose"
15
16
 
16
17
  therapy_agent_dose_id: Mapped[int] = mapped_column(primary_key=True)
17
18
  treatment_id: Mapped[int] = mapped_column(ForeignKey("stage2.treatment.treatment_id", ondelete="CASCADE"))
@@ -11,6 +11,7 @@ class TreatmentORM(BaseORM):
11
11
  __tablename__ = "treatment"
12
12
  __repr_attrs__ = ["treatment_id", "participant_id", "treatment_description"]
13
13
  __table_args__ = {"schema": "stage2"}
14
+ __data_category__ = "treatment"
14
15
 
15
16
  treatment_id: Mapped[int] = mapped_column(primary_key=True)
16
17
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
@@ -6,35 +6,38 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
6
6
  from sqlalchemy.types import JSON
7
7
 
8
8
  from cidc_api.models.db.base_orm import BaseORM
9
- from cidc_api.models.types import TrialStatus, AssayType, TrialOrganization, TrialFundingAgency
9
+ from cidc_api.models.types import AssayType, TrialOrganization, TrialFundingAgency, AgeGroup
10
10
 
11
11
 
12
12
  class TrialORM(BaseORM):
13
13
  __tablename__ = "trial"
14
14
  __repr_attrs__ = ["trial_id", "version"]
15
15
  __table_args__ = {"schema": "stage2"}
16
+ __data_category__ = "study"
16
17
 
17
18
  trial_id: Mapped[str] = mapped_column(primary_key=True)
18
19
  version: Mapped[str] = mapped_column(primary_key=True)
19
20
 
20
- nct_id: Mapped[Optional[str]]
21
- nci_id: Mapped[Optional[str]]
22
- trial_name: Mapped[Optional[str]]
23
- trial_type: Mapped[Optional[str]]
24
- trial_description: Mapped[Optional[str]]
25
- trial_organization: Mapped[Optional[TrialOrganization]]
26
- grant_or_affiliated_network: Mapped[Optional[TrialFundingAgency]]
27
- trial_status: Mapped[TrialStatus]
28
- biobank_institution_id: Mapped[Optional[int]]
29
- justification: Mapped[Optional[str]]
21
+ primary_endpoint: Mapped[str | None]
22
+ age_group: Mapped[List[AgeGroup]] = mapped_column(JSON, nullable=True)
23
+ study_population: Mapped[str | None]
24
+ nct_id: Mapped[str | None]
25
+ nci_id: Mapped[str | None]
26
+ trial_name: Mapped[str | None]
27
+ trial_type: Mapped[str | None]
28
+ trial_description: Mapped[str | None]
29
+ trial_organization: Mapped[TrialOrganization | None]
30
+ grant_or_affiliated_network: Mapped[TrialFundingAgency | None]
31
+ biobank_institution_id: Mapped[int | None]
32
+ justification: Mapped[str | None]
30
33
  dates_of_conduct_start: Mapped[datetime]
31
- dates_of_conduct_end: Mapped[Optional[datetime]]
32
- schema_file_id: Mapped[Optional[int]]
33
- biomarker_plan: Mapped[Optional[str]]
34
- data_sharing_plan: Mapped[Optional[str]]
35
- expected_assays: Mapped[Optional[List[AssayType]]] = mapped_column(JSON, nullable=True)
34
+ dates_of_conduct_end: Mapped[datetime | None]
35
+ schema_file_id: Mapped[int | None]
36
+ biomarker_plan: Mapped[str | None]
37
+ data_sharing_plan: Mapped[str | None]
38
+ expected_assays: Mapped[List[AssayType]] = mapped_column(JSON, nullable=True)
36
39
  is_liquid_tumor_trial: Mapped[bool]
37
- dbgap_study_accession: Mapped[Optional[str]]
40
+ dbgap_study_accession: Mapped[str | None]
38
41
 
39
42
  biobank: Mapped["InstitutionORM"] = relationship(back_populates="trial")
40
43
  schema: Mapped[Optional["FileORM"]] = relationship(back_populates="trial", viewonly=True)
cidc_api/models/models.py CHANGED
@@ -3399,6 +3399,7 @@ class PreprocessedFiles(CommonColumns):
3399
3399
  (cls.file_category == latest_subquery.c.file_category)
3400
3400
  & (cls._created == latest_subquery.c.latest_created),
3401
3401
  )
3402
+ .order_by(cls.file_category)
3402
3403
  .all()
3403
3404
  )
3404
3405
  return latest_files
@@ -10,14 +10,16 @@ class AdditionalTreatment(Base):
10
10
  additional_treatment_id: int | None = None
11
11
 
12
12
  # The unique internal identifier for the associated Participant record
13
- participant_id: int | None = None
13
+ participant_id: str | None = (
14
+ None # TODO: fix all stage2 models for participant_id to not be nullable, after s1 models are complete
15
+ )
14
16
 
15
17
  # Number of days from the enrollment date to the first recorded administration or occurrence of the treatment modality.
16
- days_to_start: NonNegativeInt | None = None
18
+ additional_treatment_days_to_start: NonNegativeInt | None = None
17
19
 
18
20
  # Number of days from the enrollment date to the last recorded administration or occurrence of the treatment modality.
19
- days_to_end: NonNegativeInt | None = None
21
+ additional_treatment_days_to_end: NonNegativeInt | None = None
20
22
 
21
23
  # Description of the prior treatment such as its full generic name if it is a type of therapy agent, radiotherapy procedure
22
24
  # name and location, or surgical procedure name and location.
23
- description: str
25
+ additional_treatment_description: str
@@ -25,7 +25,7 @@ class AdverseEvent(Base):
25
25
  adverse_event_id: int | None = None
26
26
 
27
27
  # The unique internal identifier of the associated participant
28
- participant_id: int | None = None
28
+ participant_id: str | None = None
29
29
 
30
30
  # The unique internal identifier of the attributed treatment, if any
31
31
  treatment_id: int | None = None
@@ -6,7 +6,11 @@ import copy
6
6
 
7
7
  class Base(BaseModel):
8
8
 
9
- model_config = ConfigDict(validate_assignment=True, from_attributes=True)
9
+ model_config = ConfigDict(
10
+ validate_assignment=True,
11
+ from_attributes=True,
12
+ # extra="forbid" # TODO: enable me one stage1 models are implemented
13
+ )
10
14
 
11
15
  # Validates the new state and updates the object if valid
12
16
  def update(self, **kwargs):
@@ -28,3 +32,17 @@ class Base(BaseModel):
28
32
  except:
29
33
  self.__dict__.update(original_dict)
30
34
  raise
35
+
36
+ @classmethod
37
+ def split_list(cls, val):
38
+ """Listify fields that are multi-valued in input data, e.g. 'lung|kidney'"""
39
+ if type(val) == list:
40
+ return val
41
+ elif type(val) == str:
42
+ if not val:
43
+ return []
44
+ return val.split("|")
45
+ elif val == None:
46
+ return []
47
+ else:
48
+ raise ValueError("Field value must be string or list")
@@ -10,7 +10,7 @@ class BaselineClinicalAssessment(Base):
10
10
  baseline_clinical_assessment_id: int | None = None
11
11
 
12
12
  # The unique identifier for the associated participant
13
- participant_id: int | None = None
13
+ participant_id: str | None = None
14
14
 
15
15
  # The numerical score that represents the functional capabilities of a participant at the
16
16
  # enrollment date using the Eastern Cooperative Oncology Group Performance Status assessment.
@@ -1,6 +1,6 @@
1
- from typing import Self
1
+ from typing import Self, Annotated, List
2
2
 
3
- from pydantic import PositiveInt, NonNegativeFloat, PositiveFloat, model_validator, field_validator
3
+ from pydantic import PositiveInt, NonNegativeFloat, PositiveFloat, model_validator, field_validator, BeforeValidator
4
4
 
5
5
  from .base import Base
6
6
  from cidc_api.models.types import (
@@ -25,7 +25,7 @@ class Demographic(Base):
25
25
 
26
26
  # The unique internal identifier for the associated participant
27
27
  # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=12220014%20and%20ver_nr=1
28
- participant_id: int | None = None
28
+ participant_id: str | None = None
29
29
 
30
30
  # The age of the subject when the subject enrolled in the study.
31
31
  # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=15742605%20and%20ver_nr=1
@@ -34,9 +34,9 @@ class Demographic(Base):
34
34
  # Unit of measurement for the age of the participant. e.g. "Years"
35
35
  age_at_enrollment_units: AgeAtEnrollmentUnits | None = None
36
36
 
37
- # Indicates whether the participant is 90 years old or older. (for PHI purposes)
37
+ # Indicates whether the participant is 90 years old or over. (for PHI purposes)
38
38
  # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=15354920%20and%20ver_nr=1
39
- age_90_or_older: bool
39
+ age_90_or_over: bool
40
40
 
41
41
  # A textual description of a person's sex at birth. e.g. "Male"
42
42
  # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=7572817%20and%20ver_nr=3
@@ -44,7 +44,7 @@ class Demographic(Base):
44
44
 
45
45
  # The race of the participant. e.g. "White"
46
46
  # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=2192199%20and%20ver_nr=1
47
- race: Race
47
+ race: Annotated[List[Race], BeforeValidator(Base.split_list)]
48
48
 
49
49
  # The ethnicity of the participant. e.g. "Hispanic or Latino"
50
50
  # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=2192217%20and%20ver_nr=2
@@ -68,15 +68,15 @@ class Demographic(Base):
68
68
 
69
69
  # The body mass index of the participant at the enrollment date.
70
70
  # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=2006410%20and%20ver_nr=3
71
- body_mass_index: PositiveFloat
71
+ body_mass_index: PositiveFloat | None = None
72
72
 
73
73
  # A decimal number that represents the measure of the 2-dimensional extent of the body surface (i.e., the skin) of the participant at the enrollment date.
74
74
  # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=6606197%20and%20ver_nr=1
75
- body_surface_area: PositiveFloat
75
+ body_surface_area: PositiveFloat | None = None
76
76
 
77
77
  # Unit of measurement for body surface area of the participant at the enrollment date. e.g. "m2"
78
78
  # https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=15114329%20and%20ver_nr=1
79
- body_surface_area_units: BodySurfaceAreaUnits
79
+ body_surface_area_units: BodySurfaceAreaUnits | None = None
80
80
 
81
81
  # The occupation/job category of the participant. e.g. "Manager"
82
82
  # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=6617540%20and%20ver_nr=1
@@ -92,23 +92,32 @@ class Demographic(Base):
92
92
 
93
93
  @model_validator(mode="after")
94
94
  def validate_age_at_enrollment_cr(self) -> Self:
95
- if self.age_90_or_older:
95
+ if self.age_90_or_over:
96
96
  if self.age_at_enrollment or self.age_at_enrollment_units:
97
97
  raise ValueError(
98
- 'If "age_90_or_older" is "Yes" then "age_at_enrollment" and "age_at_enrollment_units" must be blank.'
98
+ 'If "age_90_or_over" is "Yes" then "age_at_enrollment" and "age_at_enrollment_units" must be blank.'
99
99
  )
100
100
  else:
101
101
  if not self.age_at_enrollment or not self.age_at_enrollment_units:
102
102
  raise ValueError(
103
- 'If "age_90_or_older" is "No" then "age_at_enrollment" and "age_at_enrollment_units" are required.'
103
+ 'If "age_90_or_over" is "No" then "age_at_enrollment" and "age_at_enrollment_units" are required.'
104
104
  )
105
105
  return self
106
106
 
107
107
  @model_validator(mode="after")
108
108
  def validate_age_at_enrollment_value(self) -> Self:
109
- age_in_years = (
110
- self.age_at_enrollment if self.age_at_enrollment_units == "Years" else self.age_at_enrollment / 365.25
111
- )
112
- if age_in_years >= 90:
113
- raise ValueError('"age_at_enrollment" cannot represent a value greater than 90 years of age.')
109
+ if not self.age_90_or_over:
110
+ age_in_years = (
111
+ self.age_at_enrollment if self.age_at_enrollment_units == "Years" else self.age_at_enrollment / 365.25
112
+ )
113
+ if age_in_years >= 90:
114
+ raise ValueError('"age_at_enrollment" cannot represent a value greater than 90 years of age.')
115
+ return self
116
+
117
+ @model_validator(mode="after")
118
+ def validate_body_surface_area_units_cr(self) -> Self:
119
+ if self.body_surface_area and not self.body_surface_area_units:
120
+ raise ValueError(
121
+ 'If "body_surface_area" is provided then "body_surface_area_units_other" must also be provided.'
122
+ )
114
123
  return self