agentleFS
doublewordaidoublewordai/control-layer/.claude/skills/sqlx-queries/SKILL.md

sqlx-queries

Skill96 starsChanged 30 days agoApache-2.0View on GitHub

Use when writing or reviewing control-layer SQLx queries, repository methods, QueryBuilder SQL, SELECT or RETURNING projections, pool routing, or cached-plan result-type errors.

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 0 are distinctive, and 4 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Keep database access in dwctl/src/db/handlers/ repositories.

    line 8
  2. Very specific:

    When replacing a wildcard, preserve the existing result descriptor.

    line 18
  3. Very specific:

    Prefer query! / query_as! for static SQL.

    line 20
  4. Very specific:

    Use #[sqlx::test] and repository/API tests, including relevant dynamic filters, empty results, nulls, and read-after-write workflows.

    line 78

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

SQLx queries in control-layer

Keep database access in dwctl/src/db/handlers/ repositories. Follow the nearby repository's connection/transaction and error conventions; handlers remain generic over PoolProvider. Paths below are repository-root-relative.

Write queries with stable results

  • Name result columns explicitly in SELECT and in INSERT/UPDATE/DELETE RETURNING. Do not use table-result SELECT *, alias.*, or RETURNING *, even when the Rust struct currently matches the whole table.
  • Match the intended Rust row fields, types, nullability, and SQLx aliases. When replacing a wildcard, preserve the existing result descriptor; review regenerated .sqlx metadata for unintended changes.
  • Prefer query! / query_as! for static SQL. Bind values with parameters; use .bind() for runtime queries and QueryBuilder::push_bind() for dynamic values. Only append trusted SQL fragments or allowlisted identifiers with push(); never interpolate request input into SQL.
  • Runtime query_as and QueryBuilder SQL needs execution tests: SQLx prepare does not compile-check those query strings.

Example from the groups repository, inside its transaction:

let group = sqlx::query_as!(
    Group,
    r#"
    INSERT INTO groups (name, description, created_by, source)
    VALUES ($1, $2, $3, 'native')
    RETURNING id, name, description, created_by, created_at, updated_at, source
    "#,
    request.name,
    request.description,
    request.created_by
)
.fetch_one(&mut *self.db)
.await?;

COUNT(*) does not expand a row. Fixed CTE/typed UNNEST projections need review of the complete query before an exemption: the final client-visible result must remain stable. Do not exempt a table wildcard merely to pass the guard.

Choose the connection by semantics

OperationConnection
Mutation or atomic multi-step operationPrimary .write() transaction; scope repository borrows, then commit
Read immediately after a write, including POST then GET across endpointsPrimary .write()
Read that tolerates replication lag.read()
LISTEN, session advisory locks, migrations/maintenanceExisting dedicated direct connection/provider, never a transaction-pooled query connection

Preserve the existing schema-routing helpers, including Fusillade's transaction-local schema selection where configured. Session SET state cannot be assumed to survive transaction pooling.

Migration compatibility

SQLx compile checks validate one schema snapshot. PgBouncer can retain prepared statements after all application clients restart. Adding a column can therefore break wildcard results with cached plan must not change result type.

Explicit columns protect additive changes, not in-place changes to selected column types. Use expand → backfill → switch readers/writers → contract after old clients drain. Do not blindly replay writes to recover from cached-plan errors or treat SQLx persistent(false) as invalidation of an existing statement.

See the migration explainer and use sqlx-index-migrations for index DDL.

Validate changes

Use #[sqlx::test] and repository/API tests, including relevant dynamic filters, empty results, nulls, and read-after-write workflows. Refresh .sqlx metadata with cargo sqlx prepare --workspace against correctly migrated local databases; preserve per-crate database configuration. Run just lint rust and just test rust before pushing Rust changes.

Lint runs scripts/check_query_projections.py; reviewed exceptions live in .github/fixtures/stable-query-projections.json. This source guard is not a SQL parser. For migration-sensitive queries, extend and run both shared/scoped pooled E2Es: warm queries, apply DDL, then exercise existing and replacement clients while PgBouncer stays alive.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.