aboutsummaryrefslogtreecommitdiff
path: root/mobile/mobile.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-25 10:45:28 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-25 10:45:28 +0200
commitf110c338718a6eea3693fb6afb4f7fcc5b77003b (patch)
tree52b6adb382445a0762f63fb862361d7fbd8637f2 /mobile/mobile.go
parentfd3eda0da228d2417b8b7f9007533e214d7a5e80 (diff)
parentb24702cc9b8d7f2e408bb92032e8f7fa2aaa836b (diff)
downloadlectio-f110c338718a6eea3693fb6afb4f7fcc5b77003b.tar.gz
lectio-f110c338718a6eea3693fb6afb4f7fcc5b77003b.zip
merge: make the calendar engine stop repeating whole-year work per day
A seven-day view resolved the year seven times. Each readings.Load stacked the calendar data layers and re-read the Bible book table -- both date-independent -- and the EF path rebuilt the year's entire transfer plan and its occupancy scan on every single day. Three logic-neutral fixes: hoist the date-independent setup out of the Days loop; memoise the EF transfer plan on (year, Selection, content hash of the merged sanctoral); and build the occupancy index once alongside it rather than scanning per candidate. EF's seven-day view goes 74ms to 16ms, its multiple over OF from ~13x to ~3x. OF is unchanged, as it never touched the EF paths. Output is byte-identical throughout, proven by SHA-256 over a 492-case sweep spanning both forms, both languages, four corpora, the Triduum, a Requiem day and the three Joseph/Annunciation collision years. The caches are keyed on content, not identity, so a user overlay invalidates them -- asserted by a test that varies the overlay and requires the answer to change, itself mutation-proved by dropping the content hash and watching it fail.
Diffstat (limited to 'mobile/mobile.go')
-rw-r--r--mobile/mobile.go16
1 files changed, 13 insertions, 3 deletions
diff --git a/mobile/mobile.go b/mobile/mobile.go
index 7e4c109..bc380d2 100644
--- a/mobile/mobile.go
+++ b/mobile/mobile.go
@@ -78,7 +78,12 @@ func Day(date, form, version, lang string) string {
// Day identity (name/season/colour) in the interface language.
cfgID := config.Config{UILanguage: lang, Lectionary: lect, All: true}
- if _, info, err := readings.Load(cfgID, readings.Options{Date: date, All: true}); err == nil {
+ // cfgID and cfgR below differ only in UILanguage/ReadingVersion, never in
+ // Lectionary or Use -- the two inputs Prepare's cost depends on -- so one
+ // Prepare (keyed off cfgID; either config would do) serves both Load
+ // calls. See readings.Prepared's doc comment.
+ p := readings.Prepare(cfgID)
+ if _, info, err := readings.LoadWith(p, cfgID, readings.Options{Date: date, All: true}); err == nil {
out.Name = info.Name
out.Season = info.Season
out.Colour = info.Colour
@@ -92,7 +97,7 @@ func Day(date, form, version, lang string) string {
// language localizes the structural labels (Heading) and citation dialect;
// the corpus (version) alone decides the scripture text.
cfgR := config.Config{UILanguage: lang, Lectionary: lect, ReadingVersion: version, All: true}
- secs, _, err := readings.Load(cfgR, readings.Options{Date: date, All: true})
+ secs, _, err := readings.LoadWith(p, cfgR, readings.Options{Date: date, All: true})
if err != nil {
if out.Error == "" {
out.Error = err.Error()
@@ -166,12 +171,17 @@ func Days(start string, count int, form, lang string) string {
lect := lectByForm(form)
ui := i18n.Get(lang)
cfg := config.Config{UILanguage: lang, Lectionary: lect, All: true}
+ // cfg is identical for every date in the loop below, so the layer stack
+ // and book table it implies are too -- Prepare once here rather than
+ // letting each readings.Load call re-stack/re-parse them. See
+ // readings.Prepared's doc comment.
+ p := readings.Prepare(cfg)
out := make([]daySummary, 0, count)
for i := 0; i < count; i++ {
date := d.AddDate(0, 0, i).Format("2006-01-02")
row := daySummary{Date: date, Parts: []summaryPart{}}
- secs, info, err := readings.Load(cfg, readings.Options{Date: date, All: true})
+ secs, info, err := readings.LoadWith(p, cfg, readings.Options{Date: date, All: true})
if err != nil {
row.Error = err.Error()
} else {