Skip to content

Commit f5be139

Browse files
wesmclaude
andcommitted
fix: SQLite engine fallback and conversation_id in summaries
- Fall back to query.NewSQLiteEngine when the Parquet cache is incomplete so remote TUI endpoints work on fresh installs - Add conversation_id to list/search SELECT columns and update scanMessageRows so summary responses populate ConversationID consistently with the detail endpoint Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 72421b0 commit f5be139

File tree

2 files changed

+16
-12
lines changed

2 files changed

+16
-12
lines changed

cmd/msgvault/cmd/serve.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,25 +84,26 @@ func runServe(cmd *cobra.Command, args []string) error {
8484
}
8585

8686
// Create query engine for TUI aggregate support.
87-
// Requires a complete Parquet cache; without one the engine
88-
// would succeed at creation but fail on first query.
87+
// Prefer DuckDB over Parquet when the cache is complete; otherwise
88+
// fall back to SQLite so remote endpoints still work on fresh installs.
8989
analyticsDir := cfg.AnalyticsDir()
90-
var engine *query.DuckDBEngine
90+
var engine query.Engine
9191
if query.HasCompleteParquetData(analyticsDir) {
92-
var engineErr error
93-
engine, engineErr = query.NewDuckDBEngine(
92+
duckEngine, engineErr := query.NewDuckDBEngine(
9493
analyticsDir, dbPath, s.DB(),
9594
)
9695
if engineErr != nil {
97-
logger.Warn("query engine not available - aggregate endpoints will return 503",
96+
logger.Warn("DuckDB engine failed, falling back to SQLite",
9897
"error", engineErr)
98+
engine = query.NewSQLiteEngine(s.DB())
99+
} else {
100+
engine = duckEngine
99101
}
100102
} else {
101-
logger.Warn("parquet cache not built - run 'msgvault build-cache' to enable aggregate endpoints")
102-
}
103-
if engine != nil {
104-
defer engine.Close()
103+
logger.Info("parquet cache not built - using SQLite engine (run 'msgvault build-cache' for faster aggregates)")
104+
engine = query.NewSQLiteEngine(s.DB())
105105
}
106+
defer engine.Close()
106107

107108
// Create OAuth manager
108109
oauthMgr, err := oauth.NewManager(cfg.OAuth.ClientSecrets, cfg.TokensDir(), logger)

internal/store/api.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ func (s *Store) ListMessages(offset, limit int) ([]APIMessage, int64, error) {
4444
query := `
4545
SELECT
4646
m.id,
47+
COALESCE(m.conversation_id, 0) as conversation_id,
4748
COALESCE(m.subject, '') as subject,
4849
COALESCE(p.email_address, '') as from_email,
4950
COALESCE(m.sent_at, m.received_at, m.internal_date) as sent_at,
@@ -173,6 +174,7 @@ func (s *Store) SearchMessages(query string, offset, limit int) ([]APIMessage, i
173174
ftsQuery := `
174175
SELECT
175176
m.id,
177+
COALESCE(m.conversation_id, 0) as conversation_id,
176178
COALESCE(m.subject, '') as subject,
177179
COALESCE(p.email_address, '') as from_email,
178180
COALESCE(m.sent_at, m.received_at, m.internal_date) as sent_at,
@@ -250,6 +252,7 @@ func (s *Store) searchMessagesLike(query string, offset, limit int) ([]APIMessag
250252
searchQuery := `
251253
SELECT
252254
m.id,
255+
COALESCE(m.conversation_id, 0) as conversation_id,
253256
COALESCE(m.subject, '') as subject,
254257
COALESCE(p.email_address, '') as from_email,
255258
COALESCE(m.sent_at, m.received_at, m.internal_date) as sent_at,
@@ -288,15 +291,15 @@ func (s *Store) searchMessagesLike(query string, offset, limit int) ([]APIMessag
288291
return messages, total, nil
289292
}
290293

291-
// scanMessageRows scans the standard 7-column message row set.
294+
// scanMessageRows scans the standard 8-column message row set.
292295
// Uses string scanning for dates to handle all SQLite datetime formats robustly.
293296
func scanMessageRows(rows *sql.Rows) ([]APIMessage, []int64, error) {
294297
var messages []APIMessage
295298
var ids []int64
296299
for rows.Next() {
297300
var m APIMessage
298301
var sentAtStr sql.NullString
299-
err := rows.Scan(&m.ID, &m.Subject, &m.From, &sentAtStr, &m.Snippet, &m.HasAttachments, &m.SizeEstimate)
302+
err := rows.Scan(&m.ID, &m.ConversationID, &m.Subject, &m.From, &sentAtStr, &m.Snippet, &m.HasAttachments, &m.SizeEstimate)
300303
if err != nil {
301304
return nil, nil, err
302305
}

0 commit comments

Comments
 (0)