* Get unresolved references scoped to specific file paths. * Uses the idx_unresolved_file_path index for efficient lookup.
(filePaths: string[])
| 2172 | * Uses the idx_unresolved_file_path index for efficient lookup. |
| 2173 | */ |
| 2174 | getUnresolvedReferencesByFiles(filePaths: string[]): UnresolvedReference[] { |
| 2175 | if (filePaths.length === 0) return []; |
| 2176 | |
| 2177 | // Chunk under SQLite's parameter limit: the first sync of a very large repo |
| 2178 | // passes every changed file here, which an unbounded `IN (...)` would bind |
| 2179 | // as one parameter each — exceeding MAX_VARIABLE_NUMBER and aborting with |
| 2180 | // "too many SQL variables". (#540) |
| 2181 | const rows: UnresolvedRefRow[] = []; |
| 2182 | for (let i = 0; i < filePaths.length; i += SQLITE_PARAM_CHUNK_SIZE) { |
| 2183 | const chunk = filePaths.slice(i, i + SQLITE_PARAM_CHUNK_SIZE); |
| 2184 | const placeholders = chunk.map(() => '?').join(','); |
| 2185 | const chunkRows = this.db |
| 2186 | .prepare(`SELECT * FROM unresolved_refs WHERE status = 'pending' AND file_path IN (${placeholders})`) |
| 2187 | .all(...chunk) as UnresolvedRefRow[]; |
| 2188 | rows.push(...chunkRows); |
| 2189 | } |
| 2190 | |
| 2191 | return rows.map((row) => ({ |
| 2192 | fromNodeId: row.from_node_id, |
| 2193 | referenceName: row.reference_name, |
| 2194 | referenceKind: row.reference_kind as EdgeKind, |
| 2195 | line: row.line, |
| 2196 | column: row.col, |
| 2197 | candidates: row.candidates ? safeJsonParse(row.candidates, undefined) : undefined, |
| 2198 | filePath: row.file_path, |
| 2199 | language: row.language as Language, |
| 2200 | rowId: row.id, |
| 2201 | })); |
| 2202 | } |
| 2203 | |
| 2204 | /** |
| 2205 | * Delete all unresolved references (after resolution) |
no test coverage detected