subjects¶
subjects
¶
CRUD wrapper for the subjects table.
Same call style as noxdb.projects —
every function takes a cursor first; callers wrap them in
with transaction() as cur:.
subject_code is globally unique — subjects carry no project
affiliation (project membership lives in project_samples, reached
via the sample → visit → subject lineage). The natural-key lookup is
get_by_code rather than
get.
create
¶
Insert a subject and return its new subject_id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
subject_code
|
str
|
Stable, globally unique subject code. |
required |
sex
|
str | None
|
|
required |
origin
|
str | None
|
Optional free-text origin. |
None
|
Returns:
| Type | Description |
|---|---|
int
|
The newly inserted |
Raises:
| Type | Description |
|---|---|
IntegrityError
|
If |
Source code in src/noxdb/subjects.py
get
¶
Return the subject row for a given id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
subject_id
|
int
|
Primary key to look up. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any] | None
|
The row as |
Source code in src/noxdb/subjects.py
get_by_code
¶
Return the subject row for the globally-unique natural key.
Hot path for CSV importers: look up by subject_code before
inserting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
subject_code
|
str
|
Globally unique subject code. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any] | None
|
The row as |
Source code in src/noxdb/subjects.py
get_or_create
¶
get_or_create(cur, subject_code: str, sex: str | None, *, origin: str | None = None) -> tuple[int, bool]
Idempotently return the subject id, inserting if needed.
Existing rows are returned as-is and never updated by this call.
sex / origin are still checked against the existing row: a
mismatch raises (see Raises) so an accidental cross-study
subject_code collision fails loudly instead of silently
merging two unrelated subjects. Falls back to a re-fetch on the
UNIQUE-violation race where another transaction inserted the same
key in parallel.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
subject_code
|
str
|
Globally unique subject code. |
required |
sex
|
str | None
|
Used only on insert. |
required |
origin
|
str | None
|
Used only on insert. |
None
|
Returns:
| Type | Description |
|---|---|
int
|
|
bool
|
call inserted the row. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a subject with this |
IntegrityError
|
If the race-recovery fetch also misses. |
Source code in src/noxdb/subjects.py
list_for_project
¶
Return all subjects with at least one sample in a project.
Project membership lives in project_samples; this traverses
project_samples → samples → visits → subjects and de-duplicates,
since a subject can have many samples in the same project.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
project_id
|
int
|
Project to list. |
required |
order_by
|
str
|
Column name to order by. Must be a column of |
'subject_id'
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
All matching rows as |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/noxdb/subjects.py
count_for_project
¶
Return the number of distinct subjects with samples in a project.
Traverses project_samples → samples → visits → subjects and
counts distinct subjects (a subject can have many samples in the
project).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
project_id
|
int
|
Project to count. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of distinct subject rows. |
Source code in src/noxdb/subjects.py
update
¶
update(cur, subject_id: int, *, subject_code: str | None = None, sex: str | None = None, origin: str | None = None) -> bool
Partial update of a subject row.
Only kwargs with non-None values are written. created_at is
intentionally NOT updatable here. Use raw SQL if you really need
it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
subject_id
|
int
|
Row to update. |
required |
subject_code
|
str | None
|
New code (if not None). |
None
|
sex
|
str | None
|
New sex (if not None). |
None
|
origin
|
str | None
|
New origin (if not None). |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
run) when every kwarg is None. |
Source code in src/noxdb/subjects.py
delete
¶
Delete a subject.
visits.fk_visits_subject is ON DELETE CASCADE, so this also
removes every visit, sample, and metadata row owned by the subject.
sample_files uses ON DELETE RESTRICT and will block the
delete instead — clean those up first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
subject_id
|
int
|
Row to delete. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
Source code in src/noxdb/subjects.py
exists
¶
Return whether a subject with the given id exists.
For natural-key existence checks use
get_by_code(...) is not None.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
subject_id
|
int
|
Id to check. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|