Files
Bookra/apps/auth-service/internal/db/db.go
T
Tomas Dvorak 48c3e15a38 cleanup
2026-05-05 09:48:07 +02:00

141 lines
3.9 KiB
Go

package db
import (
"context"
"fmt"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
)
type DB struct {
pool *pgxpool.Pool
}
func New(databaseURL string) (*DB, error) {
config, err := pgxpool.ParseConfig(databaseURL)
if err != nil {
return nil, fmt.Errorf("parse database config: %w", err)
}
pool, err := pgxpool.NewWithConfig(context.Background(), config)
if err != nil {
return nil, fmt.Errorf("create pool: %w", err)
}
if err := pool.Ping(context.Background()); err != nil {
return nil, fmt.Errorf("ping database: %w", err)
}
return &DB{pool: pool}, nil
}
func (db *DB) Close() {
db.pool.Close()
}
func (db *DB) Pool() *pgxpool.Pool {
return db.pool
}
func (db *DB) QueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row {
return db.pool.QueryRow(ctx, sql, args...)
}
func (db *DB) Query(ctx context.Context, sql string, args ...interface{}) (pgx.Rows, error) {
return db.pool.Query(ctx, sql, args...)
}
func (db *DB) Exec(ctx context.Context, sql string, args ...interface{}) error {
_, err := db.pool.Exec(ctx, sql, args...)
return err
}
// Stats contains database statistics for the admin dashboard
type Stats struct {
TotalUsers int64 `json:"totalUsers"`
UsersToday int64 `json:"usersToday"`
UsersThisWeek int64 `json:"usersThisWeek"`
UsersThisMonth int64 `json:"usersThisMonth"`
ActiveUsers7Days int64 `json:"activeUsers7Days"`
ActiveUsers30Days int64 `json:"activeUsers30Days"`
MagicLinksSent int64 `json:"magicLinksSent"`
MagicLinksUsed int64 `json:"magicLinksUsed"`
MagicLinksPending int64 `json:"magicLinksPending"`
OAuthUsers int64 `json:"oauthUsers"`
PasswordUsers int64 `json:"passwordUsers"`
}
// GetStats returns database statistics for the admin dashboard
func (db *DB) GetStats(ctx context.Context) (*Stats, error) {
stats := &Stats{}
// Total users
err := db.pool.QueryRow(ctx, `SELECT COUNT(*) FROM users`).Scan(&stats.TotalUsers)
if err != nil {
return nil, err
}
// Users created today
err = db.pool.QueryRow(ctx, `SELECT COUNT(*) FROM users WHERE created_at >= CURRENT_DATE`).Scan(&stats.UsersToday)
if err != nil {
return nil, err
}
// Users created this week
err = db.pool.QueryRow(ctx, `SELECT COUNT(*) FROM users WHERE created_at >= CURRENT_DATE - INTERVAL '7 days'`).Scan(&stats.UsersThisWeek)
if err != nil {
return nil, err
}
// Users created this month
err = db.pool.QueryRow(ctx, `SELECT COUNT(*) FROM users WHERE created_at >= CURRENT_DATE - INTERVAL '30 days'`).Scan(&stats.UsersThisMonth)
if err != nil {
return nil, err
}
// Active users (logged in) in last 7 days
err = db.pool.QueryRow(ctx, `SELECT COUNT(*) FROM users WHERE last_login_at >= CURRENT_DATE - INTERVAL '7 days'`).Scan(&stats.ActiveUsers7Days)
if err != nil {
return nil, err
}
// Active users in last 30 days
err = db.pool.QueryRow(ctx, `SELECT COUNT(*) FROM users WHERE last_login_at >= CURRENT_DATE - INTERVAL '30 days'`).Scan(&stats.ActiveUsers30Days)
if err != nil {
return nil, err
}
// Magic links sent (total)
err = db.pool.QueryRow(ctx, `SELECT COUNT(*) FROM magic_links`).Scan(&stats.MagicLinksSent)
if err != nil {
return nil, err
}
// Magic links used
err = db.pool.QueryRow(ctx, `SELECT COUNT(*) FROM magic_links WHERE used = TRUE`).Scan(&stats.MagicLinksUsed)
if err != nil {
return nil, err
}
// Pending magic links
err = db.pool.QueryRow(ctx, `SELECT COUNT(*) FROM magic_links WHERE used = FALSE AND expires_at > NOW()`).Scan(&stats.MagicLinksPending)
if err != nil {
return nil, err
}
// OAuth users
err = db.pool.QueryRow(ctx, `SELECT COUNT(*) FROM users WHERE provider != 'email'`).Scan(&stats.OAuthUsers)
if err != nil {
return nil, err
}
// Password users
err = db.pool.QueryRow(ctx, `SELECT COUNT(*) FROM users WHERE password_hash IS NOT NULL`).Scan(&stats.PasswordUsers)
if err != nil {
return nil, err
}
return stats, nil
}