files¶
files
¶
Registration wrapper for the sample_files table.
Unlike the other CRUD modules, files.register doubles as a gate
between application code and the schema: it stats the file on disk,
validates that the path lives in the right storage tier, and only then
hands the row to MariaDB. The schema's CHECKs (absolute path, MD5 format,
UNIQUE path) are still in place but are now a backstop, not the first
line of defense.
Storage tier policy¶
File-type → tier is fixed by lab convention:
fastq_r1 / fastq_r2 / fastq_single / bam / counts -> archive
beer_norm / zigp_norm / edger_norm -> work
Roots are configurable via env vars (defaults shown):
NOXDB_ARCHIVE_ROOT default /lisc/archive
NOXDB_WORK_ROOT default /lisc/work
Callers can override storage_tier to 'scratch' or 'external'
(escape hatches with no path-prefix check); overriding to swap
archive/work against the type-derived value is rejected.
register
¶
register(cur, sample_id: int, file_path: str, file_type: str, *, compute_md5: bool = False, checksum_md5: str | None = None, storage_tier: str | None = None, skip_disk_check: bool = False) -> int
Validate a file on disk and insert a sample_files row.
Filesystem checks (path is absolute, regular file exists, extension
matches file_type, path lives under the tier root via realpath)
run before any SQL is executed, so a failure leaves the
transaction untouched.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
sample_id
|
int
|
Parent sample. Must already exist. |
required |
file_path
|
str
|
Absolute path on disk. |
required |
file_type
|
str
|
One of the known types ( |
required |
compute_md5
|
bool
|
If |
False
|
checksum_md5
|
str | None
|
Caller-supplied 32-char lowercase-hex MD5. |
None
|
storage_tier
|
str | None
|
Override the file-type-derived tier. Only
|
None
|
Returns:
| Type | Description |
|---|---|
int
|
The newly inserted |
Raises:
| Type | Description |
|---|---|
ValueError
|
Relative path, unknown |
FileNotFoundError
|
If the path does not exist. |
IsADirectoryError
|
If the path is a directory. |
IntegrityError
|
Unknown |
Source code in src/noxdb/files.py
get_or_register
¶
get_or_register(cur, sample_id: int, file_path: str, file_type: str, *, compute_md5: bool = False, checksum_md5: str | None = None, storage_tier: str | None = None, skip_disk_check: bool = False) -> tuple[int, bool]
Idempotently register a file. Returns (file_id, registered).
If a row with this file_path already exists, it is returned
as-is — the file is NOT re-stat'd and the other arguments are not
used to update the existing row. This means a stale path that was
registered in the past keeps returning its id even if the file has
since been deleted; call
restat if you need to refresh it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
sample_id
|
int
|
Parent sample (used only on insert). |
required |
file_path
|
str
|
Absolute path on disk. Globally unique. |
required |
file_type
|
str
|
See |
required |
compute_md5
|
bool
|
Used only on insert. |
False
|
checksum_md5
|
str | None
|
Used only on insert. |
None
|
storage_tier
|
str | None
|
Used only on insert. |
None
|
Returns:
| Type | Description |
|---|---|
int
|
|
bool
|
this call inserted the row. |
Raises:
| Type | Description |
|---|---|
IntegrityError
|
If the race-recovery fetch also misses. |
Source code in src/noxdb/files.py
get
¶
Return the file row for a given id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
file_id
|
int
|
Primary key to look up. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any] | None
|
The row as |
Source code in src/noxdb/files.py
get_by_path
¶
Return the file row for a given path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
file_path
|
str
|
Absolute path on disk. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any] | None
|
The row as |
Source code in src/noxdb/files.py
list_for_sample
¶
Return all sample_files rows for a sample.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
sample_id
|
int
|
Sample to list. |
required |
order_by
|
str
|
Column name to order by. Must be a column of |
'file_id'
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
All matching rows as |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/noxdb/files.py
count_for_sample
¶
Return the number of files registered for a sample.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
sample_id
|
int
|
Sample to count. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of |
Source code in src/noxdb/files.py
update
¶
update(cur, file_id: int, *, file_size_bytes: int | None = None, checksum_md5: str | None = None, storage_tier: str | None = None) -> bool
Partial update of a file row.
Only kwargs with non-None values are written. file_path,
file_type, sample_id, and created_at are NOT updatable
— those describe a different file. Use
restat to refresh size/checksum from
disk after a file is rewritten in place.
Updating storage_tier enforces the same file_type → tier
invariant as register: flipping
archive ↔ work is rejected; scratch / external
overrides are allowed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
file_id
|
int
|
Row to update. |
required |
file_size_bytes
|
int | None
|
New size (if not None). |
None
|
checksum_md5
|
str | None
|
New 32-char lowercase-hex MD5 (if not None). |
None
|
storage_tier
|
str | None
|
New tier (if not None). |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
Malformed |
Source code in src/noxdb/files.py
restat
¶
Re-read size (and optionally md5) from disk for an existing row.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
file_id
|
int
|
Row to refresh. |
required |
compute_md5
|
bool
|
If |
False
|
Returns:
| Type | Description |
|---|---|
bool
|
|
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the path no longer resolves. No SQL runs in that case. |
Source code in src/noxdb/files.py
delete
¶
Delete a file row.
Only removes the database record. The file on disk is untouched — clean it up separately.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
file_id
|
int
|
Row to delete. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
Source code in src/noxdb/files.py
exists
¶
Return whether a file with the given id or path exists.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cur
|
Audit-logging cursor from |
required | |
file_id
|
int | None
|
Id to check (exclusive with |
None
|
path
|
str | None
|
Path to check (exclusive with |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If both or neither of |