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,998 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright 2021 - 2022 Matrix Origin
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ """
18
+ Comprehensive online tests for snapshot functionality.
19
+ Merged from multiple snapshot test files to reduce redundancy while maintaining coverage.
20
+
21
+ This file consolidates tests from:
22
+ - test_snapshot_online.py (10 tests)
23
+ - test_snapshot_restore.py (6 tests)
24
+ - test_client_online.py (2 snapshot tests)
25
+ - test_async_client_online.py (2 async snapshot tests)
26
+ - test_matrixone_query_orm.py (3 snapshot tests)
27
+ - test_async_client_interfaces.py (2 snapshot tests)
28
+ - test_async_orm_online.py (1 snapshot test)
29
+
30
+ Total: 26 snapshot tests consolidated into one comprehensive file
31
+ """
32
+
33
+ import pytest
34
+ import pytest_asyncio
35
+ import unittest
36
+ import os
37
+ import sys
38
+ import time
39
+ from datetime import datetime
40
+
41
+ # Add the matrixone package to the path
42
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
43
+
44
+ from matrixone import Client, AsyncClient
45
+ from matrixone.snapshot import SnapshotLevel, SnapshotManager
46
+ from matrixone.exceptions import SnapshotError, ConnectionError
47
+ from matrixone.logger import create_default_logger
48
+ from .test_config import online_config
49
+
50
+
51
+ @pytest.mark.online
52
+ class TestSnapshotComprehensive:
53
+ """Comprehensive online tests for snapshot functionality"""
54
+
55
+ @pytest.fixture(scope="class")
56
+ def test_client(self):
57
+ """Create and connect Client for testing"""
58
+ host, port, user, password, database = online_config.get_connection_params()
59
+ client = Client()
60
+ client.connect(host=host, port=port, user=user, password=password, database=database)
61
+ try:
62
+ yield client
63
+ finally:
64
+ try:
65
+ client.disconnect()
66
+ except Exception as e:
67
+ print(f"Warning: Failed to disconnect client: {e}")
68
+
69
+ @pytest_asyncio.fixture(scope="function")
70
+ async def test_async_client(self):
71
+ """Create and connect AsyncClient for testing"""
72
+ host, port, user, password, database = online_config.get_connection_params()
73
+ client = AsyncClient()
74
+ await client.connect(host=host, port=port, user=user, password=password, database=database)
75
+ try:
76
+ yield client
77
+ finally:
78
+ try:
79
+ await client.disconnect()
80
+ except Exception as e:
81
+ print(f"Warning: Failed to disconnect async client: {e}")
82
+
83
+ @pytest.fixture(scope="class")
84
+ def test_database(self, test_client):
85
+ """Set up test database and table"""
86
+ test_db = "test_snapshot_db"
87
+ test_table = "test_snapshot_table"
88
+
89
+ try:
90
+ test_client.execute(f"CREATE DATABASE IF NOT EXISTS {test_db}")
91
+ test_client.execute(f"USE {test_db}")
92
+ test_client.execute(
93
+ f"""
94
+ CREATE TABLE IF NOT EXISTS {test_table} (
95
+ id INT PRIMARY KEY,
96
+ name VARCHAR(100),
97
+ value INT
98
+ )
99
+ """
100
+ )
101
+
102
+ # Clear existing data and insert test data
103
+ test_client.execute(f"DELETE FROM {test_table}")
104
+ test_client.execute(f"INSERT INTO {test_table} VALUES (1, 'test1', 100)")
105
+ test_client.execute(f"INSERT INTO {test_table} VALUES (2, 'test2', 200)")
106
+ test_client.execute(f"INSERT INTO {test_table} VALUES (3, 'test3', 300)")
107
+
108
+ yield test_db, test_table
109
+
110
+ finally:
111
+ # Clean up
112
+ try:
113
+ test_client.execute(f"DROP DATABASE IF EXISTS {test_db}")
114
+ except Exception as e:
115
+ print(f"Cleanup failed: {e}")
116
+
117
+ @pytest_asyncio.fixture(scope="function")
118
+ async def async_test_database(self, test_async_client):
119
+ """Set up test database and table for async tests"""
120
+ test_db = "test_async_snapshot_db"
121
+ test_table = "test_async_snapshot_table"
122
+
123
+ try:
124
+ await test_async_client.execute(f"CREATE DATABASE IF NOT EXISTS {test_db}")
125
+ await test_async_client.execute(f"USE {test_db}")
126
+ await test_async_client.execute(
127
+ f"""
128
+ CREATE TABLE IF NOT EXISTS {test_table} (
129
+ id INT PRIMARY KEY,
130
+ name VARCHAR(100),
131
+ value INT
132
+ )
133
+ """
134
+ )
135
+
136
+ # Clear existing data and insert test data
137
+ await test_async_client.execute(f"DELETE FROM {test_table}")
138
+ await test_async_client.execute(f"INSERT INTO {test_table} VALUES (1, 'async_test1', 100)")
139
+ await test_async_client.execute(f"INSERT INTO {test_table} VALUES (2, 'async_test2', 200)")
140
+ await test_async_client.execute(f"INSERT INTO {test_table} VALUES (3, 'async_test3', 300)")
141
+
142
+ yield test_db, test_table
143
+
144
+ finally:
145
+ # Clean up
146
+ try:
147
+ await test_async_client.execute(f"DROP DATABASE IF EXISTS {test_db}")
148
+ except Exception as e:
149
+ print(f"Async cleanup failed: {e}")
150
+
151
+ # ==================== BASIC SNAPSHOT OPERATIONS ====================
152
+
153
+ def test_snapshot_creation_and_management(self, test_client, test_database):
154
+ """Test creating and managing snapshots - from test_snapshot_online.py"""
155
+ snapshot_name = f"test_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
156
+
157
+ # Test cluster snapshot creation
158
+ snapshot = test_client.snapshots.create(snapshot_name, SnapshotLevel.CLUSTER)
159
+ assert snapshot.name == snapshot_name
160
+ assert snapshot.level == SnapshotLevel.CLUSTER
161
+
162
+ # Test snapshot exists
163
+ assert test_client.snapshots.exists(snapshot_name)
164
+
165
+ # Test getting snapshot
166
+ retrieved_snapshot = test_client.snapshots.get(snapshot_name)
167
+ assert retrieved_snapshot.name == snapshot_name
168
+
169
+ # Test listing snapshots
170
+ snapshots = test_client.snapshots.list()
171
+ snapshot_names = [s.name for s in snapshots]
172
+ assert snapshot_name in snapshot_names
173
+
174
+ # Test snapshot deletion
175
+ test_client.snapshots.delete(snapshot_name)
176
+ assert not test_client.snapshots.exists(snapshot_name)
177
+
178
+ def test_table_snapshot_creation(self, test_client, test_database):
179
+ """Test creating table-level snapshots - from test_snapshot_online.py"""
180
+ snapshot_name = f"test_table_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
181
+
182
+ # Test table snapshot creation
183
+ snapshot = test_client.snapshots.create(
184
+ snapshot_name,
185
+ SnapshotLevel.TABLE,
186
+ database="test_snapshot_db",
187
+ table="test_snapshot_table",
188
+ )
189
+ assert snapshot.name == snapshot_name
190
+ assert snapshot.level == SnapshotLevel.TABLE
191
+ assert snapshot.database == "test_snapshot_db"
192
+ assert snapshot.table == "test_snapshot_table"
193
+
194
+ # Clean up
195
+ test_client.snapshots.delete(snapshot_name)
196
+
197
+ def test_basic_snapshot_operations(self, test_client):
198
+ """Test basic snapshot creation and management - from test_snapshot_restore.py"""
199
+ # Create test data in the correct database
200
+ test_db = online_config.get_test_database()
201
+ test_client.execute(
202
+ f"CREATE TABLE IF NOT EXISTS {test_db}.snapshot_test (id INT PRIMARY KEY, name VARCHAR(50), value INT)"
203
+ )
204
+ test_client.execute(f"DELETE FROM {test_db}.snapshot_test")
205
+ test_client.execute(f"INSERT INTO {test_db}.snapshot_test VALUES (1, 'test1', 100)")
206
+ test_client.execute(f"INSERT INTO {test_db}.snapshot_test VALUES (2, 'test2', 200)")
207
+
208
+ # Verify initial data
209
+ result = test_client.execute(f"SELECT COUNT(*) FROM {test_db}.snapshot_test")
210
+ assert result.rows[0][0] == 2
211
+
212
+ # Create snapshot
213
+ snapshot_name = f"testsnapshot{int(time.time())}"
214
+ try:
215
+ snapshot = test_client.snapshots.create(
216
+ name=snapshot_name,
217
+ level="table",
218
+ database=test_db,
219
+ table="snapshot_test",
220
+ description="Test snapshot for basic operations",
221
+ )
222
+ assert snapshot is not None
223
+ assert snapshot.name == snapshot_name
224
+ except Exception as e:
225
+ pytest.skip(f"Snapshot creation not supported: {e}")
226
+
227
+ # Add more data after snapshot
228
+ test_client.execute(f"INSERT INTO {test_db}.snapshot_test VALUES (3, 'test3', 300)")
229
+ test_client.execute(f"INSERT INTO {test_db}.snapshot_test VALUES (4, 'test4', 400)")
230
+
231
+ result = test_client.execute(f"SELECT COUNT(*) FROM {test_db}.snapshot_test")
232
+ assert result.rows[0][0] == 4
233
+
234
+ # List snapshots
235
+ try:
236
+ snapshots = test_client.snapshots.list()
237
+ assert isinstance(snapshots, list)
238
+ # Check if our snapshot is in the list
239
+ snapshot_names = [s.name for s in snapshots]
240
+ assert snapshot_name in snapshot_names
241
+ except Exception as e:
242
+ pytest.skip(f"Snapshot listing not supported: {e}")
243
+
244
+ # Cleanup
245
+ try:
246
+ test_client.snapshots.delete(snapshot_name)
247
+ except Exception:
248
+ pass # Ignore cleanup errors
249
+
250
+ test_client.execute(f"DROP TABLE IF EXISTS {test_db}.snapshot_test")
251
+
252
+ def test_snapshot_enumeration(self, test_client):
253
+ """Test snapshot enumeration and information - from test_snapshot_restore.py"""
254
+ # Create test table in the correct database
255
+ test_db = online_config.get_test_database()
256
+ test_client.execute(
257
+ f"CREATE TABLE IF NOT EXISTS {test_db}.snapshot_test (id INT PRIMARY KEY, name VARCHAR(50), value INT)"
258
+ )
259
+ test_client.execute(f"DELETE FROM {test_db}.snapshot_test")
260
+ test_client.execute(f"INSERT INTO {test_db}.snapshot_test VALUES (1, 'enum_test1', 100)")
261
+ test_client.execute(f"INSERT INTO {test_db}.snapshot_test VALUES (2, 'enum_test2', 200)")
262
+
263
+ # Create multiple snapshots
264
+ snapshot_names = []
265
+ for i in range(3):
266
+ snapshot_name = f"enumsnapshot{i}{int(time.time())}"
267
+ try:
268
+ snapshot = test_client.snapshots.create(
269
+ name=snapshot_name,
270
+ level="table",
271
+ database=test_db,
272
+ table="snapshot_test",
273
+ description=f"Test snapshot {i}",
274
+ )
275
+ snapshot_names.append(snapshot_name)
276
+ except Exception as e:
277
+ pytest.skip(f"Snapshot creation not supported: {e}")
278
+
279
+ # List all snapshots
280
+ try:
281
+ snapshots = test_client.snapshots.list()
282
+ assert isinstance(snapshots, list)
283
+ assert len(snapshots) >= len(snapshot_names)
284
+
285
+ # Verify our snapshots are in the list
286
+ snapshot_names_in_list = [s.name for s in snapshots]
287
+ for name in snapshot_names:
288
+ assert name in snapshot_names_in_list
289
+ except Exception as e:
290
+ pytest.skip(f"Snapshot listing not supported: {e}")
291
+
292
+ # Cleanup
293
+ for snapshot_name in snapshot_names:
294
+ try:
295
+ test_client.snapshots.delete(snapshot_name)
296
+ except Exception:
297
+ pass # Ignore cleanup errors
298
+
299
+ test_client.execute(f"DROP TABLE IF EXISTS {test_db}.snapshot_test")
300
+
301
+ # ==================== SNAPSHOT QUERY OPERATIONS ====================
302
+
303
+ def test_snapshot_query_basic(self, test_client, test_database):
304
+ """Test basic snapshot query builder functionality - from test_snapshot_online.py"""
305
+ snapshot_name = f"test_query_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
306
+
307
+ # Create snapshot first
308
+ test_client.snapshots.create(
309
+ snapshot_name,
310
+ SnapshotLevel.TABLE,
311
+ database="test_snapshot_db",
312
+ table="test_snapshot_table",
313
+ )
314
+
315
+ try:
316
+ # Test basic query
317
+ result = (
318
+ test_client.query("test_snapshot_db.test_snapshot_table", snapshot=snapshot_name)
319
+ .select("id", "name", "value")
320
+ .execute()
321
+ )
322
+
323
+ rows = result.fetchall()
324
+ assert len(rows) == 3
325
+
326
+ # Test query with WHERE condition
327
+ result = (
328
+ test_client.query("test_snapshot_db.test_snapshot_table", snapshot=snapshot_name)
329
+ .select("id", "name", "value")
330
+ .where("value > ?", 150)
331
+ .execute()
332
+ )
333
+
334
+ rows = result.fetchall()
335
+ assert len(rows) == 2 # Only rows with value > 150
336
+
337
+ finally:
338
+ # Clean up
339
+ test_client.snapshots.delete(snapshot_name)
340
+
341
+ def test_snapshot_query_parameter_substitution(self, test_client, test_database):
342
+ """Test parameter substitution in snapshot queries - from test_snapshot_online.py"""
343
+ snapshot_name = f"test_param_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
344
+
345
+ # Create cluster snapshot first (more reliable than table snapshot)
346
+ test_client.snapshots.create(snapshot_name, SnapshotLevel.CLUSTER)
347
+
348
+ try:
349
+ # Test string parameter substitution
350
+ result = (
351
+ test_client.query("test_snapshot_db.test_snapshot_table", snapshot=snapshot_name)
352
+ .select("id", "name", "value")
353
+ .where("name = ?", "test1")
354
+ .execute()
355
+ )
356
+
357
+ rows = result.fetchall()
358
+ assert len(rows) == 1
359
+ assert rows[0][1] == "test1"
360
+
361
+ # Test numeric parameter substitution
362
+ result = (
363
+ test_client.query("test_snapshot_db.test_snapshot_table", snapshot=snapshot_name)
364
+ .select("id", "name", "value")
365
+ .where("value = ?", 200)
366
+ .execute()
367
+ )
368
+
369
+ rows = result.fetchall()
370
+ assert len(rows) == 1
371
+ assert rows[0][2] == 200
372
+
373
+ # Test multiple parameters
374
+ result = (
375
+ test_client.query("test_snapshot_db.test_snapshot_table", snapshot=snapshot_name)
376
+ .select("id", "name", "value")
377
+ .where("name = ? AND value > ?", "test2", 150)
378
+ .execute()
379
+ )
380
+
381
+ rows = result.fetchall()
382
+ assert len(rows) == 1
383
+ assert rows[0][1] == "test2"
384
+
385
+ finally:
386
+ # Clean up
387
+ test_client.snapshots.delete(snapshot_name)
388
+
389
+ def test_snapshot_query_complex_query(self, test_client, test_database):
390
+ """Test complex snapshot query with all clauses - from test_snapshot_online.py"""
391
+ snapshot_name = f"test_complex_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
392
+
393
+ # Create snapshot first
394
+ test_client.snapshots.create(
395
+ snapshot_name,
396
+ SnapshotLevel.TABLE,
397
+ database="test_snapshot_db",
398
+ table="test_snapshot_table",
399
+ )
400
+
401
+ try:
402
+ # Test complex query with ORDER BY and LIMIT
403
+ result = (
404
+ test_client.query("test_snapshot_db.test_snapshot_table", snapshot=snapshot_name)
405
+ .select("id", "name", "value")
406
+ .where("value > ?", 100)
407
+ .order_by("value DESC")
408
+ .limit(2)
409
+ .execute()
410
+ )
411
+
412
+ rows = result.fetchall()
413
+ assert len(rows) == 2
414
+ # Should be ordered by value DESC
415
+ assert rows[0][2] >= rows[1][2]
416
+
417
+ finally:
418
+ # Clean up
419
+ test_client.snapshots.delete(snapshot_name)
420
+
421
+ def test_snapshot_query_functionality(self, test_client, test_database):
422
+ """Test snapshot query functionality - from test_client_online.py"""
423
+ test_db, test_table = test_database
424
+ snapshot_name = f"test_client_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
425
+
426
+ try:
427
+ # Create snapshot
428
+ test_client.snapshots.create(snapshot_name, "table", database=test_db, table=test_table)
429
+
430
+ # Test snapshot query using query builder
431
+ result = (
432
+ test_client.query(f"{test_db}.{test_table}", snapshot=snapshot_name)
433
+ .select("*")
434
+ .where("value > ?", 150)
435
+ .execute()
436
+ )
437
+
438
+ rows = result.fetchall()
439
+ assert len(rows) == 2 # Should have 2 rows with value > 150
440
+
441
+ # Test snapshot query without parameters
442
+ result = test_client.query(f"{test_db}.{test_table}", snapshot=snapshot_name).select("COUNT(*)").execute()
443
+
444
+ count = result.fetchone()[0]
445
+ assert count == 3
446
+
447
+ finally:
448
+ # Clean up snapshot
449
+ try:
450
+ test_client.snapshots.delete(snapshot_name)
451
+ except Exception:
452
+ pass
453
+
454
+ def test_snapshot_query_syntax_validation(self, test_client, test_database):
455
+ """Test that snapshot queries use correct syntax - from test_snapshot_online.py and test_client_online.py"""
456
+ test_db, test_table = test_database
457
+ snapshot_name = f"test_syntax_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
458
+
459
+ try:
460
+ # Create snapshot
461
+ test_client.snapshots.create(snapshot_name, "table", database=test_db, table=test_table)
462
+
463
+ # This should work without errors - the SQL should be properly formatted
464
+ result = (
465
+ test_client.query(f"{test_db}.{test_table}", snapshot=snapshot_name)
466
+ .select("id", "name")
467
+ .where("id = ?", 1)
468
+ .execute()
469
+ )
470
+
471
+ rows = result.fetchall()
472
+ assert len(rows) == 1
473
+
474
+ finally:
475
+ # Clean up
476
+ test_client.snapshots.delete(snapshot_name)
477
+
478
+ # ==================== SNAPSHOT MANAGEMENT ====================
479
+
480
+ def test_snapshot_management_comprehensive(self, test_client, test_database):
481
+ """Test comprehensive snapshot management functionality - from test_snapshot_online.py"""
482
+ snapshot_name = f"test_snapshot_001_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
483
+
484
+ try:
485
+ # Create snapshot using the snapshot manager
486
+ snapshot = test_client.snapshots.create(
487
+ name=snapshot_name,
488
+ level="table",
489
+ database="test_snapshot_db",
490
+ table="test_snapshot_table",
491
+ description="Test snapshot for SDK",
492
+ )
493
+
494
+ assert snapshot is not None
495
+ assert snapshot.name == snapshot_name
496
+
497
+ # List snapshots
498
+ snapshots = test_client.snapshots.list()
499
+ snapshot_names = [s.name for s in snapshots]
500
+ assert snapshot_name in snapshot_names
501
+
502
+ # Get specific snapshot
503
+ retrieved_snapshot = test_client.snapshots.get(snapshot_name)
504
+ assert retrieved_snapshot.name == snapshot_name
505
+
506
+ # Test snapshot query using query builder
507
+ result = test_client.query("test_snapshot_db.test_snapshot_table", snapshot=snapshot_name).select("*").execute()
508
+ rows = result.fetchall()
509
+ assert len(rows) == 3 # We inserted 3 test rows
510
+
511
+ # Test snapshot context manager
512
+ with test_client.snapshot(snapshot_name) as snapshot_client:
513
+ result = snapshot_client.execute("SELECT COUNT(*) FROM test_snapshot_db.test_snapshot_table")
514
+ count = result.scalar()
515
+ assert count == 3
516
+
517
+ # Test snapshot query builder with WHERE clause
518
+ result = (
519
+ test_client.query("test_snapshot_db.test_snapshot_table", snapshot=snapshot_name)
520
+ .select("id", "name", "value")
521
+ .where("value > ?", 150)
522
+ .execute()
523
+ )
524
+ rows = result.fetchall()
525
+ assert len(rows) == 2 # Only rows with value > 150
526
+
527
+ finally:
528
+ # Clean up
529
+ test_client.snapshots.delete(snapshot_name)
530
+
531
+ # ==================== SNAPSHOT RESTORE OPERATIONS ====================
532
+
533
+ def test_snapshot_restore_operations(self, test_client):
534
+ """Test snapshot restore operations - from test_snapshot_restore.py"""
535
+ # Create test data in the correct database
536
+ test_db = online_config.get_test_database()
537
+ test_client.execute(
538
+ f"CREATE TABLE IF NOT EXISTS {test_db}.snapshot_test (id INT PRIMARY KEY, name VARCHAR(50), value INT)"
539
+ )
540
+ test_client.execute(f"DELETE FROM {test_db}.snapshot_test")
541
+ test_client.execute(f"INSERT INTO {test_db}.snapshot_test VALUES (1, 'restore_test1', 100)")
542
+ test_client.execute(f"INSERT INTO {test_db}.snapshot_test VALUES (2, 'restore_test2', 200)")
543
+
544
+ # Create snapshot
545
+ snapshot_name = f"restoresnapshot{int(time.time())}"
546
+ try:
547
+ snapshot = test_client.snapshots.create(
548
+ name=snapshot_name,
549
+ level="table",
550
+ database=test_db,
551
+ table="snapshot_test",
552
+ description="Test snapshot for restore operations",
553
+ )
554
+ except Exception as e:
555
+ pytest.skip(f"Snapshot creation not supported: {e}")
556
+
557
+ # Add more data after snapshot
558
+ test_client.execute(f"INSERT INTO {test_db}.snapshot_test VALUES (3, 'restore_test3', 300)")
559
+ test_client.execute(f"INSERT INTO {test_db}.snapshot_test VALUES (4, 'restore_test4', 400)")
560
+
561
+ result = test_client.execute(f"SELECT COUNT(*) FROM {test_db}.snapshot_test")
562
+ assert result.rows[0][0] == 4
563
+
564
+ # Restore from snapshot
565
+ try:
566
+ test_client.restore.restore_table(snapshot_name, "sys", test_db, "snapshot_test")
567
+
568
+ # Verify data after restore
569
+ result = test_client.execute(f"SELECT COUNT(*) FROM {test_db}.snapshot_test")
570
+ assert result.rows[0][0] == 2 # Should be back to original 2 records
571
+
572
+ # Verify specific data
573
+ result = test_client.execute(f"SELECT * FROM {test_db}.snapshot_test ORDER BY id")
574
+ assert len(result.rows) == 2
575
+ assert result.rows[0][0] == 1 # ID: 1
576
+ assert result.rows[1][0] == 2 # ID: 2
577
+ except Exception as e:
578
+ pytest.skip(f"Snapshot restore not supported: {e}")
579
+
580
+ # Cleanup
581
+ try:
582
+ test_client.snapshots.delete(snapshot_name)
583
+ except Exception:
584
+ pass # Ignore cleanup errors
585
+
586
+ test_client.execute(f"DROP TABLE IF EXISTS {test_db}.snapshot_test")
587
+
588
+ # ==================== ERROR HANDLING ====================
589
+
590
+ def test_snapshot_error_handling(self, test_client, test_database):
591
+ """Test snapshot error handling - from test_snapshot_online.py and test_snapshot_restore.py"""
592
+ # Test non-existent snapshot
593
+ with pytest.raises(SnapshotError):
594
+ test_client.snapshots.get("non_existent_snapshot")
595
+
596
+ # Test invalid snapshot level
597
+ with pytest.raises(SnapshotError):
598
+ test_client.snapshots.create("test", "invalid_level")
599
+
600
+ # Test creating snapshot with invalid parameters
601
+ try:
602
+ test_client.snapshots.create(
603
+ name="", # Empty name should fail
604
+ level="table",
605
+ database=online_config.get_test_database(),
606
+ table="nonexistent_table",
607
+ description="Test invalid snapshot",
608
+ )
609
+ assert False, "Should have failed with empty name"
610
+ except Exception:
611
+ pass # Expected to fail
612
+
613
+ # Test deleting non-existent snapshot
614
+ try:
615
+ test_client.snapshots.delete("nonexistent_snapshot")
616
+ assert False, "Should have failed with non-existent snapshot"
617
+ except Exception:
618
+ pass # Expected to fail
619
+
620
+ # Test restoring from non-existent snapshot
621
+ try:
622
+ test_client.restore.restore_table("nonexistent_snapshot", "sys", "test", "test_table")
623
+ assert False, "Should have failed with non-existent snapshot"
624
+ except Exception:
625
+ pass # Expected to fail
626
+
627
+ # ==================== SNAPSHOT SYNTAX VARIATIONS ====================
628
+
629
+ def test_snapshot_syntax_variations(self, test_client, test_database):
630
+ """Test different snapshot syntax variations - from test_snapshot_online.py"""
631
+ # Create a test table for syntax testing
632
+ test_table = "test_syntax_table"
633
+ test_client.execute(f"CREATE TABLE IF NOT EXISTS {test_table} (id INT PRIMARY KEY, name VARCHAR(100))")
634
+ test_client.execute(f"INSERT INTO {test_table} (id, name) VALUES (1, 'test')")
635
+
636
+ try:
637
+ # Test different snapshot syntax variations
638
+ syntax_variations = [
639
+ f"CREATE SNAPSHOT test_snapshot_001 TABLE test_snapshot_db.{test_table}",
640
+ f"CREATE SNAPSHOT test_snapshot_001 OF TABLE test_snapshot_db.{test_table}",
641
+ f"CREATE SNAPSHOT test_snapshot_001 FOR TABLE test_snapshot_db.{test_table}",
642
+ f"CREATE SNAPSHOT test_snapshot_001 FROM TABLE test_snapshot_db.{test_table}",
643
+ f"CREATE SNAPSHOT test_snapshot_001 CLONE TABLE test_snapshot_db.{test_table}",
644
+ ]
645
+
646
+ snapshot_created = False
647
+ for i, syntax in enumerate(syntax_variations):
648
+ try:
649
+ test_client.execute(syntax)
650
+ snapshot_created = True
651
+ print(f"✓ Syntax {i+1} worked: {syntax}")
652
+ break
653
+ except Exception as e:
654
+ print(f"✗ Syntax {i+1} failed: {e}")
655
+
656
+ if snapshot_created:
657
+ # Try to drop the snapshot
658
+ try:
659
+ test_client.execute("DROP SNAPSHOT test_snapshot_001")
660
+ print("✓ Snapshot dropped successfully")
661
+ except Exception as e:
662
+ print(f"✗ Failed to drop snapshot: {e}")
663
+
664
+ # Test listing snapshots
665
+ try:
666
+ result = test_client.execute("SHOW SNAPSHOTS")
667
+ snapshots = result.fetchall()
668
+ print(f"✓ SHOW SNAPSHOTS worked: {len(snapshots)} snapshots found")
669
+ except Exception as e:
670
+ print(f"✗ SHOW SNAPSHOTS failed: {e}")
671
+
672
+ # Test other snapshot commands
673
+ try:
674
+ result = test_client.execute("SELECT * FROM mo_catalog.mo_snapshots")
675
+ rows = result.fetchall()
676
+ print(f"✓ mo_catalog.mo_snapshots query worked: {len(rows)} rows")
677
+ except Exception as e:
678
+ print(f"✗ mo_catalog.mo_snapshots query failed: {e}")
679
+
680
+ finally:
681
+ # Clean up test table
682
+ test_client.execute(f"DROP TABLE IF EXISTS {test_table}")
683
+
684
+ # ==================== ASYNC SNAPSHOT OPERATIONS ====================
685
+
686
+ @pytest.mark.asyncio
687
+ async def test_async_snapshot_operations(self, test_async_client):
688
+ """Test async snapshot operations - from test_snapshot_restore.py"""
689
+ # Create test data
690
+ await test_async_client.execute(
691
+ "CREATE TABLE IF NOT EXISTS snapshot_test (id INT PRIMARY KEY, name VARCHAR(50), value INT)"
692
+ )
693
+ await test_async_client.execute("DELETE FROM snapshot_test")
694
+ await test_async_client.execute("INSERT INTO snapshot_test VALUES (1, 'async_test1', 100)")
695
+ await test_async_client.execute("INSERT INTO snapshot_test VALUES (2, 'async_test2', 200)")
696
+
697
+ # Verify initial data
698
+ result = await test_async_client.execute("SELECT COUNT(*) FROM snapshot_test")
699
+ assert result.rows[0][0] == 2
700
+
701
+ # Test snapshot operations (as per examples - handle failures gracefully)
702
+ snapshot_name = f"asyncsnapshot{int(time.time())}"
703
+
704
+ # Test snapshot listing (should work even if empty)
705
+ snapshots = await test_async_client.snapshots.list()
706
+ assert isinstance(snapshots, list)
707
+
708
+ try:
709
+ snapshot = await test_async_client.snapshots.create(
710
+ name=snapshot_name,
711
+ level="table",
712
+ database=online_config.get_test_database(),
713
+ table="snapshot_test",
714
+ description="Test async snapshot",
715
+ )
716
+ assert snapshot is not None
717
+ assert snapshot.name == snapshot_name
718
+
719
+ # Test snapshot listing after creation
720
+ snapshots = await test_async_client.snapshots.list()
721
+ assert isinstance(snapshots, list)
722
+
723
+ # Test snapshot deletion
724
+ await test_async_client.snapshots.delete(snapshot_name)
725
+
726
+ except Exception as e:
727
+ # If snapshot creation fails, test the API methods still work
728
+ assert "snapshot" in str(e).lower() or "SQL" in str(e) or "syntax" in str(e).lower() # Ignore cleanup errors
729
+
730
+ await test_async_client.execute("DROP TABLE IF EXISTS snapshot_test")
731
+
732
+ @pytest.mark.asyncio
733
+ async def test_async_snapshot_query_functionality(self, test_async_client, async_test_database):
734
+ """Test async snapshot query functionality - from test_async_client_online.py"""
735
+ test_db, test_table = async_test_database
736
+
737
+ # First create a snapshot
738
+ snapshot_name = f"test_async_client_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
739
+
740
+ try:
741
+ # Create snapshot
742
+ await test_async_client.snapshots.create(snapshot_name, "table", database=test_db, table=test_table)
743
+
744
+ # Test snapshot query using query builder
745
+ result = (
746
+ await test_async_client.query(f"{test_db}.{test_table}", snapshot=snapshot_name)
747
+ .select("*")
748
+ .where("value > ?", 150)
749
+ .execute()
750
+ )
751
+
752
+ rows = result.fetchall()
753
+ assert len(rows) == 2 # Should have 2 rows with value > 150
754
+
755
+ # Test snapshot query without parameters
756
+ result = (
757
+ await test_async_client.query(f"{test_db}.{test_table}", snapshot=snapshot_name).select("COUNT(*)").execute()
758
+ )
759
+
760
+ count = result.fetchone()[0]
761
+ assert count == 3
762
+
763
+ finally:
764
+ # Clean up snapshot
765
+ try:
766
+ await test_async_client.snapshots.delete(snapshot_name)
767
+ except Exception:
768
+ pass
769
+
770
+ @pytest.mark.asyncio
771
+ async def test_async_snapshot_query_syntax_validation(self, test_async_client, async_test_database):
772
+ """Test that async snapshot queries use correct syntax - from test_async_client_online.py"""
773
+ test_db, test_table = async_test_database
774
+ snapshot_name = f"test_async_syntax_snap_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
775
+
776
+ try:
777
+ # Create snapshot
778
+ await test_async_client.snapshots.create(snapshot_name, "table", database=test_db, table=test_table)
779
+
780
+ # Test that snapshot query works with proper syntax
781
+ result = (
782
+ await test_async_client.query(f"{test_db}.{test_table}", snapshot=snapshot_name)
783
+ .select("id", "name")
784
+ .where("id = ?", 1)
785
+ .execute()
786
+ )
787
+
788
+ rows = result.fetchall()
789
+ assert len(rows) == 1
790
+ assert rows[0][0] == 1
791
+ assert rows[0][1] == 'async_test1'
792
+
793
+ finally:
794
+ # Clean up snapshot
795
+ try:
796
+ await test_async_client.snapshots.delete(snapshot_name)
797
+ except Exception:
798
+ pass
799
+
800
+ @pytest.mark.asyncio
801
+ async def test_snapshot_query(self, test_async_client):
802
+ """Test query method with snapshot parameter - from test_async_client_interfaces.py"""
803
+ # Should return a query builder with snapshot
804
+ query = test_async_client.query("test_table", snapshot="test_snapshot")
805
+ assert query is not None
806
+ assert hasattr(query, '_snapshot_name')
807
+ assert query._snapshot_name == "test_snapshot"
808
+
809
+ @pytest.mark.asyncio
810
+ async def test_snapshot_context_manager(self, test_async_client):
811
+ """Test snapshot context manager - from test_async_client_interfaces.py"""
812
+ # Create a test table first
813
+ await test_async_client.create_table("test_snapshot_table", {"id": "int primary key", "name": "varchar(100)"})
814
+
815
+ try:
816
+ # Create a snapshot with unique name
817
+ snapshot_name = f"test_snapshot_ctx_{int(time.time())}"
818
+ await test_async_client.snapshots.create(
819
+ name=snapshot_name,
820
+ level="table",
821
+ database=online_config.get_test_database(),
822
+ table="test_snapshot_table",
823
+ )
824
+
825
+ # Test snapshot context manager
826
+ async with test_async_client.snapshot(snapshot_name) as snapshot_client:
827
+ assert snapshot_client is not None
828
+ # Should be able to execute queries
829
+ result = await snapshot_client.execute("SELECT COUNT(*) FROM test_snapshot_table")
830
+ assert result is not None
831
+
832
+ finally:
833
+ # Cleanup
834
+ try:
835
+ await test_async_client.snapshots.delete(snapshot_name)
836
+ except Exception:
837
+ pass
838
+ try:
839
+ await test_async_client.execute("DROP TABLE IF EXISTS test_snapshot_table")
840
+ except Exception:
841
+ pass
842
+
843
+ # ==================== SNAPSHOT WITH LOGGING ====================
844
+
845
+ def test_snapshot_with_logging(self, test_client):
846
+ """Test snapshot operations with custom logging - from test_snapshot_restore.py"""
847
+ # Create logger
848
+ logger = create_default_logger()
849
+
850
+ # Create test data in the correct database
851
+ test_db = online_config.get_test_database()
852
+ test_client.execute(
853
+ f"CREATE TABLE IF NOT EXISTS {test_db}.snapshot_test (id INT PRIMARY KEY, name VARCHAR(50), value INT)"
854
+ )
855
+ test_client.execute(f"DELETE FROM {test_db}.snapshot_test")
856
+ test_client.execute(f"INSERT INTO {test_db}.snapshot_test VALUES (1, 'log_test1', 100)")
857
+
858
+ # Create snapshot with logging
859
+ snapshot_name = f"logsnapshot{int(time.time())}"
860
+ try:
861
+ snapshot = test_client.snapshots.create(
862
+ name=snapshot_name,
863
+ level="table",
864
+ database=test_db,
865
+ table="snapshot_test",
866
+ description="Test snapshot with logging",
867
+ )
868
+ assert snapshot is not None
869
+ except Exception as e:
870
+ pytest.skip(f"Snapshot creation not supported: {e}")
871
+
872
+ # Cleanup
873
+ try:
874
+ test_client.snapshots.delete(snapshot_name)
875
+ except Exception:
876
+ pass # Ignore cleanup errors
877
+
878
+ test_client.execute(f"DROP TABLE IF EXISTS {test_db}.snapshot_test")
879
+
880
+ # ==================== ORM SNAPSHOT OPERATIONS ====================
881
+
882
+ def test_orm_snapshot_queries(self, test_client):
883
+ """Test ORM snapshot functionality - from test_matrixone_query_orm.py"""
884
+ # This test requires ORM setup which may not be available in all environments
885
+ # We'll create a simplified version that tests the basic snapshot query functionality
886
+
887
+ # Create test table for ORM-like testing in the correct database
888
+ test_db = online_config.get_test_database()
889
+ test_client.execute(
890
+ f"CREATE TABLE IF NOT EXISTS {test_db}.test_users (id INT PRIMARY KEY, name VARCHAR(100), email VARCHAR(100))"
891
+ )
892
+ test_client.execute(f"DELETE FROM {test_db}.test_users")
893
+ test_client.execute(f"INSERT INTO {test_db}.test_users VALUES (1, 'John Doe', 'john@example.com')")
894
+ test_client.execute(f"INSERT INTO {test_db}.test_users VALUES (2, 'Jane Smith', 'jane@example.com')")
895
+
896
+ try:
897
+ # Create a snapshot
898
+ snapshot_manager = SnapshotManager(test_client)
899
+ snapshot = snapshot_manager.create(
900
+ name="test_users_snapshot",
901
+ level=SnapshotLevel.TABLE,
902
+ database=test_db,
903
+ table="test_users",
904
+ )
905
+
906
+ # Query from snapshot using basic query builder
907
+ result = test_client.query(f"{test_db}.test_users", snapshot="test_users_snapshot").select("*").execute()
908
+ rows = result.fetchall()
909
+ assert len(rows) == 2
910
+
911
+ # Query with filter from snapshot
912
+ result = (
913
+ test_client.query(f"{test_db}.test_users", snapshot="test_users_snapshot")
914
+ .select("*")
915
+ .where("id = ?", 1)
916
+ .execute()
917
+ )
918
+ rows = result.fetchall()
919
+ assert len(rows) == 1
920
+ assert rows[0][1] == 'John Doe'
921
+
922
+ except Exception as e:
923
+ pytest.skip(f"ORM snapshot functionality not supported: {e}")
924
+
925
+ finally:
926
+ # Clean up snapshot
927
+ try:
928
+ test_client.execute("DROP SNAPSHOT test_users_snapshot")
929
+ except:
930
+ pass
931
+ test_client.execute(f"DROP TABLE IF EXISTS {test_db}.test_users")
932
+
933
+ @pytest.mark.asyncio
934
+ async def test_async_orm_snapshot_queries(self, test_async_client):
935
+ """Test async ORM snapshot functionality - from test_matrixone_query_orm.py"""
936
+ # Create test table for ORM-like testing
937
+ await test_async_client.execute(
938
+ "CREATE TABLE IF NOT EXISTS test_users (id INT PRIMARY KEY, name VARCHAR(100), email VARCHAR(100))"
939
+ )
940
+ await test_async_client.execute("DELETE FROM test_users")
941
+ await test_async_client.execute("INSERT INTO test_users VALUES (1, 'John Doe', 'john@example.com')")
942
+ await test_async_client.execute("INSERT INTO test_users VALUES (2, 'Jane Smith', 'jane@example.com')")
943
+
944
+ try:
945
+ # Create a snapshot
946
+ snapshot = await test_async_client.snapshots.create(
947
+ name="test_users_snapshot_async",
948
+ level="table",
949
+ database=online_config.get_connection_params()[4], # database name
950
+ table="test_users",
951
+ )
952
+
953
+ # Query from snapshot using basic query builder
954
+ db_name = online_config.get_connection_params()[4]
955
+ result = (
956
+ await test_async_client.query(f"{db_name}.test_users", snapshot="test_users_snapshot_async")
957
+ .select("*")
958
+ .execute()
959
+ )
960
+ rows = result.fetchall()
961
+ assert len(rows) == 2
962
+
963
+ # Query with filter from snapshot
964
+ result = (
965
+ await test_async_client.query(f"{db_name}.test_users", snapshot="test_users_snapshot_async")
966
+ .select("*")
967
+ .where("id = ?", 1)
968
+ .execute()
969
+ )
970
+ rows = result.fetchall()
971
+ assert len(rows) == 1
972
+ assert rows[0][1] == 'John Doe'
973
+
974
+ except Exception as e:
975
+ pytest.skip(f"Async ORM snapshot functionality not supported: {e}")
976
+
977
+ finally:
978
+ # Clean up snapshot
979
+ try:
980
+ await test_async_client.execute("DROP SNAPSHOT test_users_snapshot_async")
981
+ except:
982
+ pass
983
+ await test_async_client.execute("DROP TABLE IF EXISTS test_users")
984
+
985
+ def test_invalid_snapshot(self, test_client):
986
+ """Test invalid snapshot operations - from test_matrixone_query_orm.py"""
987
+ # Test querying with non-existent snapshot
988
+ try:
989
+ result = test_client.query("test_table", snapshot="non_existent_snapshot").select("*").execute()
990
+ # If this doesn't raise an exception, the result should be empty or indicate error
991
+ assert result is not None
992
+ except Exception as e:
993
+ # Expected to fail with non-existent snapshot
994
+ assert "snapshot" in str(e).lower() or "not found" in str(e).lower()
995
+
996
+
997
+ if __name__ == '__main__':
998
+ unittest.main()