Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ important operational fixes.
Recent Updates
==============

Unreleased
----------

**Fixed:**

* ``sqlspec.extensions.litestar.LitestarConfig`` now exposes the complete plugin
configuration, including ``session_table=True``, through the same type as
``sqlspec.config.LitestarConfig``.

**Removed:**

* Removed the undocumented ``sqlspec.exceptions.wrap_exceptions`` helper,
superseded by the typed per-adapter exception handlers.

v0.62.2 - Litestar config lookup diagnostics
---------------------------------------------

Expand Down
29 changes: 0 additions & 29 deletions sqlspec/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from collections.abc import Generator
from contextlib import contextmanager
from typing import Any, Final

__all__ = (
Expand Down Expand Up @@ -465,30 +463,3 @@ def _classify_timeout_or_cancellation(message: str) -> "type[OperationalError] |
if any(marker in error_msg for marker in cancellation_markers):
return OperationCancelledError
return None


@contextmanager
def wrap_exceptions(
wrap_exceptions: bool = True, suppress: "type[Exception] | tuple[type[Exception], ...] | None" = None
) -> Generator[None, None, None]:
"""Context manager for exception handling with optional suppression.

Args:
wrap_exceptions: If True, wrap exceptions in RepositoryError. If False, let them pass through.
suppress: Exception type(s) to suppress completely (like contextlib.suppress).
If provided, these exceptions are caught and ignored.
"""
try:
yield

except Exception as exc:
if suppress is not None and isinstance(exc, suppress):
return

if isinstance(exc, SQLSpecError):
raise

if wrap_exceptions is False:
raise
msg = "An error occurred during the operation."
raise RepositoryError(detail=msg) from exc
97 changes: 2 additions & 95 deletions sqlspec/extensions/litestar/config.py
Original file line number Diff line number Diff line change
@@ -1,98 +1,5 @@
"""Configuration types for Litestar session store extension."""
"""Configuration types for the Litestar SQLSpec extension."""

from typing import Any, Literal

from typing_extensions import NotRequired, TypedDict
from sqlspec.config import LitestarConfig

__all__ = ("LitestarConfig",)


class LitestarConfig(TypedDict):
"""Configuration options for Litestar session store extension.

All fields are optional with sensible defaults. Use in extension_config["litestar"]:
"""

manage_schema: NotRequired[bool]
"""Apply additive target-schema reconciliation. Default: True."""

create_schema: NotRequired[bool]
"""Create the session table during managed reconciliation. Default: True."""

run_migrations: NotRequired[bool]
"""Run packaged versioned migrations when an integration supplies a runner. Default: False."""

session_table: NotRequired[str]
"""Name of the sessions table. Default: 'litestar_session'"""

in_memory: NotRequired[bool]
"""
Enable in-memory table storage (Oracle-specific). Default: False.

When enabled, tables are created with the in-memory attribute for databases that support it.

This is an Oracle-specific feature that requires:
- Oracle Database 12.1.0.2 or higher
- Database In-Memory option license (Enterprise Edition)
- Sufficient INMEMORY_SIZE configured in the database instance

Other database adapters ignore this setting.
"""

shard_count: NotRequired[int]
"""
Optional hash shard count for session table primary key.

When set (>1), adapters that support computed shard columns
will create a generated shard_id using MOD(FARM_FINGERPRINT(session_id), shard_count)
and include it in the primary key to reduce hotspotting. Ignored by adapters
that do not support computed shards.
"""

table_options: NotRequired[str]
"""
Optional raw OPTIONS/engine-specific table options string.

Passed verbatim when the adapter supports table-level OPTIONS/clauses. Ignored by adapters that do not
support table options.
"""

index_options: NotRequired[str]
"""Optional raw OPTIONS/engine-specific options for the expires_at index.

Passed verbatim to the index definition for adapters that support index
OPTIONS/clauses. Ignored by adapters that do not support index options.
"""

partitioning: NotRequired[dict[str, Any]]
"""Configure adapter-specific session-table partitioning where supported."""

partition_expiration_days: NotRequired[int]
"""Set BigQuery partition expiration in days."""

require_partition_filter: NotRequired[bool]
"""Require partition filters for BigQuery session queries."""

enable_hash_sharded_indexes: NotRequired[bool]
"""Enable CockroachDB hash-sharded session indexes."""

hash_shard_bucket_count: NotRequired[int]
"""Set the CockroachDB hash-shard bucket count."""

ttl_expiration_expression: NotRequired[Literal[False, "expires_at"]]
"""Enable CockroachDB row-level TTL using the session ``expires_at`` column."""

fillfactor: NotRequired[int]
"""Set PostgreSQL-family session-table fillfactor. Default: 80."""

autovacuum_vacuum_scale_factor: NotRequired[float]
"""Set the PostgreSQL-family autovacuum vacuum scale factor."""

autovacuum_analyze_scale_factor: NotRequired[float]
"""Set the PostgreSQL-family autovacuum analyze scale factor."""

pragma_profile: NotRequired[bool]
"""Apply the SQLite extension-store PRAGMA profile. Default: False."""

pragma_overrides: NotRequired[dict[str, str | int | bool]]
"""Apply validated SQLite PRAGMA overrides after the optional profile."""
24 changes: 24 additions & 0 deletions tests/typing/typing_litestar_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""The public Litestar config accepts plugin options and boolean session setup."""

from sqlspec.config import ExtensionConfigs
from sqlspec.extensions.litestar import LitestarConfig


def litestar_extension_config() -> ExtensionConfigs:
config: LitestarConfig = {
"session_table": True,
"auto_trace_headers": True,
"commit_mode": "autocommit",
"connection_key": "connection",
"correlation_header": "X-Request-ID",
"correlation_headers": ["X-Correlation-ID"],
"disable_di": False,
"enable_correlation_middleware": True,
"enable_sqlcommenter_middleware": True,
"extra_commit_statuses": {201},
"extra_rollback_statuses": {409},
"migrations_path": "migrations",
"pool_key": "pool",
"session_key": "session",
}
return {"litestar": config}
32 changes: 0 additions & 32 deletions tests/unit/exceptions/test_exceptions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import pytest

from sqlspec.exceptions import (
CheckViolationError,
DatabaseConnectionError,
Expand All @@ -9,14 +7,12 @@
NotFoundError,
NotNullViolationError,
OperationalError,
RepositoryError,
SQLFileNotFoundError,
SQLSpecError,
SQLStatementNotFoundError,
StackExecutionError,
TransactionError,
UniqueViolationError,
wrap_exceptions,
)


Expand Down Expand Up @@ -172,31 +168,3 @@ def test_stack_execution_error_preserves_args() -> None:
assert len(exc.args) == 1
assert "operation 2" in exc.args[0]
assert exc.args[0] == exc.detail


def test_wrap_exceptions_wrap_exceptions_suppresses_single_type() -> None:
"""suppress=<type> silently swallows matching exceptions."""
with wrap_exceptions(suppress=ValueError):
raise ValueError("suppressed")


def test_wrap_exceptions_wrap_exceptions_suppresses_tuple_of_types() -> None:
"""suppress=(<type>, ...) silently swallows matching exceptions."""
with wrap_exceptions(suppress=(ValueError, TypeError)):
raise TypeError("suppressed")


def test_wrap_exceptions_wrap_exceptions_wraps_unmatched_suppressed_type() -> None:
"""Non-matching exceptions are still wrapped."""
with pytest.raises(RepositoryError):
with wrap_exceptions(suppress=ValueError):
raise RuntimeError("not suppressed")


def test_wrap_exceptions_wrap_exceptions_sqlspec_error_passes_through() -> None:
"""SQLSpecError is reraised when it is not explicitly suppressed."""
original = SQLSpecError("already mapped")
with pytest.raises(SQLSpecError) as exc_info:
with wrap_exceptions():
raise original
assert exc_info.value is original
10 changes: 10 additions & 0 deletions tests/unit/extensions/test_litestar/test_config_typing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""The Litestar extension exposes the canonical configuration type."""

from sqlspec.config import LitestarConfig
from sqlspec.extensions.litestar import LitestarConfig as PublicLitestarConfig
from sqlspec.extensions.litestar.config import LitestarConfig as ExtensionLitestarConfig


def test_litestar_config_reexports() -> None:
assert PublicLitestarConfig is LitestarConfig
assert ExtensionLitestarConfig is LitestarConfig
Loading