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,300 @@
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
+ Online tests for Async ORM functionality - tests actual database operations
17
+ """
18
+
19
+ import pytest
20
+ import pytest_asyncio
21
+ import asyncio
22
+ import os
23
+ import sys
24
+ from datetime import datetime
25
+
26
+ # Add the matrixone package to the path
27
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
28
+
29
+ from matrixone import AsyncClient
30
+ from sqlalchemy import Column, Integer, String, DECIMAL
31
+
32
+ # SQLAlchemy compatibility import
33
+ try:
34
+ from sqlalchemy.orm import declarative_base
35
+ except ImportError:
36
+ from matrixone.orm import declarative_base
37
+
38
+ Base = declarative_base()
39
+ from matrixone.exceptions import QueryError
40
+ from .test_config import online_config
41
+
42
+
43
+ class AsyncUser(Base):
44
+ """Test user model for async operations"""
45
+
46
+ __tablename__ = "test_async_users"
47
+
48
+ id = Column(Integer, primary_key=True)
49
+ name = Column(String(100))
50
+ email = Column(String(100))
51
+ age = Column(Integer)
52
+
53
+ def to_dict(self):
54
+ """Convert model instance to dictionary"""
55
+ return {'id': self.id, 'name': self.name, 'email': self.email, 'age': self.age}
56
+
57
+ @classmethod
58
+ def from_dict(cls, data):
59
+ """Create model instance from dictionary"""
60
+ return cls(**data)
61
+
62
+
63
+ class AsyncProduct(Base):
64
+ """Test product model for async operations"""
65
+
66
+ __tablename__ = "test_async_products"
67
+
68
+ id = Column(Integer, primary_key=True)
69
+ name = Column(String(100))
70
+ price = Column(DECIMAL(10, 2))
71
+ category = Column(String(50))
72
+
73
+ def to_dict(self):
74
+ """Convert model instance to dictionary"""
75
+ return {
76
+ 'id': self.id,
77
+ 'name': self.name,
78
+ 'price': float(self.price) if self.price is not None else None,
79
+ 'category': self.category,
80
+ }
81
+
82
+ @classmethod
83
+ def from_dict(cls, data):
84
+ """Create model instance from dictionary"""
85
+ return cls(**data)
86
+
87
+
88
+ class TestAsyncORMOnline:
89
+ """Online tests for Async ORM functionality"""
90
+
91
+ @pytest_asyncio.fixture(scope="function")
92
+ async def test_database(self):
93
+ """Set up test database and return database name"""
94
+ return "test_async_orm_db"
95
+
96
+ @pytest_asyncio.fixture(scope="function")
97
+ async def test_async_client(self, test_database):
98
+ """Create and connect AsyncClient for testing"""
99
+ host, port, user, password, _ = online_config.get_connection_params()
100
+
101
+ # First create the database using default connection
102
+ temp_client = AsyncClient()
103
+ await temp_client.connect(host, port, user, password, "test") # Connect to default database
104
+ await temp_client.execute(f"CREATE DATABASE IF NOT EXISTS {test_database}")
105
+ await temp_client.disconnect()
106
+
107
+ # Now connect to the test database
108
+ client = AsyncClient()
109
+ await client.connect(host, port, user, password, test_database)
110
+
111
+ try:
112
+ # Create test tables
113
+ await client.execute(
114
+ """
115
+ CREATE TABLE IF NOT EXISTS test_async_users (
116
+ id INT PRIMARY KEY,
117
+ name VARCHAR(100),
118
+ email VARCHAR(100),
119
+ age INT
120
+ )
121
+ """
122
+ )
123
+
124
+ await client.execute(
125
+ """
126
+ CREATE TABLE IF NOT EXISTS test_async_products (
127
+ id INT PRIMARY KEY,
128
+ name VARCHAR(100),
129
+ price DECIMAL(10,2),
130
+ category VARCHAR(50)
131
+ )
132
+ """
133
+ )
134
+
135
+ # Insert test data
136
+ await client.execute(
137
+ """
138
+ INSERT INTO test_async_users VALUES
139
+ (1, 'Alice Johnson', 'alice@example.com', 28),
140
+ (2, 'Charlie Brown', 'charlie@example.com', 32),
141
+ (3, 'Diana Prince', 'diana@example.com', 27)
142
+ """
143
+ )
144
+
145
+ await client.execute(
146
+ """
147
+ INSERT INTO test_async_products VALUES
148
+ (1, 'Tablet', 299.99, 'Electronics'),
149
+ (2, 'Notebook', 5.99, 'Stationery'),
150
+ (3, 'Headphones', 149.99, 'Electronics')
151
+ """
152
+ )
153
+
154
+ yield client
155
+
156
+ finally:
157
+ try:
158
+ await client.disconnect()
159
+ # Clean up database
160
+ cleanup_client = AsyncClient()
161
+ await cleanup_client.connect(host, port, user, password, "test")
162
+ await cleanup_client.execute(f"DROP DATABASE IF EXISTS {test_database}")
163
+ await cleanup_client.disconnect()
164
+ except Exception as e:
165
+ print(f"Warning: Failed to cleanup or disconnect: {e}")
166
+
167
+ @pytest.mark.asyncio
168
+ async def test_async_orm_query_basic_operations(self, test_async_client):
169
+ """Test basic async ORM query operations"""
170
+ # Test all() method - like SQLAlchemy, no database parameter needed
171
+ users = await test_async_client.query(AsyncUser).all()
172
+ assert len(users) == 3
173
+
174
+ # Test first() method
175
+ first_user = await test_async_client.query(AsyncUser).first()
176
+ assert first_user is not None
177
+ assert isinstance(first_user, AsyncUser)
178
+
179
+ # Test filter_by() method
180
+ alice = await test_async_client.query(AsyncUser).filter_by(name="Alice Johnson").first()
181
+ assert alice is not None
182
+ assert alice.name == "Alice Johnson"
183
+ assert alice.email == "alice@example.com"
184
+
185
+ @pytest.mark.asyncio
186
+ async def test_async_orm_query_filtering(self, test_async_client):
187
+ """Test async ORM query filtering"""
188
+ # Test filter_by with multiple conditions
189
+ electronics = await test_async_client.query(AsyncProduct).filter_by(category="Electronics").all()
190
+ assert len(electronics) == 2
191
+
192
+ # Test filter() method with conditions
193
+ expensive_products = await test_async_client.query(AsyncProduct).filter("price > ?", 100).all()
194
+ assert len(expensive_products) == 2
195
+
196
+ # Test combined filtering
197
+ expensive_electronics = (
198
+ await test_async_client.query(AsyncProduct).filter_by(category="Electronics").filter("price > ?", 100).all()
199
+ )
200
+ assert len(expensive_electronics) == 2
201
+
202
+ @pytest.mark.asyncio
203
+ async def test_async_orm_query_ordering_and_limiting(self, test_async_client):
204
+ """Test async ORM query ordering and limiting"""
205
+ # Test order_by
206
+ users_by_age = await test_async_client.query(AsyncUser).order_by("age DESC").all()
207
+ assert len(users_by_age) == 3
208
+ # Should be ordered by age descending
209
+ assert users_by_age[0].age >= users_by_age[1].age
210
+
211
+ # Test limit
212
+ limited_users = await test_async_client.query(AsyncUser).limit(2).all()
213
+ assert len(limited_users) == 2
214
+
215
+ # Test combined ordering and limiting
216
+ top_products = await test_async_client.query(AsyncProduct).order_by("price DESC").limit(2).all()
217
+ assert len(top_products) == 2
218
+ assert top_products[0].price >= top_products[1].price
219
+
220
+ @pytest.mark.asyncio
221
+ async def test_async_orm_query_count(self, test_async_client):
222
+ """Test async ORM query count functionality"""
223
+ # Test count() method
224
+ total_users = await test_async_client.query(AsyncUser).count()
225
+ assert total_users == 3
226
+
227
+ # Test count with filtering
228
+ electronics_count = await test_async_client.query(AsyncProduct).filter_by(category="Electronics").count()
229
+ assert electronics_count == 2
230
+
231
+ # Test count with complex filtering
232
+ expensive_count = await test_async_client.query(AsyncProduct).filter("price > ?", 50).count()
233
+ assert expensive_count == 2
234
+
235
+ @pytest.mark.asyncio
236
+ async def test_async_orm_query_parameter_handling(self, test_async_client):
237
+ """Test async ORM query parameter handling"""
238
+ # Test string parameters
239
+ user = await test_async_client.query(AsyncUser).filter("name = ?", "Charlie Brown").first()
240
+ assert user is not None
241
+ assert user.name == "Charlie Brown"
242
+
243
+ # Test numeric parameters
244
+ user = await test_async_client.query(AsyncUser).filter("age = ?", 28).first()
245
+ assert user is not None
246
+ assert user.age == 28
247
+
248
+ # Test multiple parameters
249
+ user = await test_async_client.query(AsyncUser).filter("name = ? AND age > ?", "Diana Prince", 25).first()
250
+ assert user is not None
251
+ assert user.name == "Diana Prince"
252
+ assert user.age > 25
253
+
254
+ @pytest.mark.asyncio
255
+ async def test_async_orm_query_error_handling(self, test_async_client):
256
+ """Test async ORM query error handling"""
257
+ # Test query with invalid condition
258
+ with pytest.raises(QueryError):
259
+ await test_async_client.query(AsyncUser).filter("invalid_syntax").all()
260
+
261
+ @pytest.mark.asyncio
262
+ async def test_async_orm_model_serialization(self, test_async_client):
263
+ """Test async ORM model serialization methods"""
264
+ # Test model creation and serialization
265
+ user = AsyncUser(id=1, name="Test User", email="test@example.com", age=30)
266
+
267
+ # Test to_dict
268
+ user_dict = user.to_dict()
269
+ assert isinstance(user_dict, dict)
270
+ assert user_dict['id'] == 1
271
+ assert user_dict['name'] == "Test User"
272
+
273
+ # Test from_dict
274
+ new_user = AsyncUser.from_dict(user_dict)
275
+ assert new_user.id == user.id
276
+ assert new_user.name == user.name
277
+ assert new_user.email == user.email
278
+ assert new_user.age == user.age
279
+
280
+ @pytest.mark.asyncio
281
+ async def test_async_orm_concurrent_operations(self, test_async_client):
282
+ """Test async ORM concurrent operations"""
283
+ # Test concurrent queries
284
+ tasks = [
285
+ test_async_client.query(AsyncUser).filter_by(name="Alice Johnson").first(),
286
+ test_async_client.query(AsyncUser).filter_by(name="Charlie Brown").first(),
287
+ test_async_client.query(AsyncUser).filter_by(name="Diana Prince").first(),
288
+ ]
289
+
290
+ results = await asyncio.gather(*tasks)
291
+
292
+ # All queries should complete successfully
293
+ assert len(results) == 3
294
+ for result in results:
295
+ assert result is not None
296
+ assert isinstance(result, AsyncUser)
297
+
298
+
299
+ if __name__ == '__main__':
300
+ pytest.main([__file__])