vgi-python 0.8.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 (124) hide show
  1. vgi/__init__.py +152 -0
  2. vgi/_duckdb.py +62 -0
  3. vgi/_storage_profile.py +132 -0
  4. vgi/_test_fixtures/__init__.py +20 -0
  5. vgi/_test_fixtures/accumulate/__init__.py +19 -0
  6. vgi/_test_fixtures/accumulate/worker.py +762 -0
  7. vgi/_test_fixtures/aggregate/__init__.py +62 -0
  8. vgi/_test_fixtures/aggregate/_common.py +21 -0
  9. vgi/_test_fixtures/aggregate/basic.py +232 -0
  10. vgi/_test_fixtures/aggregate/dynamic.py +409 -0
  11. vgi/_test_fixtures/aggregate/generic.py +86 -0
  12. vgi/_test_fixtures/aggregate/listagg.py +71 -0
  13. vgi/_test_fixtures/aggregate/percentile.py +107 -0
  14. vgi/_test_fixtures/aggregate/streaming.py +192 -0
  15. vgi/_test_fixtures/aggregate/varargs.py +75 -0
  16. vgi/_test_fixtures/aggregate/window.py +380 -0
  17. vgi/_test_fixtures/attach_options.py +308 -0
  18. vgi/_test_fixtures/bad_protocol.py +62 -0
  19. vgi/_test_fixtures/cancellable.py +336 -0
  20. vgi/_test_fixtures/catalog.py +813 -0
  21. vgi/_test_fixtures/http_server.py +394 -0
  22. vgi/_test_fixtures/nest_tensor.py +614 -0
  23. vgi/_test_fixtures/orchard_catalog.py +47 -0
  24. vgi/_test_fixtures/projection_repro/__init__.py +6 -0
  25. vgi/_test_fixtures/projection_repro/worker.py +454 -0
  26. vgi/_test_fixtures/scalar/__init__.py +116 -0
  27. vgi/_test_fixtures/scalar/_common.py +69 -0
  28. vgi/_test_fixtures/scalar/arithmetic.py +321 -0
  29. vgi/_test_fixtures/scalar/binary.py +120 -0
  30. vgi/_test_fixtures/scalar/formatting.py +176 -0
  31. vgi/_test_fixtures/scalar/geo.py +300 -0
  32. vgi/_test_fixtures/scalar/null_handling.py +107 -0
  33. vgi/_test_fixtures/scalar/random_demo.py +171 -0
  34. vgi/_test_fixtures/scalar/settings_secrets.py +102 -0
  35. vgi/_test_fixtures/scalar/type_info.py +219 -0
  36. vgi/_test_fixtures/schema_reconcile/__init__.py +29 -0
  37. vgi/_test_fixtures/schema_reconcile/worker.py +653 -0
  38. vgi/_test_fixtures/simple_writable.py +793 -0
  39. vgi/_test_fixtures/table/__init__.py +221 -0
  40. vgi/_test_fixtures/table/_common.py +162 -0
  41. vgi/_test_fixtures/table/batch_index.py +283 -0
  42. vgi/_test_fixtures/table/batch_index_broken.py +200 -0
  43. vgi/_test_fixtures/table/catalog_scans.py +162 -0
  44. vgi/_test_fixtures/table/filters.py +1005 -0
  45. vgi/_test_fixtures/table/late_materialization.py +249 -0
  46. vgi/_test_fixtures/table/make_series.py +273 -0
  47. vgi/_test_fixtures/table/misc.py +499 -0
  48. vgi/_test_fixtures/table/order_modes.py +164 -0
  49. vgi/_test_fixtures/table/pairs.py +437 -0
  50. vgi/_test_fixtures/table/partition_columns.py +472 -0
  51. vgi/_test_fixtures/table/partition_columns_broken.py +304 -0
  52. vgi/_test_fixtures/table/profiling_example.py +195 -0
  53. vgi/_test_fixtures/table/required_filters.py +234 -0
  54. vgi/_test_fixtures/table/sequence.py +710 -0
  55. vgi/_test_fixtures/table/settings.py +426 -0
  56. vgi/_test_fixtures/table/transaction_storage.py +162 -0
  57. vgi/_test_fixtures/table/tt_pushdown.py +191 -0
  58. vgi/_test_fixtures/table/versioned.py +230 -0
  59. vgi/_test_fixtures/table_in_out.py +1392 -0
  60. vgi/_test_fixtures/versioned.py +155 -0
  61. vgi/_test_fixtures/versioned_tables.py +595 -0
  62. vgi/_test_fixtures/worker.py +1631 -0
  63. vgi/_test_fixtures/writable/__init__.py +8 -0
  64. vgi/_test_fixtures/writable/generic.py +236 -0
  65. vgi/_test_fixtures/writable/table.py +149 -0
  66. vgi/_test_fixtures/writable/worker.py +1148 -0
  67. vgi/aggregate_function.py +607 -0
  68. vgi/argument_spec.py +472 -0
  69. vgi/arguments.py +1747 -0
  70. vgi/auth.py +55 -0
  71. vgi/catalog/__init__.py +88 -0
  72. vgi/catalog/attach_option.py +206 -0
  73. vgi/catalog/catalog_interface.py +2767 -0
  74. vgi/catalog/descriptors.py +870 -0
  75. vgi/catalog/duckdb_statistics.py +377 -0
  76. vgi/catalog/secret_type.py +96 -0
  77. vgi/catalog/setting.py +253 -0
  78. vgi/catalog/storage.py +372 -0
  79. vgi/client/__init__.py +67 -0
  80. vgi/client/catalog_mixin.py +1251 -0
  81. vgi/client/cli.py +582 -0
  82. vgi/client/cli_catalog.py +182 -0
  83. vgi/client/cli_schema.py +270 -0
  84. vgi/client/cli_table.py +907 -0
  85. vgi/client/cli_transaction.py +97 -0
  86. vgi/client/cli_utils.py +441 -0
  87. vgi/client/cli_view.py +303 -0
  88. vgi/client/client.py +2183 -0
  89. vgi/exceptions.py +205 -0
  90. vgi/function.py +245 -0
  91. vgi/function_storage.py +1636 -0
  92. vgi/function_storage_azure_sql.py +922 -0
  93. vgi/function_storage_cf_do.py +740 -0
  94. vgi/http/__init__.py +25 -0
  95. vgi/http/demo_storage.py +212 -0
  96. vgi/http/worker_page.py +1252 -0
  97. vgi/invocation.py +154 -0
  98. vgi/logging_config.py +93 -0
  99. vgi/meta_worker.py +661 -0
  100. vgi/metadata.py +1403 -0
  101. vgi/otel.py +406 -0
  102. vgi/protocol.py +2418 -0
  103. vgi/protocol_version.txt +1 -0
  104. vgi/py.typed +0 -0
  105. vgi/scalar_function.py +1211 -0
  106. vgi/schema_utils.py +234 -0
  107. vgi/secret_protocol.py +124 -0
  108. vgi/secret_service.py +238 -0
  109. vgi/serve.py +769 -0
  110. vgi/table_buffering_function.py +443 -0
  111. vgi/table_filter_pushdown.py +1528 -0
  112. vgi/table_function.py +1130 -0
  113. vgi/table_in_out_function.py +383 -0
  114. vgi/transactor/__init__.py +24 -0
  115. vgi/transactor/_duckdb_compat.py +27 -0
  116. vgi/transactor/client.py +137 -0
  117. vgi/transactor/protocol.py +149 -0
  118. vgi/transactor/server.py +740 -0
  119. vgi/worker.py +4761 -0
  120. vgi_python-0.8.0.dist-info/METADATA +735 -0
  121. vgi_python-0.8.0.dist-info/RECORD +124 -0
  122. vgi_python-0.8.0.dist-info/WHEEL +4 -0
  123. vgi_python-0.8.0.dist-info/entry_points.txt +5 -0
  124. vgi_python-0.8.0.dist-info/licenses/LICENSE +134 -0
