Skip to content

Commit 1a26a7a

Browse files
committed
update
1 parent c69e9e1 commit 1a26a7a

12 files changed

Lines changed: 134 additions & 87 deletions

File tree

packages/grz-db/src/grz_db/migrations/versions/66f36abbea34_rename_submission_date_to_submission_.py renamed to packages/grz-db/src/grz_db/migrations/versions/66f36abbea34_rename_submission_date_to_submission_uploaded_date.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""rename submission_date to submission_finished_date
1+
"""rename submission_date to submission_uploaded_date
22
33
Revision ID: 66f36abbea34
44
Revises: 09602efd9105
@@ -19,7 +19,7 @@
1919

2020
def upgrade() -> None:
2121
"""Upgrade schema."""
22-
op.alter_column("submissions", "submission_date", new_column_name="submission_finished_date")
22+
op.alter_column("submissions", "submission_date", new_column_name="submission_uploaded_date")
2323

2424

2525
def downgrade() -> None:

packages/grz-db/src/grz_db/models/submission/__init__.py

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ class SubmissionBase(SQLModel):
143143
pseudonym: str | None = Field(default=None, index=True)
144144

145145
# fields from Prüfbericht
146-
submission_finished_date: datetime.date | None = None
146+
submission_uploaded_date: datetime.date | None = None
147147
submission_type: SubmissionType | None = None
148148
submitter_id: SubmitterId | None = None
149149
data_node_id: GenomicDataCenterId | None = None
@@ -206,7 +206,7 @@ def diff(
206206
new_value = getattr(other, key)
207207

208208
# Ensure fields are cast to date
209-
if key == "submission_finished_date":
209+
if key == "submission_uploaded_date":
210210
if isinstance(old_value, datetime.datetime):
211211
old_value = old_value.date()
212212
if isinstance(new_value, datetime.datetime):
@@ -228,7 +228,7 @@ def from_metadata(
228228
cls,
229229
submission_id: str,
230230
metadata: GrzSubmissionMetadata,
231-
submission_finished_date: datetime.date,
231+
submission_uploaded_date: datetime.date,
232232
) -> Self:
233233
"""Construct a Submission populated with values derived from parsed metadata.
234234
@@ -241,8 +241,8 @@ def from_metadata(
241241
if isinstance(metadata_submission_date, datetime.datetime):
242242
metadata_submission_date = metadata_submission_date.date()
243243

244-
if isinstance(submission_finished_date, datetime.datetime):
245-
submission_finished_date = submission_finished_date.date()
244+
if isinstance(submission_uploaded_date, datetime.datetime):
245+
submission_uploaded_date = submission_uploaded_date.date()
246246

247247
return cls.model_validate(
248248
{
@@ -258,7 +258,7 @@ def from_metadata(
258258
"data_node_id": metadata.submission.genomic_data_center_id,
259259
"consented": metadata.consents_to_research(date=metadata_submission_date),
260260
"submission_size": metadata.get_submission_size(),
261-
"submission_finished_date": submission_finished_date,
261+
"submission_uploaded_date": submission_uploaded_date,
262262
"submission_metadata": metadata.to_redacted_dict(),
263263
}
264264
)
@@ -735,7 +735,7 @@ def _list_submitter_qc_candidates(
735735
.join(QCQueueEntry, QCQueueEntry.submission_id == Submission.id) # type: ignore[arg-type]
736736
.where(Submission.submission_type == SubmissionType.initial)
737737
.where(Submission.basic_qc_passed) # type: ignore[arg-type]
738-
.where(Submission.submission_finished_date.between(start_date, end_date)) # type: ignore[union-attr]
738+
.where(Submission.submission_uploaded_date.between(start_date, end_date)) # type: ignore[union-attr]
739739
.where(Submission.submitter_id == submitter_id)
740740
.order_by(QCQueueEntry.basic_qc_passed_at, Submission.id) # type: ignore[arg-type]
741741
).all()
@@ -780,7 +780,7 @@ def _is_randomly_selected_for_qc(
780780

781781
block_size = math.floor(1 / target_proportion)
782782
block_index = absolute_index // block_size
783-
submission_quarter, submission_year = date_to_quarter_year(submission.submission_finished_date) # type: ignore[arg-type]
783+
submission_quarter, submission_year = date_to_quarter_year(submission.submission_uploaded_date) # type: ignore[arg-type]
784784
seed = f"{submission.submitter_id}-{submission_year}-{submission_quarter}-{block_index}-{salt}"
785785
rng = random.Random(seed) # noqa: S311
786786

@@ -1033,7 +1033,7 @@ def list_submissions(
10331033
isouter=True,
10341034
)
10351035
.order_by(
1036-
sqlfn.coalesce(latest_state_per_submission.c.timestamp, Submission.submission_finished_date)
1036+
sqlfn.coalesce(latest_state_per_submission.c.timestamp, Submission.submission_uploaded_date)
10371037
.desc()
10381038
.nulls_first()
10391039
)
@@ -1117,7 +1117,7 @@ def should_qc(self, submission_id: str, target_percentage: float, salt: str | No
11171117

11181118
if submission is None:
11191119
raise SubmissionNotFoundError(submission_id)
1120-
submission_date = submission.submission_finished_date
1120+
submission_date = submission.submission_uploaded_date
11211121
if submission_date is None:
11221122
raise SubmissionDateIsNoneError()
11231123
submission_type = submission.submission_type
@@ -1181,14 +1181,14 @@ def _diff_metadata(
11811181
self,
11821182
submission_id: str,
11831183
metadata: GrzSubmissionMetadata,
1184-
submission_finished_date: datetime.date,
1184+
submission_uploaded_date: datetime.date,
11851185
ignore_fields: set[str] | None = None,
11861186
) -> SubmissionDiffCollection:
11871187
"""Compare a submission's current database state against fresh metadata.
11881188
11891189
:param submission_id: Submission ID to look up.
11901190
:param metadata: Parsed metadata from the submission's ``metadata.json``.
1191-
:param submission_finished_date: Date of submission upload finish
1191+
:param submission_uploaded_date: Date of submission upload finish
11921192
:param ignore_fields: Field names to skip entirely during the comparison.
11931193
:returns: A :class:`SubmissionDiffCollection` instance summarising all detected differences.
11941194
"""
@@ -1199,10 +1199,10 @@ def _diff_metadata(
11991199
if ignore_fields is None:
12001200
ignore_fields = set()
12011201

1202-
if isinstance(submission_finished_date, datetime.datetime):
1203-
submission_finished_date = submission_finished_date.date()
1202+
if isinstance(submission_uploaded_date, datetime.datetime):
1203+
submission_uploaded_date = submission_uploaded_date.date()
12041204

1205-
new_submission = Submission.from_metadata(submission_id, metadata, submission_finished_date)
1205+
new_submission = Submission.from_metadata(submission_id, metadata, submission_uploaded_date)
12061206

12071207
return current_submission.diff(new_submission, ignore_fields)
12081208

@@ -1242,7 +1242,7 @@ def diff(
12421242
self,
12431243
submission_id: str,
12441244
metadata: GrzSubmissionMetadata,
1245-
submission_finished_date: datetime.date | None,
1245+
submission_uploaded_date: datetime.date | None,
12461246
ignore_fields: set[str] | None = None,
12471247
) -> tuple[SubmissionDiffCollection, DonorsDiffCollection]:
12481248
"""
@@ -1255,20 +1255,20 @@ def diff(
12551255
12561256
:param submission_id: The unique identifier of the submission to be compared.
12571257
:param metadata: The metadata of the submission to compare against.
1258-
:param submission_finished_date: The date when the submission process was finished.
1258+
:param submission_uploaded_date: The date when the submission process was finished.
12591259
If None, the field will not be included in the comparison.
12601260
:param ignore_fields: Optional set of field names to be ignored during the metadata comparison.
12611261
:returns: A tuple containing the differences in the submission metadata and the corresponding donor entries.
12621262
"""
1263-
if submission_finished_date is None:
1263+
if submission_uploaded_date is None:
12641264
# set arbitrary date if not provided
1265-
submission_finished_date = metadata.submission.submission_date
1265+
submission_uploaded_date = metadata.submission.submission_date
12661266

12671267
# Add submission date to ignore fields
12681268
ignore_fields = ignore_fields or set()
1269-
ignore_fields.add("submission_finished_date")
1269+
ignore_fields.add("submission_uploaded_date")
12701270

1271-
submission_diff = self._diff_metadata(submission_id, metadata, submission_finished_date, ignore_fields)
1271+
submission_diff = self._diff_metadata(submission_id, metadata, submission_uploaded_date, ignore_fields)
12721272
donor_diff = self._diff_donors(submission_id, metadata)
12731273
return submission_diff, donor_diff
12741274

packages/grz-db/tests/test_should_qc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def _add_submission_with_history(
7979
"""
8080
db.add_submission(submission_id)
8181

82-
db.modify_submission(submission_id, "submission_finished_date", str(submission_date.isoformat()))
82+
db.modify_submission(submission_id, "submission_uploaded_date", str(submission_date.isoformat()))
8383
db.modify_submission(submission_id, "submission_type", SubmissionType.initial)
8484
db.modify_submission(submission_id, "submitter_id", submitter_id)
8585
db.modify_submission(submission_id, "basic_qc_passed", "true")
@@ -488,7 +488,7 @@ def test_should_qc_raises_on_missing_submission_type(self, db: SubmissionDb):
488488
"""Verify SubmissionTypeIsNoneError when submission_type is None."""
489489
submission_id = f"{SUBMITTER_ID}_2025-12-01_00000000"
490490
db.add_submission(submission_id)
491-
db.modify_submission(submission_id, "submission_finished_date", "2025-12-01")
491+
db.modify_submission(submission_id, "submission_uploaded_date", "2025-12-01")
492492
db.modify_submission(submission_id, "basic_qc_passed", "true")
493493

494494
with pytest.raises(SubmissionTypeIsNoneError):

packages/grz-db/tests/test_submission.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def test_from_metadata_sets_fields_from_metadata(metadata: GrzSubmissionMetadata
8383
assert submission.genomic_study_subtype == metadata.submission.genomic_study_subtype
8484
assert submission.pseudonym == metadata.submission.local_case_id
8585
assert submission.data_node_id == metadata.submission.genomic_data_center_id
86-
assert submission.submission_finished_date == explicit_date # explicit date takes precedence
86+
assert submission.submission_uploaded_date == explicit_date # explicit date takes precedence
8787
assert submission.submission_size == metadata.get_submission_size()
8888
assert submission.submission_metadata == metadata.to_redacted_dict()
8989

packages/grzctl/src/grzctl/commands/db/cli.py

Lines changed: 78 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
SequenceSubtype,
5555
SequenceType,
5656
)
57-
from pydantic import Field
57+
from pydantic import Field, ValidationError
5858
from tqdm.auto import tqdm
5959

6060
from ... import get_versions
@@ -698,20 +698,20 @@ def populate( # noqa: C901, PLR0913
698698
"or use 'grzctl db submission modify' directly."
699699
) from e
700700

701-
submission_finished_date = (
702-
submission_date.date() if submission_date is not None else submission.submission_finished_date
701+
submission_uploaded_date = (
702+
submission_date.date() if submission_date is not None else submission.submission_uploaded_date
703703
)
704704
if submission_date is None:
705705
log.warning(
706706
"No submission date provided and submission date is missing in the database. "
707707
"Will use submission date from metadata.json..."
708708
)
709-
submission_finished_date = metadata.submission.submission_date
709+
submission_uploaded_date = metadata.submission.submission_date
710710

711711
submission_diff, donors_diff = db_service.diff(
712712
submission_id,
713713
metadata,
714-
submission_finished_date=submission_finished_date,
714+
submission_uploaded_date=submission_uploaded_date,
715715
ignore_fields=set(ignore_field),
716716
)
717717

@@ -941,6 +941,69 @@ def change_request(ctx: click.Context, submission_id: str, change_str: str, data
941941
raise click.ClickException(f"Failed to update submission state: {e}") from e
942942

943943

944+
def _research_consented_today(submission: Submission) -> bool | None:
945+
"""Research consent for the submission re-evaluated as of today.
946+
947+
Unlike the persisted ``consented`` field (evaluated at the submission date),
948+
this recomputes consent from the stored redacted metadata using today's date.
949+
950+
:param submission: Submission whose stored metadata to evaluate.
951+
:returns: ``True``/``False`` for the consent decision today, or ``None`` when
952+
no metadata is stored (e.g. rows migrated without backpopulated metadata)
953+
or when the stored metadata cannot be parsed.
954+
"""
955+
if not submission.submission_metadata:
956+
return None
957+
try:
958+
metadata = GrzSubmissionMetadata.model_validate(submission.submission_metadata)
959+
except ValidationError:
960+
log.debug("Could not parse stored metadata for submission %s to evaluate consent today.", submission.id)
961+
return None
962+
return metadata.consents_to_research(date=date.today())
963+
964+
965+
def _build_attribute_table(submission: Submission, research_consented_today: bool | None) -> rich.table.Table:
966+
"""Build the attribute table shown by ``submission show``.
967+
968+
:param submission: Submission to render.
969+
:param research_consented_today: Research consent re-evaluated as of today
970+
(see :func:`_research_consented_today`), or ``None`` when unavailable.
971+
:returns: A populated rich table of submission attributes.
972+
"""
973+
attribute_table = rich.table.Table(box=None)
974+
attribute_table.add_column("Attribute", justify="right")
975+
attribute_table.add_column("Value")
976+
for label, attr_name in (
977+
("tanG", "tan_g"),
978+
("Pseudonym", "pseudonym"),
979+
("Submission Uploaded Date", "submission_uploaded_date"),
980+
("Submission Size", "submission_size"),
981+
("Submission Type", "submission_type"),
982+
("Submitter ID", "submitter_id"),
983+
("Data Node ID", "data_node_id"),
984+
("Disease Type", "disease_type"),
985+
("Genomic Study Type", "genomic_study_type"),
986+
("Genomic Study Subtype", "genomic_study_subtype"),
987+
("Basic QC Passed", "basic_qc_passed"),
988+
("Research consent (at submission)", "consented"),
989+
("Selected For QC", "selected_for_qc"),
990+
("Detailed QC Passed", "detailed_qc_passed"),
991+
):
992+
attr = getattr(submission, attr_name)
993+
attribute_table.add_row(
994+
rich.text.Text(f"{label}", style="cyan"), rich.text.Text(str(attr)) if attr is not None else _TEXT_MISSING
995+
)
996+
if attr_name == "consented":
997+
# Adjacent row: research consent re-evaluated as of today (recomputed from stored metadata).
998+
attribute_table.add_row(
999+
rich.text.Text("Research consent (today)", style="cyan"),
1000+
rich.text.Text(str(research_consented_today))
1001+
if research_consented_today is not None
1002+
else _TEXT_MISSING,
1003+
)
1004+
return attribute_table
1005+
1006+
9441007
@submission.command("show")
9451008
@click.argument("submission_id", type=str)
9461009
@output_json
@@ -956,8 +1019,11 @@ def show(ctx: click.Context, submission_id: str, output_json: bool):
9561019
console_err.print(f"[red]Error: Submission with ID '{submission_id}' not found.[/red]")
9571020
raise click.Abort()
9581021

1022+
research_consented_today = _research_consented_today(submission)
1023+
9591024
if output_json:
9601025
submission_dict = submission.model_dump(mode="json")
1026+
submission_dict["research_consented_today"] = research_consented_today
9611027
submission_dict["states"] = []
9621028

9631029
for state_log in sorted(submission.states, key=lambda s: s.timestamp):
@@ -977,29 +1043,7 @@ def show(ctx: click.Context, submission_id: str, output_json: bool):
9771043
sys.stdout.write("\n")
9781044
return
9791045

980-
attribute_table = rich.table.Table(box=None)
981-
attribute_table.add_column("Attribute", justify="right")
982-
attribute_table.add_column("Value")
983-
for label, attr_name in (
984-
("tanG", "tan_g"),
985-
("Pseudonym", "pseudonym"),
986-
("Submission Date", "submission_finished_date"),
987-
("Submission Size", "submission_size"),
988-
("Submission Type", "submission_type"),
989-
("Submitter ID", "submitter_id"),
990-
("Data Node ID", "data_node_id"),
991-
("Disease Type", "disease_type"),
992-
("Genomic Study Type", "genomic_study_type"),
993-
("Genomic Study Subtype", "genomic_study_subtype"),
994-
("Basic QC Passed", "basic_qc_passed"),
995-
("Consented", "consented"),
996-
("Selected For QC", "selected_for_qc"),
997-
("Detailed QC Passed", "detailed_qc_passed"),
998-
):
999-
attr = getattr(submission, attr_name)
1000-
attribute_table.add_row(
1001-
rich.text.Text(f"{label}", style="cyan"), rich.text.Text(str(attr)) if attr is not None else _TEXT_MISSING
1002-
)
1046+
attribute_table = _build_attribute_table(submission, research_consented_today)
10031047

10041048
renderables: list[rich.console.RenderableType] = [rich.padding.Padding(attribute_table, (1, 0))]
10051049
if submission.states:
@@ -1110,18 +1154,18 @@ def _backfill_submission( # noqa: PLR0911, PLR0913
11101154
return _BackfillResult.ERROR
11111155

11121156
try:
1113-
# If submission_finished_date is not set in the DB, replace it with the one from metadata.json.
1157+
# If submission_uploaded_date is not set in the DB, replace it with the one from metadata.json.
11141158
# This case is expected for submissions that were created before the submission_date field was added.
1115-
submission_finished_date = (
1116-
current_submission.submission_finished_date
1117-
if current_submission.submission_finished_date
1159+
submission_uploaded_date = (
1160+
current_submission.submission_uploaded_date
1161+
if current_submission.submission_uploaded_date
11181162
else metadata.submission.submission_date
11191163
)
11201164

11211165
submission_diff, donors_diff = db_service.diff(
11221166
submission_id,
11231167
metadata,
1124-
submission_finished_date=submission_finished_date,
1168+
submission_uploaded_date=submission_uploaded_date,
11251169
ignore_fields=ignore_fields or None,
11261170
)
11271171
except Exception as exc:
@@ -1223,7 +1267,7 @@ def backfill( # noqa: PLR0913
12231267
raise click.UsageError("--submission-id and --start-date/--end-date are mutually exclusive.")
12241268

12251269
ignore_fields = set(ignore_field) | {
1226-
"submission_finished_date",
1270+
"submission_uploaded_date",
12271271
"tan_g",
12281272
"local_case_id",
12291273
}

packages/grzctl/src/grzctl/commands/db/tui.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ async def load(self, database: SubmissionDb, quarter: int | None = None, year: i
120120
with database._get_session() as session:
121121
statement = (
122122
select( # type: ignore[type-var]
123-
Submission.submitter_id, Submission.submission_finished_date, Submission.detailed_qc_passed
123+
Submission.submitter_id, Submission.submission_uploaded_date, Submission.detailed_qc_passed
124124
)
125125
.where(Submission.submission_type == SubmissionType.initial)
126126
.where(Submission.basic_qc_passed) # type: ignore[arg-type]
@@ -238,7 +238,7 @@ async def search(
238238
Submission.id == latest_state_per_submission.c.submission_id, # type: ignore[arg-type]
239239
isouter=True,
240240
).order_by(
241-
sqlfn.coalesce(latest_state_per_submission.c.timestamp, Submission.submission_finished_date)
241+
sqlfn.coalesce(latest_state_per_submission.c.timestamp, Submission.submission_uploaded_date)
242242
.desc()
243243
.nulls_first()
244244
)

0 commit comments

Comments
 (0)