Skip to content

ORM improvements again #1271

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions python/lib/db/models/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship

import lib.db.models.parameter_file as db_parameter_file
import lib.db.models.file_parameter as db_file_parameter
import lib.db.models.session as db_session
from lib.db.base import Base

Expand All @@ -13,7 +13,7 @@ class DbFile(Base):

id : Mapped[int] = mapped_column('FileID', primary_key=True)
session_id : Mapped[int] = mapped_column('SessionID', ForeignKey('session.ID'))
file_name : Mapped[str] = mapped_column('File')
rel_path : Mapped[str] = mapped_column('File')
series_uid : Mapped[str | None] = mapped_column('SeriesUID')
echo_time : Mapped[float | None] = mapped_column('EchoTime')
phase_encoding_direction : Mapped[str | None] = mapped_column('PhaseEncodingDirection')
Expand All @@ -37,5 +37,5 @@ class DbFile(Base):

session : Mapped['db_session.DbSession'] \
= relationship('DbSession', back_populates='files')
parameters : Mapped[list['db_parameter_file.DbParameterFile']] \
= relationship('DbParameterFile', back_populates='file')
parameters : Mapped[list['db_file_parameter.DbFileParameter']] \
= relationship('DbFileParameter', back_populates='file')
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from lib.db.base import Base


class DbParameterFile(Base):
class DbFileParameter(Base):
__tablename__ = 'parameter_file'

id : Mapped[int] = mapped_column('ParameterFileID', primary_key=True)
Expand All @@ -18,4 +18,4 @@ class DbParameterFile(Base):
file: Mapped['db_file.DbFile'] \
= relationship('DbFile', back_populates='parameters')
type: Mapped['db_parameter_type.DbParameterType'] \
= relationship('DbParameterType', back_populates='parameter_files')
= relationship('DbParameterType', back_populates='file_parameters')
6 changes: 3 additions & 3 deletions python/lib/db/models/parameter_type.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from sqlalchemy.orm import Mapped, mapped_column, relationship

import lib.db.models.parameter_file as db_parameter_file
import lib.db.models.file_parameter as db_file_parameter
from lib.db.base import Base


Expand All @@ -20,5 +20,5 @@ class DbParameterType(Base):
queryable : Mapped[bool | None] = mapped_column('Queryable')
is_file : Mapped[bool | None] = mapped_column('IsFile')

parameter_files: Mapped[list['db_parameter_file.DbParameterFile']] \
= relationship('DbParameterFile', back_populates='type')
file_parameters: Mapped[list['db_file_parameter.DbFileParameter']] \
= relationship('DbFileParameter', back_populates='type')
14 changes: 7 additions & 7 deletions python/lib/db/queries/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from sqlalchemy.orm import Session as Database

from lib.db.models.file import DbFile
from lib.db.models.parameter_file import DbParameterFile
from lib.db.models.file_parameter import DbFileParameter
from lib.db.models.parameter_type import DbParameterType


Expand Down Expand Up @@ -30,15 +30,15 @@ def try_get_parameter_value_with_file_id_parameter_name(
db: Database,
file_id: int,
parameter_name: str
) -> DbParameterFile | None:
) -> DbFileParameter | None:
"""
Get parameter value from file ID and parameter name, or return `None` if no entry was found
"""

