Files
coder/.claude/docs/DATABASE.md
T
Thomas Kosiewski 0d3b7703f7 docs: remove dbmem references from documentation files (#18861)
Change-Id: Ic33bc383d00d0e354c25a0dd6080a4307d9862b6
Signed-off-by: Thomas Kosiewski <tk@coder.com>
2025-07-21 11:21:58 +02:00

6.2 KiB

Database Development Patterns

Database Work Overview

Database Generation Process

  1. Modify SQL files in coderd/database/queries/
  2. Run make gen
  3. If errors about audit table, update enterprise/audit/table.go
  4. Run make gen again
  5. Run make lint to catch any remaining issues

Migration Guidelines

Creating Migration Files

Location: coderd/database/migrations/ Format: {number}_{description}.{up|down}.sql

  • Number must be unique and sequential
  • Always include both up and down migrations

Helper Scripts

Script Purpose
./coderd/database/migrations/create_migration.sh "migration name" Creates new migration files
./coderd/database/migrations/fix_migration_numbers.sh Renumbers migrations to avoid conflicts
./coderd/database/migrations/create_fixture.sh "fixture name" Creates test fixtures for migrations

Database Query Organization

  • MUST DO: Any changes to database - adding queries, modifying queries should be done in the coderd/database/queries/*.sql files
  • MUST DO: Queries are grouped in files relating to context - e.g. prebuilds.sql, users.sql, oauth2.sql
  • After making changes to any coderd/database/queries/*.sql files you must run make gen to generate respective ORM changes

Handling Nullable Fields

Use sql.NullString, sql.NullBool, etc. for optional database fields:

CodeChallenge: sql.NullString{
    String: params.codeChallenge,
    Valid:  params.codeChallenge != "",
}

Set .Valid = true when providing values.

Audit Table Updates

If adding fields to auditable types:

  1. Update enterprise/audit/table.go
  2. Add each new field with appropriate action:
    • ActionTrack: Field should be tracked in audit logs
    • ActionIgnore: Field should be ignored in audit logs
    • ActionSecret: Field contains sensitive data
  3. Run make gen to verify no audit errors

Database Architecture

Core Components

  • PostgreSQL 13+ recommended for production
  • Migrations managed with migrate
  • Database authorization through dbauthz package

Authorization Patterns

// Public endpoints needing system access (OAuth2 registration)
app, err := api.Database.GetOAuth2ProviderAppByClientID(dbauthz.AsSystemRestricted(ctx), clientID)

// Authenticated endpoints with user context
app, err := api.Database.GetOAuth2ProviderAppByClientID(ctx, clientID)

// System operations in middleware
roles, err := db.GetAuthorizationUserRoles(dbauthz.AsSystemRestricted(ctx), userID)

Common Database Issues

Migration Issues

  1. Migration conflicts: Use fix_migration_numbers.sh to renumber
  2. Missing down migration: Always create both up and down files
  3. Schema inconsistencies: Verify against existing schema

Field Handling Issues

  1. Nullable field errors: Use sql.Null* types consistently
  2. Missing audit entries: Update enterprise/audit/table.go

Query Issues

  1. Query organization: Group related queries in appropriate files
  2. Generated code errors: Run make gen after query changes
  3. Performance issues: Add appropriate indexes in migrations

Database Testing

Test Database Setup

func TestDatabaseFunction(t *testing.T) {
    db := dbtestutil.NewDB(t)

    // Test with real database
    result, err := db.GetSomething(ctx, param)
    require.NoError(t, err)
    require.Equal(t, expected, result)
}

Best Practices

Schema Design

  1. Use appropriate data types: VARCHAR for strings, TIMESTAMP for times
  2. Add constraints: NOT NULL, UNIQUE, FOREIGN KEY as appropriate
  3. Create indexes: For frequently queried columns
  4. Consider performance: Normalize appropriately but avoid over-normalization

Query Writing

  1. Use parameterized queries: Prevent SQL injection
  2. Handle errors appropriately: Check for specific error types
  3. Use transactions: For related operations that must succeed together
  4. Optimize queries: Use EXPLAIN to understand query performance

Migration Writing

  1. Make migrations reversible: Always include down migration
  2. Test migrations: On copy of production data if possible
  3. Keep migrations small: One logical change per migration
  4. Document complex changes: Add comments explaining rationale

Advanced Patterns

Complex Queries

-- Example: Complex join with aggregation
SELECT
    u.id,
    u.username,
    COUNT(w.id) as workspace_count
FROM users u
LEFT JOIN workspaces w ON u.id = w.owner_id
WHERE u.created_at > $1
GROUP BY u.id, u.username
ORDER BY workspace_count DESC;

Conditional Queries

-- Example: Dynamic filtering
SELECT * FROM oauth2_provider_apps
WHERE
    ($1::text IS NULL OR name ILIKE '%' || $1 || '%')
    AND ($2::uuid IS NULL OR organization_id = $2)
ORDER BY created_at DESC;

Audit Patterns

// Example: Auditable database operation
func (q *sqlQuerier) UpdateUser(ctx context.Context, arg UpdateUserParams) (User, error) {
    // Implementation here

    // Audit the change
    if auditor := audit.FromContext(ctx); auditor != nil {
        auditor.Record(audit.UserUpdate{
            UserID: arg.ID,
            Old:    oldUser,
            New:    newUser,
        })
    }

    return newUser, nil
}

Debugging Database Issues

Common Debug Commands

# Check database connection
make test-postgres

# Run specific database tests
go test ./coderd/database/... -run TestSpecificFunction

# Check query generation
make gen

# Verify audit table
make lint

Debug Techniques

  1. Enable query logging: Set appropriate log levels
  2. Use database tools: pgAdmin, psql for direct inspection
  3. Check constraints: UNIQUE, FOREIGN KEY violations
  4. Analyze performance: Use EXPLAIN ANALYZE for slow queries

Troubleshooting Checklist

  • Migration files exist (both up and down)
  • make gen run after query changes
  • Audit table updated for new fields
  • Nullable fields use sql.Null* types
  • Authorization context appropriate for endpoint type