package db import ( "context" "database/sql" "errors" "time" ) type User struct { Id int64 Name string Role int Character string Color string Pronouns string CreatedAt time.Time Hotbar map[string]string Stats UserStats } type UserStats struct { Id int64 CoreVersion string SystemId string SystemVersion string CreatedTime int64 ModifiedTime int64 LastModifiedBy string } type Users []User func (users Users) GetById(id int) *User { return &users[id] } func (m FoundryStateModel) InsertUser(user *User, stateId int64) error { query := ` INSERT INTO users (state_id, name, role, character, color, pronouns) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id, created_at` args := []any{stateId, user.Name, user.Role, user.Character, user.Color, user.Pronouns} ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() err := m.DB.QueryRowContext(ctx, query, args...).Scan(&user.Id, &user.CreatedAt) if err != nil { return err } for k, v := range user.Hotbar { err = m.InsertUserHotbar(k, v, user.Id) if err != nil { return err } } return m.InsertUserStats(&user.Stats, user.Id) } func (m FoundryStateModel) InsertUserHotbar(key string, value string, userId int64) error { query := ` INSERT INTO users_hotbar (user_id, key, value) VALUES ($1, $2, $3)` args := []any{userId, key, value} ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() _, err := m.DB.ExecContext(ctx, query, args...) if err != nil { return err } return nil } func (m FoundryStateModel) InsertUserStats(stats *UserStats, userId int64) error { query := ` INSERT INTO users_stats (user_id, core_version, system_id, system_version, created_time, modified_time, last_modified_by) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id` args := []any{userId, stats.CoreVersion, stats.SystemId, stats.SystemVersion, stats.CreatedTime, stats.ModifiedTime, stats.LastModifiedBy} ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() return m.DB.QueryRowContext(ctx, query, args...).Scan(&stats.Id) } func (m FoundryStateModel) GetUsers(idState int64) (Users, error) { if idState < 1 { return nil, ErrorRecordNotFound } query := ` SELECT id, created_at, name, role, character, color, pronouns FROM users WHERE state_id = $1` ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() rows, err := m.DB.QueryContext(ctx, query, idState) if err != nil { switch { case errors.Is(err, sql.ErrNoRows): return nil, ErrorRecordNotFound default: return nil, err } } users := make(Users, 0, 1) for rows.Next() { var user User err := rows.Scan( &user.Id, &user.CreatedAt, &user.Name, &user.Role, &user.Character, &user.Color, &user.Pronouns, ) if err != nil { return nil, err } user.Hotbar, err = m.GetUserHotbar(user.Id) if err != nil { return nil, err } userState, err := m.GetUserStats(user.Id) if err != nil { return nil, err } user.Stats = *userState users = append(users, user) } if err := rows.Err(); err != nil { return nil, err } return users, nil } func (m FoundryStateModel) GetUserHotbar(idUser int64) (map[string]string, error) { if idUser < 1 { return nil, ErrorRecordNotFound } query := ` SELECT key, value FROM users_hotbar WHERE user_id = $1` ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() rows, err := m.DB.QueryContext(ctx, query, idUser) if err != nil { switch { case errors.Is(err, sql.ErrNoRows): return nil, ErrorRecordNotFound default: return nil, err } } hotbar := make(map[string]string) for rows.Next() { var key string var val string err := rows.Scan( &key, &val, ) if err != nil { return nil, err } hotbar[key] = val } if err != nil { switch { case errors.Is(err, sql.ErrNoRows): return nil, ErrorRecordNotFound default: return nil, err } } return hotbar, nil } func (m FoundryStateModel) GetUserStats(idSystem int64) (*UserStats, error) { if idSystem < 1 { return nil, ErrorRecordNotFound } query := ` SELECT id, core_version, system_id, system_version, created_time, modified_time, last_modified_by FROM users_stats WHERE user_id = $1` var userStats UserStats ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() err := m.DB.QueryRowContext(ctx, query, idSystem).Scan( &userStats.Id, &userStats.CoreVersion, &userStats.SystemId, &userStats.SystemVersion, &userStats.CreatedTime, &userStats.ModifiedTime, &userStats.LastModifiedBy, ) if err != nil { switch { case errors.Is(err, sql.ErrNoRows): return nil, ErrorRecordNotFound default: return nil, err } } return &userStats, nil }