View raw

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