diff --git a/JS/edgechains/vector-db/index.js b/JS/edgechains/vector-db/index.js index 425041f47..173c3c7f0 100644 --- a/JS/edgechains/vector-db/index.js +++ b/JS/edgechains/vector-db/index.js @@ -2,9 +2,4 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Supabase = void 0; var supabase_js_1 = require("./src/lib/supabase/supabase.js"); -Object.defineProperty(exports, "Supabase", { - enumerable: true, - get: function () { - return supabase_js_1.Supabase; - }, -}); +Object.defineProperty(exports, "Supabase", { enumerable: true, get: function () { return supabase_js_1.Supabase; } }); diff --git a/JS/edgechains/vector-db/src/lib/supabase/supabase.d.ts b/JS/edgechains/vector-db/src/lib/supabase/supabase.d.ts index ac4022e96..37406b88a 100644 --- a/JS/edgechains/vector-db/src/lib/supabase/supabase.d.ts +++ b/JS/edgechains/vector-db/src/lib/supabase/supabase.d.ts @@ -7,6 +7,13 @@ interface InsertVectorDataArgs { tableName: string; [key: string]: any; } +interface InsertBulkVectorDataArgs { + client: SupabaseClient; + tableName: string; + data: Array<{ + [key: string]: any; + }>; +} interface GetDataFromQueryArgs { client: SupabaseClient; functionNameToCall: string; @@ -18,15 +25,23 @@ export declare class Supabase { constructor(SUPABASE_URL: string, SUPABASE_API_KEY: string); createClient(): SupabaseClient; /** - * Insert data into a vector database using a Supabase client. - * @param client The Supabase client instance. - * @param relation The name of the relation (table) to insert data into. - * @param content The content to insert. - * @param embedding The embedding data to insert. - * @returns The inserted data if successful. - * @throws Error if insertion fails. - */ - insertVectorData({ client, tableName, ...args }: InsertVectorDataArgs): Promise; + * Insert data into a vector database using a Supabase client. + * @param client The Supabase client instance. + * @param relation The name of the relation (tableName) to insert data into. + * @param content The content to insert. + * @returns The inserted data if successful. + * @throws Error if insertion fails. + */ + insertVectorData({ client, tableName, ...args }: InsertVectorDataArgs | InsertBulkVectorDataArgs): Promise; + /** + * Insert Bulk data into a vector database using a Supabase client. + * @param client The Supabase client instance. + * @param relation The name of the relation (table) to insert data into. + * @param args The array of objects containing the data to be inserted. + * @returns The inserted data if successful. + * @throws Error if insertion fails. + */ + insertBulkVectorData({ client, tableName, data }: InsertBulkVectorDataArgs): Promise; /** * fetch data from vector database using a Supabase client * @param client - The Supabase client instance. @@ -43,11 +58,7 @@ export declare class Supabase { * @returns The fetched data if successful. * @throws Error if fetching fails. */ - getData({ - client, - tableName, - columns, - }: { + getData({ client, tableName, columns }: { client: SupabaseClient; tableName: string; columns: string; @@ -60,11 +71,7 @@ export declare class Supabase { * @returns The fetched data if successful. * @throws Error if fetching fails. */ - getDataById({ - client, - tableName, - id, - }: { + getDataById({ client, tableName, id }: { client: SupabaseClient; tableName: string; id: number; @@ -77,12 +84,7 @@ export declare class Supabase { * @returns Updated data if Success * @throws Error if fetching fails. */ - updateById({ - client, - tableName, - id, - updatedContent, - }: { + updateById({ client, tableName, id, updatedContent }: { client: SupabaseClient; tableName: string; id: number; @@ -96,11 +98,7 @@ export declare class Supabase { * @returns Success * @throws Error if deleting is fails. */ - deleteById({ - client, - tableName, - id, - }: { + deleteById({ client, tableName, id }: { client: SupabaseClient; tableName: string; id: number; diff --git a/JS/edgechains/vector-db/src/lib/supabase/supabase.js b/JS/edgechains/vector-db/src/lib/supabase/supabase.js index fa14a32bd..31fb341af 100644 --- a/JS/edgechains/vector-db/src/lib/supabase/supabase.js +++ b/JS/edgechains/vector-db/src/lib/supabase/supabase.js @@ -1,9 +1,7 @@ "use strict"; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); exports.Supabase = void 0; const supabase_js_1 = require("@supabase/supabase-js"); @@ -22,14 +20,13 @@ class Supabase { return (0, supabase_js_1.createClient)(this.SUPABASE_URL, this.SUPABASE_API_KEY); } /** - * Insert data into a vector database using a Supabase client. - * @param client The Supabase client instance. - * @param relation The name of the relation (table) to insert data into. - * @param content The content to insert. - * @param embedding The embedding data to insert. - * @returns The inserted data if successful. - * @throws Error if insertion fails. - */ + * Insert data into a vector database using a Supabase client. + * @param client The Supabase client instance. + * @param relation The name of the relation (tableName) to insert data into. + * @param content The content to insert. + * @returns The inserted data if successful. + * @throws Error if insertion fails. + */ async insertVectorData({ client, tableName, ...args }) { return new Promise((resolve, reject) => { const operation = retry_1.default.operation({ @@ -43,18 +40,55 @@ class Supabase { try { const res = await client.from(tableName).insert(args); if (res.error?.message) { - if (operation.retry(new Error())) { + if (operation.retry(new Error)) { return; } - reject( - new Error( - `Failed to insert ${JSON.stringify(args)} with error message "${res.error.message}"` - ) - ); - } else { + reject(new Error(`Failed to insert ${tableName} with error message "${res.error.message}"`)); + } + else { resolve(res); } - } catch (error) { + } + catch (error) { + if (operation.retry(error)) { + return; + } + reject(error); + } + }); + }); + } + /** + * Insert Bulk data into a vector database using a Supabase client. + * @param client The Supabase client instance. + * @param relation The name of the relation (table) to insert data into. + * @param args The array of objects containing the data to be inserted. + * @returns The inserted data if successful. + * @throws Error if insertion fails. + */ + async insertBulkVectorData({ client, tableName, data }) { + return new Promise((resolve, reject) => { + const operation = retry_1.default.operation({ + retries: 5, + factor: 3, + minTimeout: 1 * 1000, + maxTimeout: 60 * 1000, + randomize: true, + }); + operation.attempt(async (currentAttempt) => { + try { + const res = await client.from(tableName).insert(data); + if (res.error?.message) { + if (operation.retry(new Error)) { + return; + } + reject(new Error(`Failed to insert ${tableName} with error message "${res.error.message}"`)); + } + else { + resolve(res); + } + } + catch (error) { if (operation.retry(error)) { return; } @@ -83,19 +117,18 @@ class Supabase { operation.attempt(async (currentAttempt) => { try { let res = await client.rpc(functionNameToCall, args); - console.log(res); if (res.status == 200) { resolve(res.data); - } else { - if (operation.retry(new Error())) return; - reject( - new Error( - `Failed with ErrorCode:${res.statusText} and ErrorMessage:${res.data}` - ) - ); } - } catch (error) { - if (operation.retry(error)) return; + else { + if (operation.retry(new Error)) + return; + reject(new Error(`Failed with ErrorCode:${res.statusText} and ErrorMessage:${res.data}`)); + } + } + catch (error) { + if (operation.retry(error)) + return; reject(error); } }); @@ -124,10 +157,13 @@ class Supabase { if (data) { resolve(data); } - if (operation.retry(new Error())) return; + if (operation.retry(new Error)) + return; reject(error); - } catch (error) { - if (operation.retry(new Error())) return; + } + catch (error) { + if (operation.retry(new Error)) + return; reject(error); } }); @@ -149,7 +185,8 @@ class Supabase { return data; } return error; - } catch (error) { + } + catch (error) { console.error("Error inserting data into vector database:", error); throw error; } @@ -165,17 +202,13 @@ class Supabase { async updateById({ client, tableName, id, updatedContent }) { try { // Insert data into the specified relation - const { data, error } = await client - .from(tableName) - .update(updatedContent) - .eq("id", id) - .select() - .single(); + const { data, error } = await client.from(tableName).update(updatedContent).eq("id", id).select().single(); if (data) { return data; } return error; - } catch (error) { + } + catch (error) { console.error("Error inserting data into vector database:", error); throw error; } @@ -193,7 +226,8 @@ class Supabase { // Insert data into the specified relation const res = await client.from(tableName).delete().eq("id", id); return { status: res.status, messages: res.statusText }; - } catch (error) { + } + catch (error) { console.error("Error inserting data into vector database:", error); throw error; } diff --git a/JS/edgechains/vector-db/src/lib/supabase/supabase.ts b/JS/edgechains/vector-db/src/lib/supabase/supabase.ts index 969ecc091..cfd82a707 100644 --- a/JS/edgechains/vector-db/src/lib/supabase/supabase.ts +++ b/JS/edgechains/vector-db/src/lib/supabase/supabase.ts @@ -13,6 +13,12 @@ interface InsertVectorDataArgs { [key: string]: any; // Allow dynamic properties } +interface InsertBulkVectorDataArgs { + client: SupabaseClient; + tableName: string; + data: Array<{ [key: string]: any }>; +} + interface GetDataFromQueryArgs { client: SupabaseClient; functionNameToCall: string; @@ -23,7 +29,10 @@ export class Supabase { SUPABASE_URL: string; SUPABASE_API_KEY: string; - constructor(SUPABASE_URL: string, SUPABASE_API_KEY: string) { + constructor( + SUPABASE_URL: string, + SUPABASE_API_KEY: string + ) { this.SUPABASE_URL = SUPABASE_URL || process.env.SUPABASE_URL!; this.SUPABASE_API_KEY = SUPABASE_API_KEY || process.env.SUPABASE_API_KEY!; } @@ -34,15 +43,15 @@ export class Supabase { } /** - * Insert data into a vector database using a Supabase client. - * @param client The Supabase client instance. - * @param relation The name of the relation (table) to insert data into. - * @param content The content to insert. - * @param embedding The embedding data to insert. - * @returns The inserted data if successful. - * @throws Error if insertion fails. - */ - async insertVectorData({ client, tableName, ...args }: InsertVectorDataArgs): Promise { + * Insert data into a vector database using a Supabase client. + * @param client The Supabase client instance. + * @param relation The name of the relation (tableName) to insert data into. + * @param content The content to insert. + * @returns The inserted data if successful. + * @throws Error if insertion fails. + */ + async insertVectorData({ client, tableName, ...args }: InsertVectorDataArgs | InsertBulkVectorDataArgs): Promise { + return new Promise((resolve, reject) => { const operation = retry.operation({ retries: 5, @@ -50,31 +59,63 @@ export class Supabase { minTimeout: 1 * 1000, maxTimeout: 60 * 1000, randomize: true, - }); + }) operation.attempt(async (currentAttempt) => { try { - const res = await client.from(tableName).insert(args); + const res = await client.from(tableName).insert(args) if (res.error?.message) { - if (operation.retry(new Error())) { - return; - } - reject( - new Error( - `Failed to insert ${JSON.stringify(args)} with error message "${res.error.message}"` - ) - ); - } else { - resolve(res); + if (operation.retry(new Error)) { return; } + reject(new Error(`Failed to insert ${tableName} with error message "${res.error.message}"`)); + } + else { + resolve(res) } + } catch (error: any) { - if (operation.retry(error)) { - return; + if (operation.retry(error)) { return; } + reject(error); + } + }) + }) + } + + /** + * Insert Bulk data into a vector database using a Supabase client. + * @param client The Supabase client instance. + * @param relation The name of the relation (table) to insert data into. + * @param args The array of objects containing the data to be inserted. + * @returns The inserted data if successful. + * @throws Error if insertion fails. + */ + async insertBulkVectorData({ client, tableName, data }: InsertBulkVectorDataArgs): Promise { + + return new Promise((resolve, reject) => { + const operation = retry.operation({ + retries: 5, + factor: 3, + minTimeout: 1 * 1000, + maxTimeout: 60 * 1000, + randomize: true, + }) + + operation.attempt(async (currentAttempt) => { + try { + const res = await client.from(tableName).insert(data) + if (res.error?.message) { + if (operation.retry(new Error)) { return; } + reject(new Error(`Failed to insert ${tableName} with error message "${res.error.message}"`)); + } + else { + resolve(res) } + + } catch (error: any) { + if (operation.retry(error)) { return; } reject(error); } - }); - }); + }) + }) } /** @@ -85,11 +126,7 @@ export class Supabase { * @returns The fetched data if successful. * @throws Error if fetching fails. */ - async getDataFromQuery({ - client, - functionNameToCall, - ...args - }: GetDataFromQueryArgs): Promise { + async getDataFromQuery({ client, functionNameToCall, ...args }: GetDataFromQueryArgs): Promise { return new Promise((resolve, reject) => { const operation = retry.operation({ retries: 5, @@ -105,12 +142,8 @@ export class Supabase { if (res.status == 200) { resolve(res.data); } else { - if (operation.retry(new Error())) return; - reject( - new Error( - `Failed with ErrorCode:${res.statusText} and ErrorMessage:${res.data}` - ) - ); + if (operation.retry(new Error)) return; + reject(new Error(`Failed with ErrorCode:${res.statusText} and ErrorMessage:${res.data}`)); } } catch (error: any) { if (operation.retry(error)) return; @@ -126,15 +159,7 @@ export class Supabase { * @returns The fetched data if successful. * @throws Error if fetching fails. */ - async getData({ - client, - tableName, - columns, - }: { - client: SupabaseClient; - tableName: string; - columns: string; - }): Promise { + async getData({ client, tableName, columns }: { client: SupabaseClient, tableName: string, columns: string }): Promise { return new Promise((resolve, reject) => { const operation = retry.operation({ retries: 5, @@ -142,25 +167,28 @@ export class Supabase { minTimeout: 1 * 1000, maxTimeout: 60 * 1000, randomize: true, - }); + }) operation.attempt(async (currentAttempt) => { try { // Insert data into the specified relation - const { data, error } = await client.from(tableName).select(columns || "*"); + const { data, error } = await client.from(tableName).select(columns || "*") if (data) { - resolve(data); + resolve(data) } - if (operation.retry(new Error())) return; - reject(error); + if (operation.retry(new Error)) return; + reject(error) + } catch (error) { - if (operation.retry(new Error())) return; - reject(error); + if (operation.retry(new Error)) return; + reject(error) } - }); - }); + }) + }) + } + /** * fetch data by id from you database * @param client - The Supabase client instance. @@ -169,22 +197,15 @@ export class Supabase { * @returns The fetched data if successful. * @throws Error if fetching fails. */ - async getDataById({ - client, - tableName, - id, - }: { - client: SupabaseClient; - tableName: string; - id: number; - }): Promise { + async getDataById({ client, tableName, id }: { client: SupabaseClient, tableName: string, id: number }): Promise { try { // Insert data into the specified relation - const { data, error } = await client.from(tableName).select().eq("id", id).single(); + const { data, error } = await client.from(tableName).select().eq("id", id).single() if (data) { - return data; + return data } - return error; + return error + } catch (error) { console.error("Error inserting data into vector database:", error); throw error; @@ -192,36 +213,22 @@ export class Supabase { } /** - * Update data by id + * Update data by id * @param client - The Supabase client instance. * @param tableName - The tableName from you want to update * @param id - The Id of row * @returns Updated data if Success * @throws Error if fetching fails. */ - async updateById({ - client, - tableName, - id, - updatedContent, - }: { - client: SupabaseClient; - tableName: string; - id: number; - updatedContent: ArgsObject; - }): Promise { + async updateById({ client, tableName, id, updatedContent }: { client: SupabaseClient, tableName: string, id: number, updatedContent: ArgsObject }): Promise { try { // Insert data into the specified relation - const { data, error } = await client - .from(tableName) - .update(updatedContent) - .eq("id", id) - .select() - .single(); + const { data, error } = await client.from(tableName).update(updatedContent).eq("id", id).select().single() if (data) { - return data; + return data } - return error; + return error + } catch (error) { console.error("Error inserting data into vector database:", error); throw error; @@ -229,30 +236,24 @@ export class Supabase { } /** - * Delete data by id + * Delete data by id * @param client - The Supabase client instance. * @param tableName - The tableName from you want to update * @param id - The Id of row - * @returns Success + * @returns Success * @throws Error if deleting is fails. */ - async deleteById({ - client, - tableName, - id, - }: { - client: SupabaseClient; - tableName: string; - id: number; - }): Promise { + async deleteById({ client, tableName, id }: { client: SupabaseClient, tableName: string, id: number }): Promise { try { // Insert data into the specified relation - const res = await client.from(tableName).delete().eq("id", id); + const res = await client.from(tableName).delete().eq("id", id) return { status: res.status, messages: res.statusText }; + } catch (error) { console.error("Error inserting data into vector database:", error); throw error; } } + } diff --git a/JS/edgechains/vector-db/src/tests/supabase/insertBulkVectorData.test.ts b/JS/edgechains/vector-db/src/tests/supabase/insertBulkVectorData.test.ts new file mode 100644 index 000000000..1b08cafe2 --- /dev/null +++ b/JS/edgechains/vector-db/src/tests/supabase/insertBulkVectorData.test.ts @@ -0,0 +1,52 @@ +import { Supabase } from '../../../index.js'; + +const MOCK_SUPABASE_API_KEY = 'mock-api-key'; +const MOCK_SUPABASE_URL = 'https://mock-supabase.co'; + +// Mock the Supabase class to return a mock client +jest.mock('../../../index.js', () => { + return { + Supabase: jest.fn().mockImplementation(() => ({ + createClient: jest.fn(() => ({ + // Mock client methods + from: jest.fn().mockReturnThis(), + })), + getDataFromQuery: jest.fn().mockImplementation(async () => { + // Mock response data + const responseData = { id: 1, content: "Hello, world!" }; + + // Return the mock response + return responseData; + }), + insertBulkVectorData: jest.fn().mockImplementation(async ({ client, tableName, data }) => { + // Assuming content is a string and embedding is an array of length 1536 + const mockResponse = { + tableName: tableName, + data + }; + return mockResponse; + }), + })), + }; +}); + +it('should insert bulk data into the database', async () => { + let supabase = new Supabase(MOCK_SUPABASE_URL, MOCK_SUPABASE_API_KEY); + const client = supabase.createClient(); + const tableName = 'test_table'; + const content = ["hi", "hello"] + // Insert data into the database + const data = [{ content, embedding: [Array.from({ length: 1536 }, (_, i) => i), Array.from({ length: 1536 }, (_, i) => i)] }] + // Call the insertBulkVectorData function + const result = await supabase.insertBulkVectorData({ client, tableName, data }); + // Check if the insertion was successful + expect(result).toEqual(expect.objectContaining({ + tableName: tableName, + data: expect.arrayContaining([ + expect.objectContaining({ + content, + embedding: expect.arrayContaining([Array.from({ length: 1536 }, (_, i) => i), Array.from({ length: 1536 }, (_, i) => i)]), // Mocked embedding vector + }), + ]), + })); +});