{"version":3,"file":"hanavector.cjs","names":["COMPARISONS_TO_SQL: Record<string, string>","IN_OPERATORS_TO_SQL: Record<string, string>","BETWEEN_OPERATOR_TO_SQL: Record<string, string>","LIKE_OPERATOR_TO_SQL: Record<string, string>","LOGICAL_OPERATORS_TO_SQL: Record<string, string>","HANA_DISTANCE_FUNCTION: Record<DistanceStrategy, [string, string]>","VectorStore","embeddings: EmbeddingsInterface","args: HanaDBArgs","client: any","query: string","err: Error","result: any","statement: any","params: any","res: any","inputStr: string","inputInt: number | string","embedding: number[]","metadata: object[] | object","arrayAsString: string","tableName: string","columnName: string","columnType: string | string[]","columnLength?: number","dataType: string","length: number","filter?: this[\"FilterType\"]","queryTuple: Array<ComparisonRValue>","filter: this[\"FilterType\"]","operand: Filter","j: number","options: {\n      m?: number;\n      efConstruction?: number;\n      efSearch?: number;\n      indexName?: string;\n    }","buildConfig: Record<string, number>","searchConfig: Record<string, number>","options: {\n    ids?: string[];\n    filter?: Filter;\n  }","texts: string[]","metadatas: object[] | object","dbConfig: HanaDBArgs","docs: Document[]","Document","documents: Document[]","vectors: number[][]","sqlParams: [string, string, string][]","k: number","queryEmbedding: number[]","result: Array<[Document, number, number[]]>","row: any","doc: Document","options: MaxMarginalRelevanceSearchOptions<this[\"FilterType\"]>"],"sources":["../../src/vectorstores/hanavector.ts"],"sourcesContent":["import type { EmbeddingsInterface } from \"@langchain/core/embeddings\";\nimport {\n  VectorStore,\n  MaxMarginalRelevanceSearchOptions,\n} from \"@langchain/core/vectorstores\";\nimport { Document } from \"@langchain/core/documents\";\nimport { maximalMarginalRelevance } from \"@langchain/core/utils/math\";\n\nexport type DistanceStrategy = \"euclidean\" | \"cosine\";\n\nconst COMPARISONS_TO_SQL: Record<string, string> = {\n  $eq: \"=\",\n  $ne: \"<>\",\n  $lt: \"<\",\n  $lte: \"<=\",\n  $gt: \">\",\n  $gte: \">=\",\n};\n\n// Base value types that can be used in comparisons\ntype ComparisonRValue =\n  | string\n  | number\n  | boolean\n  | Date\n  | Array<ComparisonRValue>;\n// Available comparison operators for filtering\ntype Comparator =\n  | \"$eq\"\n  | \"$ne\"\n  | \"$lt\"\n  | \"$lte\"\n  | \"$gt\"\n  | \"$gte\"\n  | \"$in\"\n  | \"$nin\"\n  | \"$between\"\n  | \"$like\";\n// Filter using comparison operators\n// Defines the relationship between a comparison operator and its value\ntype ComparatorFilter = {\n  [K in Comparator]?: ComparisonRValue;\n};\n\ntype LogicalOperator = \"$and\" | \"$or\";\ntype LogicalFilter = {\n  [K in LogicalOperator]?: Filter[];\n};\ntype PropertyFilter = {\n  [property: string]: string | number | boolean | Date | ComparatorFilter;\n};\n\ntype Filter = PropertyFilter | LogicalFilter;\n\ninterface DateValue {\n  type: \"date\";\n  date: string | Date;\n}\n\nconst IN_OPERATORS_TO_SQL: Record<string, string> = {\n  $in: \"IN\",\n  $nin: \"NOT IN\",\n};\n\nconst BETWEEN_OPERATOR_TO_SQL: Record<string, string> = {\n  $between: \"BETWEEN\",\n};\n\nconst LIKE_OPERATOR_TO_SQL: Record<string, string> = {\n  $like: \"LIKE\",\n};\n\nconst LOGICAL_OPERATORS_TO_SQL: Record<string, string> = {\n  $and: \"AND\",\n  $or: \"OR\",\n};\n\nconst HANA_DISTANCE_FUNCTION: Record<DistanceStrategy, [string, string]> = {\n  cosine: [\"COSINE_SIMILARITY\", \"DESC\"],\n  euclidean: [\"L2DISTANCE\", \"ASC\"],\n};\n\nconst defaultDistanceStrategy = \"cosine\";\nconst defaultTableName = \"EMBEDDINGS\";\nconst defaultContentColumn = \"VEC_TEXT\";\nconst defaultMetadataColumn = \"VEC_META\";\nconst defaultVectorColumn = \"VEC_VECTOR\";\nconst defaultVectorColumnLength = -1; // -1 means dynamic length\n\n/**\n * Interface defining the arguments required to create an instance of\n * `HanaDB`.\n */\nexport interface HanaDBArgs {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  connection: any;\n  distanceStrategy?: DistanceStrategy;\n  tableName?: string;\n  contentColumn?: string;\n  metadataColumn?: string;\n  vectorColumn?: string;\n  vectorColumnLength?: number;\n  specificMetadataColumns?: string[];\n}\n\nexport class HanaDB extends VectorStore {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  private connection: any;\n\n  private distanceStrategy: DistanceStrategy;\n\n  // Compile pattern only once, for better performance\n  private static compiledPattern = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\n  private tableName: string;\n\n  private contentColumn: string;\n\n  private metadataColumn: string;\n\n  private vectorColumn: string;\n\n  private vectorColumnLength: number;\n\n  declare FilterType: Filter;\n\n  private specificMetadataColumns: string[];\n\n  _vectorstoreType(): string {\n    return \"hanadb\";\n  }\n\n  constructor(embeddings: EmbeddingsInterface, args: HanaDBArgs) {\n    super(embeddings, args);\n    this.distanceStrategy = args.distanceStrategy || defaultDistanceStrategy;\n    this.tableName = args.tableName || defaultTableName;\n    this.contentColumn = args.contentColumn || defaultContentColumn;\n    this.metadataColumn = args.metadataColumn || defaultMetadataColumn;\n    this.vectorColumn = args.vectorColumn || defaultVectorColumn;\n    this.vectorColumnLength = HanaDB.sanitizeInt(\n      args.vectorColumnLength || defaultVectorColumnLength,\n      -1\n    );\n    this.specificMetadataColumns = args.specificMetadataColumns || [];\n    this.connection = args.connection;\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  private executeQuery(client: any, query: string): Promise<any> {\n    return new Promise((resolve, reject) => {\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      client.exec(query, (err: Error, result: any) => {\n        if (err) {\n          reject(err);\n        } else {\n          resolve(result);\n        }\n      });\n    });\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  private prepareQuery(client: any, query: string): Promise<any> {\n    return new Promise((resolve, reject) => {\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      client.prepare(query, (err: Error, statement: any) => {\n        if (err) {\n          reject(err);\n        } else {\n          resolve(statement);\n        }\n      });\n    });\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  private executeStatement(statement: any, params: any): Promise<any> {\n    return new Promise((resolve, reject) => {\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      statement.exec(params, (err: Error, res: any) => {\n        if (err) {\n          reject(err);\n        } else {\n          resolve(res);\n        }\n      });\n    });\n  }\n\n  public async initialize() {\n    let valid_distance = false;\n    for (const key in HANA_DISTANCE_FUNCTION) {\n      if (key === this.distanceStrategy) {\n        valid_distance = true;\n        break; // Added to exit loop once a match is found\n      }\n    }\n    if (!valid_distance) {\n      throw new Error(\n        `Unsupported distance_strategy: ${this.distanceStrategy}`\n      );\n    }\n    await this.createTableIfNotExists();\n    await this.checkColumn(this.tableName, this.contentColumn, [\n      \"NCLOB\",\n      \"NVARCHAR\",\n    ]);\n    await this.checkColumn(this.tableName, this.metadataColumn, [\n      \"NCLOB\",\n      \"NVARCHAR\",\n    ]);\n    await this.checkColumn(\n      this.tableName,\n      this.vectorColumn,\n      [\"REAL_VECTOR\"],\n      this.vectorColumnLength\n    );\n  }\n  /**\n   * Sanitizes the input string by removing characters that are not alphanumeric or underscores.\n   * @param inputStr The string to be sanitized.\n   * @returns The sanitized string.\n   */\n\n  public static sanitizeName(inputStr: string): string {\n    return inputStr.replace(/[^a-zA-Z0-9_]/g, \"\");\n  }\n\n  public static escapeSqlIdentifier(inputStr: string): string {\n    return `\"${inputStr.replaceAll('\"', '\"\"')}\"`;\n  }\n\n  /**\n   * Sanitizes the input to integer. Throws an error if the value is less than lower bound.\n   * @param inputInt The input to be sanitized.\n   * @returns The sanitized integer.\n   */\n  public static sanitizeInt(inputInt: number | string, lowerBound = 0): number {\n    const value = parseInt(inputInt.toString(), 10);\n    if (Number.isNaN(value) || value < lowerBound) {\n      throw new Error(\n        `Value (${value}) must not be smaller than ${lowerBound}`\n      );\n    }\n    return value;\n  }\n\n  /**\n   * Sanitizes a list to ensure all elements are floats (numbers in TypeScript).\n   * Throws an error if any element is not a number.\n   *\n   * @param {number[]} embedding - The array of numbers (floats) to be sanitized.\n   * @returns {number[]} The sanitized array of numbers (floats).\n   * @throws {Error} Throws an error if any element is not a number.\n   */\n  public static sanitizeListFloat(embedding: number[]): number[] {\n    if (!Array.isArray(embedding)) {\n      throw new Error(\n        `Expected 'embedding' to be an array, but received ${typeof embedding}`\n      );\n    }\n    embedding.forEach((value) => {\n      if (typeof value !== \"number\") {\n        throw new Error(`Value (${value}) does not have type number`);\n      }\n    });\n    return embedding;\n  }\n\n  /**\n   * Sanitizes the keys of the metadata object to ensure they match the required pattern.\n   * Throws an error if any key does not match the pattern.\n   *\n   * @param {Record<string, any>} metadata - The metadata object with keys to be validated.\n   * @returns {object[] | object} The original metadata object if all keys are valid.\n   * @throws {Error} Throws an error if any metadata key is invalid.\n   */\n  private sanitizeMetadataKeys(metadata: object[] | object): object[] | object {\n    if (!metadata) {\n      return {};\n    }\n    Object.keys(metadata).forEach((key) => {\n      if (!HanaDB.compiledPattern.test(key)) {\n        throw new Error(`Invalid metadata key ${key}`);\n      }\n    });\n    return metadata;\n  }\n\n  /**\n   * Parses a string representation of a float array and returns an array of numbers.\n   * @param {string} arrayAsString - The string representation of the array.\n   * @returns {number[]} An array of floats parsed from the string.\n   */\n  public static parseFloatArrayFromString(arrayAsString: string): number[] {\n    const arrayWithoutBrackets = arrayAsString.slice(1, -1);\n    return arrayWithoutBrackets.split(\",\").map((x) => parseFloat(x));\n  }\n\n  /**\n   * Checks if the specified column exists in the table and validates its data type and length.\n   * @param tableName The name of the table.\n   * @param columnName The name of the column to check.\n   * @param columnType The expected data type(s) of the column.\n   * @param columnLength The expected length of the column. Optional.\n   */\n  public async checkColumn(\n    tableName: string,\n    columnName: string,\n    columnType: string | string[],\n    columnLength?: number\n  ): Promise<void> {\n    const query = `\n      SELECT DATA_TYPE_NAME, LENGTH\n      FROM SYS.TABLE_COLUMNS\n      WHERE SCHEMA_NAME = CURRENT_SCHEMA\n      AND TABLE_NAME = ?\n      AND COLUMN_NAME = ?`;\n    const client = this.connection; // Get the connection object\n    // Prepare the statement with parameter placeholders\n    const statement = await this.prepareQuery(client, query);\n    // Execute the query with actual parameters to avoid SQL injection\n    const resultSet = await this.executeStatement(statement, [\n      tableName,\n      columnName,\n    ]);\n    if (resultSet.length === 0) {\n      throw new Error(`Column ${columnName} does not exist`);\n    } else {\n      const dataType: string = resultSet[0].DATA_TYPE_NAME;\n      const length: number = resultSet[0].LENGTH;\n\n      // Check if dataType is within columnType\n      const isValidType = Array.isArray(columnType)\n        ? columnType.includes(dataType)\n        : columnType === dataType;\n      if (!isValidType) {\n        throw new Error(`Column ${columnName} has the wrong type: ${dataType}`);\n      }\n\n      // Length can either be -1 (QRC01+02-24) or 0 (QRC03-24 onwards)\n      // to indicate no length constraint being present.\n\n      // Check length, if parameter was provided\n      if (columnLength !== undefined && length !== columnLength && length > 0) {\n        throw new Error(`Column ${columnName} has the wrong length: ${length}`);\n      }\n    }\n  }\n\n  private async createTableIfNotExists() {\n    const tableExists = await this.tableExists(this.tableName);\n    if (!tableExists) {\n      // Length can either be -1 (QRC01+02-24) or 0 (QRC03-24 onwards)\n      const vectorColumnLength =\n        this.vectorColumnLength <= 0 ? null : this.vectorColumnLength;\n      const query = `\n        CREATE TABLE ${HanaDB.escapeSqlIdentifier(this.tableName)} (\n          ${HanaDB.escapeSqlIdentifier(this.contentColumn)} NCLOB,\n          ${HanaDB.escapeSqlIdentifier(this.metadataColumn)} NCLOB,\n          ${HanaDB.escapeSqlIdentifier(this.vectorColumn)} REAL_VECTOR${\n            vectorColumnLength ? `(${vectorColumnLength})` : \"\"\n          }\n        )`;\n      const client = this.connection;\n      await this.executeQuery(client, query);\n    }\n  }\n\n  public async tableExists(tableName: string): Promise<boolean> {\n    const tableExistsQuery = `SELECT COUNT(*) AS COUNT FROM SYS.TABLES WHERE SCHEMA_NAME = CURRENT_SCHEMA AND TABLE_NAME = ?`;\n    const client = this.connection; // Get the connection object\n\n    const statement = await this.prepareQuery(client, tableExistsQuery);\n    const resultSet = await this.executeStatement(statement, [tableName]);\n    if (resultSet[0].COUNT === 1) {\n      // Table does  exist\n      return true;\n    }\n    return false;\n  }\n\n  /**\n   * Creates a WHERE clause based on the provided filter object.\n   * @param filter - A filter object with keys as metadata fields and values as filter values.\n   * @returns A tuple containing the WHERE clause string and an array of query parameters.\n   */\n  private createWhereByFilter(\n    filter?: this[\"FilterType\"]\n  ): [string, Array<ComparisonRValue>] {\n    let whereStr = \"\";\n    let queryTuple: Array<ComparisonRValue> = [];\n\n    if (filter && Object.keys(filter).length > 0) {\n      const [where, params] = this.processFilterObject(filter);\n      whereStr = ` WHERE ${where}`;\n      queryTuple = params;\n    }\n\n    return [whereStr, queryTuple];\n  }\n\n  /**\n   * Processes a filter object to generate SQL WHERE clause components.\n   * @param filter - A filter object with keys as metadata fields and values as filter values.\n   * @returns A tuple containing the WHERE clause string and an array of query parameters.\n   */\n  private processFilterObject(\n    filter: this[\"FilterType\"]\n  ): [string, Array<ComparisonRValue>] {\n    let whereStr = \"\";\n    const queryTuple: Array<ComparisonRValue> = [];\n\n    Object.keys(filter).forEach((key, i) => {\n      const filterValue = filter[key as keyof Filter] as\n        | ComparisonRValue\n        | ComparatorFilter\n        | Filter[];\n      if (i !== 0) {\n        whereStr += \" AND \";\n      }\n\n      // Handling logical operators ($and, $or)\n      if (key in LOGICAL_OPERATORS_TO_SQL) {\n        const logicalOperator = LOGICAL_OPERATORS_TO_SQL[key];\n        const logicalOperands = filterValue as Filter[];\n        logicalOperands.forEach((operand: Filter, j: number) => {\n          if (j !== 0) {\n            whereStr += ` ${logicalOperator} `;\n          }\n          const [whereLogical, paramsLogical] =\n            this.processFilterObject(operand);\n          whereStr += `(${whereLogical})`;\n          queryTuple.push(...paramsLogical);\n        });\n\n        return;\n      }\n\n      // Handle special comparison operators and simple types\n      let operator = \"=\";\n      let sqlParam = \"?\";\n      if (typeof filterValue === \"number\") {\n        if (Number.isInteger(filterValue)) {\n          // hdb requires string while sap/hana-client doesn't\n          queryTuple.push(filterValue.toString());\n        } else {\n          throw new Error(\n            `Unsupported filter data-type: wrong number type for key ${key}`\n          );\n        }\n      } else if (typeof filterValue === \"string\") {\n        queryTuple.push(filterValue);\n      } else if (typeof filterValue === \"boolean\") {\n        queryTuple.push(filterValue.toString());\n      } else if (typeof filterValue === \"object\" && filterValue !== null) {\n        // Get the special operator key, like $eq, $ne, $in, $between, etc.\n        const specialOp = Object.keys(filterValue)[0] as Comparator;\n        const specialVal = (filterValue as ComparatorFilter)[specialOp];\n        // Handling of 'special' operators starting with \"$\"\n        if (specialOp in COMPARISONS_TO_SQL) {\n          operator = COMPARISONS_TO_SQL[specialOp];\n          if (specialVal === undefined) {\n            throw new Error(\n              `Operator '${specialOp}' expects a non-undefined value.`\n            );\n          }\n          if (typeof specialVal === \"boolean\") {\n            queryTuple.push(specialVal.toString());\n          } else if (typeof specialVal === \"number\") {\n            sqlParam = \"CAST(? as float)\";\n            queryTuple.push(specialVal);\n          } else if (\n            typeof specialVal === \"object\" &&\n            specialVal !== null &&\n            \"type\" in specialVal &&\n            specialVal.type === \"date\" &&\n            \"date\" in specialVal\n          ) {\n            sqlParam = \"CAST(? as DATE)\";\n            queryTuple.push((specialVal as DateValue).date);\n          } else {\n            queryTuple.push(specialVal);\n          }\n        } else if (specialOp in BETWEEN_OPERATOR_TO_SQL) {\n          // ensure the value is an array with exact length of 2\n          if (!Array.isArray(specialVal) || specialVal.length !== 2) {\n            throw new Error(`Operator '${specialOp}' expects two values.`);\n          }\n          const [betweenFrom, betweenTo] = specialVal as [\n            ComparisonRValue,\n            ComparisonRValue,\n          ];\n          operator = BETWEEN_OPERATOR_TO_SQL[specialOp];\n          sqlParam = \"? AND ?\";\n          queryTuple.push(betweenFrom.toString(), betweenTo.toString());\n        } else if (specialOp in LIKE_OPERATOR_TO_SQL) {\n          operator = LIKE_OPERATOR_TO_SQL[specialOp];\n          if (specialVal !== undefined) {\n            queryTuple.push(specialVal.toString());\n          } else {\n            throw new Error(\n              `Operator '${specialOp}' expects a non-undefined value.`\n            );\n          }\n        } else if (specialOp in IN_OPERATORS_TO_SQL) {\n          operator = IN_OPERATORS_TO_SQL[specialOp];\n          if (Array.isArray(specialVal)) {\n            const placeholders = Array(specialVal.length).fill(\"?\").join(\",\");\n            sqlParam = `(${placeholders})`;\n            queryTuple.push(\n              ...specialVal.map((listEntry) => listEntry.toString())\n            );\n          } else {\n            throw new Error(`Unsupported value for ${operator}: ${specialVal}`);\n          }\n        } else {\n          throw new Error(`Unsupported operator: ${specialOp}`);\n        }\n      } else {\n        throw new Error(`Unsupported filter data-type: ${typeof filterValue}`);\n      }\n\n      // Metadata column handling\n      const selector = this.specificMetadataColumns.includes(key)\n        ? HanaDB.escapeSqlIdentifier(key)\n        : `JSON_VALUE(${HanaDB.escapeSqlIdentifier(\n            this.metadataColumn\n          )}, '$.${key}')`;\n      whereStr += `${selector} ${operator} ${sqlParam}`;\n    });\n    return [whereStr, queryTuple];\n  }\n\n  /**\n   * Creates an HNSW vector index on a specified table and vector column with\n   * optional build and search configurations. If no configurations are provided,\n   * default parameters from the database are used. If provided values exceed the\n   * valid ranges, an error will be raised.\n   * The index is always created in ONLINE mode.\n   *\n   * @param {object} options Object containing configuration options for the index\n   * @param {number} [options.m] (Optional) Maximum number of neighbors per graph node (Valid Range: [4, 1000])\n   * @param {number} [options.efConstruction] (Optional) Maximal candidates to consider when building the graph\n   *                                           (Valid Range: [1, 100000])\n   * @param {number} [options.efSearch] (Optional) Minimum candidates for top-k-nearest neighbor queries\n   *                                     (Valid Range: [1, 100000])\n   * @param {string} [options.indexName] (Optional) Custom index name. Defaults to <table_name>_<distance_strategy>_idx\n   * @returns {Promise<void>} Promise that resolves when index is added.\n   */\n  public async createHnswIndex(\n    options: {\n      m?: number;\n      efConstruction?: number;\n      efSearch?: number;\n      indexName?: string;\n    } = {}\n  ): Promise<void> {\n    const { m, efConstruction, efSearch, indexName } = options;\n\n    // Determine the distance function based on the configured strategy\n    const distanceFuncName = HANA_DISTANCE_FUNCTION[this.distanceStrategy][0];\n    const defaultIndexName = `${this.tableName}_${distanceFuncName}_idx`;\n\n    // Use provided indexName or fallback to default\n    const finalIndexName = indexName || defaultIndexName;\n    // Initialize buildConfig and searchConfig objects\n    const buildConfig: Record<string, number> = {};\n    const searchConfig: Record<string, number> = {};\n\n    // Validate and add m parameter to buildConfig if provided\n    if (m !== undefined) {\n      const minimumHnswM = 4;\n      const maximumHnswM = 1000;\n      const sanitizedM = HanaDB.sanitizeInt(m, minimumHnswM);\n      if (sanitizedM < minimumHnswM || sanitizedM > maximumHnswM) {\n        throw new Error(\"M must be in the range [4, 1000]\");\n      }\n      buildConfig.M = sanitizedM;\n    }\n\n    // Validate and add efConstruction to buildConfig if provided\n    if (efConstruction !== undefined) {\n      const minimumEfConstruction = 1;\n      const maximumEfConstruction = 100000;\n      const sanitizedEfConstruction = HanaDB.sanitizeInt(\n        efConstruction,\n        minimumEfConstruction\n      );\n      if (\n        sanitizedEfConstruction < minimumEfConstruction ||\n        sanitizedEfConstruction > maximumEfConstruction\n      ) {\n        throw new Error(\"efConstruction must be in the range [1, 100000]\");\n      }\n      buildConfig.efConstruction = sanitizedEfConstruction;\n    }\n\n    // Validate and add efSearch to searchConfig if provided\n    if (efSearch !== undefined) {\n      const minimumEfSearch = 1;\n      const maximumEfSearch = 100000;\n      const sanitizedEfSearch = HanaDB.sanitizeInt(efSearch, minimumEfSearch);\n      if (\n        sanitizedEfSearch < minimumEfSearch ||\n        sanitizedEfSearch > maximumEfSearch\n      ) {\n        throw new Error(\"efSearch must be in the range [1, 100000]\");\n      }\n      searchConfig.efSearch = sanitizedEfSearch;\n    }\n\n    // Convert buildConfig and searchConfig to JSON strings if they contain values\n    const buildConfigStr = Object.keys(buildConfig).length\n      ? JSON.stringify(buildConfig)\n      : \"\";\n    const searchConfigStr = Object.keys(searchConfig).length\n      ? JSON.stringify(searchConfig)\n      : \"\";\n\n    // Create the base SQL string for index creation\n    let query = `\n      CREATE HNSW VECTOR INDEX ${HanaDB.escapeSqlIdentifier(finalIndexName)}\n      ON ${HanaDB.escapeSqlIdentifier(\n        this.tableName\n      )} (${HanaDB.escapeSqlIdentifier(this.vectorColumn)})\n      SIMILARITY FUNCTION ${distanceFuncName}`;\n\n    // Append buildConfig to the SQL string if provided\n    if (buildConfigStr) {\n      query += ` BUILD CONFIGURATION '${buildConfigStr}'`;\n    }\n\n    // Append searchConfig to the SQL string if provided\n    if (searchConfigStr) {\n      query += ` SEARCH CONFIGURATION '${searchConfigStr}'`;\n    }\n\n    // Add the ONLINE option\n    query += \" ONLINE;\";\n\n    const client = this.connection;\n    await this.executeQuery(client, query);\n  }\n\n  /**\n   * Deletes entries from the table based on the provided filter.\n   * @param ids - Optional. Deletion by ids is not supported and will throw an error.\n   * @param filter - Optional. A filter object to specify which entries to delete.\n   * @throws Error if 'ids' parameter is provided, as deletion by ids is not supported.\n   * @throws Error if 'filter' parameter is not provided, as it is required for deletion.\n   * to do: adjust the call signature\n   */\n  public async delete(options: {\n    ids?: string[];\n    filter?: Filter;\n  }): Promise<void> {\n    const { ids, filter } = options;\n    if (ids) {\n      throw new Error(\"Deletion via IDs is not supported\");\n    }\n    if (!filter) {\n      throw new Error(\"Parameter 'filter' is required when calling 'delete'\");\n    }\n\n    const [whereStr, queryTuple] = this.createWhereByFilter(filter);\n    const query = `DELETE FROM ${HanaDB.escapeSqlIdentifier(\n      this.tableName\n    )} ${whereStr}`;\n    const client = this.connection;\n    const statement = await this.prepareQuery(client, query);\n    await this.executeStatement(statement, queryTuple);\n  }\n\n  /**\n   * Static method to create a HanaDB instance from raw texts. This method embeds the documents,\n   * creates a table if it does not exist, and adds the documents to the table.\n   * @param texts Array of text documents to add.\n   * @param metadatas metadata for each text document.\n   * @param embedding EmbeddingsInterface instance for document embedding.\n   * @param dbConfig Configuration for the HanaDB.\n   * @returns A Promise that resolves to an instance of HanaDB.\n   */\n  static async fromTexts(\n    texts: string[],\n    metadatas: object[] | object,\n    embeddings: EmbeddingsInterface,\n    dbConfig: HanaDBArgs\n  ): Promise<HanaDB> {\n    const docs: Document[] = [];\n    for (let i = 0; i < texts.length; i += 1) {\n      const metadata = Array.isArray(metadatas) ? metadatas[i] : metadatas;\n      const newDoc = new Document({\n        pageContent: texts[i],\n        metadata,\n      });\n      docs.push(newDoc);\n    }\n    return HanaDB.fromDocuments(docs, embeddings, dbConfig);\n  }\n\n  /**\n   * Creates an instance of `HanaDB` from an array of\n   * Document instances. The documents are added to the database.\n   * @param docs List of documents to be converted to vectors.\n   * @param embeddings Embeddings instance used to convert the documents to vectors.\n   * @param dbConfig Configuration for the HanaDB.\n   * @returns Promise that resolves to an instance of `HanaDB`.\n   */\n  static async fromDocuments(\n    docs: Document[],\n    embeddings: EmbeddingsInterface,\n    dbConfig: HanaDBArgs\n  ): Promise<HanaDB> {\n    const instance = new HanaDB(embeddings, dbConfig);\n    await instance.initialize();\n    await instance.addDocuments(docs);\n    return instance;\n  }\n\n  /**\n   * Adds an array of documents to the table. The documents are first\n   * converted to vectors using the `embedDocuments` method of the\n   * `embeddings` instance.\n   * @param documents Array of Document instances to be added to the table.\n   * @returns Promise that resolves when the documents are added.\n   */\n  async addDocuments(documents: Document[]): Promise<void> {\n    const texts = documents.map(({ pageContent }) => pageContent);\n    return this.addVectors(\n      await this.embeddings.embedDocuments(texts),\n      documents\n    );\n  }\n\n  /**\n   * Adds an array of vectors and corresponding documents to the database.\n   * The vectors and documents are batch inserted into the database.\n   * @param vectors Array of vectors to be added to the table.\n   * @param documents Array of Document instances corresponding to the vectors.\n   * @returns Promise that resolves when the vectors and documents are added.\n   */\n  async addVectors(vectors: number[][], documents: Document[]): Promise<void> {\n    if (vectors.length !== documents.length) {\n      throw new Error(`Vectors and metadatas must have the same length`);\n    }\n    const texts = documents.map((doc) => doc.pageContent);\n    const metadatas = documents.map((doc) => doc.metadata);\n    const client = this.connection;\n    const sqlParams: [string, string, string][] = texts.map((text, i) => {\n      const metadata = Array.isArray(metadatas) ? metadatas[i] : metadatas;\n      // Ensure embedding is generated or provided\n      const embeddingString = `[${vectors[i].join(\", \")}]`;\n      // Prepare the SQL parameters\n      return [\n        text,\n        JSON.stringify(this.sanitizeMetadataKeys(metadata)),\n        embeddingString,\n      ];\n    });\n    // Insert data into the table, bulk insert.\n    const query = `\n      INSERT INTO ${HanaDB.escapeSqlIdentifier(this.tableName)} (\n        ${HanaDB.escapeSqlIdentifier(this.contentColumn)},\n        ${HanaDB.escapeSqlIdentifier(this.metadataColumn)},\n        ${HanaDB.escapeSqlIdentifier(this.vectorColumn)}\n      ) VALUES (?, ?, TO_REAL_VECTOR(?));`;\n    const statement = await this.prepareQuery(client, query);\n    await this.executeStatement(statement, sqlParams);\n    // stm.execBatch(sqlParams);\n  }\n\n  /**\n     * Return docs most similar to query.\n     * @param query Query text for the similarity search.\n     * @param k Number of Documents to return. Defaults to 4.\n     * @param filter A dictionary of metadata fields and values to filter by.\n                    Defaults to None.\n     * @returns Promise that resolves to a list of documents and their corresponding similarity scores.\n     */\n  async similaritySearch(\n    query: string,\n    k: number,\n    filter?: this[\"FilterType\"]\n  ): Promise<Document[]> {\n    const results = await this.similaritySearchWithScore(query, k, filter);\n    return results.map((result) => result[0]);\n  }\n\n  /**\n     * Return documents and score values most similar to query.\n     * @param query Query text for the similarity search.\n     * @param k Number of Documents to return. Defaults to 4.\n     * @param filter A dictionary of metadata fields and values to filter by.\n                    Defaults to None.\n     * @returns Promise that resolves to a list of documents and their corresponding similarity scores.\n     */\n  async similaritySearchWithScore(\n    query: string,\n    k: number,\n    filter?: this[\"FilterType\"]\n  ): Promise<[Document, number][]> {\n    const queryEmbedding = await this.embeddings.embedQuery(query);\n    return this.similaritySearchVectorWithScore(queryEmbedding, k, filter);\n  }\n\n  /**\n     * Return docs most similar to the given embedding.\n     * @param query Query embedding for the similarity search.\n     * @param k Number of Documents to return. Defaults to 4.\n     * @param filter A dictionary of metadata fields and values to filter by.\n                    Defaults to None.\n     * @returns Promise that resolves to a list of documents and their corresponding similarity scores.\n     */\n  async similaritySearchVectorWithScore(\n    queryEmbedding: number[],\n    k: number,\n    filter?: this[\"FilterType\"]\n  ): Promise<[Document, number][]> {\n    const wholeResult = await this.similaritySearchWithScoreAndVectorByVector(\n      queryEmbedding,\n      k,\n      filter\n    );\n    // Return documents and scores, discarding the vectors\n    return wholeResult.map(([doc, score]) => [doc, score]);\n  }\n\n  /**\n   * Performs a similarity search based on vector comparison and returns documents along with their similarity scores and vectors.\n   * @param embedding The vector representation of the query for similarity comparison.\n   * @param k The number of top similar documents to return.\n   * @param filter Optional filter criteria to apply to the search query.\n   * @returns A promise that resolves to an array of tuples, each containing a Document, its similarity score, and its vector.\n   */\n  async similaritySearchWithScoreAndVectorByVector(\n    embedding: number[],\n    k: number,\n    filter?: this[\"FilterType\"]\n  ): Promise<Array<[Document, number, number[]]>> {\n    // Sanitize inputs\n    const sanitizedK = HanaDB.sanitizeInt(k);\n    const sanitizedEmbedding = HanaDB.sanitizeListFloat(embedding);\n    // Determine the distance function based on the configured strategy\n    const distanceFuncName = HANA_DISTANCE_FUNCTION[this.distanceStrategy][0];\n    // Convert the embedding vector to a string for SQL query\n    const embeddingAsString = sanitizedEmbedding.join(\",\");\n    let query = `\n      SELECT TOP ${sanitizedK}\n        ${HanaDB.escapeSqlIdentifier(this.contentColumn)},\n        ${HanaDB.escapeSqlIdentifier(this.metadataColumn)},\n        TO_NVARCHAR(${HanaDB.escapeSqlIdentifier(this.vectorColumn)}) AS VECTOR,\n        ${distanceFuncName}(\n          ${HanaDB.escapeSqlIdentifier(this.vectorColumn)},\n          TO_REAL_VECTOR('[${embeddingAsString}]')\n        ) AS CS\n      FROM ${HanaDB.escapeSqlIdentifier(this.tableName)}`;\n    // Add order by clause to sort by similarity\n    const orderStr = ` ORDER BY CS ${\n      HANA_DISTANCE_FUNCTION[this.distanceStrategy][1]\n    }`;\n\n    // Prepare and execute the SQL query\n    const [whereStr, queryTuple] = this.createWhereByFilter(filter);\n\n    query += whereStr + orderStr;\n    const client = this.connection;\n    const statement = await this.prepareQuery(client, query);\n    const resultSet = await this.executeStatement(statement, queryTuple);\n    const result: Array<[Document, number, number[]]> = resultSet.map(\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      (row: any) => {\n        const metadata = JSON.parse(row[this.metadataColumn].toString(\"utf8\"));\n        const doc: Document = {\n          pageContent: row[this.contentColumn].toString(\"utf8\"),\n          metadata,\n        };\n        const resultVector = HanaDB.parseFloatArrayFromString(row.VECTOR);\n        const score = row.CS;\n        return [doc, score, resultVector];\n      }\n    );\n\n    return result;\n  }\n\n  /**\n   * Return documents selected using the maximal marginal relevance.\n   * Maximal marginal relevance optimizes for similarity to the query AND\n   * diversity among selected documents.\n   * @param query Text to look up documents similar to.\n   * @param options.k Number of documents to return.\n   * @param options.fetchK=20 Number of documents to fetch before passing to\n   *     the MMR algorithm.\n   * @param options.lambda=0.5 Number between 0 and 1 that determines the\n   *     degree of diversity among the results, where 0 corresponds to maximum\n   *     diversity and 1 to minimum diversity.\n   * @returns List of documents selected by maximal marginal relevance.\n   */\n  async maxMarginalRelevanceSearch(\n    query: string,\n    options: MaxMarginalRelevanceSearchOptions<this[\"FilterType\"]>\n  ): Promise<Document[]> {\n    const { k, fetchK = 20, lambda = 0.5 } = options;\n    const queryEmbedding = await this.embeddings.embedQuery(query);\n\n    const docs = await this.similaritySearchWithScoreAndVectorByVector(\n      queryEmbedding,\n      fetchK\n    );\n    // docs is an Array of tuples: [Document, number, number[]]\n    const embeddingList = docs.map((doc) => doc[2]); // Extracts the embedding from each tuple\n    // Re-rank the results using MMR\n    const mmrIndexes = maximalMarginalRelevance(\n      queryEmbedding,\n      embeddingList,\n      lambda,\n      k\n    );\n    const mmrDocs = mmrIndexes.map((index) => docs[index][0]);\n    return mmrDocs;\n  }\n}\n"],"mappings":"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"}