Skip to content

Commit d302608

Browse files
authored
docs: convert data_flow.rst code examples to executable tests (#230)
Replace inline code-block examples with literalinclude directives pointing to executable test files. This ensures all examples are validated via pytest and remain accurate as the codebase evolves.
1 parent 68e4669 commit d302608

16 files changed

+423
-137
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""Example 1: Direct SQL Creation with positional and named parameters."""
2+
3+
__all__ = ("test_direct_sql_creation",)
4+
5+
6+
def test_direct_sql_creation() -> None:
7+
"""Test creating SQL statements with different parameter styles."""
8+
# start-example
9+
from sqlspec import SQL
10+
11+
# Raw SQL string with positional parameters
12+
sql = SQL("SELECT * FROM users WHERE id = ?", 1)
13+
14+
# Named parameters
15+
sql = SQL("SELECT * FROM users WHERE email = :email", email="user@example.com")
16+
# end-example
17+
18+
# Verify SQL objects were created
19+
assert sql is not None
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""Example 10: SQLite Driver Execution implementation."""
2+
3+
__all__ = ("test_sqlite_driver_pattern",)
4+
5+
6+
def test_sqlite_driver_pattern() -> None:
7+
"""Test SQLite driver execution pattern."""
8+
# start-example
9+
from typing import Any
10+
11+
from sqlspec.driver import ExecutionResult, SyncDriverAdapterBase
12+
13+
class SqliteDriver(SyncDriverAdapterBase):
14+
def _execute_statement(self, cursor: Any, statement: Any) -> ExecutionResult:
15+
sql, params = self._get_compiled_sql(statement)
16+
cursor.execute(sql, params or ())
17+
return self.create_execution_result(cursor)
18+
19+
def _execute_many(self, cursor: Any, statement: Any) -> ExecutionResult:
20+
sql, params = self._get_compiled_sql(statement)
21+
cursor.executemany(sql, params)
22+
return self.create_execution_result(cursor)
23+
24+
# end-example
25+
26+
# Verify class was defined
27+
assert SqliteDriver is not None
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""Example 11: SQLResult Object."""
2+
3+
__all__ = ("test_sql_result_object",)
4+
5+
6+
def test_sql_result_object() -> None:
7+
"""Test accessing SQLResult object properties."""
8+
from sqlspec import SQLSpec
9+
from sqlspec.adapters.sqlite import SqliteConfig
10+
11+
db_manager = SQLSpec()
12+
db = db_manager.add_config(SqliteConfig(pool_config={"database": ":memory:"}))
13+
14+
# start-example
15+
with db_manager.provide_session(db) as session:
16+
result = session.execute("SELECT 'test' as col1, 'value' as col2")
17+
18+
# Access result data
19+
result.data # List of dictionaries
20+
result.rows_affected # Number of rows modified (INSERT/UPDATE/DELETE)
21+
result.column_names # Column names for SELECT
22+
result.operation_type # "SELECT", "INSERT", "UPDATE", "DELETE", "SCRIPT"
23+
# end-example
24+
25+
# Verify result properties
26+
assert result.data is not None
27+
assert result.column_names is not None
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""Example 12: Convenience Methods."""
2+
3+
__all__ = ("test_convenience_methods",)
4+
5+
6+
def test_convenience_methods() -> None:
7+
"""Test SQLResult convenience methods."""
8+
from sqlspec import SQLSpec
9+
from sqlspec.adapters.sqlite import SqliteConfig
10+
11+
db_manager = SQLSpec()
12+
db = db_manager.add_config(SqliteConfig(pool_config={"database": ":memory:"}))
13+
14+
with db_manager.provide_session(db) as session:
15+
# Create a test table
16+
session.execute("CREATE TABLE test (id INTEGER, name TEXT)")
17+
session.execute("INSERT INTO test VALUES (1, 'Alice')")
18+
19+
# start-example
20+
result = session.execute("SELECT * FROM test WHERE id = 1")
21+
22+
# Get exactly one row (raises if not exactly one)
23+
user = result.one()
24+
25+
# Get one or None
26+
user = result.one_or_none()
27+
28+
# Get scalar value (first column of first row)
29+
result2 = session.execute("SELECT COUNT(*) FROM test")
30+
count = result2.scalar()
31+
# end-example
32+
33+
# Verify results
34+
assert user is not None
35+
assert count == 1
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""Example 13: Schema Mapping."""
2+
3+
__all__ = ("test_schema_mapping",)
4+
5+
6+
def test_schema_mapping() -> None:
7+
"""Test mapping results to typed objects."""
8+
9+
# start-example
10+
from pydantic import BaseModel
11+
12+
from sqlspec import SQLSpec
13+
from sqlspec.adapters.sqlite import SqliteConfig
14+
15+
class User(BaseModel):
16+
id: int
17+
name: str
18+
email: str
19+
is_active: bool | None = True
20+
21+
db_manager = SQLSpec()
22+
db = db_manager.add_config(SqliteConfig(pool_config={"database": ":memory:"}))
23+
24+
with db_manager.provide_session(db) as session:
25+
# Create test table
26+
session.execute("CREATE TABLE users (id INTEGER, name TEXT, email TEXT, is_active INTEGER)")
27+
session.execute("INSERT INTO users VALUES (1, 'Alice', 'alice@example.com', 1)")
28+
29+
# Execute query
30+
result = session.execute("SELECT id, name, email, is_active FROM users")
31+
32+
# Map results to typed User instances
33+
users: list[User] = result.all(schema_type=User)
34+
35+
# Or get single typed user
36+
single_result = session.execute("SELECT id, name, email, is_active FROM users WHERE id = ?", 1)
37+
user: User = single_result.one(schema_type=User) # Type-safe!
38+
# end-example
39+
40+
# Verify typed results
41+
assert len(users) == 1
42+
assert isinstance(user, User)
43+
assert user.id == 1
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""Example 14: Multi-Tier Caching."""
2+
3+
__all__ = ("test_multi_tier_caching",)
4+
5+
6+
def test_multi_tier_caching() -> None:
7+
"""Test cache types in SQLSpec."""
8+
# start-example
9+
from sqlglot import Expression
10+
11+
# Cache types and their purposes:
12+
sql_cache: dict[str, str] = {} # Compiled SQL strings
13+
optimized_cache: dict[str, Expression] = {} # Post-optimization AST
14+
# end-example
15+
16+
# Verify cache dictionaries were created
17+
assert isinstance(sql_cache, dict)
18+
assert isinstance(optimized_cache, dict)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Example 15: Configuration-Driven Processing."""
2+
3+
__all__ = ("test_configuration_driven_processing",)
4+
5+
6+
def test_configuration_driven_processing() -> None:
7+
"""Test StatementConfig for controlling pipeline behavior."""
8+
# start-example
9+
from sqlspec import ParameterStyle, ParameterStyleConfig, StatementConfig
10+
11+
config = StatementConfig(
12+
dialect="postgres",
13+
enable_parsing=True, # AST generation
14+
enable_validation=True, # Security/performance checks
15+
enable_transformations=True, # AST transformations
16+
enable_caching=True, # Multi-tier caching
17+
parameter_config=ParameterStyleConfig(
18+
default_parameter_style=ParameterStyle.NUMERIC, has_native_list_expansion=False
19+
),
20+
)
21+
# end-example
22+
23+
# Verify config was created
24+
assert config is not None
25+
assert config.dialect == "postgres"
26+
assert config.enable_parsing is True
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""Example 2: Using the Query Builder."""
2+
3+
__all__ = ("test_query_builder",)
4+
5+
6+
def test_query_builder() -> None:
7+
"""Test building SQL programmatically."""
8+
# start-example
9+
from sqlspec import sql
10+
11+
# Build SQL programmatically
12+
query = sql.select("id", "name", "email").from_("users").where("status = ?", "active")
13+
# end-example
14+
15+
# Verify query object was created
16+
assert query is not None
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""Example 3: From SQL Files."""
2+
3+
from pathlib import Path
4+
5+
__all__ = ("test_sql_file_loader",)
6+
7+
8+
def test_sql_file_loader() -> None:
9+
"""Test loading SQL from files."""
10+
# start-example
11+
from sqlspec.loader import SQLFileLoader
12+
13+
loader = SQLFileLoader()
14+
queries_path = Path(__file__).resolve().parents[1] / "queries" / "users.sql"
15+
loader.load_sql(queries_path)
16+
sql = loader.get_sql("get_user_by_id")
17+
# end-example
18+
19+
# Verify SQL object was created
20+
assert sql is not None
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""Example 4: Parameter Extraction."""
2+
3+
__all__ = ("test_parameter_extraction",)
4+
5+
6+
def test_parameter_extraction() -> None:
7+
"""Show how SQL captures positional and named parameters."""
8+
from sqlspec import SQL
9+
10+
# start-example
11+
positional = SQL("SELECT * FROM users WHERE id = ? AND status = ?", 1, "active")
12+
positional_map = dict(enumerate(positional.positional_parameters))
13+
14+
named = SQL("SELECT * FROM users WHERE email = :email", email="user@example.com")
15+
named_map = named.named_parameters
16+
# end-example
17+
18+
assert positional_map == {0: 1, 1: "active"}
19+
assert named_map == {"email": "user@example.com"}

0 commit comments

Comments
 (0)