baiduvectordb.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import os
  2. from collections import UserDict
  3. from typing import Optional
  4. from unittest.mock import MagicMock
  5. import pytest
  6. from _pytest.monkeypatch import MonkeyPatch
  7. from pymochow import MochowClient # type: ignore
  8. from pymochow.model.database import Database # type: ignore
  9. from pymochow.model.enum import IndexState, IndexType, MetricType, ReadConsistency, TableState # type: ignore
  10. from pymochow.model.schema import HNSWParams, VectorIndex # type: ignore
  11. from pymochow.model.table import Table # type: ignore
  12. from requests.adapters import HTTPAdapter
  13. class AttrDict(UserDict):
  14. def __getattr__(self, item):
  15. return self.get(item)
  16. class MockBaiduVectorDBClass:
  17. def mock_vector_db_client(
  18. self,
  19. config=None,
  20. adapter: Optional[HTTPAdapter] = None,
  21. ):
  22. self.conn = MagicMock()
  23. self._config = MagicMock()
  24. def list_databases(self, config=None) -> list[Database]:
  25. return [
  26. Database(
  27. conn=self.conn,
  28. database_name="dify",
  29. config=self._config,
  30. )
  31. ]
  32. def create_database(self, database_name: str, config=None) -> Database:
  33. return Database(conn=self.conn, database_name=database_name, config=config)
  34. def list_table(self, config=None) -> list[Table]:
  35. return []
  36. def drop_table(self, table_name: str, config=None):
  37. return {"code": 0, "msg": "Success"}
  38. def create_table(
  39. self,
  40. table_name: str,
  41. replication: int,
  42. partition: int,
  43. schema,
  44. enable_dynamic_field=False,
  45. description: str = "",
  46. config=None,
  47. ) -> Table:
  48. return Table(self, table_name, replication, partition, schema, enable_dynamic_field, description, config)
  49. def describe_table(self, table_name: str, config=None) -> Table:
  50. return Table(
  51. self,
  52. table_name,
  53. 3,
  54. 1,
  55. None,
  56. enable_dynamic_field=False,
  57. description="table for dify",
  58. config=config,
  59. state=TableState.NORMAL,
  60. )
  61. def upsert(self, rows, config=None):
  62. return {"code": 0, "msg": "operation success", "affectedCount": 1}
  63. def rebuild_index(self, index_name: str, config=None):
  64. return {"code": 0, "msg": "Success"}
  65. def describe_index(self, index_name: str, config=None):
  66. return VectorIndex(
  67. index_name=index_name,
  68. index_type=IndexType.HNSW,
  69. field="vector",
  70. metric_type=MetricType.L2,
  71. params=HNSWParams(m=16, efconstruction=200),
  72. auto_build=False,
  73. state=IndexState.NORMAL,
  74. )
  75. def query(
  76. self,
  77. primary_key,
  78. partition_key=None,
  79. projections=None,
  80. retrieve_vector=False,
  81. read_consistency=ReadConsistency.EVENTUAL,
  82. config=None,
  83. ):
  84. return AttrDict(
  85. {
  86. "row": {
  87. "id": primary_key.get("id"),
  88. "vector": [0.23432432, 0.8923744, 0.89238432],
  89. "text": "text",
  90. "metadata": '{"doc_id": "doc_id_001"}',
  91. },
  92. "code": 0,
  93. "msg": "Success",
  94. }
  95. )
  96. def delete(self, primary_key=None, partition_key=None, filter=None, config=None):
  97. return {"code": 0, "msg": "Success"}
  98. def search(
  99. self,
  100. anns,
  101. partition_key=None,
  102. projections=None,
  103. retrieve_vector=False,
  104. read_consistency=ReadConsistency.EVENTUAL,
  105. config=None,
  106. ):
  107. return AttrDict(
  108. {
  109. "rows": [
  110. {
  111. "row": {
  112. "id": "doc_id_001",
  113. "vector": [0.23432432, 0.8923744, 0.89238432],
  114. "text": "text",
  115. "metadata": '{"doc_id": "doc_id_001"}',
  116. },
  117. "distance": 0.1,
  118. "score": 0.5,
  119. }
  120. ],
  121. "code": 0,
  122. "msg": "Success",
  123. }
  124. )
  125. MOCK = os.getenv("MOCK_SWITCH", "false").lower() == "true"
  126. @pytest.fixture
  127. def setup_baiduvectordb_mock(request, monkeypatch: MonkeyPatch):
  128. if MOCK:
  129. monkeypatch.setattr(MochowClient, "__init__", MockBaiduVectorDBClass.mock_vector_db_client)
  130. monkeypatch.setattr(MochowClient, "list_databases", MockBaiduVectorDBClass.list_databases)
  131. monkeypatch.setattr(MochowClient, "create_database", MockBaiduVectorDBClass.create_database)
  132. monkeypatch.setattr(Database, "table", MockBaiduVectorDBClass.describe_table)
  133. monkeypatch.setattr(Database, "list_table", MockBaiduVectorDBClass.list_table)
  134. monkeypatch.setattr(Database, "create_table", MockBaiduVectorDBClass.create_table)
  135. monkeypatch.setattr(Database, "drop_table", MockBaiduVectorDBClass.drop_table)
  136. monkeypatch.setattr(Database, "describe_table", MockBaiduVectorDBClass.describe_table)
  137. monkeypatch.setattr(Table, "rebuild_index", MockBaiduVectorDBClass.rebuild_index)
  138. monkeypatch.setattr(Table, "describe_index", MockBaiduVectorDBClass.describe_index)
  139. monkeypatch.setattr(Table, "delete", MockBaiduVectorDBClass.delete)
  140. monkeypatch.setattr(Table, "query", MockBaiduVectorDBClass.query)
  141. monkeypatch.setattr(Table, "search", MockBaiduVectorDBClass.search)
  142. yield
  143. if MOCK:
  144. monkeypatch.undo()