[OCaml] High Intensity Training Online
1
(** Parses a native Hevy CSV export into a {!Workout_import.batch}.
2
3
This is an import adapter: it turns untrusted export text into the
4
application's import use case. It does not construct canonical evidence or
5
apply Heavy Duty judgment. It depends on neither [hito.persistence] nor
6
[hito.web], so any client can import without linking a web framework. The
7
whole export text is retained verbatim through
8
{!Hito_app.Workout_import.make_batch}, so provenance survives the parse.
9
10
The adapter enforces the strict native schema. The header must carry all 14
11
verified columns, in any order. Rows the adapter cannot promote — warmups,
12
non-strength data, unknown set types, malformed fields — become
13
{!Workout_import.warning} values, not sets. The adapter drops a row, never
14
guesses at it. Rows group into workouts by the exact
15
[(title, start_time, end_time)] triple, in first-appearance order. *)
16
17
type error =
18
| Malformed_csv of { record : int; field : int; detail : string }
19
(** The CSV text does not conform to RFC4180. [record] and [field] are
20
1-based, as {!Csv.Failure} reports them. *)
21
| Missing_column of string
22
(** A required column is absent from the header. The first missing column
23
in canonical order is reported. *)
24
| Empty_file (** The export has no rows at all, not even a header. *)
25
26
val pp_error : Format.formatter -> error -> unit
27
28
val parse :
29
batch_id:Hito_app.Workout_import.batch_id ->
30
fingerprint:string ->
31
imported_at:Recovery.timestamp ->
32
utc_offset_seconds:int ->
33
string ->
34
(Hito_app.Workout_import.batch, error) result
35
(** [parse ~batch_id ~fingerprint ~imported_at ~utc_offset_seconds source]
36
parses [source] as a native Hevy export.
37
38
[utc_offset_seconds] is the offset of the wall-clock times in the export.
39
Hevy datetimes are local wall time, so UTC seconds = civil seconds - offset.
40
41
Returns [Error Empty_file] for empty input, [Error (Missing_column _)] when
42
the header lacks a required column, and [Error (Malformed_csv _)] when the
43
CSV text is not well formed. On success the batch retains [source] exactly.
44
Rows the adapter cannot use appear in {!Workout_import.batch_warnings} in
45
source order. *)
46