agentsclimarketplace

Sqlspec

Skill litestar-org/litestar-skills/skills/sqlspec

Opinionated first-party agent skills, plugins, subagents, slash commands, and MCP servers for the Litestar framework ecosystem — publishable to Claude Code, Gemini CLI, Codex CLI, Cursor, OpenCode, and VS Code/Copilot from a single repo.

Install
npx -y skills add litestar-org/litestar-skills --skill sqlspec

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 13 stars13 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Auto-activate for sqlspec, SQLSpec, SQLFileLoader, drivers, query builders, named SQL, filters, pagination, Arrow, framework extensions, ADK stores, data dictionary, or observers. Not for ORM repositories -- use advanced-alchemy.

SKILL.md

16.1 KB, ~3.8k tokens by cl100k_base, as published. Nobody here has run it

SQLSpec Skill

SQLSpec is a type-safe SQL query mapper for Python -- NOT an ORM. It provides flexible connectivity with consistent interfaces across 19 database adapter packages. Write raw SQL, use the builder API, or load SQL from files. Statements pass through a sqlglot-powered AST pipeline for validation, parameter handling, and dialect conversion.

Match-Your-Framework — read first

sqlspec ships first-party extensions for five web frameworks. If your project uses one of these, jump directly to the matching integration guide and skip the others:

  • Litestar — register configs on SQLSpec, then pass that registry to SQLSpecPlugin. The plugin adds DI, the litestar db CLI, and request observability. See references/extensions.md.
  • FastAPIreferences/fastapi-integration.mdDepends(plugin.provide_session()) DI, Annotated[...] handlers, filter providers.
  • Flaskreferences/flask-integration.mdplugin.init_app(app), pull-based plugin.get_session(), async-via-portal.
  • Starlettereferences/starlette-integration.mdrequest.state-based session access, lifespan wrapping, middleware variants.
  • Sanic — first-party ASGI-style extension for Sanic applications; match Sanic's app/request lifecycle instead of copying Litestar DI examples.

Shared topics that apply to every framework live in references/commit-modes.md (autocommit / manual middleware) and references/multi-database.md (multi-config registry). Read the framework guide first, then those for depth.

The rest of this SKILL.md covers framework-agnostic topics: adapter setup, query builder, driver methods, filters, observability, migrations, the ADK extension, and data-dictionary introspection.

Code Style Rules

  • from __future__ import annotations rule — SQLSpec adapter config modules and driver definitions avoid from __future__ import annotations because configs are introspected at runtime. Consumer application modules (handlers, services, tests that use a configured driver) MAY and typically SHOULD use it — canonical Litestar apps use it in 100+ files.

Quick Reference

Adapter Pattern

from sqlspec import SQLSpec
from sqlspec.adapters.asyncpg import AsyncpgConfig

# Configure the adapter with connection details
config = AsyncpgConfig(
    connection_config={
        "dsn": "postgresql://user:pass@localhost:5432/mydb",
        "min_size": 2,
        "max_size": 10,
    },
)
db_manager = SQLSpec()
db_manager.add_config(config)

# Use SQLSpec's session provider for connection lifecycle
async with db_manager.provide_session(config) as db:
    users = await db.select(
        "SELECT * FROM users WHERE active = $1",
        True,
        schema_type=User,
    )

Query Builder Essentials

from sqlspec import sql

# SELECT with filters
stmt = (
    sql.select("id", "name", "email")
    .from_("users")
    .where_eq("status", "active")
    .where("created_at > :since", since=cutoff_date)
    .order_by("created_at", desc=True)
    .limit(50)
    .to_statement()
)

# INSERT
stmt = (
    sql.insert("users")
    .columns("name", "email")
    .values(name="Alice", email="[email protected]")
    .to_statement()
)

# MERGE / upsert
stmt = (
    sql.merge("inventory", dialect="postgres")
    .using("updates")
    .on("inventory.product_id = updates.product_id")
    .when_matched_then_update(qty="updates.qty")
    .when_not_matched_then_insert(product_id="updates.product_id", qty="updates.qty")
    .to_statement()
)

Driver Method Summary

MethodReturnsUse Case
select() / fetch()List of rowsFiltered queries, listing
select_value()Single scalarCOUNT(*), MAX(), existence checks
select_value_or_none()Scalar or NoneOptional scalar lookup
select_one()One row (strict)Get-by-ID, raises NotFoundError
select_one_or_none()One row or NoneOptional lookup
select_with_total()Rows plus totalPagination
select_stream() / fetch_stream()Context-managed row streamBounded row iteration where adapter supports native streaming
select_to_arrow() / fetch_to_arrow()ArrowResultBulk data export, analytics
execute()SQLResultINSERT/UPDATE/DELETE metadata
execute_many()SQLResultBatch operation metadata
load_from_arrow()StorageBridgeJobAdapter-supported Arrow ingest
load_from_storage()StorageBridgeJobAdapter-supported staged-file ingest
load_from_records()StorageBridgeJobRecords normalized through the Arrow ingest path

