UNPKG

@langchain/community

Version:
1 lines • 47.4 kB
{"version":3,"file":"azion_edgesql.cjs","names":["VectorStore","embeddings: EmbeddingsInterface","args: AzionVectorStoreArgs","setupOptions: AzionSetupOptions","documents: Document[]","vectors: number[][]","mode: \"vector\" | \"hybrid\"","columns: string[] | undefined","error:\n | {\n message: string;\n operation: string;\n }\n | undefined","message: string","tables: (string | number)[] | undefined","databaseName: string","chunks: string[][]","rows: RowsInterface[]","metadataColumns: string[]","row: RowsInterface","columnNames","values","statements: string[]","array: string[]","str: string","vector: number[]","k: number","filter?: AzionFilter[]","metadataItems?: string[]","query: string","options: FullTextSearchOptions","hybridSearchOptions: HybridSearchOptions","options: SimilaritySearchOptions","ids: string[]","results: [Document, number][]","kfts: number","kvector: number","uniqueResults: [Document, number][]","results: QueryResult[] | undefined","queryResult: QueryResult","searches: SearchEmbeddingsResponse[]","resp: SearchEmbeddingsResponse","Document","metadataItems: string[] | undefined","searchType: string","filters: AzionFilter[] | undefined","columnNames: string[]","values: (string | number[])[]","string","value: string | number[]","item: string | undefined"],"sources":["../../src/vectorstores/azion_edgesql.ts"],"sourcesContent":["import { VectorStore } from \"@langchain/core/vectorstores\";\nimport {\n useQuery,\n useExecute,\n getDatabases,\n createDatabase,\n getTables,\n type AzionDatabaseResponse,\n QueryResult,\n getDatabase,\n} from \"azion/sql\";\nimport type { EmbeddingsInterface } from \"@langchain/core/embeddings\";\nimport { Document } from \"@langchain/core/documents\";\n\n/**\n * Represents a filter condition for querying the Azion database\n * @property operator - The comparison operator to use (e.g. =, !=, >, <, etc)\n * @property column - The database column to filter on\n * @property value - The value to compare against\n */\nexport type AzionFilter = { operator: Operator; column: Column; value: string };\n\n/**\n * Represents a database column name\n */\nexport type Column = string;\n\n/**\n * Valid SQL operators that can be used in filter conditions\n */\nexport type Operator =\n | \"=\"\n | \"!=\"\n | \">\"\n | \"<>\"\n | \"<\" // Basic comparison operators\n | \">=\"\n | \"<=\" // Range operators\n | \"LIKE\"\n | \"NOT LIKE\" // Pattern matching\n | \"IN\"\n | \"NOT IN\" // Set membership\n | \"IS NULL\"\n | \"IS NOT NULL\"; // NULL checks\n\n/**\n * Interface for configuring the Azion vector store setup\n * @property {string[]} columns - Additional columns to create in the database table. If expandedMetadata is true, this is required.\n * @property {\"vector\" | \"hybrid\"} mode - The search mode to enable:\n * \"vector\" - Only vector similarity search\n * \"hybrid\" - Both vector and full-text search capabilities\n */\ninterface AzionSetupOptions {\n columns?: string[];\n mode: \"vector\" | \"hybrid\";\n}\n\n/**\n * Interface representing the structure of a row in the vector store\n * @property content - The text content of the document\n * @property embedding - The vector embedding of the content as an array of numbers\n * @property metadata - Additional metadata associated with the document as key-value pairs\n */\ninterface RowsInterface {\n content: string;\n embedding: number[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n metadata: Record<string, any>;\n}\n\n/**\n * Interface for the response returned when searching embeddings.\n */\ninterface SearchEmbeddingsResponse {\n id: number;\n content: string;\n similarity: number;\n metadata: {\n searchtype: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Interface for configuring hybrid search options that combines vector and full-text search\n * @property {number} kfts - Number of results to return from full-text search\n * @property {number} kvector - Number of results to return from vector similarity search\n * @property {AzionFilter[]} [filter] - Optional array of filters to apply to search results\n * @property {string[]} [metadataItems] - Optional array of metadata fields to include in results\n */\ninterface HybridSearchOptions {\n kfts: number;\n kvector: number;\n filter?: AzionFilter[];\n metadataItems?: string[];\n}\n\n/**\n * Interface for configuring full-text search options\n * @property {number} kfts - Number of results to return from full-text search\n * @property {AzionFilter[]} [filter] - Optional array of filters to apply to search results\n * @property {string[]} [metadataItems] - Optional array of metadata fields to include in results\n */\ninterface FullTextSearchOptions {\n kfts: number;\n filter?: AzionFilter[];\n metadataItems?: string[];\n}\n\n/**\n * Interface for configuring vector similarity search options\n * @property {number} kvector - Number of results to return from vector similarity search\n * @property {AzionFilter[]} [filter] - Optional array of filters to apply to search results\n * @property {string[]} [metadataItems] - Optional array of metadata fields to include in results\n */\ninterface SimilaritySearchOptions {\n kvector: number;\n filter?: AzionFilter[];\n metadataItems?: string[];\n}\n\n/**\n * Interface for the arguments required to initialize an Azion library.\n */\nexport interface AzionVectorStoreArgs {\n tableName: string;\n filter?: AzionFilter[];\n dbName: string;\n expandedMetadata?: boolean;\n}\n\n/**\n * Example usage:\n * ```ts\n * // Initialize the vector store\n * const vectorStore = new AzionVectorStore(embeddings, {\n * dbName: \"mydb\",\n * tableName: \"documents\"\n * });\n *\n * // Setup database with hybrid search and metadata columns\n * await vectorStore.setupDatabase({\n * columns: [\"topic\", \"language\"],\n * mode: \"hybrid\"\n * });\n *\n *\n * // OR: Initialize using the static create method\n * const vectorStore = await AzionVectorStore.initialize(embeddings, {\n * dbName: \"mydb\",\n * tableName: \"documents\"\n * }, {\n * columns: [\"topic\", \"language\"],\n * mode: \"hybrid\"\n * });\n *\n * By default, the columns are not expanded, meaning that the metadata is stored in a single column:\n *\n * // Setup database with hybrid search and metadata columns\n * await vectorStore.setupDatabase({\n * columns: [\"*\"],\n * mode: \"hybrid\"\n * });\n *\n * // Add documents to the vector store\n * await vectorStore.addDocuments([\n * new Document({\n * pageContent: \"Australia is known for its unique wildlife\",\n * metadata: { topic: \"nature\", language: \"en\" }\n * })\n * ]);\n *\n * // Perform similarity search\n * const results = await vectorStore.similaritySearch(\n * \"coral reefs in Australia\",\n * 2, // Return top 2 results\n * { filter: [{ operator: \"=\", column: \"topic\", string: \"biology\" }] } // Optional AzionFilter\n * );\n *\n * // Perform full text search\n * const ftResults = await vectorStore.fullTextSearch(\n * \"Sydney Opera House\",\n * 1, // Return top result\n * { filter: [{ operator: \"=\", column: \"language\", string: \"en\" }] } // Optional AzionFilter\n * );\n * ```\n */\n\nexport class AzionVectorStore extends VectorStore {\n /** Type declaration for filter type */\n declare FilterType: AzionFilter[];\n\n /** Name of the main table to store vectors and documents */\n tableName: string;\n\n /** Name of the database to use */\n dbName: string;\n\n /** Whether the metadata is contained in a single column or multiple columns */\n expandedMetadata: boolean;\n\n _vectorstoreType(): string {\n return \"azionEdgeSQL\";\n }\n\n constructor(embeddings: EmbeddingsInterface, args: AzionVectorStoreArgs) {\n super(embeddings, args);\n this.tableName = args.tableName;\n this.dbName = args.dbName;\n this.expandedMetadata = args.expandedMetadata ?? false;\n }\n\n /**\n * Creates a new vector store instance and sets up the database.\n * @param {EmbeddingsInterface} embeddings - The embeddings interface to use for vectorizing documents\n * @param {AzionVectorStoreArgs} args - Configuration options:\n * @param {string} args.dbName - Name of the database to create/use\n * @param {string} args.tableName - Name of the table to create/use\n * @param {AzionSetupOptions} setupOptions - Database setup options:\n * @param {string[]} setupOptions.columns - Additional columns to create in the table beyond the required ones. If expandedMetadata is true, this is required.\n * @param {\"vector\"|\"hybrid\"} setupOptions.mode - The search mode to enable:\n * - \"vector\": Only vector similarity search capabilities\n * - \"hybrid\": Both vector and full-text search capabilities\n * @returns {Promise<AzionVectorStore>} A promise that resolves with the configured vector store instance\n */\n static async initialize(\n embeddings: EmbeddingsInterface,\n args: AzionVectorStoreArgs,\n setupOptions: AzionSetupOptions\n ): Promise<AzionVectorStore> {\n const instance = new AzionVectorStore(embeddings, args);\n await instance.setupDatabase(setupOptions);\n return instance;\n }\n\n /**\n * Adds documents to the vector store.\n * @param {Document[]} documents The documents to add.\n * @param {Object} options Optional parameters for adding the documents.\n * @returns A promise that resolves when the documents have been added.\n */\n async addDocuments(documents: Document[]) {\n const texts = documents.map((doc) => doc.pageContent);\n const embeddings = await this.embeddings.embedDocuments(texts);\n return this.addVectors(embeddings, documents);\n }\n\n /**\n * Adds vectors to the vector store.\n * @param {number[][]} vectors The vectors to add.\n * @param {Document[]} documents The documents associated with the vectors.\n * @param {Object} options Optional parameters for adding the vectors.\n * @returns A promise that resolves with the IDs of the added vectors when the vectors have been added.\n */\n async addVectors(vectors: number[][], documents: Document[]) {\n const rows = await this.mapRowsFromDocuments(vectors, documents);\n const insertStatements = this.createStatements(rows);\n const chunks = this.createInsertChunks(insertStatements);\n\n await this.insertChunks(chunks);\n }\n\n /**\n * Gets the dimensions of the embeddings.\n * @returns {Promise<number>} The dimensions of the embeddings.\n */\n private async getEmbeddingsDimensions(): Promise<number> {\n return (await this.embeddings.embedQuery(\"test\")).length;\n }\n\n /**\n * Maps the rows and metadata to the correct format.\n * @param vectors The vectors to map.\n * @param {Document[]} documents The documents to map.\n * @returns {Promise<RowsInterface[]>} The mapped rows and metadata.\n */\n private async mapRowsFromDocuments(\n vectors: number[][],\n documents: Document[]\n ): Promise<RowsInterface[]> {\n return vectors.map((embedding, idx) => ({\n content: documents[idx].pageContent,\n embedding,\n metadata: documents[idx].metadata,\n }));\n }\n\n /**\n * Sets up the database and tables.\n * @param {AzionSetupOptions} setupOptions The setup options:\n * - columns: string[] - The metadata columns to add to the table\n * - mode: \"vector\" | \"hybrid\" - The mode to use for the table. \"vector\" for vector search only, \"hybrid\" for vector and full-text search\n * @returns {Promise<void>} A promise that resolves when the database and tables have been set up.\n */\n async setupDatabase(setupOptions: AzionSetupOptions): Promise<void> {\n const { columns, mode } = setupOptions;\n\n if (this.expandedMetadata && !columns) {\n throw new Error(\"Columns must be informed when using expanded metadata!\");\n }\n\n await this.handleDatabase();\n\n await this.handleTables(mode, columns);\n }\n\n /**\n * Handles the table creation and setup.\n * @param {string} mode The mode.\n * @param {string[]} columns The columns to setup.\n * @returns {Promise<void>} A promise that resolves when the table has been created and setup.\n */\n private async handleTables(\n mode: \"vector\" | \"hybrid\",\n columns: string[] | undefined\n ): Promise<void> {\n const { data: dataTables, error: errorTables } = await getTables(\n this.dbName\n );\n\n this.errorHandler(errorTables, \"Error getting tables\");\n\n const tables = dataTables?.results?.[0]?.rows?.map((row) => row[1]);\n\n if (!this.areTablesSetup(tables, mode)) {\n const { error: errorSetupDb } = await this.setupTables(mode, columns);\n this.errorHandler(errorSetupDb, \"Error setting up tables\");\n }\n }\n\n /**\n * Handles the error.\n * @param {Object} error The error object.\n * @param {string} message The message to display.\n * @returns {void} A void value.\n */\n private errorHandler(\n error:\n | {\n message: string;\n operation: string;\n }\n | undefined,\n message: string\n ): void {\n if (error) {\n console.log(message, error);\n throw new Error(error?.message ?? message);\n }\n }\n\n /**\n * Checks if the tables are setup.\n * @param {string | number | string[] | number[]} tables The tables.\n * @param {string} mode The mode.\n * @returns {boolean} Whether the tables are setup.\n */\n private areTablesSetup(\n tables: (string | number)[] | undefined,\n mode: \"vector\" | \"hybrid\"\n ): boolean {\n if (!tables) {\n return false;\n }\n\n if (mode === \"hybrid\") {\n return (\n tables?.includes(this.tableName) &&\n tables?.includes(`${this.tableName}_fts`)\n );\n }\n\n return tables?.includes(this.tableName);\n }\n\n /**\n * Handles the database creation and setup.\n * @returns {Promise<void>} A promise that resolves when the database has been created and setup.\n */\n private async handleDatabase(): Promise<void> {\n const { data: dataGet, error: errorGet } = await getDatabases();\n\n this.errorHandler(errorGet, \"Error getting databases\");\n\n if (!dataGet?.databases?.find((db) => db.name === this.dbName)) {\n console.log(\"Creating database: \", this.dbName);\n const { error: errorCreate } = await createDatabase(this.dbName);\n\n await this.waitDatabaseCreation(this.dbName);\n\n console.log(`Database ${this.dbName} created`);\n\n this.errorHandler(errorCreate, \"Error creating database\");\n }\n }\n\n /**\n * Wait for the database to be created. Retry every 3 seconds until the database is created.\n * @param databaseName {string} The database name\n * @returns {Promise<void>}\n */\n private async waitDatabaseCreation(databaseName: string): Promise<string> {\n let databaseStatus = \"creating\";\n while (databaseStatus !== \"created\") {\n const { data, error } = await getDatabase(databaseName);\n\n if (error) {\n throw error;\n }\n\n if (data && data.status === \"created\") {\n databaseStatus = \"created\";\n }\n\n await new Promise((resolve) => {\n setTimeout(resolve, 3000);\n });\n }\n return \"Created\";\n }\n\n /**\n * Sets up the tables based on the specified mode and columns.\n * @param {string} mode The mode to use - either \"vector\" for vector search only or \"hybrid\" for vector + full text search\n * @param {string[]} columns Additional metadata columns to add to the tables\n * @returns {Promise<AzionDatabaseResponse<string>>} A promise that resolves when the tables have been created and setup\n */\n private async setupTables(\n mode: \"vector\" | \"hybrid\",\n columns: string[] | undefined\n ): Promise<AzionDatabaseResponse<string>> {\n let createTableColumns = \",metadata JSON\";\n\n if (this.expandedMetadata && columns) {\n createTableColumns =\n columns.length > 0\n ? `,${columns.map((key) => `${key} TEXT`).join(\",\")}`\n : \"\";\n }\n\n const createTableStatement = `\n CREATE TABLE ${this.tableName} (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n content TEXT NOT NULL,\n embedding F32_BLOB(${await this.getEmbeddingsDimensions()})\n ${createTableColumns}\n );`;\n\n const createIndexStatement = `\n CREATE INDEX ${this.tableName}_idx ON ${this.tableName} (\n libsql_vector_idx(embedding, 'metric=cosine', 'compress_neighbors=float8', 'max_neighbors=20')\n )`;\n\n let createFtsColumns = \",metadata\";\n if (this.expandedMetadata && columns) {\n createFtsColumns =\n columns.length > 0\n ? `,${columns.map((key) => `${key}`).join(\",\")}`\n : \"\";\n }\n\n const createFtsStatement = `\n CREATE VIRTUAL TABLE IF NOT EXISTS ${this.tableName}_fts USING fts5(\n content,\n id UNINDEXED\n ${createFtsColumns},\n tokenize = 'porter'\n )`;\n\n let createTriggersColumns = \",metadata\";\n let insertTriggersValues = \",new.metadata\";\n let updateTriggersColumns = \",metadata = new.metadata\";\n\n if (this.expandedMetadata && columns) {\n createTriggersColumns = columns.length > 0 ? `,${columns.join(\",\")}` : \"\";\n insertTriggersValues =\n columns.length > 0\n ? `,${columns.map((key) => `new.${key}`).join(\",\")}`\n : \"\";\n updateTriggersColumns =\n columns.length > 0\n ? `,${columns.map((key) => `${key} = new.${key}`).join(\",\")}`\n : \"\";\n }\n\n const createTriggersStatements = [\n `CREATE TRIGGER IF NOT EXISTS insert_into_${this.tableName}_fts \n AFTER INSERT ON ${this.tableName}\n BEGIN\n INSERT INTO ${this.tableName}_fts(id, content ${createTriggersColumns})\n VALUES(new.id, new.content ${insertTriggersValues});\n END`,\n\n `CREATE TRIGGER IF NOT EXISTS update_${this.tableName}_fts \n AFTER UPDATE ON ${this.tableName}\n BEGIN\n UPDATE ${this.tableName}_fts \n SET content = new.content\n ${updateTriggersColumns}\n WHERE id = old.id;\n END`,\n\n `CREATE TRIGGER IF NOT EXISTS delete_${this.tableName}_fts\n AFTER DELETE ON ${this.tableName}\n BEGIN\n DELETE FROM ${this.tableName}_fts WHERE id = old.id;\n END`,\n ];\n\n let allStatements = [\n createTableStatement,\n createIndexStatement,\n createFtsStatement,\n ...createTriggersStatements,\n ];\n\n if (mode === \"vector\") {\n allStatements = allStatements.slice(0, 2);\n }\n\n const { error } = await useExecute(this.dbName, allStatements);\n this.errorHandler(error, \"Error setting up tables\");\n return { data: \"Database setup successfully\", error: undefined };\n }\n\n /**\n * Inserts the chunks into the database.\n * @param {string[][]} chunks The chunks to insert.\n * @returns {Promise<void>} A promise that resolves when the chunks have been inserted.\n */\n private async insertChunks(chunks: string[][]): Promise<void> {\n for (const chunk of chunks) {\n console.log(\"Inserting chunk\", chunks.indexOf(chunk));\n const { error } = await useExecute(this.dbName, chunk, { debug: true });\n this.errorHandler(error, \"Error inserting chunk\");\n }\n console.log(\"Chunks inserted!\");\n }\n\n /**\n * Extracts the metadata columns from the rows.\n * @param {RowsInterface[]} rows The rows to extract the metadata columns from.\n * @returns {string[]} The metadata columns.\n */\n private extractMetadataColumns(rows: RowsInterface[]): string[] {\n const metadataColumns: string[] = [];\n\n for (const row of Object.values(rows)) {\n if (row.metadata) {\n Object.keys(row.metadata).forEach((key) => {\n if (!metadataColumns.includes(key)) {\n metadataColumns.push(key);\n }\n });\n }\n }\n return metadataColumns;\n }\n\n /**\n * Creates the insert statement for a row.\n * @param {RowsInterface} row The row to create the insert statement for.\n * @param {string[]} metadataColumns The metadata columns.\n * @returns {string} The insert statement.\n */\n private createInsertStatement(\n row: RowsInterface,\n metadataColumns: string[]\n ): string {\n if (this.expandedMetadata) {\n const columnNames = [\"content\", \"embedding\", ...metadataColumns];\n const values = [\n row.content,\n row.embedding,\n ...metadataColumns.map((col) => row.metadata?.[col] ?? null),\n ];\n return this.createInsertString(columnNames, values);\n }\n\n const columnNames = [\"content\", \"embedding\", \"metadata\"];\n const values = [row.content, row.embedding, JSON.stringify(row.metadata)];\n\n return this.createInsertString(columnNames, values);\n }\n\n /**\n * Creates the insert statements for the rows.\n * @param {RowsInterface[]} rows The rows to create the insert statements for.\n * @returns {string[]} The insert statements.\n */\n private createStatements(rows: RowsInterface[]): string[] {\n const insertStatements = [];\n const metadataColumns = this.extractMetadataColumns(rows);\n\n for (const row of rows) {\n const statement = this.createInsertStatement(row, metadataColumns);\n insertStatements.push(statement);\n }\n\n return insertStatements;\n }\n\n /**\n * Creates the insert chunks for the statements.\n * @param {string[]} statements The statements to create the insert chunks for.\n * @returns {string[][]} The insert chunks.\n */\n private createInsertChunks(statements: string[]): string[][] {\n const maxChunkLength = 1000;\n const maxMbSize = 0.8 * 1024 * 1024;\n const insertChunk = [];\n let originalStatements = statements;\n const totalSize = this.getStringBytes(originalStatements.join(\" \"));\n\n if (totalSize < maxMbSize && originalStatements.length < maxChunkLength) {\n return [originalStatements];\n }\n\n console.log(\"Total size exceeded max size. Initiating chunking...\");\n let array: string[] = [];\n while (originalStatements.length > 0) {\n for (const statement of originalStatements) {\n const totalStringBytes =\n this.getStringBytes(statement) + this.getStringBytes(array.join(\" \"));\n if (totalStringBytes > maxMbSize || array.length + 1 > maxChunkLength) {\n insertChunk.push(array);\n array = [statement];\n originalStatements = originalStatements.slice(1);\n } else {\n array.push(statement);\n if (originalStatements.length === 1) {\n insertChunk.push(array);\n }\n originalStatements = originalStatements.slice(1);\n }\n }\n }\n\n return insertChunk;\n }\n\n /**\n * Gets the number of bytes in a string.\n * @param {string} str The string to get the number of bytes for.\n * @returns {number} The number of bytes in the string.\n */\n private getStringBytes(str: string): number {\n return new TextEncoder().encode(str).length;\n }\n\n /**\n * Performs a similarity search on the vector store and returns the top 'similarityK' similar documents.\n * @param {number[]} vector The vector to search for.\n * @param {number} k The number of documents to return.\n * @param {AzionFilter[]} filter Optional filters to apply to the search.\n * @param {string[]} metadataItems Optional metadata items to include in the search.\n * @returns {Promise<[Document, number][]>} A promise that resolves with the similarity search results when the search is complete.\n */\n async similaritySearchVectorWithScore(\n vector: number[],\n k: number,\n filter?: AzionFilter[],\n metadataItems?: string[]\n ): Promise<[Document, number][]> {\n const metadata = this.generateMetadata(metadataItems, \"similarity\");\n\n const filters = this.generateFilters(filter);\n\n const similarityQuery = `\n SELECT \n id, content, ${metadata}, 1 - vector_distance_cos(embedding, vector('[${vector}]')) as similarity\n FROM ${this.tableName} \n WHERE ${filters} rowid IN vector_top_k('${this.tableName}_idx', vector('[${vector}]'), ${k})`;\n\n const { data, error } = await useQuery(this.dbName, [similarityQuery]);\n\n if (!data) {\n this.errorHandler(error, \"Error performing similarity search\");\n throw this.searchError(error);\n }\n\n const searches = this.mapRows(data.results);\n const results = this.mapSearches(searches);\n return results;\n }\n\n /**\n * Performs a full-text search on the vector store and returns the top 'k' similar documents.\n * @param query The query string to search for\n * @param options The options for the full-text search, including:\n * - kfts: The number of full-text search results to return\n * - filter: Optional filters to apply to narrow down the search results\n * - metadataItems: Optional metadata fields to include in the results\n * @returns A promise that resolves with the full-text search results when the search is complete.\n */\n async azionFullTextSearch(query: string, options: FullTextSearchOptions) {\n const { kfts, filter, metadataItems } = options;\n const metadata = this.generateMetadata(metadataItems, \"fulltextsearch\");\n\n const filters = this.generateFilters(filter);\n\n const fullTextQuery = `\n SELECT id, content, ${metadata}, rank as bm25_similarity\n FROM ${this.tableName}_fts \n WHERE ${filters} ${this.tableName}_fts MATCH '${this.convert2FTSQuery(\n query\n )}'\n LIMIT ${kfts}`;\n\n const { data, error } = await useQuery(this.dbName, [fullTextQuery]);\n\n if (!data) {\n this.errorHandler(error, \"Error performing full-text search\");\n throw this.searchError(error);\n }\n\n const searches = this.mapRows(data?.results);\n const results = this.mapSearches(searches);\n return results;\n }\n\n /**\n * Performs a hybrid search on the vector store and returns the top 'k' similar documents.\n * @param query The query string to search for\n * @param options The options for the hybrid search, including:\n * - kfts: The number of full-text search results to return\n * - kvector: The number of vector search results to return\n * - filter: Optional filters to apply to narrow down the search results\n * - metadataItems: Optional metadata fields to include in the results\n * @returns A promise that resolves with the hybrid search results when the search is complete.\n */\n async azionHybridSearch(\n query: string,\n hybridSearchOptions: HybridSearchOptions\n ): Promise<[Document, number][]> {\n const { kfts, kvector, filter, metadataItems } = hybridSearchOptions;\n\n const vector = await this.embeddings.embedQuery(query);\n const ftsResults = await this.azionFullTextSearch(query, {\n kfts,\n filter,\n metadataItems,\n });\n\n const vectorResults = await this.similaritySearchVectorWithScore(\n vector,\n kvector,\n filter,\n metadataItems\n );\n\n return this.removeDuplicates(\n [...ftsResults, ...vectorResults],\n kfts,\n kvector\n );\n }\n\n /**\n * Performs a similarity search on the vector store and returns the top 'k' similar documents.\n * @param query The query string.\n * @param options The options for the similarity search, including:\n * - kvector: The number of vector search results to return\n * - filter: Optional filters to apply to the search\n * - metadataItems: Optional metadata fields to include in results\n * @returns A promise that resolves with the similarity search results when the search is complete.\n */\n async azionSimilaritySearch(\n query: string,\n options: SimilaritySearchOptions\n ): Promise<[Document, number][]> {\n const { kvector, filter, metadataItems } = options;\n const vector = await this.embeddings.embedQuery(query);\n return this.similaritySearchVectorWithScore(\n vector,\n kvector,\n filter,\n metadataItems\n );\n }\n\n /**\n * Generates an error document based on the provided error information\n * @param {Object} error The error object containing details about the issue\n * @returns {Promise<[Document, number][]>} A promise that resolves to an array containing a single Document representing the error\n */\n private searchError(\n error:\n | {\n message: string;\n operation: string;\n }\n | undefined\n ): Error {\n throw new Error(error?.message);\n }\n\n /**\n * Deletes documents from the vector store.\n * @param {string[]} ids The IDs of the documents to delete.\n * @returns {Promise<void>} A promise that resolves when the documents have been deleted.\n */\n async delete(ids: string[]): Promise<void> {\n const deleteStatement = `DELETE FROM ${\n this.tableName\n } WHERE id IN (${ids.join(\",\")})`;\n const { error } = await useExecute(this.dbName, [deleteStatement]);\n if (error) {\n this.errorHandler(\n error,\n `Error deleting document from ${this.tableName}`\n );\n } else {\n console.log(`Deleted ${ids.length} items from ${this.tableName}`);\n }\n }\n\n /**\n * Removes duplicate results from the search results, prioritizing a mix of similarity and FTS results.\n * @param {[Document, number][]} results - The array of search results to process, containing document and score pairs\n * @param {number} kfts - Maximum number of full-text search results to include\n * @param {number} kvector - Maximum number of vector similarity search results to include\n * @returns {[Document, number][]} An array of unique search results, limited by kfts and kvector parameters\n */\n private removeDuplicates(\n results: [Document, number][],\n kfts: number,\n kvector: number\n ): [Document, number][] {\n const uniqueResults: [Document, number][] = [];\n const seenIds = new Set<string | undefined>();\n\n let similarityCount = 0;\n let ftsCount = 0;\n const maxItems = kfts + kvector;\n\n for (const result of results) {\n if (!seenIds.has(result[0].id)) {\n if (\n result[0].metadata?.searchtype === \"similarity\" &&\n similarityCount < kvector\n ) {\n seenIds.add(result[0].id);\n uniqueResults.push(result);\n similarityCount += 1;\n } else if (\n result[0].metadata.searchtype === \"fulltextsearch\" &&\n ftsCount < kfts\n ) {\n seenIds.add(result[0].id);\n uniqueResults.push(result);\n ftsCount += 1;\n }\n }\n if (similarityCount + ftsCount === maxItems) break;\n }\n return uniqueResults;\n }\n\n /**\n * Converts query results to SearchEmbeddingsResponse objects.\n * @param {QueryResult[]} results - The raw query results from the database.\n * @returns {SearchEmbeddingsResponse[]} An array of SearchEmbeddingsResponse objects.\n */\n private mapRows(\n results: QueryResult[] | undefined\n ): SearchEmbeddingsResponse[] {\n if (!results) {\n return [];\n }\n\n return results.flatMap(\n (queryResult: QueryResult): SearchEmbeddingsResponse[] => {\n if (!queryResult.rows || !queryResult.columns) {\n return [];\n }\n\n return queryResult.rows.map(\n (row): SearchEmbeddingsResponse => ({\n id: Number(row[0]),\n content: String(row[1]),\n metadata: JSON.parse(String(row[2])),\n similarity: Number(row[3]),\n })\n );\n }\n );\n }\n\n /**\n * Maps search results to Document objects.\n * @param {SearchEmbeddingsResponse[]} searches An array of SearchEmbeddingsResponse objects.\n * @returns An array of tuples, each containing a single Document object.\n */\n private mapSearches(\n searches: SearchEmbeddingsResponse[]\n ): [Document, number][] {\n return searches.map((resp: SearchEmbeddingsResponse) => [\n new Document({\n metadata: resp.metadata,\n pageContent: resp.content,\n id: resp.id.toString(),\n }),\n resp.similarity,\n ]);\n }\n\n /**\n * Generates the metadata string for the SQL query.\n * @param {string[]} metadataItems - The metadata items to include in the query.\n * @param {string} searchType - The type of search.\n * @returns {string} The metadata string.\n */\n private generateMetadata(\n metadataItems: string[] | undefined,\n searchType: string\n ): string {\n if (!metadataItems) {\n return `json_object('searchtype', '${searchType}') as metadata`;\n }\n\n if (this.expandedMetadata) {\n return `json_object('searchtype','${searchType}',${metadataItems\n .map(\n (item) => `'${this.sanitizeItem(item)}', ${this.sanitizeItem(item)}`\n )\n .join(\", \")}) as metadata`;\n }\n\n return `json_patch(json_object(${metadataItems\n ?.map(\n (item) =>\n `'${this.sanitizeItem(item)}', metadata->>'$.${this.sanitizeItem(\n item\n )}'`\n )\n .join(\", \")}), '{\"searchtype\":\"${searchType}\"}') as metadata`;\n }\n\n /**\n * Generates the filters string for the SQL query.\n * @param {AzionFilter[]} filters The filters to apply to the query.\n * @returns {string} The filters string.\n */\n private generateFilters(filters: AzionFilter[] | undefined): string {\n if (!filters || filters?.length === 0) {\n return \"\";\n }\n\n return `${filters\n .map(({ operator, column, value }) => {\n const columnRef = this.expandedMetadata\n ? this.sanitizeItem(column)\n : `metadata->>'$.${this.sanitizeItem(column)}'`;\n if ([\"IN\", \"NOT IN\"].includes(operator.toUpperCase())) {\n return `${columnRef} ${operator} (${this.sanitizeItem(value)})`;\n }\n return `${columnRef} ${operator} '${this.sanitizeItem(value)}'`;\n })\n .join(\" AND \")} AND `;\n }\n\n /**\n * Creates the insert sql query for a row.\n * @param {string[]} columnNames The column names.\n * @param {string[]} values The values.\n * @returns {string} The insert sql query.\n */\n private createInsertString(\n columnNames: string[],\n values: (string | number[])[]\n ): string {\n if (this.expandedMetadata) {\n const string = `INSERT INTO ${this.tableName} (${columnNames.join(\", \")}) \n VALUES (${values\n .map((value, index) =>\n columnNames[index] === \"embedding\"\n ? `vector('[${value}]')`\n : `'${this.escapeQuotes(value)}'`\n )\n .join(\", \")})`;\n\n return string;\n }\n\n const string = `INSERT INTO ${this.tableName} (${columnNames.join(\", \")}) \n VALUES (${values\n .map((value, index) => {\n if (columnNames[index] === \"embedding\") {\n return `vector('[${value}]')`;\n } else if (columnNames[index] === \"metadata\") {\n return `'${value}'`;\n } else {\n return `'${this.escapeQuotes(value)}'`;\n }\n })\n .join(\", \")})`;\n return string;\n }\n\n /**\n * Escapes the quotes in the value.\n * @param {string} value The value to escape the quotes in.\n * @returns {string} The value with the quotes escaped.\n */\n private escapeQuotes(value: string | number[]): string | number[] {\n if (typeof value === \"string\") {\n return value.replace(/'/g, \" \").replace(/\"/g, \" \");\n }\n return value;\n }\n\n /**\n * Sanitizes an item by removing non-alphanumeric characters.\n * @param {string} item The item to sanitize.\n * @returns {string} The sanitized item.\n */\n private sanitizeItem(item: string | undefined): string {\n if (item) {\n return item.replace(/[^a-zA-Z0-9\\s]/g, \"\");\n }\n return \"\";\n }\n\n /**\n * Converts a query to a FTS query.\n * @param query The user query\n * @returns The converted FTS query\n */\n protected convert2FTSQuery(query: string): string {\n return query\n .replace(/[^a-záàâãéèêíïóôõöúçñA-ZÁÀÂÃÉÈÊÍÏÓÔÕÖÚÇÑ0-9\\s]/g, \"\") // Remove special chars keeping accents\n .replace(/\\s+/g, \" \") // Remove multiple spaces\n .trim() // Remove leading/trailing spaces\n .split(\" \")\n .join(\" OR \");\n }\n}\n"],"mappings":"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"}