@@ -0,0 +1,1251 @@
1
+ # Copyright 2025, 2026 Query Farm LLC - https://query.farm
2
+
3
+ """CatalogClientMixin for adding catalog operations to Client.
4
+
5
+ This module provides a mixin class that adds catalog operation methods
6
+ to the VGI Client. It handles the ephemeral subprocess pattern for
7
+ catalog calls while using the Client's server_path and correlation_id.
8
+
9
+ Usage:
10
+ class CatalogEnabledClient(CatalogClientMixin, Client):
11
+ pass
12
+
13
+ client = CatalogEnabledClient("vgi-my-worker")
14
+
15
+ # List available catalogs
16
+ catalogs = client.catalogs()
17
+
18
+ # Attach to a catalog and work with schemas
19
+ result = client.catalog_attach(
20
+ name="my_catalog", data_version_spec=None, implementation_version=None
21
+ )
22
+ schemas = client.schemas(attach_opaque_data=result.attach_opaque_data)
23
+
24
+ # Use transactions for atomic operations
25
+ tx_id = client.catalog_transaction_begin(attach_opaque_data=result.attach_opaque_data)
26
+ client.schema_create(
27
+ attach_opaque_data=result.attach_opaque_data, transaction_opaque_data=tx_id, name="new_schema"
28
+ )
29
+ client.catalog_transaction_commit(
30
+ attach_opaque_data=result.attach_opaque_data, transaction_opaque_data=tx_id
31
+ )
32
+
33
+ Error Handling:
34
+ Worker exceptions are propagated via vgi_rpc's RpcError mechanism.
35
+ These are wrapped in CatalogClientError for a consistent client API.
36
+
37
+ """
38
+
39
+ from __future__ import annotations
40
+
41
+ import shlex
42
+ import sys
43
+ from collections.abc import Iterator, Sequence
44
+ from contextlib import contextmanager
45
+ from typing import Any, Literal, overload
46
+
47
+ import pyarrow as pa
48
+ from vgi_rpc import WorkerPool
49
+ from vgi_rpc.rpc import RpcError
50
+ from vgi_rpc.utils import deserialize_record_batch
51
+
52
+ from vgi.catalog import (
53
+ AttachOpaqueData,
54
+ CatalogAttachResult,
55
+ CatalogInfo,
56
+ FunctionInfo,
57
+ MacroInfo,
58
+ MacroType,
59
+ OnConflict,
60
+ ScanFunctionResult,
61
+ SchemaInfo,
62
+ SchemaObjectType,
63
+ SerializedSchema,
64
+ SqlExpression,
65
+ TableInfo,
66
+ TransactionOpaqueData,
67
+ ViewInfo,
68
+ )
69
+ from vgi.protocol import (
70
+ CatalogAttachRequest,
71
+ CatalogCreateRequest,
72
+ MacroCreateRequest,
73
+ TableCreateRequest,
74
+ VgiProtocol,
75
+ )
76
+
77
+ # Module-level worker pool shared across all CatalogClientMixin instances.
78
+ # Workers are cached by command and reused across catalog calls, avoiding
79
+ # the overhead of spawning/tearing down a subprocess for each call.
80
+ _catalog_pool = WorkerPool(max_idle=4, idle_timeout=30.0)
81
+
82
+
83
+ class CatalogClientError(Exception):
84
+ """Error raised by catalog operations."""
85
+
86
+
87
+ class CatalogClientMixin:
88
+ """Mixin that adds catalog operations to a VGI Client.
89
+
90
+ Catalog methods spawn ephemeral connections under the hood — for
91
+ subprocess transport a pooled subprocess worker; for HTTP transport a
92
+ short-lived ``http_connect`` session reusing the ``Client``'s shared
93
+ ``httpx.Client`` (bearer token, headers). Browsing catalogs over HTTP
94
+ is the canonical non-DuckDB use case this mixin supports.
95
+
96
+ Expected attributes from ``Client``:
97
+ server_path: str — worker shell command (subprocess transport).
98
+ _transport: Literal["subprocess", "http"].
99
+ _base_url: str | None — HTTP base URL.
100
+ _get_or_create_httpx_client(): shared HTTP client factory.
101
+ """
102
+
103
+ # Type hints for attributes expected from Client
104
+ server_path: str
105
+ _transport: Literal["subprocess", "http"]
106
+ _base_url: str | None
107
+ _external_location: Any | None
108
+
109
+ def _get_or_create_httpx_client(self) -> Any: # implemented by Client
110
+ raise NotImplementedError
111
+
112
+ @contextmanager
113
+ def _catalog_connect(self) -> Iterator[VgiProtocol]:
114
+ """Yield a typed ``VgiProtocol`` proxy honoring the client's transport.
115
+
116
+ Subprocess: borrows from a module-level ``WorkerPool`` keyed by
117
+ command, so repeated catalog calls reuse a warm worker.
118
+
119
+ HTTP: opens a short-lived ``http_connect`` session per call. The
120
+ underlying ``httpx.Client`` is shared across calls via
121
+ ``Client._get_or_create_httpx_client`` so auth headers and
122
+ connection pooling are consistent.
123
+
124
+ Worker errors are caught and re-raised as ``CatalogClientError``.
125
+ """
126
+ try:
127
+ if getattr(self, "_transport", "subprocess") == "http":
128
+ from vgi_rpc.http import http_connect
129
+
130
+ httpx_client = self._get_or_create_httpx_client()
131
+ with http_connect(
132
+ VgiProtocol, # type: ignore[type-abstract]
133
+ base_url=self._base_url,
134
+ client=httpx_client,
135
+ external_location=getattr(self, "_external_location", None),
136
+ ) as proxy:
137
+ yield proxy
138
+ else:
139
+ cmd = shlex.split(self.server_path, posix=sys.platform != "win32")
140
+ with _catalog_pool.connect(VgiProtocol, cmd) as proxy: # type: ignore[type-abstract]
141
+ yield proxy
142
+ except RpcError as e:
143
+ raise CatalogClientError(str(e)) from e
144
+ except CatalogClientError:
145
+ raise
146
+ except Exception as e:
147
+ raise CatalogClientError(f"Failed catalog call: {e}") from e
148
+
149
+ @staticmethod
150
+ def _options_to_batch(options: dict[str, Any] | None) -> pa.RecordBatch | None:
151
+ """Convert an options dict to a one-row RecordBatch for wire transport.
152
+
153
+ Returns None if options is empty/None.
154
+ """
155
+ if not options:
156
+ return None
157
+ return pa.RecordBatch.from_pylist([options])
158
+
159
+ # ========== Discovery Methods ==========
160
+
161
+ def catalogs(self) -> list[CatalogInfo]:
162
+ """Get list of catalog discovery records from the worker.
163
+
164
+ Returns:
165
+ List of CatalogInfo records carrying per-catalog name,
166
+ implementation_version, and data_version_spec.
167
+
168
+ """
169
+ with self._catalog_connect() as proxy:
170
+ return proxy.catalog_catalogs().to_infos()
171
+
172
+ # ========== Catalog Lifecycle Methods ==========
173
+
174
+ def catalog_attach(
175
+ self,
176
+ *,
177
+ name: str,
178
+ options: dict[str, Any] | None = None,
179
+ data_version_spec: str | None,
180
+ implementation_version: str | None,
181
+ ) -> CatalogAttachResult:
182
+ """Attach to a catalog.
183
+
184
+ Args:
185
+ name: The catalog name to attach to.
186
+ options: Optional dictionary of catalog-specific options.
187
+ data_version_spec: Semver constraint for the catalog's data version
188
+ (``None`` = unconstrained — worker picks).
189
+ implementation_version: Semver constraint for the worker's
190
+ implementation version (``None`` = unconstrained).
191
+
192
+ Returns:
193
+ CatalogAttachResult with attach_opaque_data, catalog capabilities, and
194
+ the resolved concrete versions the worker picked.
195
+
196
+ """
197
+ with self._catalog_connect() as proxy:
198
+ return proxy.catalog_attach(
199
+ request=CatalogAttachRequest(
200
+ name=name,
201
+ options=self._options_to_batch(options),
202
+ data_version_spec=data_version_spec,
203
+ implementation_version=implementation_version,
204
+ )
205
+ )
206
+
207
+ def catalog_detach(self, *, attach_opaque_data: AttachOpaqueData) -> None:
208
+ """Detach from a catalog.
209
+
210
+ Args:
211
+ attach_opaque_data: The attachment ID from catalog_attach.
212
+
213
+ """
214
+ with self._catalog_connect() as proxy:
215
+ proxy.catalog_detach(attach_opaque_data=attach_opaque_data)
216
+
217
+ def catalog_create(
218
+ self,
219
+ *,
220
+ name: str,
221
+ on_conflict: OnConflict = OnConflict.ERROR,
222
+ options: dict[str, Any] | None = None,
223
+ ) -> None:
224
+ """Create a new catalog.
225
+
226
+ Args:
227
+ name: The name for the new catalog.
228
+ on_conflict: Behavior if catalog already exists.
229
+ options: Optional dictionary of catalog-specific options.
230
+
231
+ """
232
+ with self._catalog_connect() as proxy:
233
+ proxy.catalog_create(
234
+ request=CatalogCreateRequest(
235
+ name=name,
236
+ on_conflict=on_conflict,
237
+ options=self._options_to_batch(options),
238
+ )
239
+ )
240
+
241
+ def catalog_drop(self, *, name: str) -> None:
242
+ """Drop a catalog.
243
+
244
+ Args:
245
+ name: The name of the catalog to drop.
246
+
247
+ """
248
+ with self._catalog_connect() as proxy:
249
+ proxy.catalog_drop(name=name)
250
+
251
+ def catalog_version(
252
+ self, *, attach_opaque_data: AttachOpaqueData, transaction_opaque_data: TransactionOpaqueData | None = None
253
+ ) -> int:
254
+ """Get the current catalog version.
255
+
256
+ Args:
257
+ attach_opaque_data: The attachment ID from catalog_attach.
258
+ transaction_opaque_data: Optional transaction ID for transactional reads.
259
+
260
+ Returns:
261
+ The current catalog version number, or 0 if empty.
262
+
263
+ """
264
+ with self._catalog_connect() as proxy:
265
+ return proxy.catalog_version(
266
+ attach_opaque_data=attach_opaque_data,
267
+ transaction_opaque_data=transaction_opaque_data,
268
+ ).version
269
+
270
+ # ========== Transaction Methods ==========
271
+
272
+ def catalog_transaction_begin(self, *, attach_opaque_data: AttachOpaqueData) -> TransactionOpaqueData | None:
273
+ """Begin a new transaction.
274
+
275
+ Args:
276
+ attach_opaque_data: The attachment ID from catalog_attach.
277
+
278
+ Returns:
279
+ TransactionOpaqueData for the new transaction, or None if transactions
280
+ are not supported by this catalog.
281
+
282
+ """
283
+ with self._catalog_connect() as proxy:
284
+ tx_id = proxy.catalog_transaction_begin(attach_opaque_data=attach_opaque_data).transaction_opaque_data
285
+ return TransactionOpaqueData(tx_id) if tx_id else None
286
+
287
+ def catalog_transaction_commit(
288
+ self, *, attach_opaque_data: AttachOpaqueData, transaction_opaque_data: TransactionOpaqueData
289
+ ) -> None:
290
+ """Commit a transaction.
291
+
292
+ Args:
293
+ attach_opaque_data: The attachment ID from catalog_attach.
294
+ transaction_opaque_data: The transaction ID to commit.
295
+
296
+ """
297
+ with self._catalog_connect() as proxy:
298
+ proxy.catalog_transaction_commit(
299
+ attach_opaque_data=attach_opaque_data,
300
+ transaction_opaque_data=transaction_opaque_data,
301
+ )
302
+
303
+ def catalog_transaction_rollback(
304
+ self, *, attach_opaque_data: AttachOpaqueData, transaction_opaque_data: TransactionOpaqueData
305
+ ) -> None:
306
+ """Rollback a transaction.
307
+
308
+ Args:
309
+ attach_opaque_data: The attachment ID from catalog_attach.
310
+ transaction_opaque_data: The transaction ID to rollback.
311
+
312
+ """
313
+ with self._catalog_connect() as proxy:
314
+ proxy.catalog_transaction_rollback(
315
+ attach_opaque_data=attach_opaque_data,
316
+ transaction_opaque_data=transaction_opaque_data,
317
+ )
318
+
319
+ # ========== Schema Methods ==========
320
+
321
+ def schemas(
322
+ self, *, attach_opaque_data: AttachOpaqueData, transaction_opaque_data: TransactionOpaqueData | None = None
323
+ ) -> list[SchemaInfo]:
324
+ """List schemas in the catalog.
325
+
326
+ Args:
327
+ attach_opaque_data: The attachment ID from catalog_attach.
328
+ transaction_opaque_data: Optional transaction ID for transactional reads.
329
+
330
+ Returns:
331
+ List of SchemaInfo for each schema in the catalog.
332
+
333
+ """
334
+ with self._catalog_connect() as proxy:
335
+ return proxy.catalog_schemas(
336
+ attach_opaque_data=attach_opaque_data,
337
+ transaction_opaque_data=transaction_opaque_data,
338
+ ).to_infos()
339
+
340
+ def schema_get(
341
+ self,
342
+ *,
343
+ attach_opaque_data: AttachOpaqueData,
344
+ transaction_opaque_data: TransactionOpaqueData | None = None,
345
+ name: str,
346
+ ) -> SchemaInfo | None:
347
+ """Get information about a schema.
348
+
349
+ Args:
350
+ attach_opaque_data: The attachment ID from catalog_attach.
351
+ transaction_opaque_data: Optional transaction ID for transactional reads.
352
+ name: The schema name.
353
+
354
+ Returns:
355
+ SchemaInfo for the schema, or None if not found.
356
+
357
+ """
358
+ with self._catalog_connect() as proxy:
359
+ return proxy.catalog_schema_get( # type: ignore[no-any-return]
360
+ attach_opaque_data=attach_opaque_data,
361
+ name=name,
362
+ transaction_opaque_data=transaction_opaque_data,
363
+ ).to_optional()
364
+
365
+ def schema_create(
366
+ self,
367
+ *,
368
+ attach_opaque_data: AttachOpaqueData,
369
+ transaction_opaque_data: TransactionOpaqueData | None = None,
370
+ name: str,
371
+ comment: str | None = None,
372
+ tags: dict[str, str] | None = None,
373
+ ) -> None:
374
+ """Create a new schema.
375
+
376
+ Args:
377
+ attach_opaque_data: The attachment ID from catalog_attach.
378
+ transaction_opaque_data: Optional transaction ID.
379
+ name: The name for the new schema.
380
+ comment: Optional description of the schema.
381
+ tags: Optional key-value tags for the schema.
382
+
383
+ """
384
+ with self._catalog_connect() as proxy:
385
+ proxy.catalog_schema_create(
386
+ attach_opaque_data=attach_opaque_data,
387
+ name=name,
388
+ comment=comment,
389
+ tags=tags,
390
+ transaction_opaque_data=transaction_opaque_data,
391
+ )
392
+
393
+ def schema_drop(
394
+ self,
395
+ *,
396
+ attach_opaque_data: AttachOpaqueData,
397
+ transaction_opaque_data: TransactionOpaqueData | None = None,
398
+ name: str,
399
+ ignore_not_found: bool = False,
400
+ cascade: bool = False,
401
+ ) -> None:
402
+ """Drop a schema.
403
+
404
+ Args:
405
+ attach_opaque_data: The attachment ID from catalog_attach.
406
+ transaction_opaque_data: Optional transaction ID.
407
+ name: The name of the schema to drop.
408
+ ignore_not_found: If True, don't error if schema doesn't exist.
409
+ cascade: If True, drop all contained tables and views.
410
+
411
+ """
412
+ with self._catalog_connect() as proxy:
413
+ proxy.catalog_schema_drop(
414
+ attach_opaque_data=attach_opaque_data,
415
+ name=name,
416
+ ignore_not_found=ignore_not_found,
417
+ cascade=cascade,
418
+ transaction_opaque_data=transaction_opaque_data,
419
+ )
420
+
421
+ @overload
422
+ def schema_contents(
423
+ self,
424
+ *,
425
+ attach_opaque_data: AttachOpaqueData,
426
+ transaction_opaque_data: TransactionOpaqueData | None = None,
427
+ name: str,
428
+ type: Literal[SchemaObjectType.TABLE],
429
+ ) -> Sequence[TableInfo]: ...
430
+
431
+ @overload
432
+ def schema_contents(
433
+ self,
434
+ *,
435
+ attach_opaque_data: AttachOpaqueData,
436
+ transaction_opaque_data: TransactionOpaqueData | None = None,
437
+ name: str,
438
+ type: Literal[SchemaObjectType.VIEW],
439
+ ) -> Sequence[ViewInfo]: ...
440
+
441
+ @overload
442
+ def schema_contents(
443
+ self,
444
+ *,
445
+ attach_opaque_data: AttachOpaqueData,
446
+ transaction_opaque_data: TransactionOpaqueData | None = None,
447
+ name: str,
448
+ type: Literal[SchemaObjectType.SCALAR_FUNCTION, SchemaObjectType.TABLE_FUNCTION],
449
+ ) -> Sequence[FunctionInfo]: ...
450
+
451
+ @overload
452
+ def schema_contents(
453
+ self,
454
+ *,
455
+ attach_opaque_data: AttachOpaqueData,
456
+ transaction_opaque_data: TransactionOpaqueData | None = None,
457
+ name: str,
458
+ type: Literal[SchemaObjectType.SCALAR_MACRO, SchemaObjectType.TABLE_MACRO],
459
+ ) -> Sequence[MacroInfo]: ...
460
+
461
+ @overload
462
+ def schema_contents(
463
+ self,
464
+ *,
465
+ attach_opaque_data: AttachOpaqueData,
466
+ transaction_opaque_data: TransactionOpaqueData | None = None,
467
+ name: str,
468
+ type: SchemaObjectType,
469
+ ) -> Sequence[TableInfo | ViewInfo | FunctionInfo | MacroInfo]: ...
470
+
471
+ def schema_contents(
472
+ self,
473
+ *,
474
+ attach_opaque_data: AttachOpaqueData,
475
+ transaction_opaque_data: TransactionOpaqueData | None = None,
476
+ name: str,
477
+ type: SchemaObjectType,
478
+ ) -> Sequence[TableInfo | ViewInfo | FunctionInfo | MacroInfo]:
479
+ """List contents of a schema (tables, views, functions, macros).
480
+
481
+ Args:
482
+ attach_opaque_data: The attachment ID from catalog_attach.
483
+ transaction_opaque_data: Optional transaction ID for transactional reads.
484
+ name: The schema name.
485
+ type: The type of objects to return. Must be a SchemaObjectType enum:
486
+ - SchemaObjectType.TABLE: Return only tables
487
+ - SchemaObjectType.VIEW: Return only views
488
+ - SchemaObjectType.SCALAR_FUNCTION: Return only scalar functions
489
+ - SchemaObjectType.TABLE_FUNCTION: Return only table functions
490
+ - SchemaObjectType.SCALAR_MACRO: Return only scalar macros
491
+ - SchemaObjectType.TABLE_MACRO: Return only table macros
492
+
493
+ Returns:
494
+ List of TableInfo, ViewInfo, FunctionInfo, or MacroInfo depending on the type.
495
+
496
+ """
497
+ with self._catalog_connect() as proxy:
498
+ if type == SchemaObjectType.TABLE:
499
+ return proxy.catalog_schema_contents_tables(
500
+ attach_opaque_data=attach_opaque_data,
501
+ name=name,
502
+ transaction_opaque_data=transaction_opaque_data,
503
+ ).to_infos()
504
+ elif type == SchemaObjectType.VIEW:
505
+ return proxy.catalog_schema_contents_views(
506
+ attach_opaque_data=attach_opaque_data,
507
+ name=name,
508
+ transaction_opaque_data=transaction_opaque_data,
509
+ ).to_infos()
510
+ elif type in (SchemaObjectType.SCALAR_MACRO, SchemaObjectType.TABLE_MACRO):
511
+ return proxy.catalog_schema_contents_macros(
512
+ attach_opaque_data=attach_opaque_data,
513
+ name=name,
514
+ type=type,
515
+ transaction_opaque_data=transaction_opaque_data,
516
+ ).to_infos()
517
+ else:
518
+ return proxy.catalog_schema_contents_functions(
519
+ attach_opaque_data=attach_opaque_data,
520
+ name=name,
521
+ type=type,
522
+ transaction_opaque_data=transaction_opaque_data,
523
+ ).to_infos()
524
+
525
+ # ========== Table Methods ==========
526
+
527
+ def table_get(
528
+ self,
529
+ *,
530
+ attach_opaque_data: AttachOpaqueData,
531
+ transaction_opaque_data: TransactionOpaqueData | None = None,
532
+ schema_name: str,
533
+ name: str,
534
+ ) -> TableInfo | None:
535
+ """Get information about a table.
536
+
537
+ Args:
538
+ attach_opaque_data: The attachment ID from catalog_attach.
539
+ transaction_opaque_data: Optional transaction ID for transactional reads.
540
+ schema_name: The schema containing the table.
541
+ name: The table name.
542
+
543
+ Returns:
544
+ TableInfo for the table, or None if not found.
545
+
546
+ """
547
+ with self._catalog_connect() as proxy:
548
+ return proxy.catalog_table_get( # type: ignore[no-any-return]
549
+ attach_opaque_data=attach_opaque_data,
550
+ schema_name=schema_name,
551
+ name=name,
552
+ transaction_opaque_data=transaction_opaque_data,
553
+ ).to_optional()
554
+
555
+ def table_create(
556
+ self,
557
+ *,
558
+ attach_opaque_data: AttachOpaqueData,
559
+ transaction_opaque_data: TransactionOpaqueData | None = None,
560
+ schema_name: str,
561
+ name: str,
562
+ columns: SerializedSchema,
563
+ on_conflict: OnConflict = OnConflict.ERROR,
564
+ not_null_constraints: list[int] | None = None,
565
+ unique_constraints: list[list[int]] | None = None,
566
+ check_constraints: list[str] | None = None,
567
+ ) -> None:
568
+ """Create a new table.
569
+
570
+ Args:
571
+ attach_opaque_data: The attachment ID from catalog_attach.
572
+ transaction_opaque_data: Optional transaction ID.
573
+ schema_name: The schema to create the table in.
574
+ name: The name for the new table.
575
+ columns: Serialized PyArrow schema for the table columns.
576
+ on_conflict: Behavior if table already exists.
577
+ not_null_constraints: Column indices that must not be null.
578
+ unique_constraints: Lists of column indices for unique constraints.
579
+ check_constraints: SQL expressions for check constraints.
580
+
581
+ """
582
+ with self._catalog_connect() as proxy:
583
+ proxy.catalog_table_create(
584
+ request=TableCreateRequest(
585
+ attach_opaque_data=attach_opaque_data,
586
+ schema_name=schema_name,
587
+ name=name,
588
+ columns=columns,
589
+ on_conflict=on_conflict,
590
+ not_null_constraints=not_null_constraints or [],
591
+ unique_constraints=unique_constraints or [],
592
+ check_constraints=check_constraints or [],
593
+ transaction_opaque_data=transaction_opaque_data,
594
+ )
595
+ )
596
+
597
+ def table_drop(
598
+ self,
599
+ *,
600
+ attach_opaque_data: AttachOpaqueData,
601
+ transaction_opaque_data: TransactionOpaqueData | None = None,
602
+ schema_name: str,
603
+ name: str,
604
+ ignore_not_found: bool = False,
605
+ cascade: bool = False,
606
+ ) -> None:
607
+ """Drop a table.
608
+
609
+ Args:
610
+ attach_opaque_data: The attachment ID from catalog_attach.
611
+ transaction_opaque_data: Optional transaction ID.
612
+ schema_name: The schema containing the table.
613
+ name: The name of the table to drop.
614
+ ignore_not_found: If True, don't error if table doesn't exist.
615
+ cascade: If True, also drop dependent objects.
616
+
617
+ """
618
+ with self._catalog_connect() as proxy:
619
+ proxy.catalog_table_drop(
620
+ attach_opaque_data=attach_opaque_data,
621
+ schema_name=schema_name,
622
+ name=name,
623
+ ignore_not_found=ignore_not_found,
624
+ cascade=cascade,
625
+ transaction_opaque_data=transaction_opaque_data,
626
+ )
627
+
628
+ def table_scan_function_get(
629
+ self,
630
+ *,
631
+ attach_opaque_data: AttachOpaqueData,
632
+ transaction_opaque_data: TransactionOpaqueData | None = None,
633
+ schema_name: str,
634
+ name: str,
635
+ at_unit: str | None = None,
636
+ at_value: str | None = None,
637
+ ) -> ScanFunctionResult:
638
+ """Get the scan function for a table.
639
+
640
+ Returns a ScanFunctionResult that tells the VGI DuckDB extension which
641
+ DuckDB function to call to obtain the table data.
642
+
643
+ Args:
644
+ attach_opaque_data: The attachment ID from catalog_attach.
645
+ transaction_opaque_data: Optional transaction ID for transactional reads.
646
+ schema_name: The schema containing the table.
647
+ name: The table name.
648
+ at_unit: Optional time travel unit (e.g., 'timestamp', 'version').
649
+ at_value: Optional time travel value.
650
+
651
+ Returns:
652
+ ScanFunctionResult with function_name, arguments, and extensions.
653
+
654
+ Raises:
655
+ CatalogClientError: If table_scan_function_get returned no result.
656
+
657
+ """
658
+ with self._catalog_connect() as proxy:
659
+ result_bytes = proxy.catalog_table_scan_function_get(
660
+ attach_opaque_data=attach_opaque_data,
661
+ schema_name=schema_name,
662
+ name=name,
663
+ at_unit=at_unit,
664
+ at_value=at_value,
665
+ transaction_opaque_data=transaction_opaque_data,
666
+ )
667
+ batch, _ = deserialize_record_batch(result_bytes)
668
+ return ScanFunctionResult.deserialize(batch)
669
+
670
+ def table_comment_set(
671
+ self,
672
+ *,
673
+ attach_opaque_data: AttachOpaqueData,
674
+ transaction_opaque_data: TransactionOpaqueData | None = None,
675
+ schema_name: str,
676
+ name: str,
677
+ comment: str | None,
678
+ ignore_not_found: bool = False,
679
+ ) -> None:
680
+ """Set or clear the comment on a table.
681
+
682
+ Args:
683
+ attach_opaque_data: The attachment ID from catalog_attach.
684
+ transaction_opaque_data: Optional transaction ID.
685
+ schema_name: The schema containing the table.
686
+ name: The table name.
687
+ comment: The new comment, or None to clear.
688
+ ignore_not_found: If True, don't error if table doesn't exist.
689
+
690
+ """
691
+ with self._catalog_connect() as proxy:
692
+ proxy.catalog_table_comment_set(
693
+ attach_opaque_data=attach_opaque_data,
694
+ schema_name=schema_name,
695
+ name=name,
696
+ comment=comment,
697
+ ignore_not_found=ignore_not_found,
698
+ transaction_opaque_data=transaction_opaque_data,
699
+ )
700
+
701
+ def table_rename(
702
+ self,
703
+ *,
704
+ attach_opaque_data: AttachOpaqueData,
705
+ transaction_opaque_data: TransactionOpaqueData | None = None,
706
+ schema_name: str,
707
+ name: str,
708
+ new_name: str,
709
+ ignore_not_found: bool = False,
710
+ ) -> None:
711
+ """Rename a table.
712
+
713
+ Args:
714
+ attach_opaque_data: The attachment ID from catalog_attach.
715
+ transaction_opaque_data: Optional transaction ID.
716
+ schema_name: The schema containing the table.
717
+ name: The current name of the table.
718
+ new_name: The new name for the table.
719
+ ignore_not_found: If True, don't error if table doesn't exist.
720
+
721
+ """
722
+ with self._catalog_connect() as proxy:
723
+ proxy.catalog_table_rename(
724
+ attach_opaque_data=attach_opaque_data,
725
+ schema_name=schema_name,
726
+ name=name,
727
+ new_name=new_name,
728
+ ignore_not_found=ignore_not_found,
729
+ transaction_opaque_data=transaction_opaque_data,
730
+ )
731
+
732
+ def table_column_add(
733
+ self,
734
+ *,
735
+ attach_opaque_data: AttachOpaqueData,
736
+ transaction_opaque_data: TransactionOpaqueData | None = None,
737
+ schema_name: str,
738
+ name: str,
739
+ column_definition: SerializedSchema,
740
+ ignore_not_found: bool = False,
741
+ if_column_not_exists: bool = False,
742
+ ) -> None:
743
+ """Add a new column to a table.
744
+
745
+ Args:
746
+ attach_opaque_data: The attachment ID from catalog_attach.
747
+ transaction_opaque_data: Optional transaction ID.
748
+ schema_name: The schema containing the table.
749
+ name: The table name.
750
+ column_definition: Serialized schema with single field for the new column.
751
+ ignore_not_found: If True, don't error if table doesn't exist.
752
+ if_column_not_exists: If True, don't error if column already exists.
753
+
754
+ """
755
+ with self._catalog_connect() as proxy:
756
+ proxy.catalog_table_column_add(
757
+ attach_opaque_data=attach_opaque_data,
758
+ schema_name=schema_name,
759
+ name=name,
760
+ column_definition=column_definition,
761
+ ignore_not_found=ignore_not_found,
762
+ if_column_not_exists=if_column_not_exists,
763
+ transaction_opaque_data=transaction_opaque_data,
764
+ )
765
+
766
+ def table_column_drop(
767
+ self,
768
+ *,
769
+ attach_opaque_data: AttachOpaqueData,
770
+ transaction_opaque_data: TransactionOpaqueData | None = None,
771
+ schema_name: str,
772
+ name: str,
773
+ column_name: str,
774
+ ignore_not_found: bool = False,
775
+ if_column_exists: bool = False,
776
+ cascade: bool = False,
777
+ ) -> None:
778
+ """Drop a column from a table.
779
+
780
+ Args:
781
+ attach_opaque_data: The attachment ID from catalog_attach.
782
+ transaction_opaque_data: Optional transaction ID.
783
+ schema_name: The schema containing the table.
784
+ name: The table name.
785
+ column_name: The name of the column to drop.
786
+ ignore_not_found: If True, don't error if table doesn't exist.
787
+ if_column_exists: If True, don't error if column doesn't exist.
788
+ cascade: If True, drop dependent constraints.
789
+
790
+ """
791
+ with self._catalog_connect() as proxy:
792
+ proxy.catalog_table_column_drop(
793
+ attach_opaque_data=attach_opaque_data,
794
+ schema_name=schema_name,
795
+ name=name,
796
+ column_name=column_name,
797
+ ignore_not_found=ignore_not_found,
798
+ if_column_exists=if_column_exists,
799
+ cascade=cascade,
800
+ transaction_opaque_data=transaction_opaque_data,
801
+ )
802
+
803
+ def table_column_rename(
804
+ self,
805
+ *,
806
+ attach_opaque_data: AttachOpaqueData,
807
+ transaction_opaque_data: TransactionOpaqueData | None = None,
808
+ schema_name: str,
809
+ name: str,
810
+ column_name: str,
811
+ new_column_name: str,
812
+ ignore_not_found: bool = False,
813
+ ) -> None:
814
+ """Rename a column.
815
+
816
+ Args:
817
+ attach_opaque_data: The attachment ID from catalog_attach.
818
+ transaction_opaque_data: Optional transaction ID.
819
+ schema_name: The schema containing the table.
820
+ name: The table name.
821
+ column_name: The current name of the column.
822
+ new_column_name: The new name for the column.
823
+ ignore_not_found: If True, don't error if table doesn't exist.
824
+
825
+ """
826
+ with self._catalog_connect() as proxy:
827
+ proxy.catalog_table_column_rename(
828
+ attach_opaque_data=attach_opaque_data,
829
+ schema_name=schema_name,
830
+ name=name,
831
+ column_name=column_name,
832
+ new_column_name=new_column_name,
833
+ ignore_not_found=ignore_not_found,
834
+ transaction_opaque_data=transaction_opaque_data,
835
+ )
836
+
837
+ def table_column_default_set(
838
+ self,
839
+ *,
840
+ attach_opaque_data: AttachOpaqueData,
841
+ transaction_opaque_data: TransactionOpaqueData | None = None,
842
+ schema_name: str,
843
+ name: str,
844
+ column_name: str,
845
+ expression: SqlExpression,
846
+ ignore_not_found: bool = False,
847
+ ) -> None:
848
+ """Set the default value expression for a column.
849
+
850
+ Args:
851
+ attach_opaque_data: The attachment ID from catalog_attach.
852
+ transaction_opaque_data: Optional transaction ID.
853
+ schema_name: The schema containing the table.
854
+ name: The table name.
855
+ column_name: The column to set the default for.
856
+ expression: The SQL expression for the default value.
857
+ ignore_not_found: If True, don't error if table doesn't exist.
858
+
859
+ """
860
+ with self._catalog_connect() as proxy:
861
+ proxy.catalog_table_column_default_set(
862
+ attach_opaque_data=attach_opaque_data,
863
+ schema_name=schema_name,
864
+ name=name,
865
+ column_name=column_name,
866
+ expression=expression,
867
+ ignore_not_found=ignore_not_found,
868
+ transaction_opaque_data=transaction_opaque_data,
869
+ )
870
+
871
+ def table_column_default_drop(
872
+ self,
873
+ *,
874
+ attach_opaque_data: AttachOpaqueData,
875
+ transaction_opaque_data: TransactionOpaqueData | None = None,
876
+ schema_name: str,
877
+ name: str,
878
+ column_name: str,
879
+ ignore_not_found: bool = False,
880
+ ) -> None:
881
+ """Remove the default value from a column.
882
+
883
+ Args:
884
+ attach_opaque_data: The attachment ID from catalog_attach.
885
+ transaction_opaque_data: Optional transaction ID.
886
+ schema_name: The schema containing the table.
887
+ name: The table name.
888
+ column_name: The column to remove the default from.
889
+ ignore_not_found: If True, don't error if table doesn't exist.
890
+
891
+ """
892
+ with self._catalog_connect() as proxy:
893
+ proxy.catalog_table_column_default_drop(
894
+ attach_opaque_data=attach_opaque_data,
895
+ schema_name=schema_name,
896
+ name=name,
897
+ column_name=column_name,
898
+ ignore_not_found=ignore_not_found,
899
+ transaction_opaque_data=transaction_opaque_data,
900
+ )
901
+
902
+ def table_column_type_change(
903
+ self,
904
+ *,
905
+ attach_opaque_data: AttachOpaqueData,
906
+ transaction_opaque_data: TransactionOpaqueData | None = None,
907
+ schema_name: str,
908
+ name: str,
909
+ column_definition: SerializedSchema,
910
+ expression: SqlExpression | None = None,
911
+ ignore_not_found: bool = False,
912
+ ) -> None:
913
+ """Change the type of a column.
914
+
915
+ Args:
916
+ attach_opaque_data: The attachment ID from catalog_attach.
917
+ transaction_opaque_data: Optional transaction ID.
918
+ schema_name: The schema containing the table.
919
+ name: The table name.
920
+ column_definition: Serialized schema with single field defining the
921
+ new type. Column name is taken from the schema field name.
922
+ expression: Optional SQL expression to convert existing values.
923
+ ignore_not_found: If True, don't error if table doesn't exist.
924
+
925
+ """
926
+ with self._catalog_connect() as proxy:
927
+ proxy.catalog_table_column_type_change(
928
+ attach_opaque_data=attach_opaque_data,
929
+ schema_name=schema_name,
930
+ name=name,
931
+ column_definition=column_definition,
932
+ expression=expression,
933
+ ignore_not_found=ignore_not_found,
934
+ transaction_opaque_data=transaction_opaque_data,
935
+ )
936
+
937
+ def table_not_null_drop(
938
+ self,
939
+ *,
940
+ attach_opaque_data: AttachOpaqueData,
941
+ transaction_opaque_data: TransactionOpaqueData | None = None,
942
+ schema_name: str,
943
+ name: str,
944
+ column_name: str,
945
+ ignore_not_found: bool = False,
946
+ ) -> None:
947
+ """Remove NOT NULL constraint from a column.
948
+
949
+ Args:
950
+ attach_opaque_data: The attachment ID from catalog_attach.
951
+ transaction_opaque_data: Optional transaction ID.
952
+ schema_name: The schema containing the table.
953
+ name: The table name.
954
+ column_name: The column to remove NOT NULL from.
955
+ ignore_not_found: If True, don't error if table doesn't exist.
956
+
957
+ """
958
+ with self._catalog_connect() as proxy:
959
+ proxy.catalog_table_not_null_drop(
960
+ attach_opaque_data=attach_opaque_data,
961
+ schema_name=schema_name,
962
+ name=name,
963
+ column_name=column_name,
964
+ ignore_not_found=ignore_not_found,
965
+ transaction_opaque_data=transaction_opaque_data,
966
+ )
967
+
968
+ def table_not_null_set(
969
+ self,
970
+ *,
971
+ attach_opaque_data: AttachOpaqueData,
972
+ transaction_opaque_data: TransactionOpaqueData | None = None,
973
+ schema_name: str,
974
+ name: str,
975
+ column_name: str,
976
+ ignore_not_found: bool = False,
977
+ ) -> None:
978
+ """Add NOT NULL constraint to a column.
979
+
980
+ Args:
981
+ attach_opaque_data: The attachment ID from catalog_attach.
982
+ transaction_opaque_data: Optional transaction ID.
983
+ schema_name: The schema containing the table.
984
+ name: The table name.
985
+ column_name: The column to add NOT NULL to.
986
+ ignore_not_found: If True, don't error if table doesn't exist.
987
+
988
+ """
989
+ with self._catalog_connect() as proxy:
990
+ proxy.catalog_table_not_null_set(
991
+ attach_opaque_data=attach_opaque_data,
992
+ schema_name=schema_name,
993
+ name=name,
994
+ column_name=column_name,
995
+ ignore_not_found=ignore_not_found,
996
+ transaction_opaque_data=transaction_opaque_data,
997
+ )
998
+
999
+ # ========== View Methods ==========
1000
+
1001
+ def view_get(
1002
+ self,
1003
+ *,
1004
+ attach_opaque_data: AttachOpaqueData,
1005
+ transaction_opaque_data: TransactionOpaqueData | None = None,
1006
+ schema_name: str,
1007
+ name: str,
1008
+ ) -> ViewInfo | None:
1009
+ """Get information about a view.
1010
+
1011
+ Args:
1012
+ attach_opaque_data: The attachment ID from catalog_attach.
1013
+ transaction_opaque_data: Optional transaction ID for transactional reads.
1014
+ schema_name: The schema containing the view.
1015
+ name: The view name.
1016
+
1017
+ Returns:
1018
+ ViewInfo for the view, or None if not found.
1019
+
1020
+ """
1021
+ with self._catalog_connect() as proxy:
1022
+ return proxy.catalog_view_get( # type: ignore[no-any-return]
1023
+ attach_opaque_data=attach_opaque_data,
1024
+ schema_name=schema_name,
1025
+ name=name,
1026
+ transaction_opaque_data=transaction_opaque_data,
1027
+ ).to_optional()
1028
+
1029
+ def view_create(
1030
+ self,
1031
+ *,
1032
+ attach_opaque_data: AttachOpaqueData,
1033
+ transaction_opaque_data: TransactionOpaqueData | None = None,
1034
+ schema_name: str,
1035
+ name: str,
1036
+ definition: str,
1037
+ on_conflict: OnConflict = OnConflict.ERROR,
1038
+ ) -> None:
1039
+ """Create a new view.
1040
+
1041
+ Args:
1042
+ attach_opaque_data: The attachment ID from catalog_attach.
1043
+ transaction_opaque_data: Optional transaction ID.
1044
+ schema_name: The schema to create the view in.
1045
+ name: The name for the new view.
1046
+ definition: The SQL SELECT statement defining the view.
1047
+ on_conflict: Behavior if view already exists.
1048
+
1049
+ """
1050
+ with self._catalog_connect() as proxy:
1051
+ proxy.catalog_view_create(
1052
+ attach_opaque_data=attach_opaque_data,
1053
+ schema_name=schema_name,
1054
+ name=name,
1055
+ definition=definition,
1056
+ on_conflict=on_conflict,
1057
+ transaction_opaque_data=transaction_opaque_data,
1058
+ )
1059
+
1060
+ def view_drop(
1061
+ self,
1062
+ *,
1063
+ attach_opaque_data: AttachOpaqueData,
1064
+ transaction_opaque_data: TransactionOpaqueData | None = None,
1065
+ schema_name: str,
1066
+ name: str,
1067
+ ignore_not_found: bool = False,
1068
+ cascade: bool = False,
1069
+ ) -> None:
1070
+ """Drop a view.
1071
+
1072
+ Args:
1073
+ attach_opaque_data: The attachment ID from catalog_attach.
1074
+ transaction_opaque_data: Optional transaction ID.
1075
+ schema_name: The schema containing the view.
1076
+ name: The name of the view to drop.
1077
+ ignore_not_found: If True, don't error if view doesn't exist.
1078
+ cascade: If True, also drop dependent objects.
1079
+
1080
+ """
1081
+ with self._catalog_connect() as proxy:
1082
+ proxy.catalog_view_drop(
1083
+ attach_opaque_data=attach_opaque_data,
1084
+ schema_name=schema_name,
1085
+ name=name,
1086
+ ignore_not_found=ignore_not_found,
1087
+ cascade=cascade,
1088
+ transaction_opaque_data=transaction_opaque_data,
1089
+ )
1090
+
1091
+ def view_rename(
1092
+ self,
1093
+ *,
1094
+ attach_opaque_data: AttachOpaqueData,
1095
+ transaction_opaque_data: TransactionOpaqueData | None = None,
1096
+ schema_name: str,
1097
+ name: str,
1098
+ new_name: str,
1099
+ ignore_not_found: bool = False,
1100
+ ) -> None:
1101
+ """Rename a view.
1102
+
1103
+ Args:
1104
+ attach_opaque_data: The attachment ID from catalog_attach.
1105
+ transaction_opaque_data: Optional transaction ID.
1106
+ schema_name: The schema containing the view.
1107
+ name: The current name of the view.
1108
+ new_name: The new name for the view.
1109
+ ignore_not_found: If True, don't error if view doesn't exist.
1110
+
1111
+ """
1112
+ with self._catalog_connect() as proxy:
1113
+ proxy.catalog_view_rename(
1114
+ attach_opaque_data=attach_opaque_data,
1115
+ schema_name=schema_name,
1116
+ name=name,
1117
+ new_name=new_name,
1118
+ ignore_not_found=ignore_not_found,
1119
+ transaction_opaque_data=transaction_opaque_data,
1120
+ )
1121
+
1122
+ def view_comment_set(
1123
+ self,
1124
+ *,
1125
+ attach_opaque_data: AttachOpaqueData,
1126
+ transaction_opaque_data: TransactionOpaqueData | None = None,
1127
+ schema_name: str,
1128
+ name: str,
1129
+ comment: str | None,
1130
+ ignore_not_found: bool = False,
1131
+ ) -> None:
1132
+ """Set or clear the comment on a view.
1133
+
1134
+ Args:
1135
+ attach_opaque_data: The attachment ID from catalog_attach.
1136
+ transaction_opaque_data: Optional transaction ID.
1137
+ schema_name: The schema containing the view.
1138
+ name: The view name.
1139
+ comment: The new comment, or None to clear.
1140
+ ignore_not_found: If True, don't error if view doesn't exist.
1141
+
1142
+ """
1143
+ with self._catalog_connect() as proxy:
1144
+ proxy.catalog_view_comment_set(
1145
+ attach_opaque_data=attach_opaque_data,
1146
+ schema_name=schema_name,
1147
+ name=name,
1148
+ comment=comment,
1149
+ ignore_not_found=ignore_not_found,
1150
+ transaction_opaque_data=transaction_opaque_data,
1151
+ )
1152
+
1153
+ # ========== Macro Methods ==========
1154
+
1155
+ def macro_get(
1156
+ self,
1157
+ *,
1158
+ attach_opaque_data: AttachOpaqueData,
1159
+ transaction_opaque_data: TransactionOpaqueData | None = None,
1160
+ schema_name: str,
1161
+ name: str,
1162
+ ) -> MacroInfo | None:
1163
+ """Get information about a macro.
1164
+
1165
+ Args:
1166
+ attach_opaque_data: The attachment ID from catalog_attach.
1167
+ transaction_opaque_data: Optional transaction ID for transactional reads.
1168
+ schema_name: The schema containing the macro.
1169
+ name: The macro name.
1170
+
1171
+ Returns:
1172
+ MacroInfo for the macro, or None if not found.
1173
+
1174
+ """
1175
+ with self._catalog_connect() as proxy:
1176
+ return proxy.catalog_macro_get( # type: ignore[no-any-return]
1177
+ attach_opaque_data=attach_opaque_data,
1178
+ schema_name=schema_name,
1179
+ name=name,
1180
+ transaction_opaque_data=transaction_opaque_data,
1181
+ ).to_optional()
1182
+
1183
+ def macro_create(
1184
+ self,
1185
+ *,
1186
+ attach_opaque_data: AttachOpaqueData,
1187
+ transaction_opaque_data: TransactionOpaqueData | None = None,
1188
+ schema_name: str,
1189
+ name: str,
1190
+ macro_type: MacroType,
1191
+ parameters: list[str],
1192
+ definition: str,
1193
+ on_conflict: OnConflict = OnConflict.ERROR,
1194
+ parameter_default_values: pa.RecordBatch | None = None,
1195
+ ) -> None:
1196
+ """Create a new macro.
1197
+
1198
+ Args:
1199
+ attach_opaque_data: The attachment ID from catalog_attach.
1200
+ transaction_opaque_data: Optional transaction ID.
1201
+ schema_name: The schema to create the macro in.
1202
+ name: The name for the new macro.
1203
+ macro_type: Whether this is a scalar or table macro.
1204
+ parameters: Ordered list of parameter names.
1205
+ definition: SQL expression (scalar) or query (table).
1206
+ on_conflict: Behavior if macro already exists.
1207
+ parameter_default_values: One-row RecordBatch with typed defaults.
1208
+
1209
+ """
1210
+ with self._catalog_connect() as proxy:
1211
+ proxy.catalog_macro_create(
1212
+ request=MacroCreateRequest(
1213
+ attach_opaque_data=attach_opaque_data,
1214
+ schema_name=schema_name,
1215
+ name=name,
1216
+ macro_type=macro_type,
1217
+ parameters=parameters,
1218
+ definition=definition,
1219
+ on_conflict=on_conflict,
1220
+ parameter_default_values=parameter_default_values,
1221
+ transaction_opaque_data=transaction_opaque_data,
1222
+ )
1223
+ )
1224
+
1225
+ def macro_drop(
1226
+ self,
1227
+ *,
1228
+ attach_opaque_data: AttachOpaqueData,
1229
+ transaction_opaque_data: TransactionOpaqueData | None = None,
1230
+ schema_name: str,
1231
+ name: str,
1232
+ ignore_not_found: bool = False,
1233
+ ) -> None:
1234
+ """Drop a macro.
1235
+
1236
+ Args:
1237
+ attach_opaque_data: The attachment ID from catalog_attach.
1238
+ transaction_opaque_data: Optional transaction ID.
1239
+ schema_name: The schema containing the macro.
1240
+ name: The name of the macro to drop.
1241
+ ignore_not_found: If True, don't error if macro doesn't exist.
1242
+
1243
+ """
1244
+ with self._catalog_connect() as proxy:
1245
+ proxy.catalog_macro_drop(
1246
+ attach_opaque_data=attach_opaque_data,
1247
+ schema_name=schema_name,
1248
+ name=name,
1249
+ ignore_not_found=ignore_not_found,
1250
+ transaction_opaque_data=transaction_opaque_data,
1251
+ )