Arrow Integration Basics

# Native Arrow export on adapters listed in references/adapters.md;
# conversion fallback elsewhere unless native_only=True.
arrow_result = await db.select_to_arrow(
    "SELECT * FROM large_dataset WHERE region = $1",
    region,
    return_format="reader",
    batch_size=10_000,
)

# Bulk load only when the selected adapter implements ingest.
await db.load_from_arrow("users", arrow_result)

# Bulk load records through the same native ingest path
await db.load_from_records("users", [{"id": 1, "name": "Ada"}])
<workflow>

Workflow

Step 1: Choose Adapter and Pattern

NeedAdapterKey Feature
PostgreSQL asyncasyncpg, psycopgAsync, NUMERIC/PYFORMAT params
PostgreSQL syncpsycopgSync+async, PYFORMAT params
SQLitesqlite, aiosqliteQMARK params, local dev
DuckDB analyticsduckdbArrow-native OLAP, extension load/install lifecycle
MySQL asyncasyncmyPYFORMAT params
OracleoracledbNAMED_COLON params, sync+async
BigQuery / Spannerbigquery, spannerNAMED_AT params, cloud job/session controls
Raw SQL stringsDriver methodsselect(), execute()
Dynamic queriesQuery buildersql.select()...to_statement()
SQL from filesSQLFileLoaderMetadata directives, -- param: declarations, caching
High-volume ingestStorage bridgeCheck the adapter matrix before selecting load_from_arrow(), load_from_storage(), or load_from_records()

Step 2: Implement

  1. Configure the adapter with connection details and pool settings
  2. Register the config with SQLSpec.add_config() and use SQLSpec.provide_session(config) for connection lifecycle
  3. Choose the appropriate driver method for your query shape
  4. Use schema_type parameter for typed results (Pydantic or msgspec models)
  5. Apply filters with LimitOffsetFilter, OrderByFilter, SearchFilter
  6. Use select_stream(..., native_only=True) when bounded-memory streaming is mandatory
  7. Check adapter ingest capabilities, then use load_from_records() or load_from_arrow() for high-volume ingest

Step 3: Validate

Run through the validation checkpoint below before considering the work complete.

</workflow> <guardrails>

Guardrails

  • Always use typed adapters: import the specific adapter config, not generic base classes
  • Always use schema_type for query results -- get typed objects, not raw dicts
  • Always use context managers for driver lifecycle -- async with db_manager.provide_session(config) as db:
  • Prefer the query builder for complex dynamic queries -- avoids string concatenation, handles dialect conversion
  • Prefer SQLFileLoader for static queries -- keeps SQL out of Python and reuses the global file-cache namespace
  • Use -- param: declarations for named SQL files that cross service boundaries -- load-time and execute-time validation catches name drift and required parameter omissions
  • Use native_only=True for streaming or Arrow paths only when fallback is unacceptable -- unsupported adapters otherwise use eager row conversion
  • Pass regular query bind values as positional arguments -- await db.select("... WHERE id = $1", user_id, schema_type=User), not await db.select(..., [user_id], ...)
  • Never concatenate SQL strings -- use parameterized queries or the query builder
  • Never hold connections outside context managers -- connection leaks exhaust the pool
  • Match parameter style to adapter: $1 for asyncpg, %s for psycopg, ? for sqlite, :name for oracledb
  • Do not invent adapter APIs -- BigQuery job controls live in driver_features; Spanner request controls live in driver_features or provide_session() kwargs
  • Adapter config / driver modules avoid from __future__ import annotations. Consumer app modules MAY use it.
</guardrails> <validation>

Validation Checkpoint

Before delivering SQLSpec code, verify:

  • Adapter config uses the correct import path (sqlspec.adapters.<name>)
  • Connection lifecycle uses SQLSpec.provide_session(config) context manager
  • Parameter style matches the adapter (see adapter registry table)
  • Query results use schema_type for type-safe mapping
  • Complex dynamic queries use the builder API, not string concatenation
  • Filters use SQLSpec filter objects (LimitOffsetFilter, etc.) not manual LIMIT/OFFSET
  • Streaming code uses context managers and sets native_only=True when eager fallback would be a bug
  • Bulk ingest code checks the adapter matrix before using load_from_arrow(), load_from_storage(), or load_from_records()
  • ADK stores are selected from supported adapter adk packages; BigQuery is not an ADK backend
</validation> <example>

Example

Task: "Set up an asyncpg adapter, define a typed model, and execute a parameterized query with pagination."

from dataclasses import dataclass
from sqlspec import SQLSpec
from sqlspec.adapters.asyncpg import AsyncpgConfig
from sqlspec.core.filters import LimitOffsetFilter, OrderByFilter


