@langchain/community
Version:
Third-party integrations for LangChain.js
1 lines • 47 kB
Source Map (JSON)
{"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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"}