Feat: translate db error

pull/21/head
zijiren233 1 year ago
parent 2f28d198a2
commit 7998654ede

@ -50,7 +50,7 @@ func InitDatabase(ctx context.Context) error {
DontSupportRenameColumn: true,
SkipInitializeWithVersion: false,
})
opts = append(opts, &gorm.Config{})
opts = append(opts, &gorm.Config{TranslateError: true})
case conf.DatabaseTypeSqlite3:
var dsn string
if conf.Conf.Database.DBName == "memory" || strings.HasPrefix(conf.Conf.Database.DBName, ":memory:") {
@ -67,7 +67,7 @@ func InitDatabase(ctx context.Context) error {
log.Infof("sqlite3 database file: %s", conf.Conf.Database.DBName)
}
dialector = sqlite.Open(dsn)
opts = append(opts, &gorm.Config{})
opts = append(opts, &gorm.Config{TranslateError: true})
case conf.DatabaseTypePostgres:
var dsn string
if conf.Conf.Database.Port == 0 {
@ -94,7 +94,7 @@ func InitDatabase(ctx context.Context) error {
DSN: dsn,
PreferSimpleProtocol: true,
})
opts = append(opts, &gorm.Config{})
opts = append(opts, &gorm.Config{TranslateError: true})
default:
log.Fatalf("unknown database type: %s", conf.Conf.Database.Type)
}

@ -1,7 +1,11 @@
package db
import (
"errors"
"fmt"
"github.com/synctv-org/synctv/internal/model"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
@ -12,36 +16,60 @@ func CreateMovie(movie *model.Movie) error {
func GetAllMoviesByRoomID(roomID uint) ([]*model.Movie, error) {
movies := []*model.Movie{}
err := db.Where("room_id = ?", roomID).Order("position ASC").Find(&movies).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return movies, errors.New("room not found")
}
return movies, err
}
func DeleteMovieByID(roomID, id uint) error {
return db.Unscoped().Where("room_id = ? AND id = ?", roomID, id).Delete(&model.Movie{}).Error
err := db.Unscoped().Where("room_id = ? AND id = ?", roomID, id).Delete(&model.Movie{}).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("room or movie not found")
}
return err
}
// TODO: delete error
func LoadAndDeleteMovieByID(roomID, id uint, columns ...clause.Column) (*model.Movie, error) {
movie := &model.Movie{}
err := db.Unscoped().Clauses(clause.Returning{Columns: columns}).Where("room_id = ? AND id = ?", roomID, id).Delete(movie).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return movie, errors.New("room or movie not found")
}
return movie, err
}
func DeleteMoviesByRoomID(roomID uint) error {
return db.Unscoped().Where("room_id = ?", roomID).Delete(&model.Movie{}).Error
err := db.Unscoped().Where("room_id = ?", roomID).Delete(&model.Movie{}).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("room not found")
}
return err
}
func LoadAndDeleteMoviesByRoomID(roomID uint, columns ...clause.Column) ([]*model.Movie, error) {
movies := []*model.Movie{}
err := db.Unscoped().Clauses(clause.Returning{Columns: columns}).Where("room_id = ?", roomID).Delete(&movies).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("room not found")
}
return movies, err
}
func UpdateMovie(movie *model.Movie, columns ...clause.Column) error {
return db.Model(movie).Clauses(clause.Returning{Columns: columns}).Where("room_id = ? AND id = ?", movie.RoomID, movie.ID).Updates(movie).Error
err := db.Model(movie).Clauses(clause.Returning{Columns: columns}).Where("room_id = ? AND id = ?", movie.RoomID, movie.ID).Updates(movie).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("room or movie not found")
}
return err
}
func SaveMovie(movie *model.Movie, columns ...clause.Column) error {
return db.Model(movie).Clauses(clause.Returning{Columns: columns}).Where("room_id = ? AND id = ?", movie.RoomID, movie.ID).Save(movie).Error
err := db.Model(movie).Clauses(clause.Returning{Columns: columns}).Where("room_id = ? AND id = ?", movie.RoomID, movie.ID).Save(movie).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("room or movie not found")
}
return err
}
func SwapMoviePositions(roomID uint, movie1ID uint, movie2ID uint) (err error) {
@ -57,10 +85,16 @@ func SwapMoviePositions(roomID uint, movie1ID uint, movie2ID uint) (err error) {
movie2 := &model.Movie{}
err = tx.Select("position").Where("room_id = ? AND id = ?", roomID, movie1ID).First(movie1).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
err = fmt.Errorf("movie with id %d not found", movie1ID)
}
return
}
err = tx.Select("position").Where("room_id = ? AND id = ?", roomID, movie2ID).First(movie2).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
err = fmt.Errorf("movie with id %d not found", movie2ID)
}
return
}
err = tx.Model(&model.Movie{}).Where("room_id = ? AND id = ?", roomID, movie1ID).Update("position", movie2.Position).Error