# --- Typed model ---

@dataclass
class User:
    id: int
    name: str
    email: str
    active: bool


# --- Adapter setup ---

config = AsyncpgConfig(
    connection_config={
        "dsn": "postgresql://user:pass@localhost:5432/mydb",
        "min_size": 2,
        "max_size": 10,
    },
)
db_manager = SQLSpec()
db_manager.add_config(config)


# --- Query execution ---

async def list_active_users(page: int = 1, page_size: int = 25) -> list[User]:
    filters = [
        OrderByFilter(field_name="name", sort_order="asc"),
        LimitOffsetFilter(limit=page_size, offset=(page - 1) * page_size),
    ]

    async with db_manager.provide_session(config) as db:
        users = await db.select(
            "SELECT id, name, email, active FROM users WHERE active = $1",
            True,
            *filters,
            schema_type=User,
        )
        return users


async def get_user_count() -> int:
    async with db_manager.provide_session(config) as db:
        count = await db.select_value(
            "SELECT COUNT(*) FROM users WHERE active = $1", True
        )
        return count
</example>

References Index

Choosing between sqlspec and advanced-alchemy: advanced-alchemy gives you an opinionated ORM service layer with UUIDAuditBase, lifecycle hooks, repository / service / Alembic integration, and OffsetPagination[T] out of the box — pick it when you want a complete CRUD surface with attribute-style row access and you're happy inside the SQLAlchemy ecosystem. sqlspec gives you direct SQL control, 19 adapter packages (asyncpg, oracledb, DuckDB, BigQuery, SQLite, and more), Arrow result paths for analytics, and a builder API when you need it — pick it when you want explicit SQL, heterogeneous database backends, or Arrow integration. Both skills integrate with Litestar via first-party plugins; see ../advanced-alchemy/SKILL.md for the ORM path.

For detailed instructions, patterns, and API guides, refer to the following documents:

Standards & Style

Core Utilities

Architecture & Performance

  • Architecture & Caching -- Core data flow, global cache configuration, namespaces, and driver-local statement caches.
  • Performance & Cloud Controls -- Bounded async bridge, cache/fetch tuning, BigQuery job controls, Spanner session controls.
  • Data Dictionary -- Dialect feature flags, runtime introspection (get_tables, get_columns, get_indexes), ADBC native metadata/statistics.

Query Building & Execution

Data Integration

Adapters & Drivers

Framework & Storage Integrations

Migrations & Schema

  • Native Migration Runner -- standalone sqlspec CLI, timestamp versioning, ddl_migrations tracker, extension migrations, and Litestar litestar db integration.

Observability

Advanced Patterns

  • Design Patterns -- Service layer, batch operations, upsert, AST tenant filters.
  • Service Patterns -- SQLSpecAsyncService base, named SQL templates via db_manager.get_sql, direct driver API (select_value / select_one / execute), variadic filter composition, create_filter_dependencies() wiring.
  • Dishka Integration -- FromDishka as Inject alias, multi-provider pattern (REQUEST-scoped domain services, REQUEST-scoped driver, APP-scoped singletons), handler injection.
  • Vector Search — Oracle VECTOR_DISTANCE cosine similarity, Vertex AI embedding generation, SHA256-keyed embedding cache, intent classification via exemplar similarity, pgvector cross-reference.

Key Resources

Official References

Shared Styleguide Baseline

  • Use shared styleguides for generic language/framework rules to reduce duplication in this skill.
  • General Principles
  • Python
  • Litestar
  • Keep this skill focused on tool-specific workflows, edge cases, and integration details.

Gives 1 of the 12 instructions most databases sql skills give in ~3.8k tokens

Counted across 589 of the 662 authors here whose files we hold, read 2026-08-06

  • use parameterized querieshere, and in 36 of 589, across 32 files
  • use timestamptz for timestampsin 30 of 589, across 12 files
  • create indexes concurrentlyin 29 of 589, across 23 files
  • index foreign keysin 28 of 589, across 17 files
  • use numeric type for moneyin 25 of 589, across 8 files
  • select only required columnsin 24 of 589, across 19 files
  • use cursor pagination instead of OFFSETin 23 of 589, across 15 files
  • add indexes manually on foreign key columnsin 22 of 589, across 11 files
  • read individual rule files for detailed explanationsin 18 of 589, across 4 files
  • configure connection poolingin 18 of 589, across 16 files
  • put equality columns before range columns in indexesin 17 of 589, across 9 files
  • normalize to third normal formin 17 of 589, across 8 files

Said here and by no other author read

  • use typed adapter configs
  • use context managers for sessions
  • use schema_type for query results
  • match parameter style to adapter
  • use SQLFileLoader for static queries
  • use parameter declarations for named SQL

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.