duckdb-sqlalchemy 1.5.2.2__tar.gz → 1.5.4__tar.gz

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 (84) hide show
  1. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/.github/workflows/pythonapp.yaml +1 -0
  2. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/.pre-commit-config.yaml +2 -2
  3. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/CHANGELOG.md +41 -0
  4. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/PKG-INFO +6 -5
  5. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/README.md +2 -2
  6. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/configuration.md +2 -1
  7. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/connection-urls.md +9 -0
  8. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/motherduck.md +1 -0
  9. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/olap.md +123 -5
  10. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/__init__.py +199 -146
  11. duckdb_sqlalchemy-1.5.4/duckdb_sqlalchemy/_arrow.py +39 -0
  12. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/_bulk_insert.py +9 -2
  13. duckdb_sqlalchemy-1.5.4/duckdb_sqlalchemy/_statements.py +75 -0
  14. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/datatypes.py +27 -20
  15. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/motherduck.py +12 -4
  16. duckdb_sqlalchemy-1.5.4/duckdb_sqlalchemy/olap.py +721 -0
  17. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/test_core_units.py +491 -8
  18. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/test_execution_options.py +9 -0
  19. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/test_helpers.py +83 -3
  20. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/examples/motherduck_arrow_reads.py +2 -1
  21. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/llms.txt +1 -1
  22. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/noxfile.py +7 -7
  23. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/pyproject.toml +4 -3
  24. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/uv.lock +567 -524
  25. duckdb_sqlalchemy-1.5.2.2/duckdb_sqlalchemy/olap.py +0 -61
  26. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/.codex/environments/environment.toml +0 -0
  27. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  28. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  29. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/.github/dependabot.yml +0 -0
  30. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/.github/workflows/lint.yml +0 -0
  31. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/.github/workflows/pages.yml +0 -0
  32. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/.github/workflows/publish.yaml +0 -0
  33. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/.gitignore +0 -0
  34. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/AGENTS.md +0 -0
  35. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/ARCHITECTURE.md +0 -0
  36. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/CLAUDE.md +0 -0
  37. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/CODE_OF_CONDUCT.md +0 -0
  38. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/LICENSE.txt +0 -0
  39. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/PLANS.md +0 -0
  40. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/ROADMAP.md +0 -0
  41. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/codecov.yml +0 -0
  42. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/README.md +0 -0
  43. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/_config.yml +0 -0
  44. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/alembic.md +0 -0
  45. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/exec-plans/active/2026-03-27-maintenance-review.md +0 -0
  46. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/exec-plans/active/2026-03-30-maintenance-review.md +0 -0
  47. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/exec-plans/active/2026-03-31-maintenance-review.md +0 -0
  48. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/getting-started.md +0 -0
  49. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/index.md +0 -0
  50. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/migration-from-duckdb-engine.md +0 -0
  51. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/overview.md +0 -0
  52. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/pandas-jupyter.md +0 -0
  53. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/robots.txt +0 -0
  54. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/seo-checklist.md +0 -0
  55. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/docs/types-and-caveats.md +0 -0
  56. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/_query.py +0 -0
  57. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/_supports.py +0 -0
  58. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/_validation.py +0 -0
  59. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/bulk.py +0 -0
  60. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/capabilities.py +0 -0
  61. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/config.py +0 -0
  62. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/conftest.py +0 -0
  63. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/py.typed +0 -0
  64. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/requirements.py +0 -0
  65. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/__init__.py +0 -0
  66. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/conftest.py +0 -0
  67. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/snapshots/test_datatypes/test_interval/schema.sql +0 -0
  68. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/sqlalchemy_suite/conftest.py +0 -0
  69. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/sqlalchemy_suite/test_suite.py +0 -0
  70. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/test_basic.py +0 -0
  71. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/test_datatypes.py +0 -0
  72. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/test_integration.py +0 -0
  73. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/test_pandas.py +0 -0
  74. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/test_pyarrow.py +0 -0
  75. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/test_validation.py +0 -0
  76. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/tests/util.py +0 -0
  77. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/duckdb_sqlalchemy/url.py +0 -0
  78. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/examples/motherduck_attach_modes.py +0 -0
  79. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/examples/motherduck_multi_instance_pool.py +0 -0
  80. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/examples/motherduck_queuepool_high_concurrency.py +0 -0
  81. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/examples/motherduck_read_scaling_per_user.py +0 -0
  82. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/examples/sqlalchemy_example.py +0 -0
  83. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/renovate.json +0 -0
  84. {duckdb_sqlalchemy-1.5.2.2 → duckdb_sqlalchemy-1.5.4}/test.cfg +0 -0
