Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
134 commits
Select commit Hold shift + click to select a range
62fce22
wip
cofin May 28, 2025
ba075d0
feat: wip
cofin May 28, 2025
6d39a4c
fix: most tests passing
cofin May 28, 2025
84e81c7
fix: updated base
cofin May 28, 2025
a4be401
filters
cofin May 29, 2025
cfccad0
closer
cofin May 29, 2025
65be800
wip
cofin May 29, 2025
b650b2a
wip
cofin May 31, 2025
d5362ed
feat: a lot
cofin May 31, 2025
add0351
fix: closer....
cofin May 31, 2025
16aea89
feat: closer...
cofin Jun 1, 2025
d544726
fix: test case fix
cofin Jun 1, 2025
9e0392a
fix: lots of tests
cofin Jun 1, 2025
5ea842a
feat: unit testing....
cofin Jun 1, 2025
bba9b76
feat: added obstore
cofin Jun 1, 2025
8c72dd0
wip
cofin Jun 1, 2025
7a664cf
fix: test case updates
cofin Jun 1, 2025
85417d1
fix: test cases
cofin Jun 1, 2025
ebdcd1a
fix: linting
cofin Jun 1, 2025
f614041
wip
cofin Jun 2, 2025
54435ab
closer...
cofin Jun 2, 2025
3399bdd
minor tweaks
cofin Jun 2, 2025
1c58e68
fix: linting updates
cofin Jun 2, 2025
783e0d4
fix: logic to support native fetch_df_all
cofin Jun 2, 2025
8f40550
fix: typing
cofin Jun 2, 2025
a21c396
fix: tests
cofin Jun 2, 2025
a228944
chore: rule??
cofin Jun 3, 2025
62e4477
wip
cofin Jun 3, 2025
eec6264
wip
cofin Jun 3, 2025
e4ad5c5
fix: builder refactor
cofin Jun 3, 2025
c3d514a
wip
cofin Jun 3, 2025
1fa01f5
feat: unit tests
cofin Jun 3, 2025
7c6bc32
wip
cofin Jun 4, 2025
f3340a1
wip
cofin Jun 4, 2025
630d0f8
feat: ddls and all kinds of other stuff too
cofin Jun 7, 2025
a4dccc6
feat: flatten config
cofin Jun 8, 2025
fa33d8e
feat: testing progress
cofin Jun 8, 2025
fe64e70
still broken checkpoint
cofin Jun 8, 2025
0268204
still progress
cofin Jun 8, 2025
9935822
feat: unit / integration tests passed for duckdb
cofin Jun 9, 2025
f85d6b0
formatting
cofin Jun 9, 2025
5f1509f
ready for unit tests
cofin Jun 9, 2025
1f323c5
fix: backend unit test
cofin Jun 9, 2025
f500d38
wip
cofin Jun 9, 2025
12d956b
pre-testing
cofin Jun 9, 2025
499b51d
closer
cofin Jun 9, 2025
a89ba22
wip
cofin Jun 9, 2025
6668854
maybe passing adapter unit tests
cofin Jun 9, 2025
1204523
fix: driver unit
cofin Jun 9, 2025
0071541
feat: 1 unit test failure
cofin Jun 9, 2025
7595068
fix: ast stuff
cofin Jun 9, 2025
aa2f8d9
pg fixes
cofin Jun 9, 2025
97816d7
fix: pg cast
cofin Jun 9, 2025
e5099a4
fix: asyncpg
cofin Jun 9, 2025
6785dbb
maybe further?
cofin Jun 9, 2025
44b11a9
fix: linting
cofin Jun 9, 2025
f0022d6
fix: integration and unit test
cofin Jun 9, 2025
9f4d0c4
fix: psycopg integration tests
cofin Jun 9, 2025
39058c0
fix: additional BQ tests
cofin Jun 9, 2025
d832e6f
fix: oracle arrow
cofin Jun 9, 2025
2a77c57
fix: wip - cleanup
cofin Jun 10, 2025
b897486
feat: wip checkpoint
cofin Jun 10, 2025
51e3876
chore: fixed regression; add statement splitter
cofin Jun 10, 2025
d21f29b
fix: ruff errors
cofin Jun 10, 2025
c83edeb
fix: bigquery tests
cofin Jun 10, 2025
8122886
fix: add consistent `num_rows` and `num_columns` properties
cofin Jun 10, 2025
d3bbf90
fix: cleanup
cofin Jun 11, 2025
4563b9d
fix: testing
cofin Jun 11, 2025
8b1f612
fix: linting
cofin Jun 11, 2025
b4580d4
feat: checkpoint
cofin Jun 12, 2025
3546953
wave 1
cofin Jun 13, 2025
c71ec2f
checkpoint
cofin Jun 13, 2025
276c9cc
checkpoint
cofin Jun 14, 2025
0a1e8c5
checkpoint
cofin Jun 14, 2025
89ab0cc
fixes most non-test linting
cofin Jun 14, 2025
e72601a
feat: more cleanup
cofin Jun 14, 2025
d6be2a5
feat: remove instrumentation config for now
cofin Jun 15, 2025
fb4dba6
fix: linting
cofin Jun 15, 2025
7ecff7e
fix: linting
cofin Jun 15, 2025
02e8e4f
feat: cleanup
cofin Jun 15, 2025
9c7b7cb
Checkpoint
cofin Jun 16, 2025
b09ebf1
checkpoint
cofin Jun 16, 2025
6c7729d
checkpoint
cofin Jun 16, 2025
c01e4e0
check
cofin Jun 16, 2025
76bbbc5
another checkpoint
cofin Jun 17, 2025
7527b86
feat: current progress
cofin Jun 19, 2025
6122384
feat: test fixes
cofin Jun 19, 2025
da73071
fix: unit test cleanup
cofin Jun 19, 2025
60552d3
fix: unit tests
cofin Jun 19, 2025
b127d4b
feat: unit and asyncpg
cofin Jun 20, 2025
ad31ade
chore: more test cleanup
cofin Jun 20, 2025
43cf2b8
fix: linting
cofin Jun 20, 2025
fbc7224
feat: more linting and formatting
cofin Jun 20, 2025
bebbbb1
chore: linting
cofin Jun 20, 2025
dcddcfe
feat: store parameter order
cofin Jun 21, 2025
169abb3
fix: test updates
cofin Jun 21, 2025
b21536c
feat: linting and tests
cofin Jun 21, 2025
60d92c0
fix: tests
cofin Jun 21, 2025
d5ef95f
fix: test corrections
cofin Jun 22, 2025
1fd964c
feat: test updates
cofin Jun 22, 2025
b2059fc
fix: slots
cofin Jun 22, 2025
dc7c142
fix: updated
cofin Jun 22, 2025
f6fd625
fix: linting
cofin Jun 22, 2025
e1dca84
fix: linting
cofin Jun 22, 2025
0351dda
fix: linting
cofin Jun 22, 2025
8a64b8c
fix: linting
cofin Jun 22, 2025
88315b6
fix: linting
cofin Jun 22, 2025
cd654e0
fix: linting
cofin Jun 22, 2025
680bad6
chore: linting
cofin Jun 22, 2025
6dd97ca
fix: linting
cofin Jun 22, 2025
7b29072
chore: formatting
cofin Jun 22, 2025
4ee0e0c
fix: linting
cofin Jun 22, 2025
a596993
feat: testing
cofin Jun 22, 2025
be67a6b
fix: preserve param position
cofin Jun 22, 2025
fb4b134
fix: psqlpy
cofin Jun 22, 2025
8836a28
fix: tests
cofin Jun 22, 2025
13c0c34
fix: inting
cofin Jun 22, 2025
ba66c05
chore: test
cofin Jun 23, 2025
dcf1be9
fix: linting
cofin Jun 23, 2025
6ba64ba
fix: test
cofin Jun 23, 2025
6f245eb
fix: linting
cofin Jun 23, 2025
388933a
fix: test corrections
cofin Jun 24, 2025
cb6975d
fix: test case
cofin Jun 24, 2025
4be9f50
feat: parquet test corrections
cofin Jun 24, 2025
8e8aa87
fix: psqlpy issues
cofin Jun 24, 2025
b0c126d
fix: test updates
cofin Jun 24, 2025
eae84ee
fix: psycopg tests
cofin Jun 24, 2025
f8a4d16
fix: tests
cofin Jun 24, 2025
3dccdb8
fix: oracle and others
cofin Jun 24, 2025
c9d8578
fix: ADBC tests
cofin Jun 24, 2025
2056ba8
fix: test correction
cofin Jun 24, 2025
e45cdf9
chore: ignores
cofin Jun 24, 2025
e0596f9
fix: tests
cofin Jun 24, 2025
ef042df
fix: tests
cofin Jun 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ site/
target/
.idea/
.vscode/
.claude/
.cursor/
.zed/

