Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions core/indexing/LanceDbIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {

import type * as LanceType from "vectordb";
import { tagToString } from "./utils";
import { escapeLanceSqlString } from "./escapeLanceSqlString";

interface LanceDbRow {
uuid: string;
Expand All @@ -38,6 +39,7 @@ type ItemWithChunks = { item: PathAndCacheKey; chunks: Chunk[] };

type ChunkMap = Map<string, ItemWithChunks>;


export class LanceDbIndex implements CodebaseIndex {
private static lance: typeof LanceType | null = null;

Expand Down Expand Up @@ -364,7 +366,7 @@ export class LanceDbIndex implements CodebaseIndex {

for (const { path, cacheKey } of toDel) {
await lanceTable.delete(
`cachekey = '${cacheKey}' AND path = '${path}'`,
`cachekey = '${escapeLanceSqlString(cacheKey)}' AND path = '${escapeLanceSqlString(path)}'`,
);

accumulatedProgress += 1 / toDel.length / 3;
Expand Down Expand Up @@ -419,7 +421,7 @@ export class LanceDbIndex implements CodebaseIndex {
const table = await db.openTable(tableName);
let query = table.search(vector);
if (directory) {
query = query.where(`path LIKE '${directory}%'`).limit(300);
query = query.where(`path LIKE '${escapeLanceSqlString(directory)}%'`).limit(300);
} else {
query = query.limit(n);
}
Expand Down Expand Up @@ -477,7 +479,7 @@ export class LanceDbIndex implements CodebaseIndex {
const sqliteDb = await SqliteDb.get();
const data = await sqliteDb.all(
`SELECT * FROM lance_db_cache WHERE uuid in (${allResults
.map((r) => `'${r.uuid}'`)
.map((r) => `'${escapeLanceSqlString(r.uuid)}'`)
.join(",")})`,
);

Expand Down
18 changes: 18 additions & 0 deletions core/indexing/escapeLanceSqlString.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { describe, expect, it } from "vitest";

import { escapeLanceSqlString } from "./escapeLanceSqlString";

describe("escapeLanceSqlString", () => {
it("leaves strings without quotes unchanged", () => {
expect(escapeLanceSqlString("src/normal.ts")).toBe("src/normal.ts");
});

it("doubles single quotes so LanceDB predicates stay valid", () => {
expect(escapeLanceSqlString("src/don't.ts")).toBe("src/don''t.ts");
expect(escapeLanceSqlString("it's a test/")).toBe("it''s a test/");
});

it("escapes multiple apostrophes", () => {
expect(escapeLanceSqlString("a'b'c")).toBe("a''b''c");
});
});
7 changes: 7 additions & 0 deletions core/indexing/escapeLanceSqlString.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Escape a value for use inside a single-quoted LanceDB SQL string literal.
* LanceDB / SQL standard escaping doubles single quotes.
*/
export function escapeLanceSqlString(value: string): string {
return value.replace(/'/g, "''");
}
Loading