diff --git a/nodejs/__test__/table.test.ts b/nodejs/__test__/table.test.ts index 4cad365af..1727f301e 100644 --- a/nodejs/__test__/table.test.ts +++ b/nodejs/__test__/table.test.ts @@ -2298,7 +2298,24 @@ describe.each([arrow15, arrow16, arrow17, arrow18])( ); }); - test("full text search if no embedding function provided", async () => { + test("full text search if only an unrelated embedding function is registered", async () => { + register("unused")( + class extends EmbeddingFunction { + ndims() { + return 3; + } + embeddingDataType() { + return new Float32(); + } + async computeQueryEmbeddings(_data: string) { + return [1, 2, 3]; + } + async computeSourceEmbeddings(data: string[]) { + return data.map(() => [1, 2, 3]); + } + }, + ); + const db = await connect(tmpDir.name); const data = [ { text: "hello world", vector: [0.1, 0.2, 0.3] }, diff --git a/nodejs/lancedb/connection.ts b/nodejs/lancedb/connection.ts index e63a7ae65..52ff811f9 100644 --- a/nodejs/lancedb/connection.ts +++ b/nodejs/lancedb/connection.ts @@ -535,7 +535,7 @@ export class LocalConnection extends Connection { options?.indexCacheSize, ); - let table: Table = new LocalTable(innerTable); + let table: Table = await LocalTable.create(innerTable); // "main" is the default branch, so treat it as no branch. On a real branch, // scope and pin in one step (yielding "version V of branch B"); otherwise // pin the version, if any, against main. @@ -570,7 +570,7 @@ export class LocalConnection extends Connection { options?.isShallow ?? true, ); - return new LocalTable(innerTable); + return await LocalTable.create(innerTable); } private getStorageOptions( @@ -652,7 +652,7 @@ export class LocalConnection extends Connection { storageOptions, ); - return new LocalTable(innerTable); + return await LocalTable.create(innerTable); } async createEmptyTable( @@ -698,7 +698,7 @@ export class LocalConnection extends Connection { namespacePath ?? [], storageOptions, ); - return new LocalTable(innerTable); + return await LocalTable.create(innerTable); } async dropTable(name: string, namespacePath?: string[]): Promise { diff --git a/nodejs/lancedb/permutation.ts b/nodejs/lancedb/permutation.ts index e55b68553..714caae94 100644 --- a/nodejs/lancedb/permutation.ts +++ b/nodejs/lancedb/permutation.ts @@ -172,7 +172,7 @@ export class PermutationBuilder { */ async execute(): Promise { const nativeTable: NativeTable = await this.inner.execute(); - return new LocalTable(nativeTable); + return await LocalTable.create(nativeTable); } } diff --git a/nodejs/lancedb/table.ts b/nodejs/lancedb/table.ts index 3359a2643..cde5344b0 100644 --- a/nodejs/lancedb/table.ts +++ b/nodejs/lancedb/table.ts @@ -814,10 +814,30 @@ export abstract class Table { export class LocalTable extends Table { private readonly inner: _NativeTable; + private readonly hasEmbeddingFunctions: boolean; - constructor(inner: _NativeTable) { + private constructor(inner: _NativeTable, hasEmbeddingFunctions: boolean) { super(); this.inner = inner; + this.hasEmbeddingFunctions = hasEmbeddingFunctions; + } + + static async create(inner: _NativeTable): Promise { + const schemaBuf = await inner.schema(); + const schema = tableFromIPC(schemaBuf).schema; + const serializedFunctions = schema.metadata.get("embedding_functions"); + let hasEmbeddingFunctions = false; + if (serializedFunctions !== undefined) { + try { + const functions: unknown = JSON.parse(serializedFunctions); + hasEmbeddingFunctions = + !Array.isArray(functions) || functions.length > 0; + } catch { + // Let parseFunctions report malformed metadata when the query executes. + hasEmbeddingFunctions = true; + } + } + return new LocalTable(inner, hasEmbeddingFunctions); } get name(): string { return this.inner.name; @@ -1038,7 +1058,7 @@ export class LocalTable extends Table { // fall back to full text search if no embedding functions are defined and the query is a string if ( queryType === "auto" && - (getRegistry().length() === 0 || instanceOfFullTextQuery(query)) + (!this.hasEmbeddingFunctions || instanceOfFullTextQuery(query)) ) { return this.query().fullTextSearch(query, { columns: ftsColumns, @@ -1461,7 +1481,9 @@ export class Branches { fromRef?: string, fromVersion?: number, ): Promise
{ - return new LocalTable(await this.#inner.create(name, fromRef, fromVersion)); + return await LocalTable.create( + await this.#inner.create(name, fromRef, fromVersion), + ); } /** @@ -1472,7 +1494,7 @@ export class Branches { * latest and stays writable. */ async checkout(name: string, version?: number): Promise
{ - return new LocalTable(await this.#inner.checkout(name, version)); + return await LocalTable.create(await this.#inner.checkout(name, version)); } /** Delete a branch. */