encore-go-database

Encore Go Database Operations

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 "encore-go-database" with this command: npx skills add encoredev/skills/encoredev-skills-encore-go-database

Encore Go Database Operations

Instructions

Database Setup

package user

import "encore.dev/storage/sqldb"

var db = sqldb.NewDatabase("userdb", sqldb.DatabaseConfig{ Migrations: "./migrations", })

Query Methods

Encore provides type-safe query methods using generics.

Query

  • Multiple Rows

type User struct { ID string Email string Name string }

func listActiveUsers(ctx context.Context) ([]*User, error) { rows, err := sqldb.Query[User](ctx, db, SELECT id, email, name FROM users WHERE active = true ) if err != nil { return nil, err } defer rows.Close()

var users []*User
for rows.Next() {
    users = append(users, rows.Value())
}
return users, rows.Err()

}

QueryRow

  • Single Row

func getUser(ctx context.Context, id string) (*User, error) { user, err := sqldb.QueryRow[User](ctx, db, SELECT id, email, name FROM users WHERE id = $1 , id) if errors.Is(err, sqldb.ErrNoRows) { return nil, &errs.Error{ Code: errs.NotFound, Message: "user not found", } } if err != nil { return nil, err } return user, nil }

Exec

  • No Return Value

For INSERT, UPDATE, DELETE operations:

func createUser(ctx context.Context, email, name string) error { _, err := sqldb.Exec(ctx, db, INSERT INTO users (id, email, name) VALUES ($1, $2, $3) , generateID(), email, name) return err }

func updateUser(ctx context.Context, id, name string) error { _, err := sqldb.Exec(ctx, db, UPDATE users SET name = $1 WHERE id = $2 , name, id) return err }

func deleteUser(ctx context.Context, id string) error { _, err := sqldb.Exec(ctx, db, DELETE FROM users WHERE id = $1 , id) return err }

Migrations

File Structure

user/ └── migrations/ ├── 1_create_users.up.sql ├── 2_add_posts.up.sql └── 3_add_indexes.up.sql

Naming Convention

  • Start with a number (1, 2, etc.)

  • Followed by underscore and description

  • End with .up.sql

  • Numbers must be sequential

Example Migration

-- migrations/1_create_users.up.sql CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email TEXT UNIQUE NOT NULL, name TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() );

CREATE INDEX idx_users_email ON users(email);

Transactions

func transferFunds(ctx context.Context, fromID, toID string, amount int) error { tx, err := db.Begin(ctx) if err != nil { return err } defer tx.Rollback() // No-op if committed

_, err = tx.Exec(ctx, `
    UPDATE accounts SET balance = balance - $1 WHERE id = $2
`, amount, fromID)
if err != nil {
    return err
}

_, err = tx.Exec(ctx, `
    UPDATE accounts SET balance = balance + $1 WHERE id = $2
`, amount, toID)
if err != nil {
    return err
}

return tx.Commit()

}

Struct Mapping

Query results map to struct fields by name (case-insensitive) or sql tag:

type User struct { ID string sql:"id" Email string sql:"email" Name string sql:"name" CreatedAt time.Time sql:"created_at" }

// Columns: id, email, name, created_at // Will map correctly to struct fields

SQL Injection Protection

Always use parameterized queries:

// SAFE - values are parameterized user, err := sqldb.QueryRow[User](ctx, db, SELECT * FROM users WHERE email = $1, email)

// WRONG - SQL injection risk query := fmt.Sprintf("SELECT * FROM users WHERE email = '%s'", email)

Error Handling

import ( "errors" "encore.dev/storage/sqldb" "encore.dev/beta/errs" )

func getUser(ctx context.Context, id string) (*User, error) { user, err := sqldb.QueryRow[User](ctx, db, SELECT id, email, name FROM users WHERE id = $1 , id)

if errors.Is(err, sqldb.ErrNoRows) {
    return nil, &errs.Error{
        Code:    errs.NotFound,
        Message: "user not found",
    }
}
if err != nil {
    return nil, err
}
return user, nil

}

Guidelines

  • Always use parameterized queries ($1 , $2 , etc.)

  • Use generics with sqldb.Query[T] and sqldb.QueryRow[T]

  • Check for sqldb.ErrNoRows when expecting a single row

  • Migrations are applied automatically on startup

  • Database names should be lowercase, descriptive

  • Each service typically has its own database

  • Use transactions for operations that must be atomic

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.

Coding

encore-auth

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

encore-code-review

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

encore-service

No summary provided by upstream source.

Repository SourceNeeds Review