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/snapshot.py ADDED
@@ -0,0 +1,550 @@
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 Snapshot Management
17
+ """
18
+
19
+ from datetime import datetime
20
+ from enum import Enum
21
+ from typing import List, Optional, Union
22
+
23
+ from .exceptions import CloneError, ConnectionError, SnapshotError
24
+ from .version import requires_version
25
+
26
+
27
+ class SnapshotLevel(Enum):
28
+ """Snapshot level enumeration"""
29
+
30
+ CLUSTER = "cluster"
31
+ ACCOUNT = "account"
32
+ DATABASE = "database"
33
+ TABLE = "table"
34
+
35
+
36
+ class Snapshot:
37
+ """Snapshot information"""
38
+
39
+ def __init__(
40
+ self,
41
+ name: str,
42
+ level: Union[str, SnapshotLevel],
43
+ created_at: datetime,
44
+ description: Optional[str] = None,
45
+ database: Optional[str] = None,
46
+ table: Optional[str] = None,
47
+ ):
48
+ self.name = name
49
+ # Convert string to enum if needed
50
+ if isinstance(level, str):
51
+ try:
52
+ self.level = SnapshotLevel(level.lower())
53
+ except ValueError:
54
+ raise SnapshotError(f"Invalid snapshot level: {level}")
55
+ else:
56
+ self.level = level
57
+ self.created_at = created_at
58
+ self.description = description
59
+ self.database = database
60
+ self.table = table
61
+
62
+ def __repr__(self):
63
+ return f"Snapshot(name='{self.name}', level='{self.level}', created_at='{self.created_at}')"
64
+
65
+
66
+ class SnapshotManager:
67
+ """
68
+ Snapshot management for MatrixOne database operations.
69
+
70
+ This class provides comprehensive snapshot functionality for creating, managing,
71
+ and restoring database snapshots at various levels (database, table, or cluster).
72
+ Snapshots enable point-in-time recovery and data protection capabilities.
73
+
74
+ Key Features:
75
+
76
+ - Create snapshots at database, table, or cluster level
77
+ - List and query existing snapshots
78
+ - Restore data from snapshots
79
+ - Snapshot lifecycle management
80
+ - Integration with transaction operations
81
+
82
+ Supported Snapshot Levels:
83
+ - CLUSTER: Full cluster snapshot
84
+ - DATABASE: Database-level snapshot
85
+ - TABLE: Table-level snapshot
86
+
87
+ Usage Examples::
88
+
89
+ # Create a database snapshot
90
+ snapshot = client.snapshots.create(
91
+ name='daily_backup',
92
+ level=SnapshotLevel.DATABASE,
93
+ database='my_database',
94
+ description='Daily backup snapshot'
95
+ )
96
+
97
+ # Create a table snapshot
98
+ snapshot = client.snapshots.create(
99
+ name='users_backup',
100
+ level=SnapshotLevel.TABLE,
101
+ database='my_database',
102
+ table='users',
103
+ description='Users table backup'
104
+ )
105
+
106
+ # List all snapshots
107
+ snapshots = client.snapshots.list()
108
+
109
+ # Restore from snapshot
110
+ client.snapshots.restore('daily_backup', 'restored_database')
111
+
112
+ Note: Snapshot functionality requires MatrixOne version 1.0.0 or higher. For older versions,
113
+ use backup/restore operations instead.
114
+ """
115
+
116
+ def __init__(self, client):
117
+ self.client = client
118
+
119
+ @requires_version(
120
+ min_version="1.0.0",
121
+ feature_name="snapshot_creation",
122
+ description="Snapshot creation functionality",
123
+ alternative="Use backup/restore operations instead",
124
+ )
125
+ def create(
126
+ self,
127
+ name: str,
128
+ level: Union[str, SnapshotLevel],
129
+ database: Optional[str] = None,
130
+ table: Optional[str] = None,
131
+ description: Optional[str] = None,
132
+ executor=None,
133
+ ) -> Snapshot:
134
+ """
135
+ Create a snapshot
136
+
137
+ Args::
138
+
139
+ name: Snapshot name
140
+ level: Snapshot level (SnapshotLevel enum or string)
141
+ database: Database name (for database/table level)
142
+ table: Table name (for table level)
143
+ description: Snapshot description
144
+ executor: Optional executor (e.g., transaction wrapper)
145
+
146
+ Returns::
147
+
148
+ Snapshot object
149
+ """
150
+ if not self.client._engine:
151
+ raise ConnectionError("Not connected to database")
152
+
153
+ # Convert string to enum if needed
154
+ if isinstance(level, str):
155
+ try:
156
+ level_enum = SnapshotLevel(level.lower())
157
+ except ValueError:
158
+ raise SnapshotError(f"Invalid snapshot level: {level}")
159
+ else:
160
+ level_enum = level
161
+
162
+ # Build CREATE SNAPSHOT SQL using correct MatrixOne syntax
163
+ if level_enum == SnapshotLevel.CLUSTER:
164
+ sql = f"CREATE SNAPSHOT {name} FOR CLUSTER"
165
+ elif level_enum == SnapshotLevel.ACCOUNT:
166
+ sql = f"CREATE SNAPSHOT {name} FOR ACCOUNT"
167
+ elif level_enum == SnapshotLevel.DATABASE:
168
+ if not database:
169
+ raise SnapshotError("Database name required for database level snapshot")
170
+ sql = f"CREATE SNAPSHOT {name} FOR DATABASE {database}"
171
+ elif level_enum == SnapshotLevel.TABLE:
172
+ if not database or not table:
173
+ raise SnapshotError("Database and table names required for table level snapshot")
174
+ sql = f"CREATE SNAPSHOT {name} FOR TABLE {database} {table}"
175
+
176
+ # Note: MatrixOne doesn't support COMMENT in CREATE SNAPSHOT
177
+ # if description:
178
+ # sql += f" COMMENT '{description}'"
179
+
180
+ try:
181
+ # Use provided executor or default client execute
182
+ execute_func = executor.execute if executor else self.client.execute
183
+ execute_func(sql)
184
+
185
+ # Get snapshot info
186
+ snapshot_info = self.get(name, executor=executor)
187
+ return snapshot_info
188
+
189
+ except Exception as e:
190
+ raise SnapshotError(f"Failed to create snapshot: {e}") from None
191
+
192
+ def list(self) -> List[Snapshot]:
193
+ """
194
+ List all snapshots
195
+
196
+ Returns::
197
+
198
+ List of Snapshot objects
199
+ """
200
+ if not self.client._engine:
201
+ raise ConnectionError("Not connected to database")
202
+
203
+ try:
204
+ # Query snapshot information using mo_catalog.mo_snapshots
205
+ result = self.client.execute(
206
+ """
207
+ SELECT sname, ts, level, account_name, database_name, table_name
208
+ FROM mo_catalog.mo_snapshots
209
+ ORDER BY ts DESC
210
+ """
211
+ )
212
+
213
+ snapshots = []
214
+ for row in result.fetchall():
215
+ # Convert timestamp to datetime
216
+ timestamp = datetime.fromtimestamp(row[1] / 1000000000) # Convert nanoseconds to seconds
217
+
218
+ # Convert level string to enum
219
+ level_str = row[2]
220
+ try:
221
+ level_enum = SnapshotLevel(level_str.lower())
222
+ except ValueError:
223
+ # If enum conversion fails, keep as string for backward compatibility
224
+ level_enum = level_str
225
+
226
+ snapshot = Snapshot(
227
+ name=row[0], # sname
228
+ level=level_enum, # level (now as enum)
229
+ created_at=timestamp, # ts
230
+ description=None, # Not available
231
+ database=row[4], # database_name
232
+ table=row[5], # table_name
233
+ )
234
+ snapshots.append(snapshot)
235
+
236
+ return snapshots
237
+
238
+ except Exception as e:
239
+ raise SnapshotError(f"Failed to list snapshots: {e}") from None
240
+
241
+ def get(self, name: str, executor=None) -> Snapshot:
242
+ """
243
+ Get snapshot by name
244
+
245
+ Args::
246
+
247
+ name: Snapshot name
248
+ executor: Optional executor (e.g., transaction wrapper)
249
+
250
+ Returns::
251
+
252
+ Snapshot object
253
+ """
254
+ if not self.client._engine:
255
+ raise ConnectionError("Not connected to database")
256
+
257
+ try:
258
+ # Use provided executor or default client execute
259
+ execute_func = executor.execute if executor else self.client.execute
260
+ result = execute_func(
261
+ """
262
+ SELECT sname, ts, level, account_name, database_name, table_name
263
+ FROM mo_catalog.mo_snapshots
264
+ WHERE sname = :name
265
+ """,
266
+ {"name": name},
267
+ )
268
+
269
+ row = result.fetchone()
270
+ if not row:
271
+ raise SnapshotError(f"Snapshot '{name}' not found")
272
+
273
+ # Convert timestamp to datetime
274
+ timestamp = datetime.fromtimestamp(row[1] / 1000000000) # Convert nanoseconds to seconds
275
+
276
+ # Convert level string to enum
277
+ level_str = row[2]
278
+ try:
279
+ level_enum = SnapshotLevel(level_str.lower())
280
+ except ValueError:
281
+ # If enum conversion fails, keep as string for backward compatibility
282
+ level_enum = level_str
283
+
284
+ return Snapshot(
285
+ name=row[0], # sname
286
+ level=level_enum, # level (now as enum)
287
+ created_at=timestamp, # ts
288
+ description=None, # Not available
289
+ database=row[4], # database_name
290
+ table=row[5], # table_name
291
+ )
292
+
293
+ except Exception as e:
294
+ if "not found" in str(e):
295
+ raise e
296
+ raise SnapshotError(f"Failed to get snapshot: {e}")
297
+
298
+ def delete(self, name: str, executor=None) -> None:
299
+ """
300
+ Delete snapshot
301
+
302
+ Args::
303
+
304
+ name: Snapshot name
305
+ executor: Optional executor (e.g., transaction wrapper)
306
+ """
307
+ if not self.client._engine:
308
+ raise ConnectionError("Not connected to database")
309
+
310
+ try:
311
+ # Use provided executor or default client execute
312
+ execute_func = executor.execute if executor else self.client.execute
313
+ execute_func(f"DROP SNAPSHOT {name}")
314
+ except Exception as e:
315
+ raise SnapshotError(f"Failed to delete snapshot: {e}") from None
316
+
317
+ def exists(self, name: str) -> bool:
318
+ """
319
+ Check if snapshot exists
320
+
321
+ Args::
322
+
323
+ name: Snapshot name
324
+
325
+ Returns::
326
+
327
+ True if snapshot exists, False otherwise
328
+ """
329
+ try:
330
+ self.get(name)
331
+ return True
332
+ except SnapshotError:
333
+ return False
334
+
335
+
336
+ class CloneManager:
337
+ """
338
+ Clone management for MatrixOne database operations.
339
+
340
+ This class provides comprehensive database cloning functionality for creating
341
+ copies of databases, tables, or data subsets. Cloning enables efficient
342
+ data replication, testing environments, and data distribution scenarios.
343
+
344
+ Key Features:
345
+
346
+ - Database cloning with full data replication
347
+ - Table-level cloning for specific data subsets
348
+ - Efficient cloning using MatrixOne's native capabilities
349
+ - Integration with snapshot and restore operations
350
+ - Transaction-aware cloning operations
351
+ - Support for both full and incremental cloning
352
+
353
+ Supported Cloning Levels:
354
+ - DATABASE: Full database cloning with all tables and data
355
+ - TABLE: Table-level cloning with data replication
356
+ - SUBSET: Partial data cloning based on conditions
357
+
358
+ Usage Examples::
359
+
360
+ # Initialize clone manager
361
+ clone = client.clone
362
+
363
+ # Clone entire database
364
+ success = clone.clone_database(
365
+ target_database='cloned_database',
366
+ source_database='source_database'
367
+ )
368
+
369
+ # Clone table with data
370
+ success = clone.clone_table(
371
+ target_database='cloned_database',
372
+ target_table='cloned_users',
373
+ source_database='source_database',
374
+ source_table='users'
375
+ )
376
+
377
+ # Clone table with conditions
378
+ success = clone.clone_table_with_conditions(
379
+ target_database='cloned_database',
380
+ target_table='active_users',
381
+ source_database='source_database',
382
+ source_table='users',
383
+ conditions='active = 1'
384
+ )
385
+
386
+ # List clone operations
387
+ clones = clone.list_clones()
388
+
389
+ # Get clone status
390
+ status = clone.get_clone_status('clone_job_id')
391
+
392
+ Note: Cloning functionality requires MatrixOne version 1.0.0 or higher. Clone operations may
393
+ take significant time depending on the amount of data being cloned and database complexity.
394
+ """
395
+
396
+ def __init__(self, client):
397
+ self.client = client
398
+
399
+ @requires_version(
400
+ min_version="1.0.0",
401
+ feature_name="database_cloning",
402
+ description="Database cloning functionality",
403
+ alternative="Use CREATE DATABASE and data migration instead",
404
+ )
405
+ def clone_database(
406
+ self,
407
+ target_db: str,
408
+ source_db: str,
409
+ snapshot_name: Optional[str] = None,
410
+ if_not_exists: bool = False,
411
+ executor=None,
412
+ ) -> None:
413
+ """
414
+ Clone a database
415
+
416
+ Args::
417
+
418
+ target_db: Target database name
419
+ source_db: Source database name
420
+ snapshot_name: Optional snapshot name for point-in-time clone
421
+ if_not_exists: Use IF NOT EXISTS clause
422
+ executor: Optional executor (e.g., transaction wrapper)
423
+
424
+ Raises::
425
+
426
+ ConnectionError: If not connected to database
427
+ CloneError: If clone operation fails
428
+ """
429
+ if not self.client._engine:
430
+ raise ConnectionError("Not connected to database")
431
+
432
+ # Build CLONE DATABASE SQL
433
+ if_not_exists_clause = "IF NOT EXISTS " if if_not_exists else ""
434
+
435
+ if snapshot_name:
436
+ sql = f"CREATE DATABASE {if_not_exists_clause}{target_db} CLONE {source_db} {{snapshot = '{snapshot_name}'}}"
437
+ else:
438
+ sql = f"CREATE DATABASE {if_not_exists_clause}{target_db} CLONE {source_db}"
439
+
440
+ try:
441
+ # Use provided executor or default client execute
442
+ execute_func = executor.execute if executor else self.client.execute
443
+ execute_func(sql)
444
+ except Exception as e:
445
+ raise CloneError(f"Failed to clone database: {e}") from None
446
+
447
+ def clone_table(
448
+ self,
449
+ target_table: str,
450
+ source_table: str,
451
+ snapshot_name: Optional[str] = None,
452
+ if_not_exists: bool = False,
453
+ executor=None,
454
+ ) -> None:
455
+ """
456
+ Clone a table
457
+
458
+ Args::
459
+
460
+ target_table: Target table name (can include database: db.table)
461
+ source_table: Source table name (can include database: db.table)
462
+ snapshot_name: Optional snapshot name for point-in-time clone
463
+ if_not_exists: Use IF NOT EXISTS clause
464
+ executor: Optional executor (e.g., transaction wrapper)
465
+
466
+ Raises::
467
+
468
+ ConnectionError: If not connected to database
469
+ CloneError: If clone operation fails
470
+ """
471
+ if not self.client._engine:
472
+ raise ConnectionError("Not connected to database")
473
+
474
+ # Build CLONE TABLE SQL
475
+ if_not_exists_clause = "IF NOT EXISTS " if if_not_exists else ""
476
+
477
+ if snapshot_name:
478
+ sql = (
479
+ f"CREATE TABLE {if_not_exists_clause}{target_table} "
480
+ f"CLONE {source_table} {{snapshot = '{snapshot_name}'}}"
481
+ )
482
+ else:
483
+ sql = f"CREATE TABLE {if_not_exists_clause}{target_table} CLONE {source_table}"
484
+
485
+ try:
486
+ # Use provided executor or default client execute
487
+ execute_func = executor.execute if executor else self.client.execute
488
+ execute_func(sql)
489
+ except Exception as e:
490
+ raise CloneError(f"Failed to clone table: {e}") from None
491
+
492
+ def clone_database_with_snapshot(
493
+ self,
494
+ target_db: str,
495
+ source_db: str,
496
+ snapshot_name: str,
497
+ if_not_exists: bool = False,
498
+ executor=None,
499
+ ) -> None:
500
+ """
501
+ Clone a database using a specific snapshot
502
+
503
+ Args::
504
+
505
+ target_db: Target database name
506
+ source_db: Source database name
507
+ snapshot_name: Snapshot name for point-in-time clone
508
+ if_not_exists: Use IF NOT EXISTS clause
509
+ executor: Optional executor (e.g., transaction wrapper)
510
+
511
+ Raises::
512
+
513
+ ConnectionError: If not connected to database
514
+ CloneError: If clone operation fails or snapshot doesn't exist
515
+ """
516
+ # Verify snapshot exists using snapshot manager
517
+ if not self.client.snapshots.exists(snapshot_name):
518
+ raise CloneError(f"Snapshot '{snapshot_name}' does not exist")
519
+
520
+ self.clone_database(target_db, source_db, snapshot_name, if_not_exists, executor)
521
+
522
+ def clone_table_with_snapshot(
523
+ self,
524
+ target_table: str,
525
+ source_table: str,
526
+ snapshot_name: str,
527
+ if_not_exists: bool = False,
528
+ executor=None,
529
+ ) -> None:
530
+ """
531
+ Clone a table using a specific snapshot
532
+
533
+ Args::
534
+
535
+ target_table: Target table name (can include database: db.table)
536
+ source_table: Source table name (can include database: db.table)
537
+ snapshot_name: Snapshot name for point-in-time clone
538
+ if_not_exists: Use IF NOT EXISTS clause
539
+ executor: Optional executor (e.g., transaction wrapper)
540
+
541
+ Raises::
542
+
543
+ ConnectionError: If not connected to database
544
+ CloneError: If clone operation fails or snapshot doesn't exist
545
+ """
546
+ # Verify snapshot exists using snapshot manager
547
+ if not self.client.snapshots.exists(snapshot_name):
548
+ raise CloneError(f"Snapshot '{snapshot_name}' does not exist")
549
+
550
+ self.clone_table(target_table, source_table, snapshot_name, if_not_exists, executor)