# files
**/*.so
Expand All @@ -31,3 +33,13 @@ target/
/docs/_build/
coverage.*
setup.py
tmp/
*.log
.bugs
.tmp
.todos
todo/
CLAUDE.md
CLAUDE.*.md
TODO*
.claudedocs
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ repos:
- id: mixed-line-ending
- id: trailing-whitespace
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: "v0.11.9"
rev: "v0.12.0"
hooks:
- id: ruff
args: ["--fix"]
Expand All @@ -29,7 +29,7 @@ repos:
additional_dependencies:
- tomli
- repo: https://github.com/python-formate/flake8-dunder-all
rev: v0.4.1
rev: v0.5.0
hooks:
- id: ensure-dunder-all
exclude: "test*|tools"
Expand Down
10 changes: 2 additions & 8 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@

nitpicky = True
nitpick_ignore: list[str] = []
nitpick_ignore_regex = [
(PY_RE, r"sqlspec.*\.T"),
]
nitpick_ignore_regex = [(PY_RE, r"sqlspec.*\.T")]

napoleon_google_docstring = True
napoleon_include_special_with_doc = True
Expand Down Expand Up @@ -79,11 +77,7 @@
html_title = "SQLSpec"
# html_favicon = "_static/logo.png"
# html_logo = "_static/logo.png"
html_context = {
"source_type": "github",
"source_user": "cofin",
"source_repo": project.replace("_", "-"),
}
html_context = {"source_type": "github", "source_user": "cofin", "source_repo": project.replace("_", "-")}

brand_colors = {
"--brand-primary": {"rgb": "245, 0, 87", "hex": "#f50057"},
Expand Down
22 changes: 8 additions & 14 deletions docs/examples/litestar_asyncpg.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,28 @@
# ]
# ///

from typing import Annotated, Optional
from typing import Annotated, Any

from litestar import Litestar, get
from litestar.params import Dependency

from sqlspec.adapters.asyncpg import AsyncpgConfig, AsyncpgDriver, AsyncpgPoolConfig
from sqlspec.adapters.asyncpg import AsyncpgConfig, AsyncpgDriver
from sqlspec.extensions.litestar import DatabaseConfig, SQLSpec, providers
from sqlspec.filters import FilterTypes
from sqlspec.statement import SQLResult
from sqlspec.statement.filters import FilterTypes


@get(
"/",
dependencies=providers.create_filter_dependencies({"search": "greeting", "search_ignore_case": True}),
)
@get("/", dependencies=providers.create_filter_dependencies({"search": "greeting", "search_ignore_case": True}))
async def simple_asyncpg(
db_session: AsyncpgDriver, filters: Annotated[list[FilterTypes], Dependency(skip_validation=True)]
) -> Optional[dict[str, str]]:
return await db_session.select_one_or_none(
"SELECT greeting FROM (select 'Hello, world!' as greeting) as t", *filters
)
) -> SQLResult[dict[str, Any]]:
return await db_session.execute("SELECT greeting FROM (select 'Hello, world!' as greeting) as t", *filters)


sqlspec = SQLSpec(
config=[
DatabaseConfig(
config=AsyncpgConfig(
pool_config=AsyncpgPoolConfig(dsn="postgres://app:app@localhost:15432/app", min_size=1, max_size=3),
),
config=AsyncpgConfig(dsn="postgres://app:app@localhost:15432/app", min_size=1, max_size=3),
commit_mode="autocommit",
)
]
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/litestar_duckllm.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def duckllm_chat(db_session: DuckDBDriver, data: ChatMessage) -> ChatMessage:
},
}
],
),
)
)
app = Litestar(route_handlers=[duckllm_chat], plugins=[sqlspec], debug=True)

Expand Down
7 changes: 4 additions & 3 deletions docs/examples/litestar_multi_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@

@get("/test", sync_to_thread=True)
def simple_select(etl_session: DuckDBDriver) -> dict[str, str]:
result = etl_session.select_one("SELECT 'Hello, ETL world!' AS greeting")
return {"greeting": result["greeting"]}
result = etl_session.execute("SELECT 'Hello, ETL world!' AS greeting")
greeting = result.get_first()
return {"greeting": greeting["greeting"] if greeting is not None else "hi"}


@get("/")
Expand All @@ -42,7 +43,7 @@ async def simple_sqlite(db_session: AiosqliteDriver) -> dict[str, str]:
connection_key="etl_connection",
session_key="etl_session",
),
],
]
)
app = Litestar(route_handlers=[simple_sqlite, simple_select], plugins=[sqlspec])

Expand Down
13 changes: 5 additions & 8 deletions docs/examples/litestar_psycopg.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,23 @@

from litestar import Litestar, get

from sqlspec.adapters.psycopg import PsycopgAsyncConfig, PsycopgAsyncDriver, PsycopgAsyncPoolConfig
from sqlspec.adapters.psycopg import PsycopgAsyncConfig, PsycopgAsyncDriver
from sqlspec.extensions.litestar import DatabaseConfig, SQLSpec


@get("/")
async def simple_psycopg(db_session: PsycopgAsyncDriver) -> dict[str, str]:
return await db_session.select_one("SELECT 'Hello, world!' AS greeting")
result = await db_session.execute("SELECT 'Hello, world!' AS greeting")
return result.get_first() or {"greeting": "No result found"}


sqlspec = SQLSpec(
config=[
DatabaseConfig(
config=PsycopgAsyncConfig(
pool_config=PsycopgAsyncPoolConfig(
conninfo="postgres://app:app@localhost:15432/app", min_size=1, max_size=3
),
),
config=PsycopgAsyncConfig(conninfo="postgres://app:app@localhost:15432/app", min_size=1, max_size=3),
commit_mode="autocommit",
)
],
]
)
app = Litestar(route_handlers=[simple_psycopg], plugins=[sqlspec])

Expand Down
11 changes: 2 additions & 9 deletions docs/examples/litestar_single_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@
This examples hows how to get the raw connection object from the SQLSpec plugin.
"""

# /// script
# dependencies = [
# "sqlspec[aiosqlite]",
# "litestar[standard]",
# ]
# ///

from aiosqlite import Connection
from litestar import Litestar, get

Expand All @@ -27,8 +20,8 @@ async def simple_sqlite(db_connection: Connection) -> dict[str, str]:
dict[str, str]: The greeting.
"""
result = await db_connection.execute_fetchall("SELECT 'Hello, world!' AS greeting")
return {"greeting": result[0][0]} # type: ignore
return {"greeting": next(iter(result))[0]}


sqlspec = SQLSpec(config=AiosqliteConfig())
sqlspec = SQLSpec(config=AiosqliteConfig(database=":memory:"))
app = Litestar(route_handlers=[simple_sqlite], plugins=[sqlspec])
107 changes: 107 additions & 0 deletions docs/examples/logging_setup_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"""Example of how to configure logging for SQLSpec.

Since SQLSpec no longer provides a configure_logging function,
users can set up their own logging configuration as needed.
"""

import logging
import sys

from sqlspec.utils.correlation import correlation_context
from sqlspec.utils.logging import StructuredFormatter, get_logger

__all__ = ("demo_correlation_ids", "setup_advanced_logging", "setup_simple_logging", "setup_structured_logging")


# Example 1: Basic logging setup with structured JSON output
def setup_structured_logging() -> None:
"""Set up structured JSON logging for SQLSpec."""
# Get the SQLSpec logger
sqlspec_logger = logging.getLogger("sqlspec")

# Set the logging level
sqlspec_logger.setLevel(logging.INFO)

# Create a console handler with structured formatter
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(StructuredFormatter())

# Add the handler to the logger
sqlspec_logger.addHandler(console_handler)

# Don't propagate to the root logger
sqlspec_logger.propagate = False

print("Structured logging configured for SQLSpec")


# Example 2: Simple text logging
def setup_simple_logging() -> None:
"""Set up simple text logging for SQLSpec."""
# Configure basic logging for the entire application
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler(sys.stdout)],
)

print("Simple logging configured")


# Example 3: Advanced setup with file output and custom formatting
def setup_advanced_logging() -> None:
"""Set up advanced logging with multiple handlers."""
sqlspec_logger = logging.getLogger("sqlspec")
sqlspec_logger.setLevel(logging.DEBUG)

# Console handler with simple format
console_handler = logging.StreamHandler(sys.stdout)
console_formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
console_handler.setFormatter(console_formatter)
console_handler.setLevel(logging.INFO) # Only INFO and above to console

# File handler with structured format
file_handler = logging.FileHandler("sqlspec.log")
file_handler.setFormatter(StructuredFormatter())
file_handler.setLevel(logging.DEBUG) # All messages to file

# Add both handlers
sqlspec_logger.addHandler(console_handler)
sqlspec_logger.addHandler(file_handler)

# Don't propagate to avoid duplicate logs
sqlspec_logger.propagate = False

print("Advanced logging configured with console and file output")


# Example 4: Using correlation IDs
def demo_correlation_ids() -> None:
"""Demonstrate using correlation IDs with logging."""

logger = get_logger("example")

# Without correlation ID
logger.info("This log has no correlation ID")

# With correlation ID
with correlation_context() as correlation_id:
logger.info("Starting operation with correlation ID: %s", correlation_id)
logger.info("This log will include the correlation ID automatically")

# Simulate some work
logger.debug("Processing data...")
logger.info("Operation completed")


if __name__ == "__main__":
# Choose your logging setup
print("=== Structured Logging Example ===")
setup_structured_logging()
demo_correlation_ids()

print("\n=== Simple Logging Example ===")
setup_simple_logging()

print("\n=== Advanced Logging Example ===")
setup_advanced_logging()
74 changes: 74 additions & 0 deletions docs/examples/queries/users.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
-- User Management SQL Queries
-- This file contains all user-related queries using aiosql-style named queries

-- name: get_user_by_id
-- Get a single user by their ID
SELECT
id,
username,
email,
created_at,
updated_at
FROM users
WHERE id = :user_id;

-- name: get_user_by_email
-- Find a user by their email address
SELECT
id,
username,
email,
created_at
FROM users
WHERE LOWER(email) = LOWER(:email);

-- name: list_active_users
-- List all active users with pagination
SELECT
id,
username,
email,
last_login_at
FROM users
WHERE is_active = true
ORDER BY username
LIMIT :limit OFFSET :offset;

-- name: create_user
-- Create a new user and return the created record
INSERT INTO users (
username,
email,
password_hash,
is_active
) VALUES (
:username,
:email,
:password_hash,
:is_active
)
RETURNING id, username, email, created_at;

-- name: update_user_last_login
-- Update the last login timestamp for a user
UPDATE users
SET
last_login_at = CURRENT_TIMESTAMP,
updated_at = CURRENT_TIMESTAMP
WHERE id = :user_id;

-- name: deactivate_user
-- Soft delete a user by setting is_active to false
UPDATE users
SET
is_active = false,
updated_at = CURRENT_TIMESTAMP
WHERE id = :user_id;

-- name: count_users_by_status
-- Count users grouped by their active status
SELECT
is_active,
COUNT(*) as count
FROM users
GROUP BY is_active;
Loading