package database import ( "context" "database/sql" "time" "git.eeqj.de/sneak/routewatch/internal/logger" ) const slowQueryThreshold = 25 * time.Millisecond // logSlowQuery logs queries that take longer than slowQueryThreshold func logSlowQuery(logger *logger.Logger, query string, start time.Time) { elapsed := time.Since(start) if elapsed > slowQueryThreshold { logger.Debug("Slow query", "query", query, "duration", elapsed) } } // exec wraps Exec with slow query logging func (d *Database) exec(query string, args ...any) error { start := time.Now() defer logSlowQuery(d.logger, query, start) _, err := d.db.ExecContext(context.Background(), query, args...) return err } // loggingTx wraps sql.Tx to log slow queries type loggingTx struct { *sql.Tx logger *logger.Logger } // QueryRow wraps sql.Tx.QueryRow to log slow queries func (tx *loggingTx) QueryRow(query string, args ...any) *sql.Row { start := time.Now() defer logSlowQuery(tx.logger, query, start) return tx.Tx.QueryRowContext(context.Background(), query, args...) } // QueryRowContext wraps sql.Tx.QueryRowContext to log slow queries func (tx *loggingTx) QueryRowContext( ctx context.Context, query string, args ...any, ) *sql.Row { start := time.Now() defer logSlowQuery(tx.logger, query, start) return tx.Tx.QueryRowContext(ctx, query, args...) } // QueryContext wraps sql.Tx.QueryContext to log slow queries func (tx *loggingTx) QueryContext( ctx context.Context, query string, args ...any, ) (*sql.Rows, error) { start := time.Now() defer logSlowQuery(tx.logger, query, start) //nolint:sqlclosecheck // returns the rows, which the caller closes return tx.Tx.QueryContext(ctx, query, args...) } // Exec wraps sql.Tx.Exec to log slow queries func (tx *loggingTx) Exec(query string, args ...any) (sql.Result, error) { start := time.Now() defer logSlowQuery(tx.logger, query, start) return tx.Tx.ExecContext(context.Background(), query, args...) } // ExecContext wraps sql.Tx.ExecContext to log slow queries func (tx *loggingTx) ExecContext( ctx context.Context, query string, args ...any, ) (sql.Result, error) { start := time.Now() defer logSlowQuery(tx.logger, query, start) return tx.Tx.ExecContext(ctx, query, args...) }