@langchain/community
Version:
Third-party integrations for LangChain.js
1 lines • 49.9 kB
Source Map (JSON)
{"version":3,"file":"neo4j_vector.cjs","names":["VectorStore","embeddings: EmbeddingsInterface","config: Neo4jVectorStoreArgs","neo4j","versionString: string","version: number[]","query: string","params: Any","texts: string[]","metadatas: Any","Document","docs: Document[]","textNodeProperties: string[]","values: Array<{ [key: string]: Any }>","indexName: string","vectors: number[][]","documents: Document[]","metadatas?: Record<string, Any>[]","ids?: string[]","params: Record<string, Any>","vector: number[]","k: number","indexQuery: string","filterParams: Record<string, Any>","defaultRetrieval: string","docs: [Document, number][]","result: Any","records: Neo4jRecord[]","recordValues: Record<string, Any>[]","out: { [key: string]: Any }","item: Any","obj: Any","newObj: Any","path: Neo4jPath","segment: Any","searchType: SearchType","indexType: IndexType","typeToQueryMap: { [key in SearchType]: string }","text: string | null","v1: number[]","v2: number[]","COMPARISONS_TO_NATIVE: Record<string, string>","inputQueries: [string, Record<string, Any>][]","operator: string","combinedParams: Record<string, Any>","paramCounter: Record<string, number>","inputData: [string, Record<string, string>][]","queryParts: string[]","field: string","value: Any","filterValue: Any","val: Any","filter: Record<string, Any>"],"sources":["../../src/vectorstores/neo4j_vector.ts"],"sourcesContent":["import neo4j, {\n type Driver as Neo4jDriver,\n type Record as Neo4jRecord,\n type Path as Neo4jPath,\n} from \"neo4j-driver\";\nimport * as uuid from \"uuid\";\nimport type { EmbeddingsInterface } from \"@langchain/core/embeddings\";\nimport { VectorStore } from \"@langchain/core/vectorstores\";\nimport { Document } from \"@langchain/core/documents\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Any = any;\n\nexport type SearchType = \"vector\" | \"hybrid\";\n\nexport type IndexType = \"NODE\" | \"RELATIONSHIP\";\n\nexport type DistanceStrategy = \"euclidean\" | \"cosine\";\n\nexport type Metadata = Record<string, unknown>;\n\ninterface Neo4jVectorStoreArgs {\n url: string;\n username: string;\n password: string;\n database?: string;\n preDeleteCollection?: boolean;\n textNodeProperty?: string;\n textNodeProperties?: string[];\n embeddingNodeProperty?: string;\n keywordIndexName?: string;\n indexName?: string;\n searchType?: SearchType;\n indexType?: IndexType;\n retrievalQuery?: string;\n nodeLabel?: string;\n createIdIndex?: boolean;\n}\n\nconst DEFAULT_SEARCH_TYPE = \"vector\";\nconst DEFAULT_INDEX_TYPE = \"NODE\";\nconst DEFAULT_DISTANCE_STRATEGY = \"cosine\";\nconst DEFAULT_NODE_EMBEDDING_PROPERTY = \"embedding\";\n\n/**\n * @security *Security note*: Make sure that the database connection uses credentials\n * that are narrowly-scoped to only include necessary permissions.\n * Failure to do so may result in data corruption or loss, since the calling\n * code may attempt commands that would result in deletion, mutation\n * of data if appropriately prompted or reading sensitive data if such\n * data is present in the database.\n * The best way to guard against such negative outcomes is to (as appropriate)\n * limit the permissions granted to the credentials used with this tool.\n * For example, creating read only users for the database is a good way to\n * ensure that the calling code cannot mutate or delete data.\n *\n * @link See https://js.langchain.com/docs/security for more information.\n */\nexport class Neo4jVectorStore extends VectorStore {\n private driver: Neo4jDriver;\n\n private database: string;\n\n private preDeleteCollection: boolean;\n\n private nodeLabel: string;\n\n private embeddingNodeProperty: string;\n\n private embeddingDimension: number;\n\n private textNodeProperty: string;\n\n private keywordIndexName: string;\n\n private indexName: string;\n\n private retrievalQuery: string;\n\n private searchType: SearchType;\n\n private indexType: IndexType;\n\n private distanceStrategy: DistanceStrategy = DEFAULT_DISTANCE_STRATEGY;\n\n private supportMetadataFilter = true;\n\n private isEnterprise = false;\n\n _vectorstoreType(): string {\n return \"neo4jvector\";\n }\n\n constructor(embeddings: EmbeddingsInterface, config: Neo4jVectorStoreArgs) {\n super(embeddings, config);\n }\n\n static async initialize(\n embeddings: EmbeddingsInterface,\n config: Neo4jVectorStoreArgs\n ) {\n const store = new Neo4jVectorStore(embeddings, config);\n await store._initializeDriver(config);\n await store._verifyConnectivity();\n\n const {\n preDeleteCollection = false,\n nodeLabel = \"Chunk\",\n textNodeProperty = \"text\",\n embeddingNodeProperty = DEFAULT_NODE_EMBEDDING_PROPERTY,\n keywordIndexName = \"keyword\",\n indexName = \"vector\",\n retrievalQuery = \"\",\n searchType = DEFAULT_SEARCH_TYPE,\n indexType = DEFAULT_INDEX_TYPE,\n } = config;\n\n store.embeddingDimension = (await embeddings.embedQuery(\"foo\")).length;\n store.preDeleteCollection = preDeleteCollection;\n store.nodeLabel = nodeLabel;\n store.textNodeProperty = textNodeProperty;\n store.embeddingNodeProperty = embeddingNodeProperty;\n store.keywordIndexName = keywordIndexName;\n store.indexName = indexName;\n store.retrievalQuery = retrievalQuery;\n store.searchType = searchType;\n store.indexType = indexType;\n\n if (store.preDeleteCollection) {\n await store._dropIndex();\n }\n\n return store;\n }\n\n async _initializeDriver({\n url,\n username,\n password,\n database = \"neo4j\",\n }: Neo4jVectorStoreArgs) {\n try {\n this.driver = neo4j.driver(url, neo4j.auth.basic(username, password));\n this.database = database;\n } catch {\n throw new Error(\n \"Could not create a Neo4j driver instance. Please check the connection details.\"\n );\n }\n }\n\n async _verifyConnectivity() {\n await this.driver.verifyAuthentication();\n }\n\n async _verifyVersion() {\n try {\n const data = await this.query(\"CALL dbms.components()\");\n const versionString: string = data[0].versions[0];\n const targetVersion = [5, 11, 0];\n\n let version: number[];\n\n if (versionString.includes(\"aura\")) {\n // Get the 'x.y.z' part before '-aura'\n const baseVersion = versionString.split(\"-\")[0];\n version = baseVersion.split(\".\").map(Number);\n version.push(0);\n } else {\n version = versionString.split(\".\").map(Number);\n }\n\n if (isVersionLessThan(version, targetVersion)) {\n throw new Error(\n \"Version index is only supported in Neo4j version 5.11 or greater\"\n );\n }\n\n const metadataTargetVersion = [5, 18, 0];\n if (isVersionLessThan(version, metadataTargetVersion)) {\n this.supportMetadataFilter = false;\n }\n\n this.isEnterprise = data[0].edition === \"enterprise\";\n } catch (error) {\n console.error(\"Database version check failed:\", error);\n }\n }\n\n async close() {\n await this.driver.close();\n }\n\n async _dropIndex() {\n try {\n await this.query(`\n MATCH (n:\\`${this.nodeLabel}\\`)\n CALL {\n WITH n\n DETACH DELETE n\n }\n IN TRANSACTIONS OF 10000 ROWS;\n `);\n await this.query(`DROP INDEX ${this.indexName}`);\n } catch (error) {\n console.error(\"An error occurred while dropping the index:\", error);\n }\n }\n\n async query(query: string, params: Any = {}): Promise<Any[]> {\n const session = this.driver.session({ database: this.database });\n const result = await session.run(query, params);\n return toObjects(result.records);\n }\n\n static async fromTexts(\n texts: string[],\n metadatas: Any,\n embeddings: EmbeddingsInterface,\n config: Neo4jVectorStoreArgs\n ): Promise<Neo4jVectorStore> {\n const docs = [];\n\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\n return Neo4jVectorStore.fromDocuments(docs, embeddings, config);\n }\n\n static async fromDocuments(\n docs: Document[],\n embeddings: EmbeddingsInterface,\n config: Neo4jVectorStoreArgs\n ): Promise<Neo4jVectorStore> {\n const {\n searchType = DEFAULT_SEARCH_TYPE,\n createIdIndex = true,\n textNodeProperties = [],\n } = config;\n\n const store = await this.initialize(embeddings, config);\n\n const embeddingDimension = await store.retrieveExistingIndex();\n\n if (!embeddingDimension) {\n await store.createNewIndex();\n } else if (store.embeddingDimension !== embeddingDimension) {\n throw new Error(\n `Index with name \"${store.indexName}\" already exists. The provided embedding function and vector index dimensions do not match.\n Embedding function dimension: ${store.embeddingDimension}\n Vector index dimension: ${embeddingDimension}`\n );\n }\n\n if (searchType === \"hybrid\") {\n const ftsNodeLabel = await store.retrieveExistingFtsIndex();\n\n if (!ftsNodeLabel) {\n await store.createNewKeywordIndex(textNodeProperties);\n } else {\n if (ftsNodeLabel !== store.nodeLabel) {\n throw Error(\n \"Vector and keyword index don't index the same node label\"\n );\n }\n }\n }\n\n if (createIdIndex) {\n await store.query(\n `CREATE CONSTRAINT IF NOT EXISTS FOR (n:${store.nodeLabel}) REQUIRE n.id IS UNIQUE;`\n );\n }\n\n await store.addDocuments(docs);\n\n return store;\n }\n\n static async fromExistingIndex(\n embeddings: EmbeddingsInterface,\n config: Neo4jVectorStoreArgs\n ) {\n const { searchType = DEFAULT_SEARCH_TYPE, keywordIndexName = \"keyword\" } =\n config;\n\n if (searchType === \"hybrid\" && !keywordIndexName) {\n throw Error(\n \"keyword_index name has to be specified when using hybrid search option\"\n );\n }\n\n const store = await this.initialize(embeddings, config);\n const embeddingDimension = await store.retrieveExistingIndex();\n\n if (!embeddingDimension) {\n throw Error(\n \"The specified vector index name does not exist. Make sure to check if you spelled it correctly\"\n );\n }\n\n if (store.embeddingDimension !== embeddingDimension) {\n throw new Error(\n `The provided embedding function and vector index dimensions do not match.\n Embedding function dimension: ${store.embeddingDimension}\n Vector index dimension: ${embeddingDimension}`\n );\n }\n\n if (searchType === \"hybrid\") {\n const ftsNodeLabel = await store.retrieveExistingFtsIndex();\n\n if (!ftsNodeLabel) {\n throw Error(\n \"The specified keyword index name does not exist. Make sure to check if you spelled it correctly\"\n );\n } else {\n if (ftsNodeLabel !== store.nodeLabel) {\n throw Error(\n \"Vector and keyword index don't index the same node label\"\n );\n }\n }\n }\n\n return store;\n }\n\n static async fromExistingGraph(\n embeddings: EmbeddingsInterface,\n config: Neo4jVectorStoreArgs\n ) {\n const {\n textNodeProperties = [],\n embeddingNodeProperty = DEFAULT_NODE_EMBEDDING_PROPERTY,\n searchType = DEFAULT_SEARCH_TYPE,\n retrievalQuery = \"\",\n nodeLabel,\n } = config;\n\n let _retrievalQuery = retrievalQuery;\n\n if (textNodeProperties.length === 0) {\n throw Error(\n \"Parameter `text_node_properties` must not be an empty array\"\n );\n }\n\n if (!retrievalQuery) {\n _retrievalQuery = `\n RETURN reduce(str='', k IN ${JSON.stringify(textNodeProperties)} |\n str + '\\\\n' + k + ': ' + coalesce(node[k], '')) AS text,\n node {.*, \\`${embeddingNodeProperty}\\`: Null, id: Null, ${textNodeProperties\n .map((prop) => `\\`${prop}\\`: Null`)\n .join(\", \")} } AS metadata, score\n `;\n }\n\n const store = await this.initialize(embeddings, {\n ...config,\n retrievalQuery: _retrievalQuery,\n });\n\n const embeddingDimension = await store.retrieveExistingIndex();\n\n if (!embeddingDimension) {\n await store.createNewIndex();\n } else if (store.embeddingDimension !== embeddingDimension) {\n throw new Error(\n `Index with name ${store.indexName} already exists. The provided embedding function and vector index dimensions do not match.\\nEmbedding function dimension: ${store.embeddingDimension}\\nVector index dimension: ${embeddingDimension}`\n );\n }\n\n if (searchType === \"hybrid\") {\n const ftsNodeLabel =\n await store.retrieveExistingFtsIndex(textNodeProperties);\n\n if (!ftsNodeLabel) {\n await store.createNewKeywordIndex(textNodeProperties);\n } else {\n if (ftsNodeLabel !== store.nodeLabel) {\n throw Error(\n \"Vector and keyword index don't index the same node label\"\n );\n }\n }\n }\n\n while (true) {\n const fetchQuery = `\n MATCH (n:\\`${nodeLabel}\\`)\n WHERE n.${embeddingNodeProperty} IS null\n AND any(k in $props WHERE n[k] IS NOT null)\n RETURN elementId(n) AS id, reduce(str='', k IN $props |\n str + '\\\\n' + k + ':' + coalesce(n[k], '')) AS text\n LIMIT 1000\n `;\n\n const data = await store.query(fetchQuery, { props: textNodeProperties });\n\n if (!data) {\n break;\n }\n\n const textEmbeddings = await embeddings.embedDocuments(\n data.map((el) => el.text)\n );\n\n const params = {\n data: data.map((el, index) => ({\n id: el.id,\n embedding: textEmbeddings[index],\n })),\n };\n\n await store.query(\n `\n UNWIND $data AS row\n MATCH (n:\\`${nodeLabel}\\`)\n WHERE elementId(n) = row.id\n CALL db.create.setVectorProperty(n, '${embeddingNodeProperty}', row.embedding)\n YIELD node RETURN count(*)\n `,\n params\n );\n\n if (data.length < 1000) {\n break;\n }\n }\n\n return store;\n }\n\n async createNewIndex(): Promise<void> {\n const indexQuery = `\n CALL db.index.vector.createNodeIndex(\n $index_name,\n $node_label,\n $embedding_node_property,\n toInteger($embedding_dimension),\n $similarity_metric\n )\n `;\n\n const parameters = {\n index_name: this.indexName,\n node_label: this.nodeLabel,\n embedding_node_property: this.embeddingNodeProperty,\n embedding_dimension: this.embeddingDimension,\n similarity_metric: this.distanceStrategy,\n };\n\n await this.query(indexQuery, parameters);\n }\n\n async retrieveExistingIndex() {\n let indexInformation = await this.query(\n `\n SHOW INDEXES YIELD name, type, labelsOrTypes, properties, options\n WHERE type = 'VECTOR' AND (name = $index_name\n OR (labelsOrTypes[0] = $node_label AND\n properties[0] = $embedding_node_property))\n RETURN name, labelsOrTypes, properties, options\n `,\n {\n index_name: this.indexName,\n node_label: this.nodeLabel,\n embedding_node_property: this.embeddingNodeProperty,\n }\n );\n\n if (indexInformation) {\n indexInformation = this.sortByIndexName(indexInformation, this.indexName);\n\n try {\n const [index] = indexInformation;\n const [labelOrType] = index.labelsOrTypes;\n const [property] = index.properties;\n\n this.indexName = index.name;\n this.nodeLabel = labelOrType;\n this.embeddingNodeProperty = property;\n\n const embeddingDimension =\n index.options.indexConfig[\"vector.dimensions\"];\n return Number(embeddingDimension);\n } catch {\n return null;\n }\n }\n\n return null;\n }\n\n async retrieveExistingFtsIndex(\n textNodeProperties: string[] = []\n ): Promise<string | null> {\n const indexInformation = await this.query(\n `\n SHOW INDEXES YIELD name, type, labelsOrTypes, properties, options\n WHERE type = 'FULLTEXT' AND (name = $keyword_index_name\n OR (labelsOrTypes = [$node_label] AND\n properties = $text_node_property))\n RETURN name, labelsOrTypes, properties, options\n `,\n {\n keyword_index_name: this.keywordIndexName,\n node_label: this.nodeLabel,\n text_node_property:\n textNodeProperties.length > 0\n ? textNodeProperties\n : [this.textNodeProperty],\n }\n );\n\n if (indexInformation) {\n // Sort the index information by index name\n const sortedIndexInformation = this.sortByIndexName(\n indexInformation,\n this.indexName\n );\n\n try {\n const [index] = sortedIndexInformation;\n const [labelOrType] = index.labelsOrTypes;\n const [property] = index.properties;\n\n this.keywordIndexName = index.name;\n this.textNodeProperty = property;\n this.nodeLabel = labelOrType;\n\n return labelOrType;\n } catch {\n return null;\n }\n }\n\n return null;\n }\n\n async createNewKeywordIndex(\n textNodeProperties: string[] = []\n ): Promise<void> {\n const nodeProps =\n textNodeProperties.length > 0\n ? textNodeProperties\n : [this.textNodeProperty];\n\n // Construct the Cypher query to create a new full text index\n const ftsIndexQuery = `\n CREATE FULLTEXT INDEX ${this.keywordIndexName}\n FOR (n:\\`${this.nodeLabel}\\`) ON EACH\n [${nodeProps.map((prop) => `n.\\`${prop}\\``).join(\", \")}]\n `;\n\n await this.query(ftsIndexQuery);\n }\n\n sortByIndexName(\n values: Array<{ [key: string]: Any }>,\n indexName: string\n ): Array<{ [key: string]: Any }> {\n return values.sort(\n (a, b) =>\n (a.name === indexName ? -1 : 0) - (b.name === indexName ? -1 : 0)\n );\n }\n\n async addVectors(\n vectors: number[][],\n documents: Document[],\n metadatas?: Record<string, Any>[],\n ids?: string[]\n ): Promise<string[]> {\n let _ids = ids;\n const _metadatas = metadatas;\n\n if (!_ids) {\n _ids = documents.map(() => uuid.v1());\n }\n\n const importQuery = `\n UNWIND $data AS row\n CALL {\n WITH row\n MERGE (c:\\`${this.nodeLabel}\\` {id: row.id})\n WITH c, row\n CALL db.create.setVectorProperty(c, '${this.embeddingNodeProperty}', row.embedding)\n YIELD node\n SET c.\\`${this.textNodeProperty}\\` = row.text\n SET c += row.metadata\n } IN TRANSACTIONS OF 1000 ROWS\n `;\n\n const parameters = {\n data: documents.map(({ pageContent, metadata }, index) => ({\n text: pageContent,\n metadata: _metadatas ? _metadatas[index] : metadata,\n embedding: vectors[index],\n id: _ids ? _ids[index] : null,\n })),\n };\n\n await this.query(importQuery, parameters);\n\n return _ids;\n }\n\n async addDocuments(documents: Document[]): Promise<string[]> {\n const texts = documents.map(({ pageContent }) => pageContent);\n\n return this.addVectors(\n await this.embeddings.embedDocuments(texts),\n documents\n );\n }\n\n async similaritySearch(\n query: string,\n k = 4,\n params: Record<string, Any> = {}\n ): Promise<Document[]> {\n const embedding = await this.embeddings.embedQuery(query);\n\n const results = await this.similaritySearchVectorWithScore(\n embedding,\n k,\n query,\n params\n );\n\n return results.map((result) => result[0]);\n }\n\n async similaritySearchWithScore(\n query: string,\n k = 4,\n params: Record<string, Any> = {}\n ): Promise<[Document, number][]> {\n const embedding = await this.embeddings.embedQuery(query);\n return this.similaritySearchVectorWithScore(embedding, k, query, params);\n }\n\n async similaritySearchVectorWithScore(\n vector: number[],\n k: number,\n query: string,\n params: Record<string, Any> = {}\n ): Promise<[Document, number][]> {\n let indexQuery: string;\n let filterParams: Record<string, Any>;\n\n const { filter } = params;\n\n if (filter) {\n if (!this.supportMetadataFilter) {\n throw new Error(\n \"Metadata filtering is only supported in Neo4j version 5.18 or greater.\"\n );\n }\n\n if (this.searchType === \"hybrid\") {\n throw new Error(\n \"Metadata filtering can't be use in combination with a hybrid search approach.\"\n );\n }\n\n const parallelQuery = this.isEnterprise\n ? \"CYPHER runtime = parallel parallelRuntimeSupport=all \"\n : \"\";\n\n const baseIndexQuery = `\n ${parallelQuery}\n MATCH (n:\\`${this.nodeLabel}\\`)\n WHERE n.\\`${this.embeddingNodeProperty}\\` IS NOT NULL\n AND size(n.\\`${this.embeddingNodeProperty}\\`) = toInteger(${this.embeddingDimension}) AND\n `;\n\n const baseCosineQuery = `\n WITH n as node, vector.similarity.cosine(\n n.\\`${this.embeddingNodeProperty}\\`,\n $embedding\n ) AS score ORDER BY score DESC LIMIT toInteger($k)\n `;\n const [fSnippets, fParams] = constructMetadataFilter(filter);\n\n indexQuery = baseIndexQuery + fSnippets + baseCosineQuery;\n filterParams = fParams;\n } else {\n indexQuery = getSearchIndexQuery(this.searchType, this.indexType);\n filterParams = {};\n }\n\n let defaultRetrieval: string;\n\n if (this.indexType === \"RELATIONSHIP\") {\n defaultRetrieval = `\n RETURN relationship.${this.textNodeProperty} AS text, score,\n relationship {.*, ${this.textNodeProperty}: Null,\n ${this.embeddingNodeProperty}: Null, id: Null } AS metadata\n `;\n } else {\n defaultRetrieval = `\n RETURN node.${this.textNodeProperty} AS text, score,\n node {.*, ${this.textNodeProperty}: Null,\n ${this.embeddingNodeProperty}: Null, id: Null } AS metadata\n `;\n }\n\n const retrievalQuery = this.retrievalQuery\n ? this.retrievalQuery\n : defaultRetrieval;\n const readQuery = `${indexQuery} ${retrievalQuery}`;\n\n const parameters = {\n index: this.indexName,\n k: Number(k),\n embedding: vector,\n keyword_index: this.keywordIndexName,\n query: removeLuceneChars(query),\n ...params,\n ...filterParams,\n };\n\n const results = await this.query(readQuery, parameters);\n\n if (results) {\n if (results.some((result) => result.text == null)) {\n if (!this.retrievalQuery) {\n throw new Error(\n `Make sure that none of the '${this.textNodeProperty}' properties on nodes with label '${this.nodeLabel}' are missing or empty`\n );\n } else {\n throw new Error(\n \"Inspect the 'retrievalQuery' and ensure it doesn't return null for the 'text' column\"\n );\n }\n }\n\n const docs: [Document, number][] = results.map((result: Any) => [\n new Document({\n pageContent: result.text,\n metadata: Object.fromEntries(\n Object.entries(result.metadata).filter(([_, v]) => v !== null)\n ),\n }),\n result.score,\n ]);\n\n return docs;\n }\n\n return [];\n }\n}\n\nfunction toObjects(records: Neo4jRecord[]) {\n const recordValues: Record<string, Any>[] = records.map((record) => {\n const rObj = record.toObject();\n const out: { [key: string]: Any } = {};\n Object.keys(rObj).forEach((key) => {\n out[key] = itemIntToString(rObj[key]);\n });\n return out;\n });\n return recordValues;\n}\n\nfunction itemIntToString(item: Any): Any {\n if (neo4j.isInt(item)) return item.toString();\n if (Array.isArray(item)) return item.map((ii) => itemIntToString(ii));\n if ([\"number\", \"string\", \"boolean\"].indexOf(typeof item) !== -1) return item;\n if (item === null) return item;\n if (typeof item === \"object\") return objIntToString(item);\n}\n\nfunction objIntToString(obj: Any) {\n const entry = extractFromNeoObjects(obj);\n let newObj: Any = null;\n if (Array.isArray(entry)) {\n newObj = entry.map((item) => itemIntToString(item));\n } else if (entry !== null && typeof entry === \"object\") {\n newObj = {};\n Object.keys(entry).forEach((key) => {\n newObj[key] = itemIntToString(entry[key]);\n });\n }\n return newObj;\n}\n\nfunction extractFromNeoObjects(obj: Any) {\n if (\n // eslint-disable-next-line\n obj instanceof (neo4j.types.Node as any) ||\n // eslint-disable-next-line\n obj instanceof (neo4j.types.Relationship as any)\n ) {\n return obj.properties;\n // eslint-disable-next-line\n } else if (obj instanceof (neo4j.types.Path as any)) {\n // eslint-disable-next-line\n return [].concat.apply<any[], any[], any[]>([], extractPathForRows(obj));\n }\n return obj;\n}\n\nfunction extractPathForRows(path: Neo4jPath) {\n let { segments } = path;\n // Zero length path. No relationship, end === start\n if (!Array.isArray(path.segments) || path.segments.length < 1) {\n segments = [{ ...path, end: null } as Any];\n }\n\n return segments.map((segment: Any) =>\n [\n objIntToString(segment.start),\n objIntToString(segment.relationship),\n objIntToString(segment.end),\n ].filter((part) => part !== null)\n );\n}\n\nfunction getSearchIndexQuery(\n searchType: SearchType,\n indexType: IndexType = DEFAULT_INDEX_TYPE\n): string {\n if (indexType === \"NODE\") {\n const typeToQueryMap: { [key in SearchType]: string } = {\n vector:\n \"CALL db.index.vector.queryNodes($index, $k, $embedding) YIELD node, score\",\n hybrid: `\n CALL {\n CALL db.index.vector.queryNodes($index, $k, $embedding) YIELD node, score\n WITH collect({node:node, score:score}) AS nodes, max(score) AS max\n UNWIND nodes AS n\n // We use 0 as min\n RETURN n.node AS node, (n.score / max) AS score UNION\n CALL db.index.fulltext.queryNodes($keyword_index, $query, {limit: $k}) YIELD node, score\n WITH collect({node: node, score: score}) AS nodes, max(score) AS max\n UNWIND nodes AS n\n RETURN n.node AS node, (n.score / max) AS score\n }\n WITH node, max(score) AS score ORDER BY score DESC LIMIT toInteger($k)\n `,\n };\n\n return typeToQueryMap[searchType];\n } else {\n return `\n CALL db.index.vector.queryRelationships($index, $k, $embedding)\n YIELD relationship, score\n `;\n }\n}\n\nfunction removeLuceneChars(text: string | null) {\n if (text === undefined || text === null) {\n return null;\n }\n\n // Remove Lucene special characters\n const specialChars = [\n \"+\",\n \"-\",\n \"&\",\n \"|\",\n \"!\",\n \"(\",\n \")\",\n \"{\",\n \"}\",\n \"[\",\n \"]\",\n \"^\",\n '\"',\n \"~\",\n \"*\",\n \"?\",\n \":\",\n \"\\\\\",\n ];\n let modifiedText = text;\n for (const char of specialChars) {\n modifiedText = modifiedText.split(char).join(\" \");\n }\n return modifiedText.trim();\n}\n\nfunction isVersionLessThan(v1: number[], v2: number[]): boolean {\n for (let i = 0; i < Math.min(v1.length, v2.length); i += 1) {\n if (v1[i] < v2[i]) {\n return true;\n } else if (v1[i] > v2[i]) {\n return false;\n }\n }\n // If all the corresponding parts are equal, the shorter version is less\n return v1.length < v2.length;\n}\n\n// Filter utils\n\nconst COMPARISONS_TO_NATIVE: Record<string, string> = {\n $eq: \"=\",\n $ne: \"<>\",\n $lt: \"<\",\n $lte: \"<=\",\n $gt: \">\",\n $gte: \">=\",\n};\n\nconst COMPARISONS_TO_NATIVE_OPERATORS = new Set(\n Object.keys(COMPARISONS_TO_NATIVE)\n);\n\nconst TEXT_OPERATORS = new Set([\"$like\", \"$ilike\"]);\n\nconst LOGICAL_OPERATORS = new Set([\"$and\", \"$or\"]);\n\nconst SPECIAL_CASED_OPERATORS = new Set([\"$in\", \"$nin\", \"$between\"]);\n\nconst SUPPORTED_OPERATORS = new Set([\n ...COMPARISONS_TO_NATIVE_OPERATORS,\n ...TEXT_OPERATORS,\n ...LOGICAL_OPERATORS,\n ...SPECIAL_CASED_OPERATORS,\n]);\n\nconst IS_IDENTIFIER_REGEX = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\nfunction combineQueries(\n inputQueries: [string, Record<string, Any>][],\n operator: string\n): [string, Record<string, Any>] {\n let combinedQuery = \"\";\n const combinedParams: Record<string, Any> = {};\n const paramCounter: Record<string, number> = {};\n\n for (const [query, params] of inputQueries) {\n let newQuery = query;\n for (const [param, value] of Object.entries(params)) {\n if (param in paramCounter) {\n paramCounter[param] += 1;\n } else {\n paramCounter[param] = 1;\n }\n const newParamName = `${param}_${paramCounter[param]}`;\n\n newQuery = newQuery.replace(`$${param}`, `$${newParamName}`);\n combinedParams[newParamName] = value;\n }\n\n if (combinedQuery) {\n combinedQuery += ` ${operator} `;\n }\n combinedQuery += `(${newQuery})`;\n }\n\n return [combinedQuery, combinedParams];\n}\n\nfunction collectParams(\n inputData: [string, Record<string, string>][]\n): [string[], Record<string, Any>] {\n const queryParts: string[] = [];\n const params: Record<string, Any> = {};\n\n for (const [queryPart, param] of inputData) {\n queryParts.push(queryPart);\n Object.assign(params, param);\n }\n\n return [queryParts, params];\n}\n\nfunction handleFieldFilter(\n field: string,\n value: Any,\n paramNumber = 1\n): [string, Record<string, Any>] {\n if (typeof field !== \"string\") {\n throw new Error(\n `field should be a string but got: ${typeof field} with value: ${field}`\n );\n }\n\n if (field.startsWith(\"$\")) {\n throw new Error(\n `Invalid filter condition. Expected a field but got an operator: ${field}`\n );\n }\n\n // Allow [a - zA - Z0 -9_], disallow $ for now until we support escape characters\n if (!IS_IDENTIFIER_REGEX.test(field)) {\n throw new Error(\n `Invalid field name: ${field}. Expected a valid identifier.`\n );\n }\n\n let operator: string;\n let filterValue: Any;\n\n if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n const keys = Object.keys(value);\n\n if (keys.length !== 1) {\n throw new Error(`Invalid filter condition. Expected a value which is a dictionary\n with a single key that corresponds to an operator but got a dictionary\n with ${keys.length} keys. The first few keys are: ${keys\n .slice(0, 3)\n .join(\", \")}\n `);\n }\n\n operator = keys[0];\n filterValue = value[operator];\n\n if (!SUPPORTED_OPERATORS.has(operator)) {\n throw new Error(\n `Invalid operator: ${operator}. Expected one of ${SUPPORTED_OPERATORS}`\n );\n }\n } else {\n operator = \"$eq\";\n filterValue = value;\n }\n\n if (COMPARISONS_TO_NATIVE_OPERATORS.has(operator)) {\n const native = COMPARISONS_TO_NATIVE[operator];\n const querySnippet = `n.${field} ${native} $param_${paramNumber}`;\n const queryParam = { [`param_${paramNumber}`]: filterValue };\n\n return [querySnippet, queryParam];\n } else if (operator === \"$between\") {\n const [low, high] = filterValue;\n const querySnippet = `$param_${paramNumber}_low <= n.${field} <= $param_${paramNumber}_high`;\n const queryParam = {\n [`param_${paramNumber}_low`]: low,\n [`param_${paramNumber}_high`]: high,\n };\n\n return [querySnippet, queryParam];\n } else if ([\"$in\", \"$nin\", \"$like\", \"$ilike\"].includes(operator)) {\n if ([\"$in\", \"$nin\"].includes(operator)) {\n filterValue.forEach((val: Any) => {\n if (\n typeof val !== \"string\" &&\n typeof val !== \"number\" &&\n typeof val !== \"boolean\"\n ) {\n throw new Error(`Unsupported type: ${typeof val} for value: ${val}`);\n }\n });\n }\n\n if (operator === \"$in\") {\n const querySnippet = `n.${field} IN $param_${paramNumber}`;\n const queryParam = { [`param_${paramNumber}`]: filterValue };\n return [querySnippet, queryParam];\n } else if (operator === \"$nin\") {\n const querySnippet = `n.${field} NOT IN $param_${paramNumber}`;\n const queryParam = { [`param_${paramNumber}`]: filterValue };\n return [querySnippet, queryParam];\n } else if (operator === \"$like\") {\n const querySnippet = `n.${field} CONTAINS $param_${paramNumber}`;\n const queryParam = { [`param_${paramNumber}`]: filterValue.slice(0, -1) };\n return [querySnippet, queryParam];\n } else if (operator === \"$ilike\") {\n const querySnippet = `toLower(n.${field}) CONTAINS $param_${paramNumber}`;\n const queryParam = { [`param_${paramNumber}`]: filterValue.slice(0, -1) };\n return [querySnippet, queryParam];\n } else {\n throw new Error(\"Not Implemented\");\n }\n } else {\n throw new Error(\"Not Implemented\");\n }\n}\n\nfunction constructMetadataFilter(\n filter: Record<string, Any>\n): [string, Record<string, Any>] {\n if (typeof filter !== \"object\" || filter === null) {\n throw new Error(\"Expected a dictionary representing the filter condition.\");\n }\n\n const entries = Object.entries(filter);\n\n if (entries.length === 1) {\n const [key, value] = entries[0];\n\n if (key.startsWith(\"$\")) {\n if (![\"$and\", \"$or\"].includes(key.toLowerCase())) {\n throw new Error(\n `Invalid filter condition. Expected $and or $or but got: ${key}`\n );\n }\n\n if (!Array.isArray(value)) {\n throw new Error(\n `Expected an array for logical conditions, but got ${typeof value} for value: ${value}`\n );\n }\n\n const operation = key.toLowerCase() === \"$and\" ? \"AND\" : \"OR\";\n const combinedQueries = combineQueries(\n value.map((v) => constructMetadataFilter(v)),\n operation\n );\n\n return combinedQueries;\n } else {\n return handleFieldFilter(key, value);\n }\n } else if (entries.length > 1) {\n for (const [key] of entries) {\n if (key.startsWith(\"$\")) {\n throw new Error(\n `Invalid filter condition. Expected a field but got an operator: ${key}`\n );\n }\n }\n\n const and_multiple = collectParams(\n entries.map(([field, val], index) =>\n handleFieldFilter(field, val, index + 1)\n )\n );\n\n if (and_multiple.length >= 1) {\n return [and_multiple[0].join(\" AND \"), and_multiple[1]];\n } else {\n throw Error(\n \"Invalid filter condition. Expected a dictionary but got an empty dictionary\"\n );\n }\n } else {\n throw new Error(\"Filter condition contains no entries.\");\n }\n}\n"],"mappings":"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"}