* Find nodes whose name contains a substring (LIKE-based). * Useful for CamelCase-part matching where FTS fails because * e.g. "TransportSearchAction" is one FTS token, not matchable by "Search"*. * * Results are ordered by name length (shorter = more likely to be the core type).
(
substring: string,
options: SearchOptions & { excludePrefix?: boolean } = {}
)
| 1210 | * Results are ordered by name length (shorter = more likely to be the core type). |
| 1211 | */ |
| 1212 | findNodesByNameSubstring( |
| 1213 | substring: string, |
| 1214 | options: SearchOptions & { excludePrefix?: boolean } = {} |
| 1215 | ): SearchResult[] { |
| 1216 | const { kinds, languages, limit = 30, excludePrefix } = options; |
| 1217 | |
| 1218 | let sql = ` |
| 1219 | SELECT nodes.*, 1.0 as score |
| 1220 | FROM nodes |
| 1221 | WHERE name LIKE ? |
| 1222 | `; |
| 1223 | const params: (string | number)[] = [`%${substring}%`]; |
| 1224 | |
| 1225 | // Exclude prefix matches (handled by FTS-based prefix search in Step 2b) |
| 1226 | if (excludePrefix) { |
| 1227 | sql += ` AND name NOT LIKE ?`; |
| 1228 | params.push(`${substring}%`); |
| 1229 | } |
| 1230 | |
| 1231 | if (kinds && kinds.length > 0) { |
| 1232 | sql += ` AND kind IN (${kinds.map(() => '?').join(',')})`; |
| 1233 | params.push(...kinds); |
| 1234 | } |
| 1235 | |
| 1236 | if (languages && languages.length > 0) { |
| 1237 | sql += ` AND language IN (${languages.map(() => '?').join(',')})`; |
| 1238 | params.push(...languages); |
| 1239 | } |
| 1240 | |
| 1241 | sql += ' ORDER BY length(name) ASC LIMIT ?'; |
| 1242 | params.push(limit); |
| 1243 | |
| 1244 | const rows = this.db.prepare(sql).all(...params) as (NodeRow & { score: number })[]; |
| 1245 | return rows.map((row) => ({ |
| 1246 | node: rowToNode(row), |
| 1247 | score: row.score, |
| 1248 | })); |
| 1249 | } |
| 1250 | |
| 1251 | // =========================================================================== |
| 1252 | // Edge Operations |
no test coverage detected