{"version":3,"file":"neo4j.mjs","names":["#opts","#driver","#neo4j","#run","#dims","#parseMeta","#project"],"sources":["../../../src/batteries/vector/neo4j/index.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/vector/neo4j\n *\n * Neo4j adapter (native vector index, 5.13+). Each collection is a node label; records are\n * nodes with `id`/`vec`/`document`/`metadata` properties and a `VECTOR INDEX` on `vec`. KNN\n * uses `db.index.vector.queryNodes(index, k, vector)` (score is the similarity, already [0,1]\n * for cosine). Metadata is a JSON string property filtered with the neutral filter tree's JS\n * reference evaluator for exact cross-adapter parity.\n *\n * Driver: `neo4j-driver` (pure JS). Labels/index names can't be Cypher-parameterized, so they\n * are derived from the (sanitized) collection name; all values are parameterized.\n */\n\nimport { evaluateFilter } from '../filters'\nimport { BaseVectorStore } from '../contract'\nimport { validateRecords } from '../validation'\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport {\n  E_VECTOR_STORE_DRIVER_UNAVAILABLE,\n  E_VECTOR_STORE_CONNECTION_FAILED,\n  E_VECTOR_STORE_COLLECTION_FAILED,\n  E_VECTOR_STORE_UPSERT_FAILED,\n  E_VECTOR_STORE_SEARCH_FAILED,\n  E_VECTOR_STORE_DELETE_FAILED,\n  E_VECTOR_STORE_DIMENSION_MISMATCH,\n  E_VECTOR_STORE_UNSUPPORTED_OPERATION,\n} from '../exceptions'\nimport type { SearchPlan, UpsertPlan, DeletePlan, CollectionSpec } from '../plan'\nimport type {\n  VectorMatch,\n  VectorStoreCapabilities,\n  BaseVectorStoreOptions,\n  VectorMetadata,\n  DistanceMetric,\n} from '../types'\n\nexport interface Neo4jVectorStoreOptions extends BaseVectorStoreOptions {\n  /** Connection and authentication parameters for the backend. */\n  connection: { url: string; username?: string; password?: string; database?: string }\n}\n\nconst getNeo4j = async () => {\n  try {\n    const mod = await import('neo4j-driver')\n    return (mod as any).default ?? mod\n  } catch {\n    throw new E_VECTOR_STORE_DRIVER_UNAVAILABLE(['neo4j-driver'])\n  }\n}\n\n// A Cypher-safe label/index token derived from the collection (labels can't be parameterized).\nconst sanitize = (name: string): string => name.replace(/[^A-Za-z0-9_]/g, '_')\nconst labelFor = (collection: string): string => 'Vec_' + sanitize(collection)\nconst indexFor = (collection: string): string => 'vecidx_' + sanitize(collection)\n\nconst similarityFn = (metric: DistanceMetric): string =>\n  metric === 'euclidean' ? 'euclidean' : 'cosine'\n\nexport class Neo4jVectorStore extends BaseVectorStore {\n  readonly capabilities: VectorStoreCapabilities = {\n    transactions: false,\n    namedVectors: false,\n    rename: false,\n    rawSql: false,\n    builtInEncoding: false,\n    // Writes commit synchronously over Bolt and the index awaits; visible on resolve. No-op option.\n    consistency: { configurable: false, default: 'strong', modes: ['strong'] },\n  }\n\n  #driver: any | null = null\n  #neo4j: any | null = null\n  #dims: Map<string, number> = new Map()\n\n  get #opts(): Neo4jVectorStoreOptions {\n    return this.options as Neo4jVectorStoreOptions\n  }\n\n  /** Static availability probe: whether this adapter's runtime driver can load in the current environment. */\n  static isAvailable(): boolean {\n    return typeof process !== 'undefined'\n  }\n  isAvailable(): boolean {\n    return typeof process !== 'undefined'\n  }\n\n  async connect(): Promise<void> {\n    if (this.#driver) return\n    const neo4j = await getNeo4j()\n    this.#neo4j = neo4j\n    const c = this.#opts.connection\n    try {\n      this.#driver = neo4j.driver(\n        c.url,\n        c.username ? neo4j.auth.basic(c.username, c.password ?? '') : undefined\n      )\n    } catch (err) {\n      throw new E_VECTOR_STORE_CONNECTION_FAILED([String(err)])\n    }\n  }\n\n  async close(): Promise<void> {\n    if (this.#driver) {\n      await this.#driver.close()\n      this.#driver = null\n    }\n  }\n\n  async #run(cypher: string, params?: Record<string, unknown>): Promise<any[]> {\n    if (!this.#driver) await this.connect()\n    const db = this.#opts.connection.database\n    const session = this.#driver.session(db ? { database: db } : undefined)\n    try {\n      const res = await session.run(cypher, params)\n      return res.records\n    } finally {\n      await session.close()\n    }\n  }\n\n  async createCollection(spec: CollectionSpec, ifNotExists: boolean): Promise<void> {\n    this.#dims.set(spec.collection, spec.vector.dimensions)\n    const label = labelFor(spec.collection)\n    const index = indexFor(spec.collection)\n    try {\n      if (!ifNotExists) {\n        await this.#run(`DROP INDEX ${index} IF EXISTS`)\n      }\n      await this.#run(\n        `CREATE VECTOR INDEX ${index} IF NOT EXISTS FOR (n:${label}) ON (n.vec) ` +\n          `OPTIONS {indexConfig: {\\`vector.dimensions\\`: $dim, \\`vector.similarity_function\\`: $sim}}`,\n        { dim: this.#neo4j.int(spec.vector.dimensions), sim: similarityFn(spec.vector.metric) }\n      )\n      await this.#run(`CALL db.awaitIndex($index, $timeout)`, {\n        index,\n        timeout: this.#neo4j.int(30),\n      }).catch(() => undefined)\n    } catch (err) {\n      throw new E_VECTOR_STORE_COLLECTION_FAILED(['createCollection', String(err)])\n    }\n  }\n\n  async dropCollection(collection: string, _ifExists: boolean): Promise<void> {\n    const label = labelFor(collection)\n    const index = indexFor(collection)\n    try {\n      await this.#run(`DROP INDEX ${index} IF EXISTS`)\n      await this.#run(`MATCH (n:${label}) DETACH DELETE n`)\n      this.#dims.delete(collection)\n    } catch (err) {\n      throw new E_VECTOR_STORE_COLLECTION_FAILED(['dropCollection', String(err)])\n    }\n  }\n\n  async hasCollection(collection: string): Promise<boolean> {\n    const index = indexFor(collection)\n    try {\n      const recs = await this.#run(`SHOW INDEXES YIELD name WHERE name = $index RETURN name`, {\n        index,\n      })\n      return recs.length > 0\n    } catch {\n      return false\n    }\n  }\n\n  async renameCollection(_from: string, _to: string): Promise<void> {\n    throw new E_VECTOR_STORE_UNSUPPORTED_OPERATION(['renameCollection', 'neo4j'])\n  }\n\n  async executeUpsert(plan: UpsertPlan): Promise<void> {\n    if (plan.records.length === 0) return\n    validateRecords(plan.records)\n    const label = labelFor(plan.collection)\n    const expected = this.#opts.dimensions ?? this.#dims.get(plan.collection)\n    try {\n      for (const r of plan.records) {\n        let vector = r.vector\n        if (!vector && r.document) {\n          const [v] = await this.encode([r.document], 'document')\n          vector = v\n        }\n        if (!vector) {\n          throw new E_VECTOR_STORE_UPSERT_FAILED(['Record missing vector and document'])\n        }\n        if (expected !== undefined && vector.length !== expected) {\n          throw new E_VECTOR_STORE_DIMENSION_MISMATCH([expected, vector.length])\n        }\n        await this.#run(\n          `MERGE (n:${label} {id: $id}) ` +\n            `SET n.vec = $vec, n.document = $document, n.metadata = $metadata`,\n          {\n            id: r.id,\n            vec: vector,\n            document: r.document ?? '',\n            metadata: r.metadata ? JSON.stringify(r.metadata) : '{}',\n          }\n        )\n      }\n    } catch (err) {\n      if (\n        isInstanceOf(err, 'E_VECTOR_STORE_DIMENSION_MISMATCH', E_VECTOR_STORE_DIMENSION_MISMATCH) ||\n        isInstanceOf(err, 'E_VECTOR_STORE_UPSERT_FAILED', E_VECTOR_STORE_UPSERT_FAILED)\n      ) {\n        throw err\n      }\n      throw new E_VECTOR_STORE_UPSERT_FAILED([String(err)])\n    }\n  }\n\n  async executeSearch(plan: SearchPlan): Promise<VectorMatch[]> {\n    const label = labelFor(plan.collection)\n    const index = indexFor(plan.collection)\n    let queryVector: number[] | undefined\n    if (plan.near) {\n      if ('vector' in plan.near) {\n        queryVector = plan.near.vector\n      } else if ('serverText' in plan.near) {\n        const [v] = await this.encode([plan.near.serverText], 'query')\n        queryVector = v\n      } else if ('id' in plan.near) {\n        const recs = await this.#run(`MATCH (n:${label} {id: $id}) RETURN n.vec AS vec`, {\n          id: plan.near.id,\n        })\n        if (recs.length === 0) {\n          throw new E_VECTOR_STORE_SEARCH_FAILED(['Referenced id not found: ' + plan.near.id])\n        }\n        queryVector = recs[0].get('vec') as number[]\n      }\n    }\n\n    const offset = plan.offset ?? 0\n    try {\n      if (queryVector) {\n        // Over-fetch when filtering so the JS post-filter still yields topK.\n        const k = plan.filter ? 1000 : plan.topK + offset\n        const recs = await this.#run(\n          `CALL db.index.vector.queryNodes($index, $k, $qv) YIELD node, score ` +\n            `RETURN node.id AS id, node.vec AS vec, node.document AS document, ` +\n            `node.metadata AS metadata, score ORDER BY score DESC`,\n          { index, k: this.#neo4j.int(k), qv: queryVector }\n        )\n        const mapped = recs.map((rec: any) => ({\n          row: {\n            id: rec.get('id'),\n            vec: rec.get('vec'),\n            document: rec.get('document'),\n            metadata: rec.get('metadata'),\n            score: rec.get('score'),\n          },\n        }))\n        const filtered = plan.filter\n          ? mapped.filter((m: any) => evaluateFilter(plan.filter!, this.#parseMeta(m.row.metadata)))\n          : mapped\n        return filtered\n          .slice(offset, offset + plan.topK)\n          .map((m: any) => this.#project(m.row, plan, true))\n      } else {\n        const recs = await this.#run(\n          `MATCH (n:${label}) RETURN n.id AS id, n.vec AS vec, n.document AS document, n.metadata AS metadata`\n        )\n        const rows = recs.map((rec: any) => ({\n          id: rec.get('id'),\n          vec: rec.get('vec'),\n          document: rec.get('document'),\n          metadata: rec.get('metadata'),\n        }))\n        const filtered = plan.filter\n          ? rows.filter((row: any) => evaluateFilter(plan.filter!, this.#parseMeta(row.metadata)))\n          : rows\n        return filtered\n          .slice(offset, offset + plan.topK)\n          .map((row: any) => this.#project(row, plan, false))\n      }\n    } catch (err) {\n      throw new E_VECTOR_STORE_SEARCH_FAILED([String(err)])\n    }\n  }\n\n  #parseMeta(val: unknown): VectorMetadata {\n    if (typeof val === 'string') {\n      try {\n        return JSON.parse(val) as VectorMetadata\n      } catch {\n        return {}\n      }\n    }\n    if (val && typeof val === 'object') return val as VectorMetadata\n    return {}\n  }\n\n  #project(row: any, plan: SearchPlan, isKnn: boolean): VectorMatch {\n    const proj = plan.projection\n    const out: VectorMatch = {}\n    if (proj.id) out.id = row.id as string\n    if (proj.vector && Array.isArray(row.vec)) out.vector = (row.vec as number[]).map(Number)\n    if (proj.document) out.document = (row.document ?? undefined) as string | undefined\n    if (proj.metadata) out.metadata = this.#parseMeta(row.metadata)\n    if (isKnn && row.score !== undefined && row.score !== null) {\n      // Neo4j cosine similarity score is already in [0,1], higher = closer.\n      out.score = Number(row.score)\n    }\n    return out\n  }\n\n  async executeDelete(plan: DeletePlan): Promise<void> {\n    const label = labelFor(plan.collection)\n    try {\n      if (plan.ids && plan.ids.length > 0) {\n        await this.#run(`MATCH (n:${label}) WHERE n.id IN $ids DETACH DELETE n`, { ids: plan.ids })\n      } else if (plan.filter) {\n        const recs = await this.#run(`MATCH (n:${label}) RETURN n.id AS id, n.metadata AS metadata`)\n        const targets = recs\n          .filter((rec: any) => evaluateFilter(plan.filter!, this.#parseMeta(rec.get('metadata'))))\n          .map((rec: any) => rec.get('id') as string)\n        if (targets.length > 0) {\n          await this.#run(`MATCH (n:${label}) WHERE n.id IN $ids DETACH DELETE n`, { ids: targets })\n        }\n      } else {\n        await this.#run(`MATCH (n:${label}) DETACH DELETE n`)\n      }\n    } catch (err) {\n      throw new E_VECTOR_STORE_DELETE_FAILED([String(err)])\n    }\n  }\n}\n"],"mappings":"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"}