MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / findNodesByExactName

Method findNodesByExactName

src/db/queries.ts:1512–1591  ·  view source on GitHub ↗

* Find nodes by exact name match * * Used for hybrid search - looks up symbols by exact name or case-insensitive match. * Returns high-confidence matches for known symbol names extracted from query. * * @param names - Array of symbol names to look up * @param options - Search optio

(names: string[], options: SearchOptions = {})

Source from the content-addressed store, hash-verified

1510 * @returns SearchResult array with exact matches scored at 1.0
1511 */
1512 findNodesByExactName(names: string[], options: SearchOptions = {}): SearchResult[] {
1513 if (names.length === 0) return [];
1514
1515 const { kinds, languages, limit = 50 } = options;
1516
1517 // Two-pass approach to handle common names (e.g., "run" has 40+ matches):
1518 // Pass 1: Find which files contain distinctive (rare) symbols from the query.
1519 // Pass 2: Query each name, boosting results that co-locate with distinctive symbols.
1520
1521 // Pass 1: Find files containing each queried name, identify distinctive names
1522 const nameToFiles = new Map<string, Set<string>>();
1523 for (const name of names) {
1524 let sql = 'SELECT DISTINCT file_path FROM nodes WHERE name COLLATE NOCASE = ?';
1525 const params: (string | number)[] = [name];
1526 if (kinds && kinds.length > 0) {
1527 sql += ` AND kind IN (${kinds.map(() => '?').join(',')})`;
1528 params.push(...kinds);
1529 }
1530 sql += ' LIMIT 100';
1531 const rows = this.db.prepare(sql).all(...params) as { file_path: string }[];
1532 nameToFiles.set(name.toLowerCase(), new Set(rows.map(r => r.file_path)));
1533 }
1534
1535 // Distinctive names are those with fewer than 10 file matches (e.g., "scrapeLoop" = 1 file)
1536 const distinctiveFiles = new Set<string>();
1537 for (const [, files] of nameToFiles) {
1538 if (files.size > 0 && files.size < 10) {
1539 for (const f of files) distinctiveFiles.add(f);
1540 }
1541 }
1542
1543 // Pass 2: Query each name with per-name limit, scoring by co-location
1544 const perNameLimit = Math.max(8, Math.ceil(limit / names.length));
1545 const allResults: SearchResult[] = [];
1546 const seenIds = new Set<string>();
1547
1548 for (const name of names) {
1549 let sql = `
1550 SELECT nodes.*, 1.0 as score
1551 FROM nodes
1552 WHERE name COLLATE NOCASE = ?
1553 `;
1554 const params: (string | number)[] = [name];
1555
1556 if (kinds && kinds.length > 0) {
1557 sql += ` AND kind IN (${kinds.map(() => '?').join(',')})`;
1558 params.push(...kinds);
1559 }
1560
1561 if (languages && languages.length > 0) {
1562 sql += ` AND language IN (${languages.map(() => '?').join(',')})`;
1563 params.push(...languages);
1564 }
1565
1566 // Fetch enough to find co-located results among common names
1567 sql += ' LIMIT ?';
1568 params.push(Math.max(perNameLimit * 3, 50));
1569

Callers 1

findRelevantContextMethod · 0.80

Calls 6

rowToNodeFunction · 0.85
hasMethod · 0.80
allMethod · 0.65
prepareMethod · 0.65
joinMethod · 0.45
setMethod · 0.45

Tested by

no test coverage detected