return db.execute(select(DbParameterFile)
.join(DbParameterFile.type)
return db.execute(select(DbFileParameter)
.join(DbFileParameter.type)
.where(DbParameterType.name == parameter_name)
.where(DbParameterFile.file_id == file_id)
.where(DbFileParameter.file_id == file_id)
).scalar_one_or_none()


Expand All @@ -50,7 +50,7 @@ def try_get_file_with_hash(db: Database, file_hash: str) -> DbFile | None:

return db.execute(select(DbFile)
.join(DbFile.parameters)
.join(DbParameterFile.type)
.join(DbFileParameter.type)
.where(DbParameterType.name.in_(['file_blake2b_hash', 'md5hash']))
.where(DbParameterFile.value == file_hash)
.where(DbFileParameter.value == file_hash)
).scalar_one_or_none()
25 changes: 12 additions & 13 deletions python/tests/integration/scripts/test_run_nifti_insertion.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,12 +334,12 @@ def test_nifti_mri_protocol_violated_scans_features():
violated_scan_entry = violated_scans[0]

# Check that the NIfTI file can be found on the disk
assert violated_scan_entry.file_rel_path is not None \
and os.path.exists(os.path.join('/data/loris/', str(violated_scan_entry.file_rel_path)))
assert violated_scan_entry.file_rel_path is not None
assert os.path.exists(os.path.join('/data/loris/', violated_scan_entry.file_rel_path))

# Rerun the script to test that it did not duplicate the entry in MRI protocol violated scans
# Note: need to copy the violated file into incoming to rerun the script
new_nifti_path = os.path.join('/data/loris/', str(violated_scan_entry.file_rel_path))
new_nifti_path = os.path.join('/data/loris/', violated_scan_entry.file_rel_path)
new_json_path = new_nifti_path.replace('.nii.gz', '.json')
shutil.copyfile(new_nifti_path, nifti_path)
shutil.copyfile(new_json_path, json_path)
Expand Down Expand Up @@ -398,7 +398,7 @@ def test_nifti_mri_protocol_violated_scans_features():

# Check that all files related to that image have been properly linked in the database
file_base_rel_path = 'assembly_bids/sub-400184/ses-V3/anat/sub-400184_ses-V3_run-1_T1w'
assert str(file.file_name) == f'{file_base_rel_path}.nii.gz'
assert file.rel_path == f'{file_base_rel_path}.nii.gz'
file_json_data = try_get_parameter_value_with_file_id_parameter_name(db, file.id, 'bids_json_file')
file_pic_data = try_get_parameter_value_with_file_id_parameter_name(db, file.id, 'check_pic_filename')
assert file_json_data is not None and file_json_data.value == f'{file_base_rel_path}.json'
Expand All @@ -409,7 +409,7 @@ def test_nifti_mri_protocol_violated_scans_features():
'sub-400184': {
'ses-V3': {
'anat': {
basename(str(file.file_name)): None,
basename(file.rel_path): None,
basename(str(file_json_data.value)): None,
}
}
Expand Down Expand Up @@ -486,10 +486,9 @@ def test_nifti_mri_violations_log_exclude_features():
assert violation_entry.severity == 'exclude'

# Check that the NIfTI file can be found in the filesystem
assert violation_entry.file_rel_path is not None \
and os.path.exists(os.path.join('/data/loris/', str(violation_entry.file_rel_path)))
assert os.path.exists(os.path.join('/data/loris/', violation_entry.file_rel_path))
# Check that the rest of the expected files have been created
new_nifti_path = os.path.join('/data/loris/', str(violation_entry.file_rel_path))
new_nifti_path = os.path.join('/data/loris/', violation_entry.file_rel_path)
new_json_path = new_nifti_path.replace('.nii.gz', '.json')
new_bval_path = new_nifti_path.replace('.nii.gz', '.bval')
new_bvec_path = new_nifti_path.replace('.nii.gz', '.bvec')
Expand Down Expand Up @@ -561,7 +560,7 @@ def test_nifti_mri_violations_log_exclude_features():

# Check that all files related to that image have been properly linked in the database
file_base_rel_path = 'assembly_bids/sub-400184/ses-V3/dwi/sub-400184_ses-V3_acq-65dir_run-1_dwi'
assert str(file.file_name) == f'{file_base_rel_path}.nii.gz'
assert file.rel_path == f'{file_base_rel_path}.nii.gz'
file_json_data = try_get_parameter_value_with_file_id_parameter_name(db, file.id, 'bids_json_file')
file_bval_data = try_get_parameter_value_with_file_id_parameter_name(db, file.id, 'check_bval_filename')
file_bvec_data = try_get_parameter_value_with_file_id_parameter_name(db, file.id, 'check_bvec_filename')
Expand All @@ -576,7 +575,7 @@ def test_nifti_mri_violations_log_exclude_features():
'sub-400184': {
'ses-V3': {
'dwi': {
basename(str(file.file_name)): None,
basename(file.rel_path): None,
basename(str(file_bval_data.value)): None,
basename(str(file_bvec_data.value)): None,
basename(str(file_json_data.value)): None,
Expand Down Expand Up @@ -645,8 +644,8 @@ def test_dwi_insertion_with_mri_violations_log_warning():

# Check that all files related to that image have been properly linked in the database
file_base_rel_path = 'assembly_bids/sub-400184/ses-V3/dwi/sub-400184_ses-V3_acq-25dir_run-1_dwi'
assert str(violation_entry.file_rel_path) \
== str(file.file_name) \
assert violation_entry.file_rel_path \
== file.rel_path \
== f'{file_base_rel_path}.nii.gz'
file_json_data = try_get_parameter_value_with_file_id_parameter_name(db, file.id, 'bids_json_file')
file_bval_data = try_get_parameter_value_with_file_id_parameter_name(db, file.id, 'check_bval_filename')
Expand All @@ -662,7 +661,7 @@ def test_dwi_insertion_with_mri_violations_log_warning():
'sub-400184': {
'ses-V3': {
'dwi': {
basename(str(file.file_name)): None,
basename(file.rel_path): None,
basename(str(file_bval_data.value)): None,
basename(str(file_bvec_data.value)): None,
basename(str(file_json_data.value)): None,
Expand Down
Loading