Files
b0esche_cloud/go_cloud/internal/database/db.go
2025-12-17 22:57:57 +01:00

125 lines
2.9 KiB
Go

package database
import (
"context"
"database/sql"
"time"
"github.com/google/uuid"
)
type DB struct {
*sql.DB
}
func New(db *sql.DB) *DB {
return &DB{DB: db}
}
type User struct {
ID uuid.UUID
Email string
DisplayName string
CreatedAt time.Time
LastLoginAt *time.Time
}
type Session struct {
ID uuid.UUID
UserID uuid.UUID
ExpiresAt time.Time
RevokedAt *time.Time
}
type Organization struct {
ID uuid.UUID
Name string
Slug string
CreatedAt time.Time
}
type Membership struct {
UserID uuid.UUID
OrgID uuid.UUID
Role string
CreatedAt time.Time
}
func (db *DB) GetOrCreateUser(ctx context.Context, sub, email, name string) (*User, error) {
var user User
err := db.QueryRowContext(ctx, `
INSERT INTO users (id, email, display_name)
VALUES (gen_random_uuid(), $1, $2)
ON CONFLICT (email) DO UPDATE SET
display_name = EXCLUDED.display_name,
last_login_at = NOW()
RETURNING id, email, display_name, created_at, last_login_at
`, email, name).Scan(&user.ID, &user.Email, &user.DisplayName, &user.CreatedAt, &user.LastLoginAt)
if err != nil {
return nil, err
}
return &user, nil
}
func (db *DB) CreateSession(ctx context.Context, userID uuid.UUID, expiresAt time.Time) (*Session, error) {
var session Session
err := db.QueryRowContext(ctx, `
INSERT INTO sessions (user_id, expires_at)
VALUES ($1, $2)
RETURNING id, user_id, expires_at, revoked_at
`, userID, expiresAt).Scan(&session.ID, &session.UserID, &session.ExpiresAt, &session.RevokedAt)
if err != nil {
return nil, err
}
return &session, nil
}
func (db *DB) GetSession(ctx context.Context, sessionID uuid.UUID) (*Session, error) {
var session Session
err := db.QueryRowContext(ctx, `
SELECT id, user_id, expires_at, revoked_at
FROM sessions
WHERE id = $1
`, sessionID).Scan(&session.ID, &session.UserID, &session.ExpiresAt, &session.RevokedAt)
if err != nil {
return nil, err
}
return &session, nil
}
func (db *DB) GetUserOrganizations(ctx context.Context, userID uuid.UUID) ([]Organization, error) {
rows, err := db.QueryContext(ctx, `
SELECT o.id, o.name, o.slug, o.created_at
FROM organizations o
JOIN memberships m ON o.id = m.org_id
WHERE m.user_id = $1
`, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var orgs []Organization
for rows.Next() {
var org Organization
if err := rows.Scan(&org.ID, &org.Name, &org.Slug, &org.CreatedAt); err != nil {
return nil, err
}
orgs = append(orgs, org)
}
return orgs, rows.Err()
}
func (db *DB) GetUserMembership(ctx context.Context, userID, orgID uuid.UUID) (*Membership, error) {
var membership Membership
err := db.QueryRowContext(ctx, `
SELECT user_id, org_id, role, created_at
FROM memberships
WHERE user_id = $1 AND org_id = $2
`, userID, orgID).Scan(&membership.UserID, &membership.OrgID, &membership.Role, &membership.CreatedAt)
if err != nil {
return nil, err
}
return &membership, nil
}