{"version":3,"file":"azion_edgesql.cjs","names":["BaseRetriever","embeddings: EmbeddingsInterface","args: AzionRetrieverArgs","filters: AzionFilter[]","embeddedQuery: number[]","queryEntities: string","metadata: string","query: string","SystemMessage","HumanMessage","error:\n      | {\n          message: string;\n          operation: string;\n        }\n      | undefined","result: [Document][]","results: SearchEmbeddingsResponse[]","uniqueResults: SearchEmbeddingsResponse[]","results: QueryResult[] | undefined","queryResult: QueryResult","searches: SearchEmbeddingsResponse[]","resp: SearchEmbeddingsResponse","Document","item: string | undefined"],"sources":["../../src/retrievers/azion_edgesql.ts"],"sourcesContent":["import { QueryResult, useQuery } from \"azion/sql\";\nimport type { EmbeddingsInterface } from \"@langchain/core/embeddings\";\nimport { Document } from \"@langchain/core/documents\";\nimport { BaseRetriever, BaseRetrieverInput } from \"@langchain/core/retrievers\";\nimport { SystemMessage, HumanMessage } from \"@langchain/core/messages\";\nimport { BaseChatModel } from \"@langchain/core/language_models/chat_models\";\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 the response returned when searching embeddings.\n */\ninterface SearchEmbeddingsResponse {\n  id: number;\n  content: string;\n  metadata: {\n    searchtype: string;\n    [key: string]: unknown;\n  };\n}\n\n/**\n * Interface for the arguments required to initialize an Azion library.\n */\nexport interface AzionRetrieverArgs extends BaseRetrieverInput {\n  /**\n   * Search type to perform. Cosine similarity and hybrid (vector + FTS) are currently supported.\n   */\n  searchType?: \"hybrid\" | \"similarity\";\n\n  /**\n   * The number of documents retrieved with cosine similarity (vector) search. Minimum is 1.\n   */\n  similarityK?: number;\n\n  /**\n   * The number of documents retrieved with full text search. Minimum is 1.\n   */\n  ftsK?: number;\n\n  /**\n   * The name of the database to search for documents.\n   */\n  dbName?: string;\n\n  /**\n   * The prompt to the chatmodel to extract entities to perform Full text search on the database\n   */\n  promptEntityExtractor?: string;\n\n  /**\n   * The chatmodel to extract entities to perform Full text search on the database\n   */\n  entityExtractor?: BaseChatModel;\n\n  /**\n   * Max items to maintain per searchtype. Default is 3.\n   */\n  maxItemsSearch?: number;\n\n  /**\n   * The columns from the tables that metadata must contain\n   */\n  metadataItems?: string[];\n\n  /**\n   * Name of the table to perform vector similarity seach. Default is 'documents'\n   */\n  vectorTable?: string;\n\n  /**\n   * Name of the table to perform full text search. Default is 'document_fts'\n   */\n  ftsTable?: string;\n\n  /**\n   * Filters to apply to the search. Default is an empty array.\n   */\n  filters?: AzionFilter[];\n\n  /** Whether the metadata is contained in a single column or multiple columns */\n  expandedMetadata?: boolean;\n}\n\n/**\n * class for performing hybrid search operations on Azion's Edge SQL database.\n * It extends the 'BaseRetriever' class and implements methods for\n * similarity search and full-text search (FTS).\n */\n/**\n * Example usage:\n * ```ts\n * // Initialize embeddings and chat model\n * const embeddings = new OpenAIEmbeddings();\n * const chatModel = new ChatOpenAI({ model: \"gpt-4o-mini\" });\n *\n * // Create retriever with hybrid search\n * const retriever = new AzionRetriever(embeddings, chatModel, {\n *   searchType: 'hybrid',\n *   similarityK: 3,\n *   ftsK: 2,\n *   dbName: 'my_docs',\n *   metadataItems: ['category', 'author'],\n *   vectorTable: 'documents',\n *   ftsTable: 'documents_fts',\n *   filters: [\n *     { operator: '=', column: 'status', value: 'published' }\n *   ]\n * });\n *\n * // Retrieve relevant documents\n * const docs = await retriever.invoke(\n *   \"What are coral reefs in Australia?\"\n * );\n *\n * // Create retriever with similarity search only\n * const simRetriever = new AzionRetriever(embeddings, chatModel, {\n *   searchType: 'similarity',\n *   similarityK: 5,\n *   dbName: 'my_docs',\n *   vectorTable: 'documents'\n * });\n *\n * // Customize entity extraction prompt\n * const customRetriever = new AzionRetriever(embeddings, chatModel, {\n *   searchType: 'hybrid',\n *   similarityK: 3,\n *   ftsK: 2,\n *   dbName: 'my_docs',\n *   promptEntityExtractor: \"Extract key entities from: {{query}}\"\n * });\n * ```\n */\n\nexport class AzionRetriever extends BaseRetriever {\n  static lc_name() {\n    return \"azionRetriever\";\n  }\n\n  /** Namespace for the retriever in LangChain */\n  lc_namespace = [\"langchain\", \"retrievers\", \"azion\"];\n\n  /** Type of search to perform - either hybrid (combining vector + FTS) or similarity only */\n  searchType?: \"hybrid\" | \"similarity\";\n\n  /** Number of results to return from similarity search. Minimum is 1. */\n  similarityK: number;\n\n  /** Number of results to return from full text search. Minimum is 1. */\n  ftsK: number;\n\n  /** Interface for generating embeddings from text */\n  embeddings: EmbeddingsInterface;\n\n  /** Name of the database to search */\n  dbName: string;\n\n  /** Optional ChatModel used to extract entities from queries */\n  entityExtractor?: BaseChatModel;\n\n  /** Prompt template for entity extraction */\n  promptEntityExtractor: string;\n\n  /** Optional metadata columns to include in results */\n  metadataItems?: string[];\n\n  /** Name of table containing vector embeddings for similarity search */\n  vectorTable: string;\n\n  /** Name of table containing documents for full text search */\n  ftsTable: string;\n\n  /** Array of filters to apply to search results */\n  filters: AzionFilter[];\n\n  /** Whether the metadata is contained in a single column or multiple columns */\n  expandedMetadata: boolean;\n\n  constructor(embeddings: EmbeddingsInterface, args: AzionRetrieverArgs) {\n    super(args);\n\n    this.ftsTable = args.ftsTable || \"vectors_fts\";\n    this.vectorTable = args.vectorTable || \"vectors\";\n    this.similarityK = Math.max(1, args.similarityK || 1);\n    this.ftsK = Math.max(1, args.ftsK || 1);\n    this.dbName = args.dbName || \"vectorstore\";\n\n    this.embeddings = embeddings;\n    this.searchType = args.searchType || \"similarity\";\n\n    this.entityExtractor = args.entityExtractor || undefined;\n    this.metadataItems = args.metadataItems || undefined;\n    this.promptEntityExtractor =\n      args.promptEntityExtractor ||\n      \"Provide them as a space-separated string in lowercase, translated to English.\";\n    this.filters = args.filters || [];\n    this.expandedMetadata = args.expandedMetadata || false;\n  }\n\n  /**\n   * Generates a string of filters for the SQL query.\n   * @param {AzionFilter[]} filters - The filters to apply to the search.\n   * @returns {string} A string of filters for the SQL query.\n   */\n  protected generateFilters(filters: AzionFilter[]): 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   * Generates SQL queries for full-text search and similarity search.\n   * @param {number[]} embeddedQuery - The embedded query vector.\n   * @param {string} queryEntities - The entities extracted from the query for full-text search.\n   * @param {string} metadata - Additional metadata columns to be included in the results.\n   * @returns An object containing the FTS query and similarity query strings.\n   */\n  protected generateSqlQueries(\n    embeddedQuery: number[],\n    queryEntities: string,\n    metadata: string\n  ): { ftsQuery: string; similarityQuery: string } {\n    const filters = this.generateFilters(this.filters);\n\n    let rowsNumber = this.similarityK;\n    if (this.searchType === \"hybrid\") {\n      rowsNumber += this.ftsK;\n    }\n\n    const ftsQuery = `\n      SELECT id, content, ${metadata.replace(\"hybrid\", \"fts\")}\n      FROM ${this.ftsTable} \n      WHERE ${filters} ${this.ftsTable} MATCH '${queryEntities}'\n      ORDER BY rank \n      LIMIT ${rowsNumber}\n    `;\n\n    const similarityQuery = `\n      SELECT id, content, ${metadata.replace(\"hybrid\", \"similarity\")}\n      FROM ${this.vectorTable}  \n      WHERE ${filters} rowid IN vector_top_k('${\n        this.vectorTable\n      }_idx', vector('[${embeddedQuery}]'), ${rowsNumber})\n    `;\n\n    return { ftsQuery, similarityQuery };\n  }\n\n  /**\n   * Generates the SQL statements for the similarity search and full-text search.\n   * @param query The user query.\n   * @returns An array of SQL statements.\n   */\n  protected async generateStatements(query: string): Promise<string[]> {\n    const embeddedQuery = await this.embeddings.embedQuery(query);\n\n    const metadata = this.generateMetadata();\n\n    let queryEntities = \"\";\n    if (this.searchType === \"hybrid\") {\n      queryEntities = await this.extractEntities(query);\n    }\n\n    const { ftsQuery, similarityQuery } = this.generateSqlQueries(\n      embeddedQuery,\n      queryEntities,\n      metadata\n    );\n\n    if (this.searchType === \"similarity\") {\n      return [similarityQuery];\n    }\n\n    return [similarityQuery, ftsQuery];\n  }\n\n  /**\n   * Generates the metadata string for the SQL query.\n   * @returns {string} The metadata string.\n   */\n  protected generateMetadata(): string {\n    if (!this.metadataItems) {\n      return `json_object('searchtype', '${this.searchType}') as metadata`;\n    }\n\n    if (this.expandedMetadata) {\n      return `json_object('searchtype','${this.searchType}',${this.metadataItems\n        .map(\n          (item) => `'${this.sanitizeItem(item)}', ${this.sanitizeItem(item)}`\n        )\n        .join(\", \")}) as metadata`;\n    }\n\n    return `json_patch(json_object(${this.metadataItems\n      ?.map(\n        (item) =>\n          `'${this.sanitizeItem(item)}', metadata->>'$.${this.sanitizeItem(\n            item\n          )}'`\n      )\n      .join(\", \")}), '{\"searchtype\":\"${this.searchType}\"}') as metadata`;\n  }\n\n  /**\n   * Performs a similarity search on the vector store and returns the top 'similarityK' similar documents.\n   * @param query The query string.\n   * @returns A promise that resolves with the similarity search results when the search is complete.\n   */\n  protected async similaritySearchWithScore(\n    query: string\n  ): Promise<[Document][]> {\n    const statements = await this.generateStatements(query);\n\n    const { data: response, error: errorQuery } = await useQuery(\n      this.dbName,\n      statements\n    );\n\n    if (!response) {\n      console.error(\"RESPONSE ERROR: \", errorQuery);\n      throw this.searchError(errorQuery);\n    }\n    const searches = this.mapRows(response.results);\n    const result = this.mapSearches(searches);\n    return result;\n  }\n\n  /**\n   * Extracts entities from a user query using the entityExtractor model.\n   * @param query The user query\n   * @returns A promise that resolves with the extracted entities when the extraction is complete.\n   */\n  protected async extractEntities(query: string): Promise<string> {\n    if (!this.entityExtractor) {\n      return this.convert2FTSQuery(query);\n    }\n\n    const entityExtractionPrompt = new SystemMessage(\n      this.promptEntityExtractor\n    );\n\n    const entityQuery = await this.entityExtractor.invoke([\n      entityExtractionPrompt,\n      new HumanMessage(query),\n    ]);\n    return this.convert2FTSQuery(entityQuery.content.toString());\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  /**\n   * Performs a hybrid search on the vector store, using cosine similarity and FTS search, and\n   * returns the top 'similarityK' + 'ftsK' similar documents.\n   * @param query The user query\n   * @returns A promise that resolves with the hybrid search results when the search is complete.\n   */\n  protected async hybridSearchAzion(query: string): Promise<[Document][]> {\n    const statements = await this.generateStatements(query);\n\n    const { data: response, error: errorQuery } = await useQuery(\n      this.dbName,\n      statements\n    );\n\n    if (!response) {\n      console.error(\"RESPONSE ERROR: \", errorQuery);\n      throw this.searchError(errorQuery);\n    }\n\n    const results = this.mapRows(response.results);\n\n    const finalResults = this.removeDuplicates(results);\n\n    return this.mapSearches(finalResults);\n  }\n\n  /**\n   * Generates an error document based on the provided error information\n   * @param error The error object containing details about the issue\n   * @returns A promise that resolves to an array containing a single Document representing the error\n   */\n  protected 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   * Performs the selected search and returns the documents retrieved.\n   * @param query The user query\n   * @returns A promise that resolves with the completion of the search results.\n   */\n  async _getRelevantDocuments(query: string): Promise<Document[]> {\n    let result: [Document][];\n\n    if (this.searchType === \"similarity\") {\n      result = await this.similaritySearchWithScore(query);\n    } else {\n      result = await this.hybridSearchAzion(query);\n    }\n\n    return result.map(([doc]) => doc);\n  }\n\n  /**\n   * Removes duplicate results from the search results, prioritizing a mix of similarity and FTS results.\n   * @param {SearchEmbeddingsResponse[]} results - The array of search results to process.\n   * @returns {SearchEmbeddingsResponse[]} An array of unique search results, with a maximum of 3 similarity and 3 FTS results.\n   */\n  private removeDuplicates(\n    results: SearchEmbeddingsResponse[]\n  ): SearchEmbeddingsResponse[] {\n    const uniqueResults: SearchEmbeddingsResponse[] = [];\n    const seenIds = new Set<number>();\n\n    let similarityCount = 0;\n    let ftsCount = 0;\n    const maxItems = this.ftsK + this.similarityK;\n\n    for (const result of results) {\n      if (!seenIds.has(result.id)) {\n        if (\n          result.metadata.searchtype === \"similarity\" &&\n          similarityCount < this.similarityK\n        ) {\n          seenIds.add(result.id);\n          uniqueResults.push(result);\n          similarityCount += 1;\n        } else if (\n          result.metadata.searchtype === \"fts\" &&\n          ftsCount < this.ftsK\n        ) {\n          seenIds.add(result.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          })\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  protected mapSearches(searches: SearchEmbeddingsResponse[]): [Document][] {\n    return searches.map((resp: SearchEmbeddingsResponse) => [\n      new Document({\n        metadata: resp.metadata,\n        pageContent: resp.content,\n        id: resp.id.toString(),\n      }),\n    ]);\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"],"mappings":"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"}