package store import ( "database/sql" "fmt" sq "github.com/Masterminds/squirrel" "git.ctrlz.es/mgdelacroix/craban/model" ) var userColumns = []string{"id", "name", "mail", "username", "password", "admin"} type UserStore struct { Conn *sql.DB } func NewUserStore(s *Store) *UserStore { return &UserStore{Conn: s.Conn} } func (us *UserStore) Q() sq.StatementBuilderType { return sq.StatementBuilder.RunWith(us.Conn) } func (us *UserStore) usersFromRows(rows *sql.Rows) ([]*model.User, error) { users := []*model.User{} for rows.Next() { var user model.User err := rows.Scan( &user.ID, &user.Name, &user.Mail, &user.Username, &user.Password, &user.Admin, ) if err != nil { return nil, err } users = append(users, &user) } return users, nil } func (us *UserStore) GetByID(id int) (*model.User, error) { return us.getUserByCondition(sq.Eq{"id": id}) } func (us *UserStore) GetByUsername(username string) (*model.User, error) { return us.getUserByCondition(sq.Eq{"username": username}) } func (us *UserStore) getUserByCondition(condition sq.Eq) (*model.User, error) { users, err := us.getUsersByCondition(condition) if err != nil { return nil, err } return users[0], nil } func (us *UserStore) getUsersByCondition(condition sq.Eq) ([]*model.User, error) { rows, err := us.Q().Select(userColumns...). From("users"). Where(condition). Query() if err != nil { return nil, fmt.Errorf("cannot get users: %w", err) } defer rows.Close() users, err := us.usersFromRows(rows) if err != nil { return nil, fmt.Errorf("cannot get users from rows: %w", err) } if len(users) == 0 { return nil, sql.ErrNoRows } return users, nil } func (us *UserStore) Create(user *model.User) (*model.User, error) { query := us.Q().Insert("users"). Columns(userColumns[1:]...). Values(user.Name, user.Mail, user.Username, user.Password, user.Admin) res, err := query.Exec() if err != nil { return nil, fmt.Errorf("cannot insert user: %w", err) } id, err := res.LastInsertId() if err != nil { return nil, fmt.Errorf("cannot get last insert id for created user: %w", err) } return us.GetByID(int(id)) } // ToDo: add pagination and filtering func (us *UserStore) List() ([]*model.User, error) { return us.getUsersByCondition(sq.Eq{}) } func (us *UserStore) DeleteByUsername(username string) error { // ToDo: add transaction // ToDo: manage user owned games, probably at app level user, err := us.GetByUsername(username) if err != nil { return fmt.Errorf("cannot get user for deletion: %w", err) } _, err = us.Q().Delete("users"). Where(sq.Eq{"username": username}). Exec() if err != nil { return fmt.Errorf("cannot delete user: %w", err) } _, err = us.Q().Delete("gamemembers"). Where(sq.Eq{"user_id": user.ID}). Exec() if err != nil { return fmt.Errorf("cannot delete game members when deleting user: %w", err) } return nil }