From 4c2fcb991fab3da73428d3544a162cdc9b415470 Mon Sep 17 00:00:00 2001 From: Simon Martens Date: Sat, 10 Jan 2026 23:36:10 +0100 Subject: [PATCH] BUGFIX: FTS5 -- make sure only minimum updates happen --- controllers/almanach.go | 12 ++++++++++-- controllers/almanach_edit.go | 18 +++++++++++++++--- controllers/ort_edit.go | 23 ++++++++++++++++++----- controllers/person_edit.go | 23 ++++++++++++++++++----- controllers/reihe_edit.go | 23 ++++++++++++++++++----- 5 files changed, 79 insertions(+), 20 deletions(-) diff --git a/controllers/almanach.go b/controllers/almanach.go index df25f5d..4c35188 100644 --- a/controllers/almanach.go +++ b/controllers/almanach.go @@ -232,6 +232,11 @@ func HasScans(contents []*dbmodels.Content) bool { } func updateEntryFTS5(app core.App, entry *dbmodels.Entry) error { + // Always update contents for backward compatibility + return updateEntryFTS5WithContents(app, entry, true) +} + +func updateEntryFTS5WithContents(app core.App, entry *dbmodels.Entry, updateContents bool) error { if entry == nil { return nil } @@ -267,6 +272,9 @@ func updateEntryFTS5(app core.App, entry *dbmodels.Entry) error { } } - // Update entry and all related contents - return dbmodels.UpdateFTS5EntryAndRelatedContents(app, entry, places, agents, series) + // Update entry and conditionally update related contents + if updateContents { + return dbmodels.UpdateFTS5EntryAndRelatedContents(app, entry, places, agents, series) + } + return dbmodels.UpdateFTS5Entry(app, entry, places, agents, series) } diff --git a/controllers/almanach_edit.go b/controllers/almanach_edit.go index 30378fe..c2426e6 100644 --- a/controllers/almanach_edit.go +++ b/controllers/almanach_edit.go @@ -192,6 +192,13 @@ func (p *AlmanachEditPage) POSTSave(engine *templating.Engine, app core.App) Han } } + // Capture old values that affect content FTS5 records + oldPreferredTitle := entry.PreferredTitle() + oldYear := entry.Year() + + // Check if agent relations will change (affects contents) + agentRelationsChanged := len(payload.NewAgentRelations) > 0 || len(payload.DeletedAgentRelationIDs) > 0 + user := req.User() if err := app.RunInTransaction(func(tx core.App) error { if err := applyEntryChanges(tx, entry, &payload, user); err != nil { @@ -214,17 +221,22 @@ func (p *AlmanachEditPage) POSTSave(engine *templating.Engine, app core.App) Han }) } + // Check if fields that affect contents changed + contentsNeedUpdate := entry.PreferredTitle() != oldPreferredTitle || + entry.Year() != oldYear || + agentRelationsChanged + // Update FTS5 index asynchronously - go func(appInstance core.App, entryID string) { + go func(appInstance core.App, entryID string, updateContents bool) { freshEntry, err := dbmodels.Entries_ID(appInstance, entryID) if err != nil { appInstance.Logger().Error("Failed to load entry for FTS5 update", "entry_id", entryID, "error", err) return } - if err := updateEntryFTS5(appInstance, freshEntry); err != nil { + if err := updateEntryFTS5WithContents(appInstance, freshEntry, updateContents); err != nil { appInstance.Logger().Error("Failed to update FTS5 index for entry", "entry_id", entryID, "error", err) } - }(app, entry.Id) + }(app, entry.Id, contentsNeedUpdate) freshEntry, err := dbmodels.Entries_MusenalmID(app, id) if err == nil { diff --git a/controllers/ort_edit.go b/controllers/ort_edit.go index f032f60..67e2d1b 100644 --- a/controllers/ort_edit.go +++ b/controllers/ort_edit.go @@ -197,6 +197,9 @@ func (p *OrtEditPage) POST(engine *templating.Engine, app core.App) HandleFunc { return p.renderError(engine, app, e, "Ungültiger Status.") } + // Capture old name (entries depend on place name) + oldName := place.Name() + user := req.User() if err := app.RunInTransaction(func(tx core.App) error { applyPlaceForm(place, formdata, name, status, user) @@ -206,17 +209,27 @@ func (p *OrtEditPage) POST(engine *templating.Engine, app core.App) HandleFunc { return p.renderError(engine, app, e, "Speichern fehlgeschlagen.") } - // Update FTS5 index for place and all related entries asynchronously - go func(appInstance core.App, placeID string) { + // Check if name changed (entries store place name) + nameChanged := place.Name() != oldName + + // Update FTS5 index for place and conditionally update related entries asynchronously + go func(appInstance core.App, placeID string, updateEntries bool) { freshPlace, err := dbmodels.Places_ID(appInstance, placeID) if err != nil { appInstance.Logger().Error("Failed to load place for FTS5 update", "place_id", placeID, "error", err) return } - if err := dbmodels.UpdateFTS5PlaceAndRelatedEntries(appInstance, freshPlace); err != nil { - appInstance.Logger().Error("Failed to update FTS5 index for place and related records", "place_id", placeID, "error", err) + // If name changed, update place + entries. Otherwise just update place. + if updateEntries { + if err := dbmodels.UpdateFTS5PlaceAndRelatedEntries(appInstance, freshPlace); err != nil { + appInstance.Logger().Error("Failed to update FTS5 index for place and entries", "place_id", placeID, "error", err) + } + } else { + if err := dbmodels.UpdateFTS5Place(appInstance, freshPlace); err != nil { + appInstance.Logger().Error("Failed to update FTS5 index for place", "place_id", placeID, "error", err) + } } - }(app, place.Id) + }(app, place.Id, nameChanged) redirect := fmt.Sprintf("/ort/%s/edit?saved_message=%s", id, url.QueryEscape("Änderungen gespeichert.")) return e.Redirect(http.StatusSeeOther, redirect) diff --git a/controllers/person_edit.go b/controllers/person_edit.go index e93262d..06017fc 100644 --- a/controllers/person_edit.go +++ b/controllers/person_edit.go @@ -303,6 +303,9 @@ func (p *PersonEditPage) POST(engine *templating.Engine, app core.App) HandleFun return p.renderError(engine, app, e, "Ungültiger Status.") } + // Capture old name (entries and contents depend on agent name) + oldName := agent.Name() + user := req.User() if err := app.RunInTransaction(func(tx core.App) error { applyPersonForm(agent, formdata, name, status, user) @@ -312,17 +315,27 @@ func (p *PersonEditPage) POST(engine *templating.Engine, app core.App) HandleFun return p.renderError(engine, app, e, "Speichern fehlgeschlagen.") } - // Update FTS5 index for agent and all related entries/contents asynchronously - go func(appInstance core.App, agentID string) { + // Check if name changed (entries and contents store agent name) + nameChanged := agent.Name() != oldName + + // Update FTS5 index for agent and conditionally update related entries/contents asynchronously + go func(appInstance core.App, agentID string, updateRelated bool) { freshAgent, err := dbmodels.Agents_ID(appInstance, agentID) if err != nil { appInstance.Logger().Error("Failed to load agent for FTS5 update", "agent_id", agentID, "error", err) return } - if err := dbmodels.UpdateFTS5AgentAndRelated(appInstance, freshAgent); err != nil { - appInstance.Logger().Error("Failed to update FTS5 index for agent and related records", "agent_id", agentID, "error", err) + // If name changed, update agent + entries + contents. Otherwise just update agent. + if updateRelated { + if err := dbmodels.UpdateFTS5AgentAndRelated(appInstance, freshAgent); err != nil { + appInstance.Logger().Error("Failed to update FTS5 index for agent and related records", "agent_id", agentID, "error", err) + } + } else { + if err := dbmodels.UpdateFTS5Agent(appInstance, freshAgent); err != nil { + appInstance.Logger().Error("Failed to update FTS5 index for agent", "agent_id", agentID, "error", err) + } } - }(app, agent.Id) + }(app, agent.Id, nameChanged) redirect := fmt.Sprintf("/person/%s/edit?saved_message=%s", id, url.QueryEscape("Änderungen gespeichert.")) return e.Redirect(http.StatusSeeOther, redirect) diff --git a/controllers/reihe_edit.go b/controllers/reihe_edit.go index 963a53d..56d23a8 100644 --- a/controllers/reihe_edit.go +++ b/controllers/reihe_edit.go @@ -409,6 +409,9 @@ func (p *ReiheEditPage) POST(engine *templating.Engine, app core.App) HandleFunc return p.renderError(engine, app, e, "Ungültiger Status.") } + // Capture old title (entries depend on series title) + oldTitle := series.Title() + user := req.User() if err := app.RunInTransaction(func(tx core.App) error { applySeriesForm(series, formdata, title, status, user) @@ -418,17 +421,27 @@ func (p *ReiheEditPage) POST(engine *templating.Engine, app core.App) HandleFunc return p.renderError(engine, app, e, "Speichern fehlgeschlagen.") } - // Update FTS5 index for series and all related entries asynchronously - go func(appInstance core.App, seriesID string) { + // Check if title changed (entries store series title) + titleChanged := series.Title() != oldTitle + + // Update FTS5 index for series and conditionally update related entries asynchronously + go func(appInstance core.App, seriesID string, updateEntries bool) { freshSeries, err := dbmodels.Series_ID(appInstance, seriesID) if err != nil { appInstance.Logger().Error("Failed to load series for FTS5 update", "series_id", seriesID, "error", err) return } - if err := dbmodels.UpdateFTS5SeriesAndRelatedEntries(appInstance, freshSeries); err != nil { - appInstance.Logger().Error("Failed to update FTS5 index for series and related records", "series_id", seriesID, "error", err) + // If title changed, update series + entries. Otherwise just update series. + if updateEntries { + if err := dbmodels.UpdateFTS5SeriesAndRelatedEntries(appInstance, freshSeries); err != nil { + appInstance.Logger().Error("Failed to update FTS5 index for series and entries", "series_id", seriesID, "error", err) + } + } else { + if err := dbmodels.UpdateFTS5Series(appInstance, freshSeries); err != nil { + appInstance.Logger().Error("Failed to update FTS5 index for series", "series_id", seriesID, "error", err) + } } - }(app, series.Id) + }(app, series.Id, titleChanged) redirect := fmt.Sprintf("/reihe/%s/edit?saved_message=%s", id, url.QueryEscape("Änderungen gespeichert.")) return e.Redirect(http.StatusSeeOther, redirect)