@@ -66,4 +66,5 @@ jobs:
66
66
  token: ${{ secrets.CODECOV_TOKEN }}
67
67
  env_vars: PYTHON
68
68
  fail_ci_if_error: true
69
+ use_pypi: true
69
70
  verbose: true
@@ -23,10 +23,10 @@ repos:
23
23
  language: python
24
24
  files: ^duckdb_sqlalchemy/(?!tests/).*\.py$
25
25
  additional_dependencies:
26
- - "ty==0.0.34"
26
+ - "ty==0.0.54"
27
27
  - repo: https://github.com/astral-sh/ruff-pre-commit
28
28
  # Ruff version.
29
- rev: 'v0.15.11'
29
+ rev: 'v0.15.20'
30
30
  hooks:
31
31
  - id: ruff
32
32
  args:
@@ -8,6 +8,47 @@ preserved from the upstream project for historical context.
8
8
 
9
9
  ## Unreleased
10
10
 
11
+ ## [1.5.4](https://github.com/leonardovida/duckdb-sqlalchemy/compare/v1.5.3...v1.5.4) (2026-06-26)
12
+
13
+ ### Features
14
+
15
+ - expose MotherDuck `md_user_info().c.region` and Flight run `config` columns in the SQLAlchemy table-function helpers
16
+ - document one-off `md_run_flight(config=...)` overrides and selecting effective Flight run config
17
+ - route `motherduck_enable_server_side_temp_tables` through the MotherDuck startup URL parameter bucket
18
+
19
+ ### Bug Fixes
20
+
21
+ - restore SQLAlchemy 2.0.0+ compatibility by using a reflection fallback on early 2.0 releases
22
+ - reject empty MotherDuck Flight config keys before compiling Flight helper calls
23
+ - reject invalid MotherDuck Flight config map keys and NUL-containing values before compiling Flight helper calls
24
+
25
+ ### Tooling
26
+
27
+ - extend the validated compatibility matrix to DuckDB 1.5.4 and SQLAlchemy 2.0.51
28
+ - bump the local `ty` pin to `0.0.54` and the Ruff pre-commit hook to `0.15.20` after validating the current checks against the latest non-breaking releases
29
+ - refresh the locked development dependency set to the latest non-breaking transitive releases within existing version caps
30
+
31
+ ## [1.5.3](https://github.com/leonardovida/duckdb-sqlalchemy/compare/v1.5.2.2...v1.5.3) (2026-06-02)
32
+
33
+ ### Features
34
+
35
+ - add `quack_query()` for stateless DuckDB Quack remote queries on DuckDB 1.5.3+
36
+ - add `pragma_storage_info()` for SQLAlchemy access to DuckDB storage metadata
37
+ - add MotherDuck job table-function helpers for job metadata, versions, runs, logs, and job lifecycle operations
38
+ - add MotherDuck Dive table-function helpers for Dives-as-code create, update, fetch, versioning, and cleanup workflows
39
+
40
+ ### Bug Fixes
41
+
42
+ - quote validated table-function named parameters so reserved names such as `limit` and `offset` work with SQLAlchemy helpers
43
+
44
+ ### Tooling
45
+
46
+ - focus the nox compatibility matrix on active DuckDB release lines while keeping the runtime dependency floor unchanged
47
+ - extend the DuckDB compatibility test matrix to include DuckDB 1.5.3
48
+ - update the SQLAlchemy compatibility matrix to include SQLAlchemy 2.0.50
49
+ - refresh the locked development dependency set to the latest non-breaking releases within existing version caps
50
+ - bump the local `ty` pin to `0.0.38` after validating the current checks against the latest non-breaking release
51
+
11
52
  ## [1.5.2.2](https://github.com/leonardovida/duckdb-sqlalchemy/compare/v1.5.2.1...v1.5.2.2) (2026-05-11)
