{"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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"}