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
matrixone/restore.py ADDED
@@ -0,0 +1,411 @@
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 Python SDK - Restore Manager
17
+ Provides restore functionality for MatrixOne snapshots
18
+ """
19
+
20
+ from typing import Optional
21
+
22
+ from .exceptions import RestoreError
23
+
24
+
25
+ class RestoreManager:
26
+ """
27
+ Manager for restore operations from snapshots in MatrixOne.
28
+
29
+ This class provides comprehensive restore functionality for recovering data
30
+ from snapshots. It supports restoring entire clusters, databases, or tables
31
+ from previously created snapshots, enabling data recovery and disaster
32
+ recovery scenarios.
33
+
34
+ Key Features:
35
+
36
+ - Restore entire clusters from snapshots
37
+ - Restore specific databases from snapshots
38
+ - Restore individual tables from snapshots
39
+ - Integration with snapshot management
40
+ - Transaction-aware restore operations
41
+ - Support for both full and incremental restores
42
+
43
+ Supported Restore Levels:
44
+ - CLUSTER: Full cluster restore from snapshot
45
+ - DATABASE: Database-level restore from snapshot
46
+ - TABLE: Table-level restore from snapshot
47
+
48
+ Usage Examples::
49
+
50
+ # Initialize restore manager
51
+ restore = client.restore
52
+
53
+ # Restore entire cluster from snapshot
54
+ success = restore.restore_cluster('daily_backup_snapshot')
55
+
56
+ # Restore database from snapshot
57
+ success = restore.restore_database(
58
+ snapshot_name='daily_backup',
59
+ target_database='restored_database'
60
+ )
61
+
62
+ # Restore table from snapshot
63
+ success = restore.restore_table(
64
+ snapshot_name='users_backup',
65
+ target_database='restored_database',
66
+ target_table='restored_users'
67
+ )
68
+
69
+ # List available snapshots for restore
70
+ snapshots = client.snapshots.list()
71
+
72
+ # Get restore status
73
+ status = restore.get_restore_status('restore_job_id')
74
+
75
+ Note: Restore operations require appropriate snapshots to be available. Restore operations may
76
+ take significant time depending on the amount of data being restored and the snapshot size.
77
+ """
78
+
79
+ def __init__(self, client):
80
+ """Initialize RestoreManager with client connection"""
81
+ self._client = client
82
+
83
+ def restore_cluster(self, snapshot_name: str) -> bool:
84
+ """
85
+ Restore entire cluster from snapshot
86
+
87
+ Args::
88
+
89
+ snapshot_name: Name of the snapshot to restore from
90
+
91
+ Returns::
92
+
93
+ bool: True if restore was successful
94
+
95
+ Raises::
96
+
97
+ RestoreError: If restore operation fails
98
+
99
+ Example
100
+
101
+ >>> client = Client()
102
+ >>> client.connect(...)
103
+ >>> success = client.restore.restore_cluster("cluster_snapshot_1")
104
+ """
105
+ try:
106
+ sql = f"RESTORE CLUSTER FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)}"
107
+ result = self._client.execute(sql)
108
+ return result is not None
109
+ except Exception as e:
110
+ raise RestoreError(f"Failed to restore cluster from snapshot '{snapshot_name}': {e}") from None
111
+
112
+ def restore_tenant(self, snapshot_name: str, account_name: str, to_account: Optional[str] = None) -> bool:
113
+ """
114
+ Restore tenant from snapshot
115
+
116
+ Args::
117
+
118
+ snapshot_name: Name of the snapshot to restore from
119
+ account_name: Name of the account to restore
120
+ to_account: Optional target account name (for cross-tenant restore)
121
+
122
+ Returns::
123
+
124
+ bool: True if restore was successful
125
+
126
+ Raises::
127
+
128
+ RestoreError: If restore operation fails
129
+
130
+ Example
131
+
132
+ >>> # Restore tenant to itself
133
+ >>> success = client.restore.restore_tenant("acc1_snap1", "acc1")
134
+ >>>
135
+ >>> # Restore tenant to new tenant
136
+ >>> success = client.restore.restore_tenant("acc1_snap1", "acc1", "acc2")
137
+ """
138
+ try:
139
+ if to_account:
140
+ # Cross-tenant restore
141
+ sql = (
142
+ f"RESTORE ACCOUNT {self._client._escape_identifier(account_name)} "
143
+ f"FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)} "
144
+ f"TO ACCOUNT {self._client._escape_identifier(to_account)}"
145
+ )
146
+ else:
147
+ # Restore to same tenant
148
+ sql = (
149
+ f"RESTORE ACCOUNT {self._client._escape_identifier(account_name)} "
150
+ f"FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)}"
151
+ )
152
+
153
+ result = self._client.execute(sql)
154
+ return result is not None
155
+ except Exception as e:
156
+ raise RestoreError(f"Failed to restore tenant '{account_name}' from snapshot '{snapshot_name}': {e}") from None
157
+
158
+ def restore_database(
159
+ self,
160
+ snapshot_name: str,
161
+ account_name: str,
162
+ database_name: str,
163
+ to_account: Optional[str] = None,
164
+ ) -> bool:
165
+ """
166
+ Restore database from snapshot
167
+
168
+ Args::
169
+
170
+ snapshot_name: Name of the snapshot to restore from
171
+ account_name: Name of the account
172
+ database_name: Name of the database to restore
173
+ to_account: Optional target account name (for cross-tenant restore)
174
+
175
+ Returns::
176
+
177
+ bool: True if restore was successful
178
+
179
+ Raises::
180
+
181
+ RestoreError: If restore operation fails
182
+
183
+ Example
184
+
185
+ >>> success = client.restore.restore_database("acc1_db_snap1", "acc1", "db1")
186
+ """
187
+ try:
188
+ if to_account:
189
+ # Cross-tenant restore
190
+ sql = (
191
+ f"RESTORE ACCOUNT {self._client._escape_identifier(account_name)} "
192
+ f"DATABASE {self._client._escape_identifier(database_name)} "
193
+ f"FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)} "
194
+ f"TO ACCOUNT {self._client._escape_identifier(to_account)}"
195
+ )
196
+ else:
197
+ # Restore to same tenant
198
+ sql = (
199
+ f"RESTORE ACCOUNT {self._client._escape_identifier(account_name)} "
200
+ f"DATABASE {self._client._escape_identifier(database_name)} "
201
+ f"FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)}"
202
+ )
203
+
204
+ result = self._client.execute(sql)
205
+ return result is not None
206
+ except Exception as e:
207
+ raise RestoreError(f"Failed to restore database '{database_name}' from snapshot '{snapshot_name}': {e}") from None
208
+
209
+ def restore_table(
210
+ self,
211
+ snapshot_name: str,
212
+ account_name: str,
213
+ database_name: str,
214
+ table_name: str,
215
+ to_account: Optional[str] = None,
216
+ ) -> bool:
217
+ """
218
+ Restore table from snapshot
219
+
220
+ Args::
221
+
222
+ snapshot_name: Name of the snapshot to restore from
223
+ account_name: Name of the account
224
+ database_name: Name of the database
225
+ table_name: Name of the table to restore
226
+ to_account: Optional target account name (for cross-tenant restore)
227
+
228
+ Returns::
229
+
230
+ bool: True if restore was successful
231
+
232
+ Raises::
233
+
234
+ RestoreError: If restore operation fails
235
+
236
+ Example
237
+
238
+ >>> success = client.restore.restore_table("acc1_tab_snap1", "acc1", "db1", "t1")
239
+ """
240
+ try:
241
+ if to_account:
242
+ # Cross-tenant restore
243
+ sql = (
244
+ f"RESTORE ACCOUNT {self._client._escape_identifier(account_name)} "
245
+ f"DATABASE {self._client._escape_identifier(database_name)} "
246
+ f"TABLE {self._client._escape_identifier(table_name)} "
247
+ f"FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)} "
248
+ f"TO ACCOUNT {self._client._escape_identifier(to_account)}"
249
+ )
250
+ else:
251
+ # Restore to same tenant
252
+ sql = (
253
+ f"RESTORE ACCOUNT {self._client._escape_identifier(account_name)} "
254
+ f"DATABASE {self._client._escape_identifier(database_name)} "
255
+ f"TABLE {self._client._escape_identifier(table_name)} "
256
+ f"FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)}"
257
+ )
258
+
259
+ result = self._client.execute(sql)
260
+ return result is not None
261
+ except Exception as e:
262
+ raise RestoreError(f"Failed to restore table '{table_name}' from snapshot '{snapshot_name}': {e}") from None
263
+
264
+ def restore_with_executor(
265
+ self,
266
+ restore_type: str,
267
+ snapshot_name: str,
268
+ account_name: Optional[str] = None,
269
+ database_name: Optional[str] = None,
270
+ table_name: Optional[str] = None,
271
+ to_account: Optional[str] = None,
272
+ executor=None,
273
+ ) -> bool:
274
+ """
275
+ Restore with custom executor (for transaction support)
276
+
277
+ Args::
278
+
279
+ restore_type: Type of restore ('cluster', 'tenant', 'database', 'table')
280
+ snapshot_name: Name of the snapshot to restore from
281
+ account_name: Name of the account (required for tenant/database/table)
282
+ database_name: Name of the database (required for database/table)
283
+ table_name: Name of the table (required for table)
284
+ to_account: Optional target account name
285
+ executor: Custom executor (transaction wrapper)
286
+
287
+ Returns::
288
+
289
+ bool: True if restore was successful
290
+ """
291
+ try:
292
+ if restore_type == "cluster":
293
+ sql = f"RESTORE CLUSTER FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)}"
294
+ elif restore_type == "tenant":
295
+ if not account_name:
296
+ raise RestoreError("Account name is required for tenant restore") from None
297
+ if to_account:
298
+ sql = (
299
+ f"RESTORE ACCOUNT {self._client._escape_identifier(account_name)} "
300
+ f"FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)} "
301
+ f"TO ACCOUNT {self._client._escape_identifier(to_account)}"
302
+ )
303
+ else:
304
+ sql = (
305
+ f"RESTORE ACCOUNT {self._client._escape_identifier(account_name)} "
306
+ f"FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)}"
307
+ )
308
+ elif restore_type == "database":
309
+ if not account_name or not database_name:
310
+ raise RestoreError("Account name and database name are required for database restore") from None
311
+ if to_account:
312
+ sql = (
313
+ f"RESTORE ACCOUNT {self._client._escape_identifier(account_name)} "
314
+ f"DATABASE {self._client._escape_identifier(database_name)} "
315
+ f"FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)} "
316
+ f"TO ACCOUNT {self._client._escape_identifier(to_account)}"
317
+ )
318
+ else:
319
+ sql = (
320
+ f"RESTORE ACCOUNT {self._client._escape_identifier(account_name)} "
321
+ f"DATABASE {self._client._escape_identifier(database_name)} "
322
+ f"FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)}"
323
+ )
324
+ elif restore_type == "table":
325
+ if not all([account_name, database_name, table_name]):
326
+ raise RestoreError("Account name, database name, and table name are required for table restore") from None
327
+ if to_account:
328
+ sql = (
329
+ f"RESTORE ACCOUNT {self._client._escape_identifier(account_name)} "
330
+ f"DATABASE {self._client._escape_identifier(database_name)} "
331
+ f"TABLE {self._client._escape_identifier(table_name)} "
332
+ f"FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)} "
333
+ f"TO ACCOUNT {self._client._escape_identifier(to_account)}"
334
+ )
335
+ else:
336
+ sql = (
337
+ f"RESTORE ACCOUNT {self._client._escape_identifier(account_name)} "
338
+ f"DATABASE {self._client._escape_identifier(database_name)} "
339
+ f"TABLE {self._client._escape_identifier(table_name)} "
340
+ f"FROM SNAPSHOT {self._client._escape_identifier(snapshot_name)}"
341
+ )
342
+ else:
343
+ raise RestoreError(f"Invalid restore type: {restore_type}") from None
344
+
345
+ if executor:
346
+ result = executor.execute(sql)
347
+ else:
348
+ result = self._client.execute(sql)
349
+
350
+ return result is not None
351
+ except Exception as e:
352
+ raise RestoreError(f"Failed to restore {restore_type} from snapshot '{snapshot_name}': {e}") from None
353
+
354
+
355
+ class TransactionRestoreManager(RestoreManager):
356
+ """RestoreManager for use within transactions"""
357
+
358
+ def __init__(self, client, transaction_wrapper):
359
+ """Initialize TransactionRestoreManager with client and transaction wrapper"""
360
+ super().__init__(client)
361
+ self._transaction_wrapper = transaction_wrapper
362
+
363
+ def restore_cluster(self, snapshot_name: str) -> bool:
364
+ """Restore cluster within transaction"""
365
+ return self.restore_with_executor("cluster", snapshot_name, executor=self._transaction_wrapper)
366
+
367
+ def restore_tenant(self, snapshot_name: str, account_name: str, to_account: Optional[str] = None) -> bool:
368
+ """Restore tenant within transaction"""
369
+ return self.restore_with_executor(
370
+ "tenant",
371
+ snapshot_name,
372
+ account_name,
373
+ to_account=to_account,
374
+ executor=self._transaction_wrapper,
375
+ )
376
+
377
+ def restore_database(
378
+ self,
379
+ snapshot_name: str,
380
+ account_name: str,
381
+ database_name: str,
382
+ to_account: Optional[str] = None,
383
+ ) -> bool:
384
+ """Restore database within transaction"""
385
+ return self.restore_with_executor(
386
+ "database",
387
+ snapshot_name,
388
+ account_name,
389
+ database_name,
390
+ to_account=to_account,
391
+ executor=self._transaction_wrapper,
392
+ )
393
+
394
+ def restore_table(
395
+ self,
396
+ snapshot_name: str,
397
+ account_name: str,
398
+ database_name: str,
399
+ table_name: str,
400
+ to_account: Optional[str] = None,
401
+ ) -> bool:
402
+ """Restore table within transaction"""
403
+ return self.restore_with_executor(
404
+ "table",
405
+ snapshot_name,
406
+ account_name,
407
+ database_name,
408
+ table_name,
409
+ to_account=to_account,
410
+ executor=self._transaction_wrapper,
411
+ )