data-access-patterns

Data Access Patterns Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "data-access-patterns" with this command: npx skills add sjtw/tarkov-build-optimiser/sjtw-tarkov-build-optimiser-data-access-patterns

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 jsonb_agg and jsonb_build_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:

  • Composite Writes: If a function calls multiple other write functions (e.g., UpsertWeapon calling upsertManySlot ), it MUST accept a *sql.Tx .

  • Top-Level Orchestration: Start the transaction at the highest possible level (usually in the importer or service layer).

  • 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.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

use-taskfile

No summary provided by upstream source.

Repository SourceNeeds Review
General

run-tests

No summary provided by upstream source.

Repository SourceNeeds Review
General

create-migration

No summary provided by upstream source.

Repository SourceNeeds Review
General

api-endpoint-pattern

No summary provided by upstream source.

Repository SourceNeeds Review