matrixone-python-sdk 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. matrixone/__init__.py +155 -0
  2. matrixone/account.py +723 -0
  3. matrixone/async_client.py +3913 -0
  4. matrixone/async_metadata_manager.py +311 -0
  5. matrixone/async_orm.py +123 -0
  6. matrixone/async_vector_index_manager.py +633 -0
  7. matrixone/base_client.py +208 -0
  8. matrixone/client.py +4672 -0
  9. matrixone/config.py +452 -0
  10. matrixone/connection_hooks.py +286 -0
  11. matrixone/exceptions.py +89 -0
  12. matrixone/logger.py +782 -0
  13. matrixone/metadata.py +820 -0
  14. matrixone/moctl.py +219 -0
  15. matrixone/orm.py +2277 -0
  16. matrixone/pitr.py +646 -0
  17. matrixone/pubsub.py +771 -0
  18. matrixone/restore.py +411 -0
  19. matrixone/search_vector_index.py +1176 -0
  20. matrixone/snapshot.py +550 -0
  21. matrixone/sql_builder.py +844 -0
  22. matrixone/sqlalchemy_ext/__init__.py +161 -0
  23. matrixone/sqlalchemy_ext/adapters.py +163 -0
  24. matrixone/sqlalchemy_ext/dialect.py +534 -0
  25. matrixone/sqlalchemy_ext/fulltext_index.py +895 -0
  26. matrixone/sqlalchemy_ext/fulltext_search.py +1686 -0
  27. matrixone/sqlalchemy_ext/hnsw_config.py +194 -0
  28. matrixone/sqlalchemy_ext/ivf_config.py +252 -0
  29. matrixone/sqlalchemy_ext/table_builder.py +351 -0
  30. matrixone/sqlalchemy_ext/vector_index.py +1721 -0
  31. matrixone/sqlalchemy_ext/vector_type.py +948 -0
  32. matrixone/version.py +580 -0
  33. matrixone_python_sdk-0.1.0.dist-info/METADATA +706 -0
  34. matrixone_python_sdk-0.1.0.dist-info/RECORD +122 -0
  35. matrixone_python_sdk-0.1.0.dist-info/WHEEL +5 -0
  36. matrixone_python_sdk-0.1.0.dist-info/entry_points.txt +5 -0
  37. matrixone_python_sdk-0.1.0.dist-info/licenses/LICENSE +200 -0
  38. matrixone_python_sdk-0.1.0.dist-info/top_level.txt +2 -0
  39. tests/__init__.py +19 -0
  40. tests/offline/__init__.py +20 -0
  41. tests/offline/conftest.py +77 -0
  42. tests/offline/test_account.py +703 -0
  43. tests/offline/test_async_client_query_comprehensive.py +1218 -0
  44. tests/offline/test_basic.py +54 -0
  45. tests/offline/test_case_sensitivity.py +227 -0
  46. tests/offline/test_connection_hooks_offline.py +287 -0
  47. tests/offline/test_dialect_schema_handling.py +609 -0
  48. tests/offline/test_explain_methods.py +346 -0
  49. tests/offline/test_filter_logical_in.py +237 -0
  50. tests/offline/test_fulltext_search_comprehensive.py +795 -0
  51. tests/offline/test_ivf_config.py +249 -0
  52. tests/offline/test_join_methods.py +281 -0
  53. tests/offline/test_join_sqlalchemy_compatibility.py +276 -0
  54. tests/offline/test_logical_in_method.py +237 -0
  55. tests/offline/test_matrixone_version_parsing.py +264 -0
  56. tests/offline/test_metadata_offline.py +557 -0
  57. tests/offline/test_moctl.py +300 -0
  58. tests/offline/test_moctl_simple.py +251 -0
  59. tests/offline/test_model_support_offline.py +359 -0
  60. tests/offline/test_model_support_simple.py +225 -0
  61. tests/offline/test_pinecone_filter_offline.py +377 -0
  62. tests/offline/test_pitr.py +585 -0
  63. tests/offline/test_pubsub.py +712 -0
  64. tests/offline/test_query_update.py +283 -0
  65. tests/offline/test_restore.py +445 -0
  66. tests/offline/test_snapshot_comprehensive.py +384 -0
  67. tests/offline/test_sql_escaping_edge_cases.py +551 -0
  68. tests/offline/test_sqlalchemy_integration.py +382 -0
  69. tests/offline/test_sqlalchemy_vector_integration.py +434 -0
  70. tests/offline/test_table_builder.py +198 -0
  71. tests/offline/test_unified_filter.py +398 -0
  72. tests/offline/test_unified_transaction.py +495 -0
  73. tests/offline/test_vector_index.py +238 -0
  74. tests/offline/test_vector_operations.py +688 -0
  75. tests/offline/test_vector_type.py +174 -0
  76. tests/offline/test_version_core.py +328 -0
  77. tests/offline/test_version_management.py +372 -0
  78. tests/offline/test_version_standalone.py +652 -0
  79. tests/online/__init__.py +20 -0
  80. tests/online/conftest.py +216 -0
  81. tests/online/test_account_management.py +194 -0
  82. tests/online/test_advanced_features.py +344 -0
  83. tests/online/test_async_client_interfaces.py +330 -0
  84. tests/online/test_async_client_online.py +285 -0
  85. tests/online/test_async_model_insert_online.py +293 -0
  86. tests/online/test_async_orm_online.py +300 -0
  87. tests/online/test_async_simple_query_online.py +802 -0
  88. tests/online/test_async_transaction_simple_query.py +300 -0
  89. tests/online/test_basic_connection.py +130 -0
  90. tests/online/test_client_online.py +238 -0
  91. tests/online/test_config.py +90 -0
  92. tests/online/test_config_validation.py +123 -0
  93. tests/online/test_connection_hooks_new_online.py +217 -0
  94. tests/online/test_dialect_schema_handling_online.py +331 -0
  95. tests/online/test_filter_logical_in_online.py +374 -0
  96. tests/online/test_fulltext_comprehensive.py +1773 -0
  97. tests/online/test_fulltext_label_online.py +433 -0
  98. tests/online/test_fulltext_search_online.py +842 -0
  99. tests/online/test_ivf_stats_online.py +506 -0
  100. tests/online/test_logger_integration.py +311 -0
  101. tests/online/test_matrixone_query_orm.py +540 -0
  102. tests/online/test_metadata_online.py +579 -0
  103. tests/online/test_model_insert_online.py +255 -0
  104. tests/online/test_mysql_driver_validation.py +213 -0
  105. tests/online/test_orm_advanced_features.py +2022 -0
  106. tests/online/test_orm_cte_integration.py +269 -0
  107. tests/online/test_orm_online.py +270 -0
  108. tests/online/test_pinecone_filter.py +708 -0
  109. tests/online/test_pubsub_operations.py +352 -0
  110. tests/online/test_query_methods.py +225 -0
  111. tests/online/test_query_update_online.py +433 -0
  112. tests/online/test_search_vector_index.py +557 -0
  113. tests/online/test_simple_fulltext_online.py +915 -0
  114. tests/online/test_snapshot_comprehensive.py +998 -0
  115. tests/online/test_sqlalchemy_engine_integration.py +336 -0
  116. tests/online/test_sqlalchemy_integration.py +425 -0
  117. tests/online/test_transaction_contexts.py +1219 -0
  118. tests/online/test_transaction_insert_methods.py +356 -0
  119. tests/online/test_transaction_query_methods.py +288 -0
  120. tests/online/test_unified_filter_online.py +529 -0
  121. tests/online/test_vector_comprehensive.py +706 -0
  122. tests/online/test_version_management.py +291 -0
