Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ Run unit tests:
pytest
```

### Test database
- Tests run against a separate SQLite file to avoid touching your local/prod data.
- Default path: `soa_builder_web_tests.db` in the repo root. Override with env var `SOA_BUILDER_DB`.
- A pytest session fixture removes any stale test DB/WAL/SHM files at start to prevent I/O errors.
- Manually clear the test DB before a run if needed:
```bash
rm -f soa_builder_web_tests.db soa_builder_web_tests.db-wal soa_builder_web_tests.db-shm
```

> Full, updated endpoint reference (including Elements, freezes, audits, JSON CRUD and UI helpers) lives in `README_endpoints.md`. Consult that file for detailed request/response examples, curl snippets, and future enhancement notes.

Endpoints:
Expand All @@ -77,7 +86,7 @@ Running the script produces (in `--out-dir`):

### visits.csv Columns
- `visit_id`: Sequential numeric id.
- `raw_header`: Original header text.
- `label`: Original header text.
- `visit_name`: Header stripped of parenthetical codes.
- `visit_code`: Code extracted from parentheses (e.g., `C1D1`, `EOT`).
- `sequence_index`: Positional order.
Expand Down
2 changes: 1 addition & 1 deletion README_endpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Response:

| Method | Path | Purpose |
| ------ | ---- | ------- |
| POST | `/soa/{soa_id}/visits` | Create visit `{ name, raw_header?, epoch_id? }` |
| POST | `/soa/{soa_id}/visits` | Create visit `{ name, label?, epoch_id? }` |
| PATCH | `/soa/{soa_id}/visits/{visit_id}` | Update visit (partial) returns `updated_fields` |
| DELETE | `/soa/{soa_id}/visits/{visit_id}` | Delete visit (and its cells) |
| GET | `/soa/{soa_id}/visits/{visit_id}` | Fetch visit detail |
Expand Down
10 changes: 5 additions & 5 deletions normalize_soa.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
@dataclass
class Visit:
visit_id: int
raw_header: str
label: str
visit_name: str
visit_code: Optional[str]
sequence_index: int
Expand Down Expand Up @@ -229,7 +229,7 @@ def build_visits(headers: List[str]) -> List[Visit]:
visits.append(
Visit(
visit_id=idx,
raw_header=h,
label=h,
visit_name=re.sub(r"\s*\(.*?\)", "", h).strip(),
visit_code=code,
sequence_index=idx,
Expand Down Expand Up @@ -305,7 +305,7 @@ def build_schedule_rules(
rule_id = 1
# From headers (e.g., Survival FU (q12w))
for v in visits:
header_lower = v.raw_header.lower()
header_lower = v.label.lower()
for pat in REPEAT_PATTERNS:
if pat in header_lower:
rules.append(
Expand All @@ -316,7 +316,7 @@ def build_schedule_rules(
source_type="header",
activity_id=None,
visit_id=v.visit_id,
raw_text=v.raw_header,
raw_text=v.label,
)
)
rule_id += 1
Expand Down Expand Up @@ -386,7 +386,7 @@ def to_sqlite(
"""
CREATE TABLE IF NOT EXISTS visits (
visit_id INTEGER PRIMARY KEY,
raw_header TEXT,
label TEXT,
visit_name TEXT,
visit_code TEXT,
sequence_index INTEGER,
Expand Down
2 changes: 1 addition & 1 deletion src/soa_builder/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def _load_visits(normalized_dir: str) -> dict:
visits[vid] = VisitStub(
visit_id=vid,
visit_name=r.get("visit_name", ""),
raw_header=r.get("raw_header", ""),
label=r.get("label", ""),
sequence_index=int(r.get("sequence_index", "0")),
)
return visits
Expand Down
8 changes: 4 additions & 4 deletions src/soa_builder/normalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
@dataclass
class Visit:
visit_id: int
raw_header: str
label: str
visit_name: str
visit_code: Optional[str]
sequence_index: int
Expand Down Expand Up @@ -246,7 +246,7 @@ def build_schedule_rules(
rid = 1
# headers
for v in visits:
low = v.raw_header.lower()
low = v.label.lower()
for pat in REPEAT_PATTERNS:
if pat in low:
rules.append(
Expand All @@ -257,7 +257,7 @@ def build_schedule_rules(
"header",
None,
v.visit_id,
v.raw_header,
v.label,
)
)
rid += 1
Expand Down Expand Up @@ -342,7 +342,7 @@ def write(name: str, items: List[Any]):
]:
cur.execute(f"DROP TABLE IF EXISTS {tbl}")
cur.execute(
"""CREATE TABLE visits (visit_id INTEGER PRIMARY KEY, raw_header TEXT, visit_name TEXT, visit_code TEXT, sequence_index INTEGER, window_lower INTEGER, window_upper INTEGER, repeat_pattern TEXT, category TEXT)"""
"""CREATE TABLE visits (visit_id INTEGER PRIMARY KEY, label TEXT, visit_name TEXT, visit_code TEXT, sequence_index INTEGER, window_lower INTEGER, window_upper INTEGER, repeat_pattern TEXT, category TEXT)"""
)
cur.execute(
"""CREATE TABLE activities (activity_id INTEGER PRIMARY KEY, activity_name TEXT)"""
Expand Down
8 changes: 3 additions & 5 deletions src/soa_builder/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
class VisitStub:
visit_id: int
visit_name: str
raw_header: str
label: str
sequence_index: int


Expand Down Expand Up @@ -88,7 +88,7 @@ def derive_nominal_day_for_visit(
v: VisitStub, cycle_length_days: int, cycle_lengths: Optional[List[int]]
) -> int:
name = v.visit_name.lower()
header = v.raw_header.lower()
header = v.label.lower()
for txt in (name, header):
mc = CYCLE_DAY1_RE.search(txt)
if mc:
Expand Down Expand Up @@ -183,9 +183,7 @@ def expand_schedule_rules(
anchor_cycle = 1
if rule.visit_id and rule.visit_id in visits:
txt = (
visits[rule.visit_id].visit_name
+ " "
+ visits[rule.visit_id].raw_header
visits[rule.visit_id].visit_name + " " + visits[rule.visit_id].label
).lower()
mc = CYCLE_DAY1_RE.search(txt)
if mc:
Expand Down
Loading