返回 DeepSeek-Reasonix
directory_scan.go
根目录 / internal / sessioncatalog / directory_scan.go
1 package sessioncatalog
2
3 import (
4 "context"
5 "database/sql"
6 "errors"
7 )
8
9 type DirectoryScanStatus struct {
10 Known bool
11 State string
12 Error string
13 }
14
15 // CountDirectorySessions reports the number of non-missing rows currently
16 // projected for a directory. It is intentionally content-free so diagnostics
17 // can compare the disposable projection with authoritative file enumeration.
18 func (c *Catalog) CountDirectorySessions(ctx context.Context, path string) (int64, error) {
19 if c == nil || c.db == nil {
20 return 0, nil
21 }
22 var count int64
23 err := c.db.QueryRowContext(ctx, `SELECT COUNT(*) FROM catalog_sessions WHERE directory_key=? AND missing_since=0`, c.pathKey(path)).Scan(&count)
24 return count, err
25 }
26
27 // DirectoryStatus exposes only scan completeness, never session contents.
28 // Desktop uses it to publish a per-workspace partial/complete projection while
29 // allowing already-indexed rows to remain visible during another directory's
30 // first scan or failure.
31 func (c *Catalog) DirectoryStatus(ctx context.Context, path string) DirectoryScanStatus {
32 if c == nil || c.db == nil {
33 return DirectoryScanStatus{}
34 }
35 path = cleanCatalogAccessPath(path)
36 if path == "" {
37 return DirectoryScanStatus{}
38 }
39 var status DirectoryScanStatus
40 err := c.db.QueryRowContext(ctx, `SELECT state,error FROM catalog_directories WHERE path_key=?`, c.pathKey(path)).Scan(&status.State, &status.Error)
41 if errors.Is(err, sql.ErrNoRows) || err != nil {
42 return DirectoryScanStatus{}
43 }
44 status.Known = true
45 return status
46 }
47
48 // DirectoryScanReady reports whether this directory has finished at least one
49 // catalog scan. An opened-but-unscanned current cache is not ready: ListTopics would
50 // otherwise treat "no rows yet" as "the user has no conversations".
51 func (c *Catalog) DirectoryScanReady(ctx context.Context, path string) bool {
52 return c.DirectoryStatus(ctx, path).State == "ready"
53 }
54
55 // HasWorkspaceRecords reports whether any non-missing session is already
56 // projected for this workspace. Used so an in-progress scan that has written
57 // rows stays authoritative, while a brand-new empty cache does not.
58 func (c *Catalog) HasWorkspaceRecords(ctx context.Context, scope, workspaceRoot string) bool {
59 if c == nil || c.db == nil {
60 return false
61 }
62 scope, workspaceRoot = normalizeScope(scope, workspaceRoot)
63 var n int
64 err := c.db.QueryRowContext(ctx, `SELECT COUNT(*) FROM catalog_sessions WHERE scope=? AND workspace_root_key=? AND missing_since=0`,
65 scope, c.workspaceRootKey(scope, workspaceRoot)).Scan(&n)
66 return err == nil && n > 0
67 }
68
68 lines GO