@@ -0,0 +1,311 @@
1
+ # Copyright 2021 - 2022 Matrix Origin
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ MatrixOne Async Metadata Operations
17
+
18
+ This module provides async metadata scanning capabilities for MatrixOne tables,
19
+ allowing users to analyze table statistics, column information, and data distribution.
20
+ """
21
+
22
+ from typing import Optional, List, Dict, Any, Union
23
+ from sqlalchemy.engine import Result
24
+ from .metadata import BaseMetadataManager, MetadataColumn, MetadataRow
25
+
26
+
27
+ class AsyncMetadataManager(BaseMetadataManager):
28
+ """
29
+ Async metadata manager for MatrixOne table metadata operations.
30
+
31
+ Provides async methods to scan table metadata including column statistics,
32
+ row counts, null counts, and data distribution information.
33
+ """
34
+
35
+ def __init__(self, client):
36
+ """
37
+ Initialize async metadata manager.
38
+
39
+ Args:
40
+
41
+ client: MatrixOne AsyncClient instance
42
+ """
43
+ self.client = client
44
+
45
+ async def _execute_sql(self, sql: str):
46
+ """
47
+ Execute SQL query asynchronously.
48
+
49
+ Args:
50
+
51
+ sql: SQL query to execute
52
+
53
+ Returns:
54
+
55
+ SQLAlchemy Result object
56
+ """
57
+ return await self.client.execute(sql)
58
+
59
+ async def scan(
60
+ self,
61
+ dbname: str,
62
+ tablename: str,
63
+ is_tombstone: Optional[bool] = None,
64
+ indexname: Optional[str] = None,
65
+ columns: Optional[List[Union[MetadataColumn, str]]] = None,
66
+ distinct_object_name: Optional[bool] = None,
67
+ ) -> Union[Result, List[MetadataRow]]:
68
+ """
69
+ Scan table metadata using metadata_scan function (async).
70
+
71
+ Args:
72
+
73
+ dbname: Database name
74
+ tablename: Table name
75
+ is_tombstone: Optional tombstone flag (True/False)
76
+ indexname: Optional index name
77
+
78
+ Returns:
79
+
80
+ SQLAlchemy Result object containing metadata scan results
81
+
82
+ Example:
83
+
84
+ ```python
85
+ # Scan all columns of a table
86
+ result = await client.metadata.scan("test_db", "users")
87
+
88
+ # Scan specific column
89
+ result = await client.metadata.scan("test_db", "users", indexname="id")
90
+
91
+ # Scan with tombstone filter
92
+ result = await client.metadata.scan("test_db", "users", is_tombstone=False)
93
+
94
+ # Scan tombstone objects
95
+ result = await client.metadata.scan("test_db", "users", is_tombstone=True)
96
+
97
+ # Scan specific index
98
+ result = await client.metadata.scan("test_db", "users", indexname="idx_name")
99
+ ```
100
+ """
101
+ # Build SQL query
102
+ sql = self._build_metadata_scan_sql(dbname, tablename, is_tombstone, indexname, distinct_object_name)
103
+
104
+ # Execute the query
105
+ result = await self._execute_sql(sql)
106
+
107
+ # Process result based on columns parameter
108
+ return self._process_scan_result(result, columns)
109
+
110
+ async def get_table_brief_stats(
111
+ self,
112
+ dbname: str,
113
+ tablename: str,
114
+ is_tombstone: Optional[bool] = None,
115
+ indexname: Optional[str] = None,
116
+ include_tombstone: bool = False,
117
+ include_indexes: Optional[List[str]] = None,
118
+ ) -> Dict[str, Dict[str, Any]]:
119
+ """
120
+ Get brief statistics for a table, tombstone, and indexes (async).
121
+
122
+ Args:
123
+
124
+ dbname: Database name
125
+ tablename: Table name
126
+ is_tombstone: Optional tombstone flag (True/False)
127
+ indexname: Optional index name
128
+ include_tombstone: Whether to include tombstone statistics
129
+ include_indexes: List of index names to include
130
+
131
+ Returns:
132
+
133
+ Dictionary with brief statistics for table, tombstone, and indexes
134
+ """
135
+
136
+ # Create a wrapper function that awaits the async execution
137
+ async def async_execute_func(sql: str):
138
+ return await self._execute_sql(sql)
139
+
140
+ return await self._get_table_brief_stats_logic_async(
141
+ dbname, tablename, is_tombstone, indexname, include_tombstone, include_indexes, async_execute_func
142
+ )
143
+
144
+ async def get_table_detail_stats(
145
+ self,
146
+ dbname: str,
147
+ tablename: str,
148
+ is_tombstone: Optional[bool] = None,
149
+ indexname: Optional[str] = None,
150
+ include_tombstone: bool = False,
151
+ include_indexes: Optional[List[str]] = None,
152
+ ) -> Dict[str, List[Dict[str, Any]]]:
153
+ """
154
+ Get detailed statistics for a table, tombstone, and indexes (async).
155
+
156
+ Args:
157
+
158
+ dbname: Database name
159
+ tablename: Table name
160
+ is_tombstone: Optional tombstone flag (True/False)
161
+ indexname: Optional index name
162
+ include_tombstone: Whether to include tombstone statistics
163
+ include_indexes: List of index names to include
164
+
165
+ Returns:
166
+
167
+ Dictionary with detailed statistics for table, tombstone, and indexes
168
+ """
169
+
170
+ # Create a wrapper function that awaits the async execution
171
+ async def async_execute_func(sql: str):
172
+ return await self._execute_sql(sql)
173
+
174
+ return await self._get_table_detail_stats_logic_async(
175
+ dbname, tablename, is_tombstone, indexname, include_tombstone, include_indexes, async_execute_func
176
+ )
177
+
178
+
179
+ class AsyncTransactionMetadataManager(BaseMetadataManager):
180
+ """
181
+ Async transaction metadata manager for MatrixOne table metadata operations within transactions.
182
+
183
+ Provides async methods to scan table metadata including column statistics,
184
+ row counts, null counts, and data distribution information within a transaction context.
185
+ """
186
+
187
+ def __init__(self, client, transaction_wrapper):
188
+ """
189
+ Initialize async transaction metadata manager.
190
+
191
+ Args:
192
+
193
+ client: MatrixOne AsyncClient instance
194
+ transaction_wrapper: Async transaction wrapper instance
195
+ """
196
+ self.client = client
197
+ self.transaction_wrapper = transaction_wrapper
198
+
199
+ async def _execute_sql(self, sql: str):
200
+ """
201
+ Execute SQL query using async transaction wrapper.
202
+
203
+ Args:
204
+
205
+ sql: SQL query to execute
206
+
207
+ Returns:
208
+
209
+ SQLAlchemy Result object
210
+ """
211
+ return await self.transaction_wrapper.execute(sql)
212
+
213
+ async def scan(
214
+ self,
215
+ dbname: str,
216
+ tablename: str,
217
+ is_tombstone: Optional[bool] = None,
218
+ indexname: Optional[str] = None,
219
+ columns: Optional[List[Union[MetadataColumn, str]]] = None,
220
+ distinct_object_name: Optional[bool] = None,
221
+ ) -> Union[Result, List[MetadataRow]]:
222
+ """
223
+ Scan table metadata using metadata_scan function within transaction (async).
224
+
225
+ Args:
226
+
227
+ dbname: Database name
228
+ tablename: Table name
229
+ is_tombstone: Optional tombstone flag (True/False)
230
+ indexname: Optional index name
231
+
232
+ Returns:
233
+
234
+ SQLAlchemy Result object containing metadata scan results
235
+ """
236
+ # Build SQL query
237
+ sql = self._build_metadata_scan_sql(dbname, tablename, is_tombstone, indexname, distinct_object_name)
238
+
239
+ # Execute the query within transaction
240
+ result = await self._execute_sql(sql)
241
+
242
+ # Process result based on columns parameter
243
+ return self._process_scan_result(result, columns)
244
+
245
+ async def get_table_brief_stats(
246
+ self,
247
+ dbname: str,
248
+ tablename: str,
249
+ is_tombstone: Optional[bool] = None,
250
+ indexname: Optional[str] = None,
251
+ include_tombstone: bool = False,
252
+ include_indexes: Optional[List[str]] = None,
253
+ ) -> Dict[str, Dict[str, Any]]:
254
+ """
255
+ Get brief statistics for a table, tombstone, and indexes within transaction (async).
256
+
257
+ Args:
258
+
259
+ dbname: Database name
260
+ tablename: Table name
261
+ is_tombstone: Optional tombstone flag (True/False)
262
+ indexname: Optional index name
263
+ include_tombstone: Whether to include tombstone statistics
264
+ include_indexes: List of index names to include
265
+
266
+ Returns:
267
+
268
+ Dictionary with brief statistics for table, tombstone, and indexes
269
+ """
270
+
271
+ # Create a wrapper function that awaits the async execution
272
+ async def async_execute_func(sql: str):
273
+ return await self._execute_sql(sql)
274
+
275
+ return await self._get_table_brief_stats_logic_async(
276
+ dbname, tablename, is_tombstone, indexname, include_tombstone, include_indexes, async_execute_func
277
+ )
278
+
279
+ async def get_table_detail_stats(
280
+ self,
281
+ dbname: str,
282
+ tablename: str,
283
+ is_tombstone: Optional[bool] = None,
284
+ indexname: Optional[str] = None,
285
+ include_tombstone: bool = False,
286
+ include_indexes: Optional[List[str]] = None,
287
+ ) -> Dict[str, List[Dict[str, Any]]]:
288
+ """
289
+ Get detailed statistics for a table, tombstone, and indexes within transaction (async).
290
+
291
+ Args:
292
+
293
+ dbname: Database name
294
+ tablename: Table name
295
+ is_tombstone: Optional tombstone flag (True/False)
296
+ indexname: Optional index name
297
+ include_tombstone: Whether to include tombstone statistics
298
+ include_indexes: List of index names to include
299
+
300
+ Returns:
301
+
302
+ Dictionary with detailed statistics for table, tombstone, and indexes
303
+ """
304
+
305
+ # Create a wrapper function that awaits the async execution
306
+ async def async_execute_func(sql: str):
307
+ return await self._execute_sql(sql)
308
+
309
+ return await self._get_table_detail_stats_logic_async(
310
+ dbname, tablename, is_tombstone, indexname, include_tombstone, include_indexes, async_execute_func
311
+ )
matrixone/async_orm.py ADDED
@@ -0,0 +1,123 @@
1
+ # Copyright 2021 - 2022 Matrix Origin
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ MatrixOne Async ORM - SQLAlchemy-like interface for MatrixOne database (Async)
17
+ """
18
+
19
+ from typing import Any, List, Optional, TypeVar
20
+
21
+ from .orm import BaseMatrixOneQuery
22
+
23
+ T = TypeVar("T")
24
+
25
+
26
+ class AsyncMatrixOneQuery(BaseMatrixOneQuery):
27
+ """Async MatrixOne Query builder that mimics SQLAlchemy Query interface"""
28
+
29
+ def __init__(self, model_class, client, database: str = None, transaction_wrapper=None, snapshot=None):
30
+ super().__init__(model_class, client, transaction_wrapper, snapshot)
31
+ self.database = database
32
+
33
+ def _build_sql(self) -> tuple[str, List[Any]]:
34
+ """Build SQL query with database prefix support"""
35
+ # Add database prefix if provided
36
+ original_table_name = self._table_name
37
+ if self.database:
38
+ self._table_name = f"{self.database}.{original_table_name}"
39
+
40
+ # Call parent's _build_sql method
41
+ sql, params = super()._build_sql()
42
+
43
+ # Restore original table name
44
+ self._table_name = original_table_name
45
+
46
+ return sql, params
47
+
48
+ async def _execute(self, sql, params=None):
49
+ """Execute SQL using either transaction wrapper or client asynchronously"""
50
+ if self.transaction_wrapper:
51
+ return await self.transaction_wrapper.execute(sql, params)
52
+ else:
53
+ return await self.client.execute(sql, params)
54
+
55
+ async def all(self) -> List:
56
+ """Execute query and return all results - SQLAlchemy style"""
57
+ sql, params = self._build_sql()
58
+ result = await self._execute(sql, params)
59
+
60
+ models = []
61
+ for row in result.rows:
62
+ # Check if this is an aggregate query (has custom select columns)
63
+ if self._select_columns:
64
+ # For aggregate queries, return raw row data as a simple object
65
+ select_cols = self._extract_select_columns()
66
+ row_data = self._create_row_data(row, select_cols)
67
+ models.append(row_data)
68
+ else:
69
+ # Regular model query
70
+ if self._is_sqlalchemy_model:
71
+ # For SQLAlchemy models, create instance directly
72
+ row_dict = {}
73
+ for i, col_name in enumerate(self._columns.keys()):
74
+ if i < len(row):
75
+ row_dict[col_name] = row[i]
76
+
77
+ # Create SQLAlchemy model instance
78
+ model = self.model_class(**row_dict)
79
+ models.append(model)
80
+ else:
81
+ # For non-SQLAlchemy models, create instance directly
82
+ row_dict = {}
83
+ for i, col_name in enumerate(self._columns.keys()):
84
+ if i < len(row):
85
+ row_dict[col_name] = row[i]
86
+
87
+ # Create model instance
88
+ model = self.model_class(**row_dict)
89
+ models.append(model)
90
+
91
+ return models
92
+
93
+ async def first(self) -> Optional:
94
+ """Execute query and return first result - SQLAlchemy style"""
95
+ self._limit_count = 1
96
+ results = await self.all()
97
+ return results[0] if results else None
98
+
99
+ async def count(self) -> int:
100
+ """Execute query and return count of results - SQLAlchemy style"""
101
+ sql, params = self._build_sql()
102
+ # Replace SELECT * with COUNT(*)
103
+ sql = sql.replace("SELECT *", "SELECT COUNT(*)")
104
+
105
+ result = await self._execute(sql, params)
106
+ return result.rows[0][0] if result.rows else 0
107
+
108
+ async def execute(self) -> Any:
109
+ """Execute the query based on its type"""
110
+ if self._query_type == "SELECT":
111
+ sql, params = self._build_sql()
112
+ return await self._execute(sql, params)
113
+ elif self._query_type == "INSERT":
114
+ sql, params = self._build_insert_sql()
115
+ return await self._execute(sql, params)
116
+ elif self._query_type == "UPDATE":
117
+ sql, params = self._build_update_sql()
118
+ return await self._execute(sql, params)
119
+ elif self._query_type == "DELETE":
120
+ sql, params = self._build_delete_sql()
121
+ return await self._execute(sql, params)
122
+ else:
123
+ raise ValueError(f"Unknown query type: {self._query_type}")