omop-constructs 0.2.8__tar.gz → 0.2.10__tar.gz
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.
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/PKG-INFO +1 -1
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/pyproject.toml +1 -1
- omop_constructs-0.2.10/src/omop_constructs/alchemy/events/__init__.py +50 -0
- omop_constructs-0.2.10/src/omop_constructs/alchemy/events/dx_linked_event_mv.py +168 -0
- omop_constructs-0.2.10/src/omop_constructs/alchemy/events/event_factories.py +195 -0
- omop_constructs-0.2.10/src/omop_constructs/alchemy/events/event_queries.py +75 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/README.md +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/__init__.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/__init__.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/adapters.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/concepts/__init__.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/concepts/concept_mappers.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/concepts/concept_standardisation.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/conditions/__init__.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/conditions/condition_joins.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/conditions/condition_mappers.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/episodes/__init__.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/episodes/condition_episode_mv.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/episodes/condition_episode_objects.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/episodes/episode_factories.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/episodes/episode_joins.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/modifiers/__init__.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/modifiers/condition_modifier_join.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/modifiers/condition_modifier_mv.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/modifiers/modifier_factories.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/modifiers/modifier_joins.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/modifiers/modifier_mappers.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/source_factories.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/core/__init__.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/core/base.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/core/constructs.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/core/ddl.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/core/errors.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/core/materialized.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/core/plan.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/core/registry.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/py.typed +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/semantics/__init__.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/semantics/adapters.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/semantics/lookups.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/semantics/runtime_lookups.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/services/__init__.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/services/concept.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/services/person.py +0 -0
- {omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/typing.py +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from .dx_linked_event_mv import (
|
|
2
|
+
WeightDxMV,
|
|
3
|
+
WeightChangeDxMV,
|
|
4
|
+
HeightDxMV,
|
|
5
|
+
BSADxMV,
|
|
6
|
+
CreatinineClearanceDxMV,
|
|
7
|
+
EGFRDxMV,
|
|
8
|
+
FEV1DxMV,
|
|
9
|
+
DistressThermometerDxMV,
|
|
10
|
+
ECOGDxMV,
|
|
11
|
+
SmokingPYHDxMV,
|
|
12
|
+
)
|
|
13
|
+
from .event_factories import measurement_attached_to_condition_episode, episode_relevant_window
|
|
14
|
+
from .event_queries import (
|
|
15
|
+
weight_query,
|
|
16
|
+
weight_change_query,
|
|
17
|
+
height_query,
|
|
18
|
+
bsa_query,
|
|
19
|
+
creatinine_clearance_query,
|
|
20
|
+
est_gfr_query,
|
|
21
|
+
fev1_query,
|
|
22
|
+
distress_thermometer_query,
|
|
23
|
+
ecog_query,
|
|
24
|
+
smoking_pyh_query,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"WeightDxMV",
|
|
29
|
+
"WeightChangeDxMV",
|
|
30
|
+
"HeightDxMV",
|
|
31
|
+
"BSADxMV",
|
|
32
|
+
"CreatinineClearanceDxMV",
|
|
33
|
+
"EGFRDxMV",
|
|
34
|
+
"FEV1DxMV",
|
|
35
|
+
"DistressThermometerDxMV",
|
|
36
|
+
"ECOGDxMV",
|
|
37
|
+
"SmokingPYHDxMV",
|
|
38
|
+
"measurement_attached_to_condition_episode",
|
|
39
|
+
"episode_relevant_window",
|
|
40
|
+
"weight_query",
|
|
41
|
+
"weight_change_query",
|
|
42
|
+
"height_query",
|
|
43
|
+
"bsa_query",
|
|
44
|
+
"creatinine_clearance_query",
|
|
45
|
+
"est_gfr_query",
|
|
46
|
+
"fev1_query",
|
|
47
|
+
"distress_thermometer_query",
|
|
48
|
+
"ecog_query",
|
|
49
|
+
"smoking_pyh_query",
|
|
50
|
+
]
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import sqlalchemy as sa
|
|
2
|
+
import sqlalchemy.orm as so
|
|
3
|
+
from datetime import date
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from orm_loader.helpers import Base
|
|
6
|
+
from ...core.materialized import MaterializedViewMixin
|
|
7
|
+
from ...core.constructs import register_construct
|
|
8
|
+
|
|
9
|
+
from .event_queries import (
|
|
10
|
+
weight_change_dx,
|
|
11
|
+
weight_dx,
|
|
12
|
+
height_dx,
|
|
13
|
+
bsa_dx,
|
|
14
|
+
creat_dx,
|
|
15
|
+
egfr_dx,
|
|
16
|
+
fev1_dx,
|
|
17
|
+
dtherm_dx,
|
|
18
|
+
ecog_dx,
|
|
19
|
+
pyh_dx
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
class ConditionEpisodeMeasurementCols:
|
|
23
|
+
__table_args__ = {"extend_existing": True}
|
|
24
|
+
|
|
25
|
+
mv_id: so.Mapped[int] = so.mapped_column(primary_key=True)
|
|
26
|
+
|
|
27
|
+
person_id: so.Mapped[int] = so.mapped_column(sa.Integer)
|
|
28
|
+
event_id: so.Mapped[int] = so.mapped_column(sa.Integer)
|
|
29
|
+
event_date: so.Mapped[date] = so.mapped_column(sa.Date)
|
|
30
|
+
event_concept_id: so.Mapped[int] = so.mapped_column(sa.Integer)
|
|
31
|
+
event_label: so.Mapped[Optional[str]] = so.mapped_column(sa.String, nullable=True)
|
|
32
|
+
|
|
33
|
+
value_as_number: so.Mapped[Optional[float]] = so.mapped_column(sa.Float, nullable=True)
|
|
34
|
+
unit_concept_id: so.Mapped[Optional[int]] = so.mapped_column(sa.Integer, nullable=True)
|
|
35
|
+
|
|
36
|
+
disease_episode_id: so.Mapped[Optional[int]] = so.mapped_column(sa.Integer, nullable=True)
|
|
37
|
+
disease_episode_concept_id: so.Mapped[Optional[int]] = so.mapped_column(sa.Integer, nullable=True)
|
|
38
|
+
disease_episode_label: so.Mapped[Optional[str]] = so.mapped_column(sa.String, nullable=True)
|
|
39
|
+
|
|
40
|
+
disease_episode_start_date: so.Mapped[Optional[date]] = so.mapped_column(sa.Date, nullable=True)
|
|
41
|
+
disease_episode_end_date: so.Mapped[Optional[date]] = so.mapped_column(sa.Date, nullable=True)
|
|
42
|
+
|
|
43
|
+
episode_delta_days: so.Mapped[Optional[int]] = so.mapped_column(sa.Integer, nullable=True)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@register_construct
|
|
47
|
+
class WeightDxMV(
|
|
48
|
+
ConditionEpisodeMeasurementCols,
|
|
49
|
+
MaterializedViewMixin,
|
|
50
|
+
Base,
|
|
51
|
+
):
|
|
52
|
+
__mv_name__ = "weight_dx_mv"
|
|
53
|
+
__mv_select__ = weight_dx.select()
|
|
54
|
+
__mv_index__ = "person_id"
|
|
55
|
+
__deps__ = ()
|
|
56
|
+
__tablename__ = __mv_name__
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@register_construct
|
|
60
|
+
class WeightChangeDxMV(
|
|
61
|
+
ConditionEpisodeMeasurementCols,
|
|
62
|
+
MaterializedViewMixin,
|
|
63
|
+
Base,
|
|
64
|
+
):
|
|
65
|
+
__mv_name__ = "weight_change_dx_mv"
|
|
66
|
+
__mv_select__ = weight_change_dx.select()
|
|
67
|
+
__mv_index__ = "person_id"
|
|
68
|
+
__deps__ = ()
|
|
69
|
+
__tablename__ = __mv_name__
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@register_construct
|
|
73
|
+
class HeightDxMV(
|
|
74
|
+
ConditionEpisodeMeasurementCols,
|
|
75
|
+
MaterializedViewMixin,
|
|
76
|
+
Base,
|
|
77
|
+
):
|
|
78
|
+
__mv_name__ = "height_dx_mv"
|
|
79
|
+
__mv_select__ = height_dx.select()
|
|
80
|
+
__mv_index__ = "person_id"
|
|
81
|
+
__deps__ = ()
|
|
82
|
+
__tablename__ = __mv_name__
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@register_construct
|
|
86
|
+
class BSADxMV(
|
|
87
|
+
ConditionEpisodeMeasurementCols,
|
|
88
|
+
MaterializedViewMixin,
|
|
89
|
+
Base,
|
|
90
|
+
):
|
|
91
|
+
__mv_name__ = "bsa_dx_mv"
|
|
92
|
+
__mv_select__ = bsa_dx.select()
|
|
93
|
+
__mv_index__ = "person_id"
|
|
94
|
+
__deps__ = ()
|
|
95
|
+
__tablename__ = __mv_name__
|
|
96
|
+
|
|
97
|
+
@register_construct
|
|
98
|
+
class CreatinineClearanceDxMV(
|
|
99
|
+
ConditionEpisodeMeasurementCols,
|
|
100
|
+
MaterializedViewMixin,
|
|
101
|
+
Base,
|
|
102
|
+
):
|
|
103
|
+
__mv_name__ = "creatinine_clearance_dx_mv"
|
|
104
|
+
__mv_select__ = creat_dx.select()
|
|
105
|
+
__mv_index__ = "person_id"
|
|
106
|
+
__deps__ = ()
|
|
107
|
+
__tablename__ = __mv_name__
|
|
108
|
+
|
|
109
|
+
@register_construct
|
|
110
|
+
class EGFRDxMV(
|
|
111
|
+
ConditionEpisodeMeasurementCols,
|
|
112
|
+
MaterializedViewMixin,
|
|
113
|
+
Base,
|
|
114
|
+
):
|
|
115
|
+
__mv_name__ = "egfr_dx_mv"
|
|
116
|
+
__mv_select__ = egfr_dx.select()
|
|
117
|
+
__mv_index__ = "person_id"
|
|
118
|
+
__deps__ = ()
|
|
119
|
+
__tablename__ = __mv_name__
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@register_construct
|
|
123
|
+
class FEV1DxMV(
|
|
124
|
+
ConditionEpisodeMeasurementCols,
|
|
125
|
+
MaterializedViewMixin,
|
|
126
|
+
Base,
|
|
127
|
+
):
|
|
128
|
+
__mv_name__ = "fev1_dx_mv"
|
|
129
|
+
__mv_select__ = fev1_dx.select()
|
|
130
|
+
__mv_index__ = "person_id"
|
|
131
|
+
__deps__ = ()
|
|
132
|
+
__tablename__ = __mv_name__
|
|
133
|
+
|
|
134
|
+
@register_construct
|
|
135
|
+
class DistressThermometerDxMV(
|
|
136
|
+
ConditionEpisodeMeasurementCols,
|
|
137
|
+
MaterializedViewMixin,
|
|
138
|
+
Base,
|
|
139
|
+
):
|
|
140
|
+
__mv_name__ = "dtherm_dx_mv"
|
|
141
|
+
__mv_select__ = dtherm_dx.select()
|
|
142
|
+
__mv_index__ = "person_id"
|
|
143
|
+
__deps__ = ()
|
|
144
|
+
__tablename__ = __mv_name__
|
|
145
|
+
|
|
146
|
+
@register_construct
|
|
147
|
+
class ECOGDxMV(
|
|
148
|
+
ConditionEpisodeMeasurementCols,
|
|
149
|
+
MaterializedViewMixin,
|
|
150
|
+
Base,
|
|
151
|
+
):
|
|
152
|
+
__mv_name__ = "ecog_dx_mv"
|
|
153
|
+
__mv_select__ = ecog_dx.select()
|
|
154
|
+
__mv_index__ = "person_id"
|
|
155
|
+
__deps__ = ()
|
|
156
|
+
__tablename__ = __mv_name__
|
|
157
|
+
|
|
158
|
+
@register_construct
|
|
159
|
+
class SmokingPYHDxMV(
|
|
160
|
+
ConditionEpisodeMeasurementCols,
|
|
161
|
+
MaterializedViewMixin,
|
|
162
|
+
Base,
|
|
163
|
+
):
|
|
164
|
+
__mv_name__ = "smoking_pyh_dx_mv"
|
|
165
|
+
__mv_select__ = pyh_dx.select()
|
|
166
|
+
__mv_index__ = "person_id"
|
|
167
|
+
__deps__ = ()
|
|
168
|
+
__tablename__ = __mv_name__
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import sqlalchemy as sa
|
|
2
|
+
import sqlalchemy.orm as so
|
|
3
|
+
from sqlalchemy.sql import ColumnElement
|
|
4
|
+
from typing import Iterable, Any, Sequence, Union
|
|
5
|
+
from omop_constructs.alchemy.episodes import ConditionEpisodeMV
|
|
6
|
+
from omop_alchemy.cdm.model.structural import Episode_Event
|
|
7
|
+
from omop_semantics.runtime.default_valuesets import runtime # type: ignore
|
|
8
|
+
from omop_alchemy.cdm.model import Measurement, Concept
|
|
9
|
+
|
|
10
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
|
11
|
+
SQLExpr = Union[ColumnElement[Any], InstrumentedAttribute[Any]]
|
|
12
|
+
|
|
13
|
+
modifier_concept = so.aliased(Concept, name="modifier_concept")
|
|
14
|
+
|
|
15
|
+
def attach_to_condition_episode_via_episode_event(
|
|
16
|
+
base_event_subq: sa.Subquery,
|
|
17
|
+
*,
|
|
18
|
+
event_id_col: ColumnElement[Any],
|
|
19
|
+
name: str,
|
|
20
|
+
) -> sa.Subquery:
|
|
21
|
+
"""
|
|
22
|
+
Attach base events to ConditionEpisodeMV via Episode_Event links.
|
|
23
|
+
"""
|
|
24
|
+
return (
|
|
25
|
+
sa.select(
|
|
26
|
+
*base_event_subq.c,
|
|
27
|
+
ConditionEpisodeMV.disease_episode_id,
|
|
28
|
+
ConditionEpisodeMV.disease_episode_concept_id,
|
|
29
|
+
ConditionEpisodeMV.disease_episode_label,
|
|
30
|
+
ConditionEpisodeMV.disease_episode_start_date,
|
|
31
|
+
ConditionEpisodeMV.disease_episode_end_date,
|
|
32
|
+
)
|
|
33
|
+
.join(
|
|
34
|
+
Episode_Event,
|
|
35
|
+
sa.and_(
|
|
36
|
+
Episode_Event.event_id == event_id_col,
|
|
37
|
+
Episode_Event.episode_event_field_concept_id
|
|
38
|
+
== runtime.modifiers.modifier_fields.measurement_id,
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
.join(
|
|
42
|
+
ConditionEpisodeMV,
|
|
43
|
+
ConditionEpisodeMV.disease_episode_id == Episode_Event.episode_id,
|
|
44
|
+
)
|
|
45
|
+
.subquery(name=name)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
def attach_to_condition_episode_by_time_window(
|
|
49
|
+
base_event_subq: sa.Subquery,
|
|
50
|
+
*,
|
|
51
|
+
date_col: ColumnElement[Any],
|
|
52
|
+
person_col: ColumnElement[Any],
|
|
53
|
+
name: str,
|
|
54
|
+
) -> sa.Subquery:
|
|
55
|
+
"""
|
|
56
|
+
Time-window attach to ConditionEpisodeMV (fallback when no Episode_Event link exists).
|
|
57
|
+
"""
|
|
58
|
+
return (
|
|
59
|
+
sa.select(
|
|
60
|
+
*base_event_subq.c,
|
|
61
|
+
|
|
62
|
+
ConditionEpisodeMV.disease_episode_id,
|
|
63
|
+
ConditionEpisodeMV.disease_episode_concept_id,
|
|
64
|
+
ConditionEpisodeMV.disease_episode_label,
|
|
65
|
+
ConditionEpisodeMV.disease_episode_start_date,
|
|
66
|
+
ConditionEpisodeMV.disease_episode_end_date,
|
|
67
|
+
(date_col - ConditionEpisodeMV.disease_episode_start_date).label("episode_delta_days"),
|
|
68
|
+
)
|
|
69
|
+
.join(
|
|
70
|
+
ConditionEpisodeMV,
|
|
71
|
+
sa.and_(
|
|
72
|
+
ConditionEpisodeMV.person_id == person_col,
|
|
73
|
+
date_col >= ConditionEpisodeMV.disease_episode_start_date,
|
|
74
|
+
sa.or_(
|
|
75
|
+
ConditionEpisodeMV.disease_episode_end_date == None,
|
|
76
|
+
date_col <= ConditionEpisodeMV.disease_episode_end_date,
|
|
77
|
+
),
|
|
78
|
+
),
|
|
79
|
+
isouter=True,
|
|
80
|
+
)
|
|
81
|
+
.subquery(name=name)
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
def attach_to_condition_episode(
|
|
85
|
+
base_event_subq: sa.Subquery,
|
|
86
|
+
*,
|
|
87
|
+
event_id_col: ColumnElement[Any],
|
|
88
|
+
date_col: ColumnElement[Any],
|
|
89
|
+
person_col: ColumnElement[Any],
|
|
90
|
+
name: str,
|
|
91
|
+
prefer_explicit_link: bool = True,
|
|
92
|
+
) -> sa.Subquery:
|
|
93
|
+
"""
|
|
94
|
+
Attach events to ConditionEpisodeMV.
|
|
95
|
+
|
|
96
|
+
Prefers explicit Episode_Event links; can fall back to time-window logic.
|
|
97
|
+
"""
|
|
98
|
+
explicit = attach_to_condition_episode_via_episode_event(
|
|
99
|
+
base_event_subq,
|
|
100
|
+
event_id_col=event_id_col,
|
|
101
|
+
name=f"{name}_explicit",
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if not prefer_explicit_link:
|
|
105
|
+
return explicit
|
|
106
|
+
|
|
107
|
+
fallback = attach_to_condition_episode_by_time_window(
|
|
108
|
+
base_event_subq,
|
|
109
|
+
date_col=date_col,
|
|
110
|
+
person_col=person_col,
|
|
111
|
+
name=f"{name}_fallback",
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
sa.select(*explicit.c)
|
|
116
|
+
.union_all(sa.select(*fallback.c))
|
|
117
|
+
.subquery(name=name)
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def measurement_event_core(
|
|
121
|
+
*,
|
|
122
|
+
concept_ids: Iterable[int] | None = None,
|
|
123
|
+
name: str = "measurement_core",
|
|
124
|
+
include_cols: Sequence[SQLExpr] = (),
|
|
125
|
+
unlinked_only: bool = True,
|
|
126
|
+
) -> sa.Subquery:
|
|
127
|
+
"""
|
|
128
|
+
Minimal measurement event surface (person/id/date/concept/label + extras).
|
|
129
|
+
"""
|
|
130
|
+
q = (
|
|
131
|
+
sa.select(
|
|
132
|
+
Measurement.person_id.label("person_id"),
|
|
133
|
+
Measurement.measurement_id.label("event_id"),
|
|
134
|
+
Measurement.measurement_date.label("event_date"),
|
|
135
|
+
Measurement.measurement_concept_id.label("event_concept_id"),
|
|
136
|
+
modifier_concept.concept_name.label("event_label"),
|
|
137
|
+
*include_cols,
|
|
138
|
+
)
|
|
139
|
+
.join(
|
|
140
|
+
modifier_concept,
|
|
141
|
+
modifier_concept.concept_id == Measurement.measurement_concept_id,
|
|
142
|
+
isouter=True,
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
if unlinked_only:
|
|
147
|
+
q = q.where(Measurement.modifier_of_event_id == None)
|
|
148
|
+
|
|
149
|
+
if concept_ids is not None:
|
|
150
|
+
q = q.where(Measurement.measurement_concept_id.in_(list(concept_ids)))
|
|
151
|
+
|
|
152
|
+
return q.subquery(name=name)
|
|
153
|
+
|
|
154
|
+
def measurement_attached_to_condition_episode(
|
|
155
|
+
*,
|
|
156
|
+
concept_ids: Iterable[int] | None = None,
|
|
157
|
+
include_cols: Sequence[SQLExpr] = (),
|
|
158
|
+
name: str,
|
|
159
|
+
unlinked_only: bool = True,
|
|
160
|
+
) -> sa.Subquery:
|
|
161
|
+
core = measurement_event_core(
|
|
162
|
+
concept_ids=concept_ids,
|
|
163
|
+
include_cols=include_cols,
|
|
164
|
+
name=f"{name}_core",
|
|
165
|
+
unlinked_only=unlinked_only,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
return attach_to_condition_episode(
|
|
169
|
+
core,
|
|
170
|
+
event_id_col=core.c.event_id,
|
|
171
|
+
date_col=core.c.event_date,
|
|
172
|
+
person_col=core.c.person_id,
|
|
173
|
+
name=name,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
def episode_relevant_window(
|
|
177
|
+
starting_query: sa.Subquery,
|
|
178
|
+
*,
|
|
179
|
+
max_days_post: int = 90,
|
|
180
|
+
max_days_prior: int = 30,
|
|
181
|
+
name: str | None = None,
|
|
182
|
+
) -> sa.Subquery:
|
|
183
|
+
return (
|
|
184
|
+
sa.select(
|
|
185
|
+
sa.func.row_number().over().label("mv_id"),
|
|
186
|
+
*starting_query.c,
|
|
187
|
+
)
|
|
188
|
+
.where(
|
|
189
|
+
sa.and_(
|
|
190
|
+
starting_query.c.episode_delta_days <= max_days_post,
|
|
191
|
+
starting_query.c.episode_delta_days >= -1 * max_days_prior,
|
|
192
|
+
)
|
|
193
|
+
)
|
|
194
|
+
.subquery(name=name or starting_query.name)
|
|
195
|
+
)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from omop_alchemy.cdm.model import Measurement
|
|
2
|
+
from omop_semantics.runtime.default_valuesets import runtime # type: ignore
|
|
3
|
+
from .event_factories import measurement_attached_to_condition_episode, episode_relevant_window
|
|
4
|
+
|
|
5
|
+
weight_query = measurement_attached_to_condition_episode(
|
|
6
|
+
concept_ids=[runtime.measurements_numeric.body_size_measurements.weight], # type: ignore
|
|
7
|
+
include_cols=[Measurement.value_as_number, Measurement.unit_concept_id],
|
|
8
|
+
name="weight",
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
weight_change_query = measurement_attached_to_condition_episode(
|
|
12
|
+
concept_ids=[runtime.measurements_numeric.body_size_measurements.weight_change], # type: ignore
|
|
13
|
+
include_cols=[Measurement.value_as_number, Measurement.unit_concept_id],
|
|
14
|
+
name="weight_change",
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
height_query = measurement_attached_to_condition_episode(
|
|
18
|
+
concept_ids=[runtime.measurements_numeric.body_size_measurements.height], # type: ignore
|
|
19
|
+
include_cols=[Measurement.value_as_number, Measurement.unit_concept_id],
|
|
20
|
+
name="height",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
bsa_query = measurement_attached_to_condition_episode(
|
|
24
|
+
concept_ids=[runtime.measurements_numeric.body_size_measurements.bsa], # type: ignore
|
|
25
|
+
include_cols=[Measurement.value_as_number, Measurement.unit_concept_id],
|
|
26
|
+
name="bsa",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
creatinine_clearance_query = measurement_attached_to_condition_episode(
|
|
30
|
+
concept_ids=[runtime.measurements_numeric.lab_measurements.creatinine_clearance], # type: ignore
|
|
31
|
+
include_cols=[Measurement.value_as_number, Measurement.unit_concept_id],
|
|
32
|
+
name="creatinine_clearance",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
est_gfr_query = measurement_attached_to_condition_episode(
|
|
36
|
+
concept_ids=[runtime.measurements_numeric.lab_measurements.egfr], # type: ignore
|
|
37
|
+
include_cols=[Measurement.value_as_number, Measurement.unit_concept_id],
|
|
38
|
+
name="egfr",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
fev1_query = measurement_attached_to_condition_episode(
|
|
42
|
+
concept_ids=[runtime.measurements_numeric.lab_measurements.fev1], # type: ignore
|
|
43
|
+
include_cols=[Measurement.value_as_number, Measurement.unit_concept_id],
|
|
44
|
+
name="fev1",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
distress_thermometer_query = measurement_attached_to_condition_episode(
|
|
48
|
+
concept_ids=[runtime.measurements_numeric.proms_numeric.distress_thermometer], # type: ignore
|
|
49
|
+
include_cols=[Measurement.value_as_number],
|
|
50
|
+
name="dtherm",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
ecog_query = measurement_attached_to_condition_episode(
|
|
54
|
+
concept_ids=[runtime.measurements_numeric.performance_status_measurements.ecog_performance_status], # type: ignore
|
|
55
|
+
include_cols=[Measurement.value_as_number],
|
|
56
|
+
name="ecog",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
smoking_pyh_query = measurement_attached_to_condition_episode(
|
|
60
|
+
concept_ids=[runtime.measurements_numeric.smoking_numeric.pyh], # type: ignore
|
|
61
|
+
include_cols=[Measurement.value_as_number],
|
|
62
|
+
name="smoking_pyh",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
weight_dx = episode_relevant_window(weight_query, max_days_post=90, max_days_prior=30, name="weight_dx")
|
|
67
|
+
weight_change_dx = episode_relevant_window(weight_change_query, max_days_post=90, max_days_prior=30, name="weight_change_dx")
|
|
68
|
+
height_dx = episode_relevant_window(height_query, max_days_post=90, max_days_prior=30, name="height_dx")
|
|
69
|
+
bsa_dx = episode_relevant_window(bsa_query, max_days_post=90, max_days_prior=30, name="bsa_dx")
|
|
70
|
+
creat_dx = episode_relevant_window(creatinine_clearance_query, max_days_post=90, max_days_prior=30, name="creat_dx")
|
|
71
|
+
egfr_dx = episode_relevant_window(est_gfr_query, max_days_post=90, max_days_prior=30, name="egfr_dx")
|
|
72
|
+
fev1_dx = episode_relevant_window(fev1_query, max_days_post=90, max_days_prior=30, name="fev1_dx")
|
|
73
|
+
dtherm_dx = episode_relevant_window(distress_thermometer_query, max_days_post=90, max_days_prior=30, name="dtherm_dx")
|
|
74
|
+
ecog_dx = episode_relevant_window(ecog_query, max_days_post=90, max_days_prior=30, name="ecog_dx")
|
|
75
|
+
pyh_dx = episode_relevant_window(smoking_pyh_query, max_days_post=90, max_days_prior=30, name="pyh_dx")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/concepts/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/conditions/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/episodes/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/modifiers/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/alchemy/source_factories.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{omop_constructs-0.2.8 → omop_constructs-0.2.10}/src/omop_constructs/semantics/runtime_lookups.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|