12
53
 
13
54
  ### Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: duckdb-sqlalchemy
3
- Version: 1.5.2.2
3
+ Version: 1.5.4
4
4
  Summary: DuckDB SQLAlchemy dialect for DuckDB and MotherDuck
5
5
  Project-URL: Bug Tracker, https://github.com/leonardovida/duckdb-sqlalchemy/issues
6
6
  Project-URL: Changelog, https://github.com/leonardovida/duckdb-sqlalchemy/releases
@@ -27,7 +27,8 @@ Classifier: Topic :: Database :: Front-Ends
27
27
  Requires-Python: <4,>=3.9
28
28
  Requires-Dist: duckdb>=0.5.0
29
29
  Requires-Dist: packaging>=21
30
- Requires-Dist: sqlalchemy>=2.0.45
30
+ Requires-Dist: sqlalchemy>=2.0.0; python_version < '3.14'
31
+ Requires-Dist: sqlalchemy>=2.0.45; python_version >= '3.14'
31
32
  Provides-Extra: dev
32
33
  Requires-Dist: fsspec<2027.0.0,>=2025.2.0; extra == 'dev'
33
34
  Requires-Dist: github-action-utils<2.0.0,>=1.1.0; extra == 'dev'
@@ -46,7 +47,7 @@ Requires-Dist: pytest-snapshot<1.0.0,>=0.9.0; extra == 'dev'
46
47
  Requires-Dist: pytest<10.0.0,>=8.0.0; extra == 'dev'
47
48
  Requires-Dist: pytz>=2024.2; (python_version >= '3.12') and extra == 'dev'
48
49
  Requires-Dist: toml<0.11.0,>=0.10.2; extra == 'dev'
49
- Requires-Dist: ty==0.0.34; extra == 'dev'
50
+ Requires-Dist: ty==0.0.54; extra == 'dev'
50
51
  Provides-Extra: devtools
51
52
  Requires-Dist: nox<2027.0.0,>=2026.4.10; extra == 'devtools'
52
53
  Requires-Dist: pdbpp<0.13.0,>=0.11.0; extra == 'devtools'
@@ -106,8 +107,8 @@ Current direction in this repository:
106
107
  | Component | Supported versions |
107
108
  | --- | --- |
108
109
  | Python | 3.9+ |
109
- | SQLAlchemy | 2.0.45+ (CI-tested: 2.0.45, 2.0.49) |
110
- | DuckDB | 0.5.0+ (CI-tested currently: 1.1.3 to 1.5.2) |
110
+ | SQLAlchemy | 2.0.0+ on Python <3.14; 2.0.45+ on Python 3.14+ (CI-tested: 2.0.0, 2.0.51) |
111
+ | DuckDB | 0.5.0+ (CI-tested currently: 1.3.0 to 1.5.4) |
111
112
 
112
113
  ## Install
113
114
 
@@ -51,8 +51,8 @@ Current direction in this repository:
51
51
  | Component | Supported versions |
52
52
  | --- | --- |
53
53
  | Python | 3.9+ |
54
- | SQLAlchemy | 2.0.45+ (CI-tested: 2.0.45, 2.0.49) |
55
- | DuckDB | 0.5.0+ (CI-tested currently: 1.1.3 to 1.5.2) |
54
+ | SQLAlchemy | 2.0.0+ on Python <3.14; 2.0.45+ on Python 3.14+ (CI-tested: 2.0.0, 2.0.51) |
55
+ | DuckDB | 0.5.0+ (CI-tested currently: 1.3.0 to 1.5.4) |
56
56
 
57
57
  ## Install
58
58
 
