package psql import ( "context" "database/sql" "errors" "math" "time" "ymgb/database" "github.com/shopspring/decimal" "github.com/vinovest/sqlx" ) type User struct { ID int64 Balance decimal.Decimal Name string GroupID int `db:"group_id"` Level int Exp int WorkID int `db:"work_id"` WorkTime time.Time `db:"work_time"` AutoID sql.NullInt32 `db:"auto_id"` BusinessID sql.NullInt32 `db:"business_id"` MaidID sql.NullInt32 `db:"maid_id"` MinerID sql.NullInt32 `db:"miner_id"` IncomeTime time.Time `db:"income_time"` BTC decimal.Decimal Invested decimal.Decimal PairID sql.NullInt64 `db:"pair_id"` Greeting string Donat int FractionID sql.NullInt32 `db:"fraction_id"` MoneyIncome decimal.Decimal `db:"money_income"` ExpIncome int `db:"exp_income"` BtcIncome decimal.Decimal `db:"btc_income"` WaifuSearchTime time.Time `db:"waifu_search_time"` Group *Group Work *Work Auto *ShopAuto Business *ShopBusiness Maid *ShopMaid Miner *ShopMiner Pair *User Fraction *Fraction } type UserRepository struct { db *sqlx.DB } func newUserRepository(db *sqlx.DB) UserRepository { return UserRepository{db} } func NewUserRepository(db *database.Context) UserRepository { return newUserRepository(db.Postgres) } func (rep UserRepository) GetOrCreate(tgId int64, name string) (*User, error) { user, err := rep.GetById(tgId) if errors.Is(err, sql.ErrNoRows) { user, err = rep.Create(tgId, name) } return user, err } func (rep UserRepository) Create(id int64, name string) (*User, error) { user := new(User) err := rep.db.Get(user, "INSERT INTO users (id, name) VALUES ($1, $2) RETURNING *;", id, name) return user, err } func (rep UserRepository) GetById(telegramId int64) (*User, error) { user := new(User) err := rep.db.Get(user, "SELECT * FROM users WHERE id=$1;", telegramId) if err != nil { return user, err } return rep.GetJoins(user) } func (rep UserRepository) GetJoins(user *User) (*User, error) { err := sqlx.Transact(rep.db, func(ctx context.Context, db sqlx.Queryable) error { user.Group = new(Group) err := rep.db.Get(user.Group, "SELECT * FROM groups WHERE id=$1;", user.GroupID) if err != nil { return err } user.Work = new(Work) err = rep.db.Get(user.Work, "SELECT * FROM works WHERE id=$1;", user.WorkID) if err != nil { return err } shopRep := newShopRepository(rep.db) if user.AutoID.Valid { auto, err := shopRep.GetAuto(user.AutoID.Int32) if err != nil { return err } user.Auto = &auto } if user.BusinessID.Valid { business, err := shopRep.GetBusiness(user.BusinessID.Int32) if err != nil { return err } user.Business = &business } if user.MaidID.Valid { maid, err := shopRep.GetMaid(user.MaidID.Int32) if err != nil { return err } user.Maid = &maid } if user.MinerID.Valid { miner, err := shopRep.GetMiner(user.MinerID.Int32) if err != nil { return err } user.Miner = &miner } if user.PairID.Valid { pair, err := rep.GetById(user.PairID.Int64) if err != nil { return err } user.Pair = pair } if user.FractionID.Valid { fractionRep := newFractionRepository(rep.db) fraction, err := fractionRep.GetById(user.FractionID.Int32) if err != nil { return err } user.Fraction = &fraction } return nil }) return user, err } func (rep UserRepository) Update(user *User) (*User, error) { _, err := rep.db.NamedExec( `UPDATE users SET balance=:balance, name=:name, group_id=:group_id, level=:level, exp=:exp, work_id=:work_id, work_time=:work_time, auto_id=:auto_id, business_id=:business_id, maid_id=:maid_id, miner_id=:miner_id, income_time=:income_time, btc=:btc, invested=:invested, pair_id=:pair_id, greeting=:greeting, donat=:donat, fraction_id=:fraction_id, money_income=:money_income, exp_income=:exp_income, btc_income=:btc_income, waifu_search_time=:waifu_search_time WHERE id=:id;`, user, ) if err != nil { return nil, err } return rep.GetById(user.ID) } func (rep UserRepository) GetAll() ([]User, error) { users := make([]User, 0) err := rep.db.Select(&users, "SELECT * FROM users ORDER BY id;") if err != nil { return nil, err } outUsers := make([]User, len(users)) for i, user := range users { u, err := rep.GetJoins(&user) if err != nil { return nil, err } outUsers[i] = *u } return outUsers, nil } func CountLevel(userXp int) (int, int) { xp := 0 nextLevel := 2 for { xp = int(math.Pow(float64(nextLevel), 3)) * (nextLevel * 3) if xp > userXp { break } if nextLevel == 200 { break } nextLevel++ } return nextLevel - 1, xp }