package levelrepo import ( "context" "database/sql" ) type Level struct { GuildID int64 UserID int64 Level int XP int64 } type Repo struct { db *sql.DB } func NewRepo(db *sql.DB) *Repo { return &Repo{db: db} } func (r *Repo) GetLevel(ctx context.Context, guildID, userID int64) (*Level, error) { const q = ` SELECT level, xp FROM levels WHERE guild = $1 AND user_id = $2 ` row := r.db.QueryRowContext(ctx, q, guildID, userID) var lvl Level lvl.GuildID = guildID lvl.UserID = userID switch err := row.Scan(&lvl.Level, &lvl.XP); err { case sql.ErrNoRows: // default new user lvl.Level = 0 lvl.XP = 0 return &lvl, nil case nil: return &lvl, nil default: return nil, err } } func (r *Repo) UpsertLevel(ctx context.Context, lvl *Level) error { const q = ` INSERT INTO levels (guild, user_id, level, xp) VALUES ($1, $2, $3, $4) ON CONFLICT (guild, user_id) DO UPDATE SET level = EXCLUDED.level, xp = EXCLUDED.xp ` _, err := r.db.ExecContext(ctx, q, lvl.GuildID, lvl.UserID, lvl.Level, lvl.XP) return err } func (r *Repo) SetLevel(ctx context.Context, guildID, userID int64, level int) error { const q = ` INSERT INTO levels (guild, user_id, level, xp) VALUES ($1, $2, $3, 99) ON CONFLICT (guild, user_id) DO UPDATE SET level = EXCLUDED.level, xp = 99 ` _, err := r.db.ExecContext(ctx, q, guildID, userID, level) return err } func (r *Repo) TopLevels(ctx context.Context, guildID int64, limit int) ([]*Level, error) { const q = ` SELECT user_id, level, xp FROM levels WHERE guild = $1 ORDER BY level DESC, xp DESC, user_id ASC LIMIT $2 ` rows, err := r.db.QueryContext(ctx, q, guildID, limit) if err != nil { return nil, err } defer rows.Close() out := make([]*Level, 0, limit) for rows.Next() { lvl := &Level{GuildID: guildID} if err := rows.Scan(&lvl.UserID, &lvl.Level, &lvl.XP); err != nil { return nil, err } out = append(out, lvl) } if err := rows.Err(); err != nil { return nil, err } return out, nil }