maven: calendar event querying (task 3)
Store: CalendarEvents(ctx, from, to) — filters caldav facts by key date prefix. IPC: full wiring through interface, server dispatch, and client. Router: ParseCalendarDate (сегодня/завтра), CalendarEventFormatter (RU reply). Voice: calendar detection before notes RAG in IntentQuery handler. Tests: store integration test, date parser tests, formatter tests. Co-Authored-By: opencode <opencode@anthropic.com>
This commit is contained in:
@@ -79,6 +79,32 @@ func (s *Store) RecentFacts(ctx context.Context, n int) ([]Fact, error) {
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
// CalendarEvents returns caldav facts whose key date falls within [from, to).
|
||||
// Calendar event keys have the format calendar_event_YYYYMMDD_<summary>.
|
||||
func (s *Store) CalendarEvents(ctx context.Context, from, to time.Time) ([]Fact, error) {
|
||||
prefixFrom := fmt.Sprintf("calendar_event_%s", from.Format("20060102"))
|
||||
prefixTo := fmt.Sprintf("calendar_event_%s", to.Format("20060102"))
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT id, ts, kind, key, value, source, confidence, voids_id
|
||||
FROM facts
|
||||
WHERE source = 'poll:caldav'
|
||||
AND key >= ? AND key < ?
|
||||
ORDER BY key`, prefixFrom, prefixTo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("calendar events: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []Fact
|
||||
for rows.Next() {
|
||||
f, err := scanFact(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, f)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
// LatestFactBySource — provenance-scoped. A rule on `service_down` trusts only
|
||||
// source=poll:healthcheck; a compromised poller can't forge a trigger. Use this
|
||||
// from rules, not LatestFact, whenever the rule's source contract matters.
|
||||
|
||||
@@ -334,4 +334,47 @@ func TestPresenceStateSingletonRoundtrip(t *testing.T) {
|
||||
if b, score, _, err := s.LoadPresenceState(ctx); err != nil || b != Present || score != 0.83 {
|
||||
t.Fatalf("after save: want Present/0.83, got %s/%f (%v)", b, score, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalendarEvents(t *testing.T) {
|
||||
store := newTestStore(t)
|
||||
defer store.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
now := time.Date(2026, 7, 6, 12, 0, 0, 0, time.UTC)
|
||||
|
||||
// Write facts for different dates
|
||||
store.WriteFact(ctx, time.Date(2026, 7, 6, 8, 0, 0, 0, time.UTC), KindSelf, "calendar_event_20260706_Morning-standup", `"Morning standup @ 10:00-10:30"`, "poll:caldav", 1.0, sql.NullInt64{})
|
||||
store.WriteFact(ctx, time.Date(2026, 7, 6, 8, 0, 0, 0, time.UTC), KindSelf, "calendar_event_20260706_Lunch", `"Lunch @ 12:00-13:00"`, "poll:caldav", 1.0, sql.NullInt64{})
|
||||
store.WriteFact(ctx, time.Date(2026, 7, 6, 8, 0, 0, 0, time.UTC), KindSelf, "calendar_event_20260707_Doctor", `"Doctor @ 14:00-15:00"`, "poll:caldav", 1.0, sql.NullInt64{})
|
||||
store.WriteFact(ctx, time.Date(2026, 7, 6, 8, 0, 0, 0, time.UTC), KindSelf, "calendar_event_20260705_Yesterday", `"Yesterday thing"`, "poll:caldav", 1.0, sql.NullInt64{})
|
||||
|
||||
// Query July 6
|
||||
events, err := store.CalendarEvents(ctx, now.Truncate(24*time.Hour), now.Truncate(24*time.Hour).Add(24*time.Hour))
|
||||
if err != nil {
|
||||
t.Fatalf("CalendarEvents: %v", err)
|
||||
}
|
||||
if len(events) != 2 {
|
||||
t.Fatalf("expected 2 events on July 6, got %d", len(events))
|
||||
}
|
||||
|
||||
// Query July 7
|
||||
t7 := time.Date(2026, 7, 7, 0, 0, 0, 0, time.UTC)
|
||||
events, err = store.CalendarEvents(ctx, t7, t7.Add(24*time.Hour))
|
||||
if err != nil {
|
||||
t.Fatalf("CalendarEvents: %v", err)
|
||||
}
|
||||
if len(events) != 1 {
|
||||
t.Fatalf("expected 1 event on July 7, got %d", len(events))
|
||||
}
|
||||
|
||||
// Query date with no events
|
||||
t8 := time.Date(2026, 7, 8, 0, 0, 0, 0, time.UTC)
|
||||
events, err = store.CalendarEvents(ctx, t8, t8.Add(24*time.Hour))
|
||||
if err != nil {
|
||||
t.Fatalf("CalendarEvents: %v", err)
|
||||
}
|
||||
if len(events) != 0 {
|
||||
t.Fatalf("expected 0 events on July 8, got %d", len(events))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user