smithery.ai

data-access-patterns

Guidelines for database interactions using raw SQL and idiomatic Go patterns

First seen Mar 27, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 3,775 B
  • docs SUMMARY.md 104 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Data Access Patterns Skill

Use this skill when writing or modifying database access code in internal/models/.

This project uses explicit SQL over ORMs for performance, readability, and fine-grained control.


Core Principles

  • No ORM: Use database/sql directly. Do NOT introduce or use any ORM.
  • PostgreSQL Driver: The project uses github.com/lib/pq (imported in internal/db/db.go).
  • Raw SQL: Write explicit, readable SQL queries. Use PostgreSQL-specific features (JSONB, ON CONFLICT) and $1, $2 placeholders.
  • Transactional Integrity: Use *sql.Tx when multiple operations must complete together or fail (atomicity).
  • Separation of Concerns: Keep database models and access logic in internal/models/. Repository functions should focus on data retrieval and persistence.

Repository Function Naming

Pattern Purpose Example Signature
Get[Entity]ById Retrieve a single entity GetWeaponById(db sql.DB, id string) (Weapon, error)
Get[Entities]By[Field] Filtered retrieval GetTraderOffersByItemID(db *sql.DB, itemID string) ([]TraderOffer, error)
Upsert[Entity] Insert or update one record UpsertWeapon(tx *sql.Tx, weapon Weapon) error
UpsertMany[Entity] Batch insert/update UpsertManyWeapon(tx *sql.Tx, weapons []Weapon) error
Purge[Entity] Clean up records PurgeOptimumBuilds(db *sql.DB) error

Writing Efficient Queries

JSONB for Complex Trees

When fetching an entity with nested children (e.g., a weapon with many slots), use jsonbagg and jsonbbuild_object to minimize round-trips and simplify Go-side scanning.

// Example: Single query to fetch weapon and all its slots
query := `
    SELECT w.name,
           w.item_id,
           jsonb_agg(jsonb_build_object(
               'slot_id', ws.slot_id, 
               'name', ws.name
           )) as slots
    FROM weapons w
    JOIN slots ws ON w.item_id = ws.item_id
    WHERE w.item_id = $1
    GROUP BY w.name, w.item_id;`

Idempotent Writes (ON CONFLICT)

Prefer ON CONFLICT for upsert operations to ensure idempotency and handle existing records gracefully.

query := `
    INSERT INTO weapons (item_id, name)
    VALUES ($1, $2)
    ON CONFLICT (item_id) DO UPDATE SET
        name = EXCLUDED.name;`

Transaction Management Checklist

When implementing writes:

  1. Composite Writes: If a function calls multiple other write functions (e.g., UpsertWeapon calling upsertManySlot), it MUST accept a *sql.Tx.
  2. Top-Level Orchestration: Start the transaction at the highest possible level (usually in the importer or service layer).
  3. Defer Rollback: Defer a rollback immediately after starting a transaction to prevent leaks on error.
tx, err := db.Begin()
if err != nil {
    return err
}
defer tx.Rollback() // Safe: does nothing if committed

if err := UpsertManyWeapon(tx, weapons); err != nil {
    return err
}

return tx.Commit()

Developer Best Practices

  • ✅ Explicit Scanning: Scan rows into structs carefully; match types exactly with the DB schema.
  • ✅ Resource Management: defer rows.Close() immediately after a Query call.
  • ✅ Strict Errors: Check errors after rows.Scan() AND after the loop with rows.Err().
  • ✅ Clean Signatures: Pass sql.DB for read-only operations and sql.Tx for multi-step write operations.
  • ❌ Avoid SELECT *: Explicitly list required columns to prevent breakage from schema changes.
  • ❌ No Global DB: Pass the database handle as an argument.