Skip to content

Commit 2cb5dfe

Browse files
authored
feat: add pipelined stack execution (#242)
Implement `StatementStack` and `StackOperation` for managing SQL execution sequences
1 parent 46f58d4 commit 2cb5dfe

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+3959
-247
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ target/
1919
.vscode/
2020
.cursor/
2121
.zed/
22+
.cache
2223
.coverage*
2324
# files
2425
**/*.so

.pre-commit-config.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ repos:
1717
- id: mixed-line-ending
1818
- id: trailing-whitespace
1919
- repo: https://github.com/charliermarsh/ruff-pre-commit
20-
rev: "v0.14.4"
20+
rev: "v0.14.5"
2121
hooks:
2222
- id: ruff
2323
args: ["--fix"]
@@ -43,6 +43,7 @@ repos:
4343
rev: "v1.0.1"
4444
hooks:
4545
- id: sphinx-lint
46+
args: ["--jobs", "1"]
4647
- repo: local
4748
hooks:
4849
- id: pypi-readme

AGENTS.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,25 @@ SQLSpec is a type-safe SQL query mapper designed for minimal abstraction between
185185
- **Single-Pass Processing**: Parse once → transform once → validate once - SQL object is single source of truth
186186
- **Abstract Methods with Concrete Implementations**: Protocol defines abstract methods, base classes provide concrete sync/async implementations
187187

188+
### Query Stack Implementation Guidelines
189+
190+
- **Builder Discipline**
191+
- `StatementStack` and `StackOperation` are immutable (`__slots__`, tuple storage). Every push helper returns a new stack; never mutate `_operations` in place.
192+
- Validate inputs at push time (non-empty SQL, execute_many payloads, reject nested stacks) so drivers can assume well-formed operations.
193+
- **Adapter Responsibilities**
194+
- Add a single capability gate per adapter (e.g., Oracle pipeline version check, `psycopg.capabilities.has_pipeline()`), return `super().execute_stack()` immediately when unsupported.
195+
- Preserve `StackResult.result` by building SQL/Arrow results via `create_sql_result()` / `create_arrow_result()` instead of copying row data.
196+
- Honor manual toggles via `driver_features={"stack_native_disabled": True}` and document the behavior in the adapter guide.
197+
- **Telemetry + Tracing**
198+
- Always wrap adapter overrides with `StackExecutionObserver(self, stack, continue_on_error, native_pipeline=bool)`.
199+
- Do **not** emit duplicate metrics; the observer already increments `stack.execute.*`, logs `stack.execute.start/complete/failed`, and publishes the `sqlspec.stack.execute` span.
200+
- **Error Handling**
201+
- Wrap driver exceptions in `StackExecutionError` with `operation_index`, summarized SQL (`describe_stack_statement()`), adapter name, and execution mode.
202+
- Continue-on-error stacks append `StackResult.from_error()` and keep executing. Fail-fast stacks roll back (if they started the transaction) before re-raising the wrapped error.
203+
- **Testing Expectations**
204+
- Add integration tests under `tests/integration/test_adapters/<adapter>/test_driver.py::test_*statement_stack*` that cover native path, sequential fallback, and continue-on-error.
205+
- Guard base behavior (empty stacks, large stacks, transaction boundaries) via `tests/integration/test_stack_edge_cases.py`.
206+
188207
### Driver Parameter Profile Registry
189208

190209
- All adapter parameter defaults live in `DriverParameterProfile` entries inside `sqlspec/core/parameters.py`.

docs/changelog.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ SQLSpec Changelog
1010
Recent Updates
1111
==============
1212

13+
Query Stack Documentation Suite
14+
--------------------------------
15+
16+
- Expanded the :doc:`/reference/query-stack` API reference (``StatementStack``, ``StackResult``, driver hooks, and ``StackExecutionError``) with the high-level workflow, execution modes, telemetry, and troubleshooting tips.
17+
- Added :doc:`/examples/patterns/stacks/query_stack_example` that runs the same stack against SQLite and AioSQLite.
18+
- Captured the detailed architecture and performance guidance inside the internal specs workspace for future agent runs.
19+
- Updated every adapter reference with a **Query Stack Support** section so behavior is documented per database.
20+
1321
Migration Convenience Methods on Config Classes
1422
------------------------------------------------
1523

docs/examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ This directory now mirrors the way developers explore SQLSpec:
66
- `frameworks/` groups runnable apps (Litestar for now) that rely on lightweight backends (aiosqlite, duckdb).
77
- `adapters/` holds connection-focused snippets for production drivers such as asyncpg, psycopg, and oracledb.
88
- `patterns/` demonstrates SQL builder usage, migrations, and multi-tenant routing.
9+
- `arrow/` collects Arrow integration demos so advanced exports stay discoverable without bloating other folders.
910
- `loaders/` shows how to hydrate SQL from files for quick demos.
1011
- `extensions/` keeps integration-specific samples (Adapter Development Kit in this pass).
1112

docs/examples/arrow/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Arrow integration examples for SQLSpec."""
2+
3+
__all__ = ()
File renamed without changes.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Arrow: Basic Usage
2+
==================
3+
4+
Demonstrate the ``select_to_arrow()`` helper across multiple adapters and
5+
conversion targets (native Arrow, pandas, polars, and Parquet exports).
6+
7+
.. code-block:: console
8+
9+
uv run python docs/examples/arrow/arrow_basic_usage.py
10+
11+
Source
12+
------
13+
14+
.. literalinclude:: arrow_basic_usage.py
15+
:language: python
16+
:linenos:

docs/examples/index.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,19 @@ Patterns
9191
- Routing requests to dedicated SQLite configs per tenant slug.
9292
* - ``patterns/configs/multi_adapter_registry.py``
9393
- Register multiple adapters on a single SQLSpec registry.
94+
* - ``patterns/stacks/query_stack_example.py``
95+
- Immutable StatementStack workflow executed against SQLite and AioSQLite drivers.
96+
97+
Arrow
98+
-----
99+
100+
.. list-table:: Arrow-powered exports
101+
:header-rows: 1
102+
103+
* - File
104+
- Scenario
105+
* - ``arrow/arrow_basic_usage.py``
106+
- ``select_to_arrow()`` walkthrough covering native Arrow, pandas, polars, and Parquet exports.
94107

95108
Loaders
96109
-------
@@ -142,4 +155,6 @@ Shared Utilities
142155
frameworks/starlette/aiosqlite_app
143156
frameworks/flask/sqlite_app
144157
patterns/configs/multi_adapter_registry
158+
patterns/stacks/query_stack_example
159+
arrow/arrow_basic_usage
145160
README
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Statement stack examples for SQLSpec documentation."""
2+
3+
__all__ = ()

0 commit comments

Comments
 (0)