Skip to content

Commit 8055553

Browse files
docs(search): annotate search and parsing helpers
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
1 parent 7e2c83a commit 8055553

5 files changed

Lines changed: 60 additions & 8 deletions

File tree

internal/parse/treesitter/walker.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ func (w *Walker) executeQueries(root *sitter.Node, content []byte, filePath stri
232232
var interfaces []interfaceInfo
233233

234234
// nodeKey → index in nodes slice for O(1) dedup lookup
235+
// @intent key duplicate symbol matches by name and source span during one query execution.
235236
type nodeKey struct {
236237
name string
237238
startLine int
@@ -690,6 +691,8 @@ func (w *Walker) ExtractComments(ctx context.Context, filePath string, content [
690691
return comments, nil
691692
}
692693

694+
// parseSourceCtx parses one source buffer with cancellation support, returning the resulting tree.
695+
// @intent let long parses honor caller cancellation while reusing pooled parsers for throughput.
693696
func (w *Walker) parseSourceCtx(ctx context.Context, content []byte) (*sitter.Tree, error) {
694697
if err := ctx.Err(); err != nil {
695698
return nil, err
@@ -920,6 +923,7 @@ func (w *Walker) tryExtractDocstring(exprStmt *sitter.Node, content []byte) (Com
920923
}
921924
}
922925

926+
// @intent accept only Python string literal forms that can legally act as docstrings.
923927
func isSupportedPythonDocstringLiteral(text string) bool {
924928
lower := strings.ToLower(text)
925929
for _, quote := range []string{"\"\"\"", "'''"} {
@@ -985,6 +989,8 @@ func mergeCommentBlocks(comments, docstrings []CommentBlock) []CommentBlock {
985989
return merged
986990
}
987991

992+
// acquireParser borrows a Tree-sitter parser from the per-walker pool, creating one on first use.
993+
// @intent amortize parser construction cost across many parses on the same language.
988994
func (w *Walker) acquireParser() *sitter.Parser {
989995
if w.lang == nil {
990996
return nil
@@ -997,6 +1003,8 @@ func (w *Walker) acquireParser() *sitter.Parser {
9971003
return p
9981004
}
9991005

1006+
// releaseParser returns a parser instance to the pool for reuse.
1007+
// @intent keep allocated parsers alive between parses instead of letting them be garbage collected.
10001008
func (w *Walker) releaseParser(p *sitter.Parser) {
10011009
if p == nil || w.lang == nil {
10021010
return
@@ -1040,6 +1048,7 @@ func (w *Walker) getLanguage() (*sitter.Language, error) {
10401048

10411049
// rangesOverlap reports whether two inclusive line ranges share at least one line.
10421050
// @intent detect whether two symbol captures refer to overlapping source spans
1051+
// @intent detect overlapping source spans when deduplicating competing Tree-sitter captures.
10431052
func rangesOverlap(aStart, aEnd, bStart, bEnd int) bool {
10441053
return aStart <= bEnd && bStart <= aEnd
10451054
}

internal/pathutil/exclude.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ func LoadIncludePathsFromConfig(dir string) ([]string, error) {
116116
return cfg.IncludePaths, nil
117117
}
118118

119+
// MatchIncludePaths reports whether relPath falls inside or is an ancestor of any configured include path.
120+
// @intent let walkers prune directories that lie outside user-selected include scopes while still descending into ancestors.
119121
func MatchIncludePaths(relPath string, includePaths []string) bool {
120122
relPath = normalizeIncludePath(relPath)
121123
for _, inc := range includePaths {
@@ -129,6 +131,7 @@ func MatchIncludePaths(relPath string, includePaths []string) bool {
129131

130132
// HasPathPrefix reports whether path is the same as prefix or is nested under it.
131133
// Both inputs are normalized to slash-separated clean relative paths.
134+
// @intent compare include path scopes after normalization so callers can test path containment reliably.
132135
func HasPathPrefix(pathValue, prefix string) bool {
133136
pathValue = normalizeIncludePath(pathValue)
134137
prefix = normalizeIncludePath(prefix)
@@ -138,6 +141,8 @@ func HasPathPrefix(pathValue, prefix string) bool {
138141
return pathValue == prefix || strings.HasPrefix(pathValue, prefix+"/")
139142
}
140143

144+
// normalizeIncludePath converts user-supplied include paths to a comparable slash form.
145+
// @intent guarantee comparisons treat "./foo", "foo", and "foo/" as the same logical path.
141146
func normalizeIncludePath(p string) string {
142147
clean := path.Clean(strings.ReplaceAll(filepath.ToSlash(strings.TrimSpace(p)), `\`, "/"))
143148
if clean == "." {

internal/store/search/postgres.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ func (p *PostgresBackend) PurgeNamespace(ctx context.Context, db *gorm.DB) error
118118
return nil
119119
}
120120

121+
// resultRow scans node_id values from PostgreSQL tsquery matches.
122+
// @intent decode the single-column tsquery result before joining back to nodes.
123+
type resultRow struct {
124+
NodeID uint
125+
}
126+
121127
// Query는 PostgreSQL tsquery로 관련 노드를 검색한다.
122128
// @intent 사용자 검색어를 prefix tsquery로 변환해 관련 노드를 찾는다.
123129
// @requires limit는 0보다 커야 의미 있는 결과를 얻는다.
@@ -132,10 +138,6 @@ func (p *PostgresBackend) Query(ctx context.Context, db *gorm.DB, query string,
132138
}
133139
ns := ctxns.FromContext(ctx)
134140

135-
type resultRow struct {
136-
NodeID uint
137-
}
138-
139141
var rows []resultRow
140142
querySQL := `
141143
SELECT sd.node_id

internal/store/search/sanitize.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
// @index Query sanitizers for backend-specific full-text search syntax.
12
package search
23

34
import (
45
"strings"
56
"unicode"
67
)
78

9+
// sanitizeTokens extracts lowercase identifier-like terms from raw search input.
10+
// @intent normalize user queries into backend-safe tokens before they are embedded into FTS syntax.
811
func sanitizeTokens(query string) []string {
912
fields := strings.FieldsFunc(query, func(r rune) bool {
1013
return !(unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_')
@@ -20,6 +23,7 @@ func sanitizeTokens(query string) []string {
2023
}
2124

2225
// SanitizeFTS5 converts raw user input into a safe FTS5 prefix query.
26+
// @intent build SQLite FTS queries that preserve prefix matching without exposing parser-breaking characters.
2327
func SanitizeFTS5(query string) string {
2428
tokens := sanitizeTokens(query)
2529
if len(tokens) == 0 {
@@ -33,6 +37,7 @@ func SanitizeFTS5(query string) string {
3337
}
3438

3539
// SanitizePostgresTSQuery converts raw user input into a safe prefix tsquery.
40+
// @intent translate free-form user input into a PostgreSQL tsquery that mirrors the SQLite prefix search behavior.
3641
func SanitizePostgresTSQuery(query string) string {
3742
tokens := sanitizeTokens(query)
3843
if len(tokens) == 0 {

internal/store/search/sqlite.go

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ func (s *SQLiteBackend) PurgeNamespace(ctx context.Context, db *gorm.DB) error {
9797
return db.WithContext(ctx).Exec("DELETE FROM "+sqliteFTSTable+" WHERE namespace = ?", ctxns.FromContext(ctx)).Error
9898
}
9999

100+
// rebuildTable clears all FTS rows for the current namespace in tableName and
101+
// repopulates them from search_documents in batches. Used by both full Rebuild
102+
// and the legacy-upgrade path.
103+
// @intent resynchronize one namespace-scoped SQLite FTS table from persisted search documents without disturbing other namespaces.
100104
func (s *SQLiteBackend) rebuildTable(ctx context.Context, db *gorm.DB, tableName string) error {
101105
ns := ctxns.FromContext(ctx)
102106
clearSQL := fmt.Sprintf("DELETE FROM %s WHERE namespace = ?", tableName)
@@ -125,6 +129,10 @@ func (s *SQLiteBackend) rebuildTable(ctx context.Context, db *gorm.DB, tableName
125129
})
126130
}
127131

132+
// rebuildTableNodes deletes and re-inserts FTS rows only for the given nodeIDs
133+
// within the current namespace, processing them in chunks of scopedRebuildChunkSize
134+
// to avoid oversized IN clauses.
135+
// @intent refresh only the requested node documents in SQLite FTS so incremental updates can avoid a full namespace rebuild.
128136
func (s *SQLiteBackend) rebuildTableNodes(ctx context.Context, db *gorm.DB, tableName string, nodeIDs []uint) error {
129137
ns := ctxns.FromContext(ctx)
130138
return db.WithContext(ctx).Transaction(func(outerTx *gorm.DB) error {
@@ -154,6 +162,10 @@ func (s *SQLiteBackend) rebuildTableNodes(ctx context.Context, db *gorm.DB, tabl
154162
})
155163
}
156164

165+
// insertSQLiteFTSBatch executes one bulk INSERT for a batch of search documents into an FTS table.
166+
// @intent push many rows in a single statement so rebuild paths avoid per-row round trips.
167+
// @sideEffect inserts rows into the supplied FTS virtual table.
168+
// @mutates search_fts virtual table contents
157169
func insertSQLiteFTSBatch(ctx context.Context, tx *gorm.DB, tableName string, docs []model.SearchDocument) error {
158170
if len(docs) == 0 {
159171
return nil
@@ -162,6 +174,10 @@ func insertSQLiteFTSBatch(ctx context.Context, tx *gorm.DB, tableName string, do
162174
return tx.WithContext(ctx).Exec(insertSQL, args...).Error
163175
}
164176

177+
// buildSQLiteFTSInsert constructs a bulk INSERT statement for the FTS virtual
178+
// table, returning the SQL string and its positional arguments. Each document
179+
// maps to a (node_id, content, language, namespace) value row.
180+
// @intent batch SQLite FTS inserts into one statement so rebuild paths can stream many documents with minimal per-row overhead.
165181
func buildSQLiteFTSInsert(tableName string, docs []model.SearchDocument) (string, []any) {
166182
if len(docs) == 0 {
167183
return "", nil
@@ -180,6 +196,12 @@ func buildSQLiteFTSInsert(tableName string, docs []model.SearchDocument) (string
180196
return insertSQL, args
181197
}
182198

199+
// ftsRow scans node_id values from search_fts MATCH queries.
200+
// @intent decode the single-column FTS result before joining back to nodes.
201+
type ftsRow struct {
202+
NodeID uint
203+
}
204+
183205
// Query는 FTS5 MATCH 질의로 관련 노드를 검색한다.
184206
// @intent 사용자 검색어를 SQLite FTS prefix 질의로 변환해 노드를 찾는다.
185207
// @requires limit는 0보다 커야 의미 있는 결과를 얻는다.
@@ -194,10 +216,6 @@ func (s *SQLiteBackend) Query(ctx context.Context, db *gorm.DB, query string, li
194216
}
195217
ns := ctxns.FromContext(ctx)
196218

197-
type ftsRow struct {
198-
NodeID uint
199-
}
200-
201219
var rows []ftsRow
202220
querySQL := `SELECT CAST(node_id AS INTEGER) AS node_id
203221
FROM search_fts
@@ -245,6 +263,8 @@ func (s *SQLiteBackend) Query(ctx context.Context, db *gorm.DB, query string, li
245263
return result, nil
246264
}
247265

266+
// sqliteColumnExists reports whether a column is present on a given SQLite table via PRAGMA table_info.
267+
// @intent gate schema migrations on actual table layout instead of guessing from version markers.
248268
func sqliteColumnExists(db *gorm.DB, tableName, columnName string) (bool, error) {
249269
rows, err := db.Raw("PRAGMA table_info(" + tableName + ")").Rows()
250270
if err != nil {
@@ -266,6 +286,10 @@ func sqliteColumnExists(db *gorm.DB, tableName, columnName string) (bool, error)
266286
return false, rows.Err()
267287
}
268288

289+
// createSQLiteFTSTable issues a CREATE VIRTUAL TABLE … USING fts5 DDL for the
290+
// given tableName. When ifNotExists is true the statement is idempotent; when
291+
// false it is used for the upgrade shadow table where a fresh schema is required.
292+
// @intent create the namespace-aware SQLite FTS table shape used by both first-run migration and legacy upgrade flows.
269293
func createSQLiteFTSTable(db *gorm.DB, tableName string, ifNotExists bool) error {
270294
clause := ""
271295
if ifNotExists {
@@ -278,6 +302,11 @@ func createSQLiteFTSTable(db *gorm.DB, tableName string, ifNotExists bool) error
278302
return db.Exec(stmt).Error
279303
}
280304

305+
// upgradeLegacyFTSTable migrates a pre-namespace search_fts schema to the
306+
// current four-column layout (node_id, content, language, namespace). It builds
307+
// a shadow table, populates it via rebuildTable, then swaps it into place using
308+
// RENAME, keeping the old table as a backup until the swap succeeds.
309+
// @intent upgrade legacy SQLite FTS storage to the namespace-aware schema without losing the indexed search snapshot.
281310
func (s *SQLiteBackend) upgradeLegacyFTSTable(db *gorm.DB) error {
282311
for _, tableName := range []string{sqliteFTSUpgradeTable, sqliteFTSLegacyBackup} {
283312
if err := db.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s", tableName)).Error; err != nil {
@@ -306,6 +335,8 @@ func (s *SQLiteBackend) upgradeLegacyFTSTable(db *gorm.DB) error {
306335
return nil
307336
}
308337

338+
// sqliteTableExists reports whether a regular table with the given name exists in sqlite_master.
339+
// @intent let migration code branch on table presence without depending on GORM AutoMigrate side effects.
309340
func sqliteTableExists(db *gorm.DB, tableName string) (bool, error) {
310341
var count int64
311342
if err := db.Raw("SELECT count(*) FROM sqlite_master WHERE type = 'table' AND name = ?", tableName).Scan(&count).Error; err != nil {

0 commit comments

Comments
 (0)