summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-11 13:00:51 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-11 13:00:51 +0200
commit5046defebb8e04d00489a6be070b1b7e7a49ce84 (patch)
treeb68d8566dbcbb362f8f79f58d3583bb5ae833a44 /lib
parent2747e01ca00e3be9b8b94c4eddc2c9a17daedce7 (diff)
downloadcolitur-5046defebb8e04d00489a6be070b1b7e7a49ce84.tar.gz
colitur-5046defebb8e04d00489a6be070b1b7e7a49ce84.zip
kernel(record): flat all-string canonical output view
The boundary where rite-parametric types stop. CSV, JSON and the template engine all render from this one schema, so they never see a type variable. headers/to_row cover the scalar columns; names and citations are variable-arity and wait for the richer encoders in Plan 5.
Diffstat (limited to 'lib')
-rw-r--r--lib/kernel/record.ml40
-rw-r--r--lib/kernel/record.mli23
2 files changed, 63 insertions, 0 deletions
diff --git a/lib/kernel/record.ml b/lib/kernel/record.ml
new file mode 100644
index 0000000..af55f07
--- /dev/null
+++ b/lib/kernel/record.ml
@@ -0,0 +1,40 @@
+(* The canonical flat output view (spec ยง2.4). Rite-parametric types stop here:
+ every field is a string, so CSV, JSON and the template engine never see a
+ type variable. *)
+type t = {
+ date : string;
+ rite : string;
+ season : string;
+ week : string; (** "" when the day is outside a numbered week *)
+ weekday : string;
+ slug : string;
+ rank : string;
+ colour : string;
+ subject : string;
+ names : (string * string) list;
+ citations : (string * string) list;
+}
+
+let of_temporal ~rite vocab date (t : ('s, 'r) Temporal.t) =
+ let cel = t.Temporal.office in
+ {
+ date = Date.to_iso8601 date;
+ rite;
+ season = vocab.Vocab.season_to_string t.Temporal.season;
+ week = (match t.Temporal.week with Some n -> string_of_int n | None -> "");
+ weekday = Date.weekday_to_string t.Temporal.weekday;
+ slug = Slug.to_string cel.Celebration.slug;
+ rank = vocab.Vocab.rank_to_string cel.Celebration.rank;
+ colour = Colour.to_string cel.Celebration.colour;
+ subject = Subject.to_string cel.Celebration.subject;
+ names = List.map (fun (l, n) -> (Lang.to_string l, n)) (Names.to_list cel.Celebration.names);
+ citations =
+ List.map (fun c -> (Citation.part_to_string c.Citation.part, c.Citation.reference))
+ cel.Celebration.citations;
+ }
+
+let headers =
+ [ "date"; "rite"; "season"; "week"; "weekday"; "slug"; "rank"; "colour"; "subject" ]
+
+let to_row r =
+ [ r.date; r.rite; r.season; r.week; r.weekday; r.slug; r.rank; r.colour; r.subject ]
diff --git a/lib/kernel/record.mli b/lib/kernel/record.mli
new file mode 100644
index 0000000..858f125
--- /dev/null
+++ b/lib/kernel/record.mli
@@ -0,0 +1,23 @@
+(** The canonical flat output view: one row per day, every field a string. This
+ is the boundary at which rite-parametric types stop. *)
+type t = {
+ date : string;
+ rite : string;
+ season : string;
+ week : string;
+ weekday : string;
+ slug : string;
+ rank : string;
+ colour : string;
+ subject : string;
+ names : (string * string) list;
+ citations : (string * string) list;
+}
+
+val of_temporal : rite:string -> ('s, 'r) Vocab.t -> Date.t -> ('s, 'r) Temporal.t -> t
+
+(** Column names for [to_row]. Names and citations are excluded: they are
+ variable-arity and belong to richer encodings, added in Plan 5. *)
+val headers : string list
+
+val to_row : t -> string list