@ -1,9 +1,17 @@
package db
import "github.com/synctv-org/synctv/internal/model"
import (
"errors"
"github.com/synctv-org/synctv/internal/model"
"gorm.io/gorm"
)
func GetRoomUserRelation(roomID, userID uint) (*model.RoomUserRelation, error) {
roomUserRelation := &model.RoomUserRelation{}
err := db.Where("room_id = ? AND user_id = ?", roomID, userID).First(roomUserRelation).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return roomUserRelation, errors.New("room or user not found")
}
return roomUserRelation, err
}

@ -1,9 +1,12 @@
package db
import (
"errors"
"github.com/synctv-org/synctv/internal/model"
"github.com/zijiren233/stream"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
type CreateRoomConfig func(r *model.Room)
@ -42,46 +45,74 @@ func CreateRoom(name, password string, conf ...CreateRoomConfig) (*model.Room, e
for _, c := range conf {
c(r)
}
return r, db.Create(r).Error
err := db.Create(r).Error
if err != nil && errors.Is(err, gorm.ErrDuplicatedKey) {
return r, errors.New("room already exists")
}
return r, err
}
func GetRoomByID(id uint) (*model.Room, error) {
r := &model.Room{}
err := db.Where("id = ?", id).First(r).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return r, errors.New("room not found")
}
return r, err
}
func GetRoomAndCreatorByID(id uint) (*model.Room, error) {
r := &model.Room{}
err := db.Preload("Creator").Where("id = ?", id).First(r).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return r, errors.New("room not found")
}
return r, err
}
func ChangeRoomSetting(roomID uint, setting model.Setting) error {
return db.Model(&model.Room{}).Where("id = ?", roomID).Update("setting", setting).Error
err := db.Model(&model.Room{}).Where("id = ?", roomID).Update("setting", setting).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("room not found")
}
return err
}
func ChangeUserPermission(roomID uint, userID uint, permission model.Permission) error {
return db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("permissions", permission).Error
err := db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("permissions", permission).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("room or user not found")
}
return err
}
func HasPermission(roomID uint, userID uint, permission model.Permission) (bool, error) {
ur := &model.RoomUserRelation{}
err := db.Where("room_id = ? AND user_id = ?", roomID, userID).First(ur).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
err = errors.New("room or user not found")
}
return false, err
}
return ur.Permissions.Has(permission), nil
}
func DeleteRoomByID(roomID uint) error {
return db.Where("id = ?", roomID).Delete(&model.Room{}).Error
err := db.Where("id = ?", roomID).Delete(&model.Room{}).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("room not found")
}
return err
}
func HasRoom(roomID uint) (bool, error) {
r := &model.Room{}
err := db.Where("id = ?", roomID).First(r).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
err = nil
}
return false, err
}
return true, nil
@ -91,6 +122,9 @@ func HasRoomByName(name string) (bool, error) {
r := &model.Room{}
err := db.Where("name = ?", name).First(r).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
err = nil
}
return false, err
}
return true, nil
@ -105,37 +139,63 @@ func SetRoomPassword(roomID uint, password string) error {
return err
}
}
return db.Model(&model.Room{}).Where("id = ?", roomID).Update("hashed_password", hashedPassword).Error
return SetRoomHashedPassword(roomID, hashedPassword)
}
func SetRoomHashedPassword(roomID uint, hashedPassword []byte) error {
return db.Model(&model.Room{}).Where("id = ?", roomID).Update("hashed_password", hashedPassword).Error
err := db.Model(&model.Room{}).Where("id = ?", roomID).Update("hashed_password", hashedPassword).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("room not found")
}
return err
}
func SetUserRole(roomID uint, userID uint, role model.Role) error {
return db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("role", role).Error
err := db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("role", role).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("room or user not found")
}
return err
}
func SetUserPermission(roomID uint, userID uint, permission model.Permission) error {
return db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("permissions", permission).Error
err := db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("permissions", permission).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("room or user not found")
}
return err
}
func AddUserPermission(roomID uint, userID uint, permission model.Permission) error {
return db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("permissions", db.Raw("permissions | ?", permission)).Error
err := db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("permissions", db.Raw("permissions | ?", permission)).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("room or user not found")
}
return err
}
func RemoveUserPermission(roomID uint, userID uint, permission model.Permission) error {
return db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("permissions", db.Raw("permissions & ?", ^permission)).Error
err := db.Model(&model.RoomUserRelation{}).Where("room_id = ? AND user_id = ?", roomID, userID).Update("permissions", db.Raw("permissions & ?", ^permission)).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("room or user not found")
}
return err
}
func GetAllRooms() ([]*model.Room, error) {
rooms := []*model.Room{}
err := db.Find(&rooms).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return rooms, nil
}
return rooms, err
}
func GetAllRoomsAndCreator() ([]*model.Room, error) {
rooms := []*model.Room{}
err := db.Preload("Creater").Find(&rooms).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return rooms, nil
}
return rooms, err
}

