From efa221116f1676e29e6454c36a27dd23e7b4622c Mon Sep 17 00:00:00 2001
From: fatmelon <708842811@qq.com>
Date: Wed, 20 Nov 2024 09:58:25 +0800
Subject: [PATCH] feat: integrate with azure cosmos db mongo vCore (#1500)

Co-authored-by: root <root@CPC-yangq-FRSGK>
Co-authored-by: Alex Yang <himself65@outlook.com>
---
 .changeset/tough-rings-roll.md                |  5 ++
 .../AzureCosmosMongovCoreDocumentStore.ts     | 49 +++++++++++
 packages/llamaindex/src/storage/index.ts      |  3 +
 .../AzureCosmosMongovCoreIndexStore.ts        | 49 +++++++++++
 .../kvStore/AzureCosmosMongovCoreKVStore.ts   | 88 +++++++++++++++++++
 5 files changed, 194 insertions(+)
 create mode 100644 .changeset/tough-rings-roll.md
 create mode 100644 packages/llamaindex/src/storage/docStore/AzureCosmosMongovCoreDocumentStore.ts
 create mode 100644 packages/llamaindex/src/storage/indexStore/AzureCosmosMongovCoreIndexStore.ts
 create mode 100644 packages/llamaindex/src/storage/kvStore/AzureCosmosMongovCoreKVStore.ts

diff --git a/.changeset/tough-rings-roll.md b/.changeset/tough-rings-roll.md
new file mode 100644
index 000000000..04a577249
--- /dev/null
+++ b/.changeset/tough-rings-roll.md
@@ -0,0 +1,5 @@
+---
+"llamaindex": patch
+---
+
+feat: add Azure Cosmos DB mongo vCore DocumentStore, IndexStore, KVStore
diff --git a/packages/llamaindex/src/storage/docStore/AzureCosmosMongovCoreDocumentStore.ts b/packages/llamaindex/src/storage/docStore/AzureCosmosMongovCoreDocumentStore.ts
new file mode 100644
index 000000000..f9fbe83ff
--- /dev/null
+++ b/packages/llamaindex/src/storage/docStore/AzureCosmosMongovCoreDocumentStore.ts
@@ -0,0 +1,49 @@
+import { MongoClient } from "mongodb";
+import { AzureCosmosVCoreKVStore } from "../kvStore/AzureCosmosMongovCoreKVStore.js";
+import { KVDocumentStore } from "./KVDocumentStore.js";
+
+const DEFAULT_DATABASE = "DocumentStoreDB";
+const DEFAULT_COLLECTION = "DocumentStoreCollection";
+
+export interface AzureCosmosVCoreDocumentStoreArgs {
+  azureCosmosVCoreKVStore: AzureCosmosVCoreKVStore;
+  namespace?: string;
+}
+
+export class AzureCosmosVCoreDocumentStore extends KVDocumentStore {
+  constructor({
+    azureCosmosVCoreKVStore,
+    namespace,
+  }: AzureCosmosVCoreDocumentStoreArgs) {
+    super(azureCosmosVCoreKVStore, namespace);
+  }
+
+  /**
+   * Static method for creating an instance using a MongoClient.
+   * @returns Instance of AzureCosmosVCoreDocumentStore
+   * @param mongoClient - MongoClient instance
+   * @param dbName - Database name
+   * @param collectionName - Collection name
+   * @example
+   * ```ts
+   * const mongoClient = new MongoClient("mongodb://localhost:27017");
+   * const indexStore = AzureCosmosVCoreDocumentStore.fromMongoClient(mongoClient, "my_db", "my_collection");
+   * ```
+   */
+  static fromMongoClient(
+    mongoClient: MongoClient,
+    dbName: string = DEFAULT_DATABASE,
+    collectionName: string = DEFAULT_COLLECTION,
+  ) {
+    const azureCosmosVCoreKVStore = new AzureCosmosVCoreKVStore({
+      mongoClient,
+      dbName,
+      collectionName,
+    });
+    const namespace = `${dbName}.${collectionName}`;
+    return new AzureCosmosVCoreDocumentStore({
+      azureCosmosVCoreKVStore,
+      namespace,
+    });
+  }
+}
diff --git a/packages/llamaindex/src/storage/index.ts b/packages/llamaindex/src/storage/index.ts
index bb08b4980..d0b99ae5d 100644
--- a/packages/llamaindex/src/storage/index.ts
+++ b/packages/llamaindex/src/storage/index.ts
@@ -3,12 +3,15 @@ export * from "@llamaindex/core/storage/doc-store";
 export * from "@llamaindex/core/storage/index-store";
 export * from "@llamaindex/core/storage/kv-store";
 export * from "./chatStore/AzureCosmosNoSqlChatStore.js";
+export * from "./docStore/AzureCosmosMongovCoreDocumentStore.js";
 export * from "./docStore/AzureCosmosNoSqlDocumentStore.js";
 export { PostgresDocumentStore } from "./docStore/PostgresDocumentStore.js";
 export { SimpleDocumentStore } from "./docStore/SimpleDocumentStore.js";
 export * from "./FileSystem.js";
+export * from "./indexStore/AzureCosmosMongovCoreIndexStore.js";
 export * from "./indexStore/AzureCosmosNoSqlIndexStore.js";
 export { PostgresIndexStore } from "./indexStore/PostgresIndexStore.js";
+export * from "./kvStore/AzureCosmosMongovCoreKVStore.js";
 export * from "./kvStore/AzureCosmosNoSqlKVStore.js";
 export { PostgresKVStore } from "./kvStore/PostgresKVStore.js";
 export * from "./StorageContext.js";
diff --git a/packages/llamaindex/src/storage/indexStore/AzureCosmosMongovCoreIndexStore.ts b/packages/llamaindex/src/storage/indexStore/AzureCosmosMongovCoreIndexStore.ts
new file mode 100644
index 000000000..2d7118d05
--- /dev/null
+++ b/packages/llamaindex/src/storage/indexStore/AzureCosmosMongovCoreIndexStore.ts
@@ -0,0 +1,49 @@
+import { MongoClient } from "mongodb";
+import { AzureCosmosVCoreKVStore } from "../kvStore/AzureCosmosMongovCoreKVStore.js";
+import { KVIndexStore } from "./KVIndexStore.js";
+
+const DEFAULT_DATABASE = "IndexStoreDB";
+const DEFAULT_COLLECTION = "IndexStoreCollection";
+
+export interface AzureCosmosVCoreIndexStoreArgs {
+  azureCosmosVCoreKVStore: AzureCosmosVCoreKVStore;
+  namespace?: string;
+}
+
+export class AzureCosmosVCoreIndexStore extends KVIndexStore {
+  constructor({
+    azureCosmosVCoreKVStore,
+    namespace,
+  }: AzureCosmosVCoreIndexStoreArgs) {
+    super(azureCosmosVCoreKVStore, namespace);
+  }
+
+  /**
+   * Static method for creating an instance using a MongoClient.
+   * @returns Instance of AzureCosmosVCoreIndexStore
+   * @param mongoClient - MongoClient instance
+   * @param dbName - Database name
+   * @param collectionName - Collection name
+   * @example
+   * ```ts
+   * const mongoClient = new MongoClient("mongodb://localhost:27017");
+   * const indexStore = AzureCosmosVCoreIndexStore.fromMongoClient(mongoClient, "my_db", "my_collection");
+   * ```
+   */
+  static fromMongoClient(
+    mongoClient: MongoClient,
+    dbName: string = DEFAULT_DATABASE,
+    collectionName: string = DEFAULT_COLLECTION,
+  ) {
+    const azureCosmosVCoreKVStore = new AzureCosmosVCoreKVStore({
+      mongoClient,
+      dbName,
+      collectionName,
+    });
+    const namespace = `${dbName}.${collectionName}`;
+    return new AzureCosmosVCoreIndexStore({
+      azureCosmosVCoreKVStore,
+      namespace,
+    });
+  }
+}
diff --git a/packages/llamaindex/src/storage/kvStore/AzureCosmosMongovCoreKVStore.ts b/packages/llamaindex/src/storage/kvStore/AzureCosmosMongovCoreKVStore.ts
new file mode 100644
index 000000000..534334006
--- /dev/null
+++ b/packages/llamaindex/src/storage/kvStore/AzureCosmosMongovCoreKVStore.ts
@@ -0,0 +1,88 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import { BaseKVStore } from "@llamaindex/core/storage/kv-store";
+import type { Collection } from "mongodb";
+import { MongoClient } from "mongodb";
+const DEFAULT_CHAT_DATABASE = "KVStoreDB";
+const DEFAULT_CHAT_Collection = "KVStoreCollection";
+
+export interface VcoreConnectionStringOptions
+  extends AzureCosmosVCoreKVStoreConfig {
+  connectionString?: string;
+}
+
+export interface AzureCosmosVCoreKVStoreConfig {
+  mongoClient?: MongoClient;
+  dbName?: string;
+  collectionName?: string;
+}
+
+export class AzureCosmosVCoreKVStore extends BaseKVStore {
+  private mongoClient: MongoClient;
+
+  private dbName: string;
+  private collectionName: string;
+
+  private collection?: Collection;
+
+  /**
+   * Create a new AzureCosmosDBNoSQLVectorStore instance.
+   */
+  constructor({
+    mongoClient,
+    dbName = DEFAULT_CHAT_DATABASE,
+    collectionName = DEFAULT_CHAT_Collection,
+  }: AzureCosmosVCoreKVStoreConfig) {
+    super();
+    if (!mongoClient) {
+      throw new Error(
+        "MongoClient is required for AzureCosmosDBNoSQLVectorStore initialization",
+      );
+    }
+    this.mongoClient = mongoClient;
+    this.dbName = dbName;
+    this.collectionName = collectionName;
+  }
+
+  client(): MongoClient {
+    return this.mongoClient;
+  }
+
+  private async ensureCollection(): Promise<Collection> {
+    if (!this.collection) {
+      this.collection = this.mongoClient
+        .db(this.dbName)
+        .collection(this.collectionName);
+    }
+    return this.collection;
+  }
+
+  async put(key: string, val: Record<string, any>): Promise<void> {
+    const collection = await this.ensureCollection();
+    const insertResult = await collection.insertOne({
+      id: key,
+      messages: val,
+    });
+  }
+
+  async get(key: string): Promise<Record<string, any> | null> {
+    const collection = await this.ensureCollection();
+    const result = await collection.findOne({ id: key });
+    return result || null;
+  }
+
+  async getAll(): Promise<Record<string, Record<string, any>>> {
+    const collection = await this.ensureCollection();
+    const cursor = collection.find();
+    const output: Record<string, Record<string, any>> = {};
+    await cursor.forEach((item) => {
+      output[item.id] = item.messages;
+    });
+    return output;
+  }
+
+  async delete(key: string): Promise<boolean> {
+    const collection = await this.ensureCollection();
+    await collection.deleteOne({ id: key });
+    return true;
+  }
+}
-- 
GitLab