@@ -50,7 +50,8 @@ engine = create_engine("duckdb:///analytics.db", connect_args={"read_only": True
50
50
  - Unknown but syntactically valid keys are forwarded to DuckDB and may fail with
51
51
  DuckDB's native "unrecognized configuration parameter" error.
52
52
  - MotherDuck path-query options (`attach_mode`, `session_name`, `access_mode`,
53
- and related keys) are handled specially for `md:` URLs. See
53
+ `motherduck_enable_server_side_temp_tables`, and related keys) are handled
54
+ specially for `md:` URLs. See
54
55
  [motherduck.md](motherduck) and [connection-urls.md](connection-urls).
55
56
 
56
57
  ## Preload extensions
@@ -108,6 +108,15 @@ engine = create_engine(f"duckdb:///md:my_db?motherduck_token={escaped}")
108
108
 
109
109
  See [motherduck.md](motherduck) for MotherDuck-specific examples and options.
110
110
 
111
+ ## Quack remotes
112
+
113
+ DuckDB 1.5.3 ships Quack as a core extension for remote DuckDB access. Quack is
114
+ normally used from SQL with `ATTACH 'quack:host' AS name (...)` or the
115
+ `quack_query` table function; keep the SQLAlchemy engine connected to a local
116
+ DuckDB database and attach the remote from that session.
117
+
118
+ See [olap.md](olap) for `quack_query` and `ATTACH` examples.
119
+
111
120
  ## Pool defaults
112
121
 
113
122
  Pooling behavior is described in [configuration.md](configuration)
@@ -70,6 +70,7 @@ Parameters that are treated as part of the database string:
70
70
  - `dbinstance_inactivity_ttl` (preferred; `motherduck_dbinstance_inactivity_ttl`
71
71
  remains supported but is deprecated)
72
72
  - `saas_mode` (`pgendpoint` is supported when you need PG endpoint-compatible routing)
73
+ - `motherduck_enable_server_side_temp_tables`
73
74
  - `cache_buster`
74
75
 
75
76
  For backward compatibility the dialect also accepts `session_hint`,
@@ -50,25 +50,131 @@ parquet = table_function(
50
50
  stmt = select(parquet.c.event_id, parquet.c.ts)
51
51
  ```
52
52
 
53
- ## MotherDuck user metadata
53
+ ## Storage metadata
54
54
 
55
- MotherDuck exposes `md_user_info()` for the current user and organization.
56
- The helper names the released columns so they are available through SQLAlchemy:
55
+ Use `pragma_storage_info` to inspect DuckDB table storage through SQLAlchemy:
57
56
 
58
57
  ```python
59
58
  from sqlalchemy import select
60
- from duckdb_sqlalchemy import md_user_info
59
+ from duckdb_sqlalchemy import pragma_storage_info
60
+
61
+ storage = pragma_storage_info("events")
62
+ stmt = select(storage.c.column_name, storage.c.segment_type, storage.c.compression)
63
+ ```
64
+
65
+ The helper names DuckDB's released columns by default. On engines that support
66
+ the optional segment-info argument, pass `include_segment_info=True`.
67
+
68
+ ## Quack remote queries
69
+
70
+ DuckDB 1.5.3 ships Quack as a core extension. Use `quack_query` for stateless
71
+ remote queries and name the returned columns for SQLAlchemy:
72
+
73
+ ```python
74
+ from sqlalchemy import select
75
+ from duckdb_sqlalchemy import quack_query
76
+
77
+ remote = quack_query(
78
+ "quack:localhost",
79
+ "SELECT 42 AS answer",
80
+ columns=["answer"],
81
+ token="MY_QUACK_TOKEN_01234567890ABCDEF",
82
+ )
83
+ stmt = select(remote.c.answer)
84
+ ```
85
+
86
+ ## MotherDuck metadata
87
+
88
+ MotherDuck exposes table functions for account and Dive metadata. The helpers
89
+ name the released columns so they are available through SQLAlchemy:
90
+
91
+ ```python
92
+ from sqlalchemy import select
93
+ from duckdb_sqlalchemy import md_access_tokens, md_list_dives, md_user_info
61
94
 
62
95
  user_info = md_user_info()
63
- stmt = select(
96
+ user_stmt = select(
64
97
  user_info.c.user_id,
65
98
  user_info.c.username,
66
99
  user_info.c.org_id,
67
100
  user_info.c.org_name,
68
101
  user_info.c.org_type,
102
+ user_info.c.region,
69
103
  )
104
+
105
+ dives = md_list_dives()
106
+ dives_stmt = select(dives.c.id, dives.c.title, dives.c.required_resources)
107
+
108
+ tokens = md_access_tokens()
109
+ tokens_stmt = select(tokens.c.token_name, tokens.c.token_type, tokens.c.expire_at)
70
110
  ```
71
111
 
112
+ ## MotherDuck Dives as code
113
+
114
+ Dive helpers expose the SQL functions MotherDuck provides for managing Dives
115
+ from a SQL client or deployment script:
116
+
117
+ ```python
118
+ from sqlalchemy import select
119
+ from duckdb_sqlalchemy import (
120
+ md_create_dive,
121
+ md_get_dive,
122
+ md_list_dive_versions,
123
+ md_update_dive_content,
124
+ )
125
+
126
+ created = md_create_dive(
127
+ title="Sales overview",
128
+ content="export default function Dive() { return null }",
129
+ api_version=1,
130
+ required_resources=[{"url": "md:analytics", "alias": "analytics"}],
131
+ )
132
+ create_stmt = select(created.c.id, created.c.version_id)
133
+
134
+ dive = md_get_dive(id="00000000-0000-0000-0000-000000000000")
135
+ dive_stmt = select(dive.c.title, dive.c.content)
136
+
137
+ updated = md_update_dive_content(
138
+ id="00000000-0000-0000-0000-000000000000",
139
+ content="export default function Dive() { return null }",
140
+ )
141
+ update_stmt = select(updated.c.version, updated.c.storage_url)
142
+
143
+ versions = md_list_dive_versions(id="00000000-0000-0000-0000-000000000000")
144
+ versions_stmt = select(versions.c.version, versions.c.created_at)
145
+ ```
146
+
147
+ ## MotherDuck Flights
148
+
149
+ MotherDuck also exposes preview table functions for Flight metadata. The
150
+ read-only helpers are useful for listing Flights, runs, logs, and versions:
151
+
152
+ ```python
153
+ from sqlalchemy import select
154
+ from duckdb_sqlalchemy import md_flight_runs, md_flight_versions, md_flights
155
+
156
+ flights = md_flights(limit=10)
157
+ flights_stmt = select(flights.c.flight_id, flights.c.flight_name, flights.c.status)
158
+
159
+ runs = md_flight_runs(flight_id="00000000-0000-0000-0000-000000000000", limit=10)
160
+ runs_stmt = select(runs.c.run_number, runs.c.status, runs.c.config, runs.c.started_at)
161
+
162
+ versions = md_flight_versions(flight_id="00000000-0000-0000-0000-000000000000")
163
+ versions_stmt = select(versions.c.flight_version, versions.c.requirements_txt)
164
+ ```
165
+
166
+ Mutating Flight functions are available as helpers too:
167
+ `md_create_flight`, `md_update_flight`, `md_delete_flight`, `md_run_flight`,
168
+ and `md_cancel_flight_run`. They only execute when the SQLAlchemy statement is
169
+ run. `md_run_flight` accepts a `config` map to override a Flight's config for
170
+ that run only; run result helpers expose the effective `config` column. Config
171
+ map keys must be strings, non-empty, and cannot contain `=` or NUL bytes.
172
+ Config values must be strings or `None`, and cannot contain NUL bytes.
173
+
174
+ The older `md_*job*` helper names remain as deprecated compatibility aliases.
175
+ They compile through the current Flight functions while preserving legacy
176
+ `job_*` column access where possible.
177
+
72
178
  ## Arrow results
73
179
 
74
180
  For large reads, you can request Arrow tables directly:
@@ -162,6 +268,18 @@ conn.execute(text("ATTACH 'analytics.duckdb' AS analytics"))
162
268
  rows = conn.execute(text("SELECT * FROM analytics.events LIMIT 10")).fetchall()
163
269
  ```
164
270
 
271
+ Quack remotes can be attached the same way when a Quack server is available:
272
+
273
+ ```python
274
+ conn.execute(
275
+ text(
276
+ "ATTACH 'quack:localhost' AS remote_db "
277
+ "(TOKEN 'MY_QUACK_TOKEN_01234567890ABCDEF')"
278
+ )
279
+ )
280
+ rows = conn.execute(text("SELECT * FROM remote_db.events LIMIT 10")).fetchall()
281
+ ```
282
+
165
283
  ## Notes
166
284
 
167
285
  - Column naming for table functions requires SQLAlchemy >= 1.4 (uses `table_valued`).