@ -1,7 +1,12 @@
package db
import (
"errors"
"github.com/synctv-org/synctv/internal/model"
"github.com/zijiren233/stream"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
@ -10,7 +15,11 @@ func CreateUser(username string, hashedPassword []byte) (*model.User, error) {
Username: username,
HashedPassword: hashedPassword,
}
return u, db.Where(*u).FirstOrCreate(u).Error
err := db.Create(u).Error
if err != nil && errors.Is(err, gorm.ErrDuplicatedKey) {
return u, errors.New("username already exists")
}
return u, err
}
func AddUserToRoom(userID uint, roomID uint, role model.Role, permission model.Permission) error {
@ -20,51 +29,94 @@ func AddUserToRoom(userID uint, roomID uint, role model.Role, permission model.P
Role: role,
Permissions: permission,
}
return db.Attrs(ur).FirstOrCreate(ur).Error
err := db.Create(ur).Error
if err != nil && errors.Is(err, gorm.ErrDuplicatedKey) {
return errors.New("user already exists in room")
}
return err
}
func GetUserByUsername(username string) (*model.User, error) {
u := &model.User{}
err := db.Where("username = ?", username).First(u).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return u, errors.New("user not found")
}
return u, err
}
func GetUserByID(id uint) (*model.User, error) {
u := &model.User{}
err := db.Where("id = ?", id).First(u).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return u, errors.New("user not found")
}
return u, err
}
func GetUsersByRoomID(roomID uint) ([]model.User, error) {
users := []model.User{}
err := db.Model(&model.RoomUserRelation{}).Where("room_id = ?", roomID).Find(&users).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return users, errors.New("room not found")
}
return users, err
}
func DeleteUserByID(userID uint) error {
return db.Where("id = ?", userID).Delete(&model.User{}).Error
err := db.Where("id = ?", userID).Delete(&model.User{}).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("user not found")
}
return err
}
func LoadAndDeleteUserByID(userID uint, columns ...clause.Column) (*model.User, error) {
u := &model.User{}
err := db.Clauses(clause.Returning{Columns: columns}).Where("id = ?", userID).Delete(u).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return u, errors.New("user not found")
}
return u, err
}
func DeleteUserByUsername(username string) error {
return db.Where("username = ?", username).Delete(&model.User{}).Error
err := db.Where("username = ?", username).Delete(&model.User{}).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("user not found")
}
return err
}
func LoadAndDeleteUserByUsername(username string, columns ...clause.Column) (*model.User, error) {
u := &model.User{}
err := db.Clauses(clause.Returning{Columns: columns}).Where("username = ?", username).Delete(u).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return u, errors.New("user not found")
}
return u, err
}
func SetUserPassword(userID uint, hashedPassword []byte) error {
return db.Model(&model.User{}).Where("id = ?", userID).Update("hashed_password", hashedPassword).Error
func SetUserPassword(userID uint, password string) error {
var hashedPassword []byte
if password != "" {
var err error
hashedPassword, err = bcrypt.GenerateFromPassword(stream.StringToBytes(password), bcrypt.DefaultCost)
if err != nil {
return err
}
}
return SetUserHashedPassword(userID, hashedPassword)
}
func SetUserHashedPassword(userID uint, hashedPassword []byte) error {
err := db.Model(&model.User{}).Where("id = ?", userID).Update("hashed_password", hashedPassword).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("user not found")
}
return err
}
func UpdateUser(u *model.User) error {
func SaveUser(u *model.User) error {
return db.Save(u).Error
}

@ -70,5 +70,5 @@ func (u *User) SetPassword(password string) error {
}
u.HashedPassword = hashedPassword
atomic.AddUint32(&u.version, 1)
return db.SetUserPassword(u.ID, hashedPassword)
return db.SetUserHashedPassword(u.ID, hashedPassword)
}

@ -100,9 +100,9 @@ func DeleteUserByUsername(username string) error {
return nil
}
func UpdateUser(u *model.User) error {
func SaveUser(u *model.User) error {
userCache.Remove(u.ID)
return db.UpdateUser(u)
return db.SaveUser(u)
}
func GetUserName(userID uint) string {

Loading…
Cancel
Save