{"version":3,"file":"azion_edgesql.cjs","names":["VectorStore","Document"],"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  // oxlint-disable-next-line typescript/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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"}