Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion internal/adapters/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Piece struct {
PieceComplexity models.PieceComplexity
State models.PieceState
Practices []Practice
Users []*User `gorm:"many2many:user_practices;"`
}

type Lesson struct {
Expand All @@ -35,6 +36,7 @@ type Lesson struct {
StartDate time.Time
EndDate time.Time
Comment string
UserID uint
}

type Practice struct {
Expand All @@ -47,6 +49,7 @@ type Practice struct {
Piece Piece
LessonID uint
Lesson Lesson
UserID uint
}

type Warmup struct {
Expand All @@ -57,6 +60,16 @@ type Warmup struct {
State models.WarmupState
LessonID uint
Lesson Lesson
UserID uint
}

type User struct {
gorm.Model
ID uint `gorm:"primary_key"`
Name string `gorm:"primary_key"`
Pieces []Piece `gorm:"many2many:user_pieces;"`
Practices []Practice `gorm:"many2many:user_practices;"`
Warmups []Warmup `gorm:"many2many:user_warmups;"`
}

type Adapter struct {
Expand All @@ -71,7 +84,7 @@ func NewAdapter(dbUrl string) (*Adapter, error) {
return nil, fmt.Errorf("Db connection error: %v", openErr)
}
if err := db.AutoMigrate(
&Composer{}, &Piece{}, &Practice{}, &Lesson{}, &Warmup{},
&Composer{}, &Piece{}, &Practice{}, &Lesson{}, &Warmup{}, &User{},
); err != nil {
return nil, fmt.Errorf("Db migration error: %v", err)
}
Expand Down Expand Up @@ -304,3 +317,37 @@ func (a *Adapter) UpdatePractice(practice *models.Practice) error {
res := a.db.Save(practice)
return res.Error
}

func (a *Adapter) AddUser(user *models.User) (*models.User, error) {
userModel := User{
Name: user.Name,
}
res := a.db.Create(&userModel)
if res.Error == nil {
user.ID = int64(userModel.ID)
}
return user, res.Error
}
func (a *Adapter) GetUser(id int64) (*models.User, error) {
var u User
res := a.db.First(&u, id)
user := models.User{
ID: int64(u.ID),
Name: u.Name,
}
return &user, res.Error
}

func (a *Adapter) GetUsers() ([]*models.User, error) {
var urs []User
var users []*models.User
a.db.Find(&urs)
for _, u := range urs {
user := models.User{
ID: int64(u.ID),
Name: u.Name,
}
users = append(users, &user)
}
return users, nil
}
4 changes: 4 additions & 0 deletions internal/ports/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@ type DBPort interface {
AddWarmup(warmup *models.Warmup) error
UpdateWarmup(warmup *models.Warmup) error
GetActiveWarmup() (*models.Warmup, error)
// User
AddUser(user *models.User) (*models.User, error)
GetUser(id int64) (*models.User, error)
GetUsers() ([]*models.User, error)
}
26 changes: 26 additions & 0 deletions models/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package models

import "slices"

type User struct {
ID int64 `json:"id"`
Name string `json:"name"`
Pieces []*Piece `json:"pieces"`
Practices []*Practice `json:"practices"`
}

func NewUser(name string) *User {
return &User{Name: name}
}

func (u *User) AssignPiece(piece *Piece) {
if !slices.Contains(u.Pieces, piece) {
u.Pieces = append(u.Pieces, piece)
}
}

func (u *User) PracticePiece(practice *Practice, lesson *Lesson) {
if !slices.Contains(u.Practices, practice) {
u.Practices = append(u.Practices, practice)
}
}
17 changes: 17 additions & 0 deletions models/user_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package models

import (
"slices"
"testing"
)

func TestAssignPiece(t *testing.T) {
piece := NewPiece("test piece", "test composer", PieceComplexityEasy)
user := NewUser("test")

user.AssignPiece(piece)
if !slices.Contains(user.Pieces, piece) {
t.Fatal("Piece wasn't added")
}

}
3 changes: 3 additions & 0 deletions musgit.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Musgit struct {
Practice services.PracticeService
Lesson services.LessonService
Piece services.PieceService
User services.UserService
}

func New(dbUri string) *Musgit {
Expand All @@ -23,10 +24,12 @@ func New(dbUri string) *Musgit {
practiceService := services.NewPracticeService(dbAdapter)
lessonService := services.NewLessonService(dbAdapter)
pieceService := services.NewPieceService(dbAdapter)
userService := services.NewUserService(dbAdapter)
return &Musgit{
db: dbAdapter,
Practice: *practiceService,
Lesson: *lessonService,
Piece: *pieceService,
User: *userService,
}
}
69 changes: 69 additions & 0 deletions services/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package services

import (
"errors"

"github.com/musgit-dev/musgit/internal/ports"
"github.com/musgit-dev/musgit/models"
)

var (
ErrUserNotFound = errors.New("User not found")
)

type UserService struct {
db ports.DBPort
}

func NewUserService(db ports.DBPort) *UserService {
return &UserService{db: db}
}

func (s *UserService) GetAll() ([]*models.User, error) {
users, err := s.db.GetUsers()
if err != nil {
return []*models.User{}, err
}
return users, nil
}

func (s *UserService) Get(id int64) (*models.User, error) {
user, err := s.db.GetUser(id)
if err != nil {
return &models.User{}, err
}
return user, nil
}

func (s *UserService) Add(name string) (*models.User, error) {
u := models.NewUser(name)
u, err := s.db.AddUser(u)
if err != nil {
return u, err
}
return u, nil
}

func (s *UserService) AssignPiece(userId int64, piece models.Piece) error {
user, err := s.Get(userId)
if err != nil {
return ErrUserNotFound
}
user.AssignPiece(&piece)
return nil
}

func (s *UserService) StartPractice(
userId, pieceId, lessonId int64,
) (*models.Practice, error) {
var practice *models.Practice
user, err := s.Get(userId)
if err != nil {
return practice, ErrUserNotFound
}
piece, err := s.db.GetPiece(pieceId)
lesson, err := s.db.GetLesson(lessonId)
practice, err = piece.StartPractice()
user.PracticePiece(practice, &lesson)
return practice, err
}
60 changes: 60 additions & 0 deletions services/user_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package services

import (
"fmt"
"os"
"testing"

"github.com/musgit-dev/musgit/internal/adapters/db"
"github.com/musgit-dev/musgit/models"
)

var service *UserService
var pieceService *PieceService

func TestMain(m *testing.M) {
dbPort, err := db.NewAdapter(":memory:")
if err != nil {
os.Exit(1)
}
pieceService = NewPieceService(dbPort)

piece, err := pieceService.Add(
"test_piece",
"test_composer",
models.PieceComplexityUnknown,
)
if err != nil {
os.Exit(1)
}
fmt.Println("Added piece", piece.ID)
service = NewUserService(dbPort)
exitVal := m.Run()
os.Exit(exitVal)
}

func TestAdd(t *testing.T) {
user, err := service.Add("test_user")
if err != nil {
t.Fatal(err)
}
if user.Name != "test_user" {
t.Fatalf("Unexpected user name, got %s, expected test user", user.Name)
}
}

func TestAssignPiece(t *testing.T) {
user, err := service.Add("test_user")
if err != nil {
t.Fatal(err)
}
piece, _ := pieceService.Get(1)
if piece.ID != 1 {
t.Fatal("Unknown piece")
}
user.AssignPiece(&piece)
if len(user.Pieces) != 1 {
t.Fatalf("Piece wasn't added")
}

}