Skip to content
This repository has been archived by the owner on Aug 18, 2024. It is now read-only.

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
hayato24s committed Mar 15, 2024
1 parent 1832f65 commit 4566471
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 50 deletions.
42 changes: 9 additions & 33 deletions handler/api/rest/v3/registered_course.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package restv3

import (
"context"
"fmt"

"github.com/labstack/echo/v4"
"github.com/samber/lo"
Expand All @@ -14,7 +13,7 @@ import (
timetabledomain "github.com/twin-te/twinte-back/module/timetable/domain"
)

func toApiRegisteredCourse(registeredCourse *timetabledomain.RegisteredCourse, idToCourse map[idtype.CourseID]*timetabledomain.Course) (ret openapi.RegisteredCourse, err error) {
func toApiRegisteredCourse(registeredCourse *timetabledomain.RegisteredCourse) (ret openapi.RegisteredCourse, err error) {
ret = openapi.RegisteredCourse{
Absence: int(registeredCourse.Absence),
Attendance: int(registeredCourse.Attendance),
Expand All @@ -31,8 +30,8 @@ func toApiRegisteredCourse(registeredCourse *timetabledomain.RegisteredCourse, i
Year: registeredCourse.Year.Int(),
}

if registeredCourse.CourseID != nil {
course, err := toApiCourse(idToCourse[*registeredCourse.CourseID])
if registeredCourse.HasBasedCourse() {
course, err := toApiCourse(registeredCourse.CourseAssociation.MustGet())
if err != nil {
return openapi.RegisteredCourse{}, err
}
Expand Down Expand Up @@ -80,7 +79,7 @@ func (h *impl) GetRegisteredCourses(ctx context.Context, request openapi.GetRegi
return
}

apiRegisteredCourses, err := h.getApiRegisteredCourses(ctx, registeredCourses)
apiRegisteredCourses, err := base.MapWithErr(registeredCourses, toApiRegisteredCourse)
if err != nil {
return
}
Expand All @@ -106,7 +105,7 @@ func (h *impl) postRegisteredCourses0(ctx context.Context, reqBody openapi.PostR
return
}

apiRegisteredCourses, err := h.getApiRegisteredCourses(ctx, registeredCourses)
apiRegisteredCourses, err := base.MapWithErr(registeredCourses, toApiRegisteredCourse)
if err != nil {
return
}
Expand Down Expand Up @@ -142,7 +141,7 @@ func (h *impl) postRegisteredCourses1(ctx context.Context, reqBody openapi.PostR
registeredCourses = append(registeredCourses, rcs...)
}

return h.getApiRegisteredCourses(ctx, registeredCourses)
return base.MapWithErr(registeredCourses, toApiRegisteredCourse)
}

func (h *impl) postRegisteredCourses2(ctx context.Context, reqBody openapi.PostRegisteredCoursesJSONBody2) (apiRegisteredCourse openapi.RegisteredCourse, err error) {
Expand Down Expand Up @@ -180,7 +179,7 @@ func (h *impl) postRegisteredCourses2(ctx context.Context, reqBody openapi.PostR
return
}

apiRegisteredCourses, err := h.getApiRegisteredCourses(ctx, []*timetabledomain.RegisteredCourse{registeredCourse})
apiRegisteredCourses, err := base.MapWithErr([]*timetabledomain.RegisteredCourse{registeredCourse}, toApiRegisteredCourse)
if err != nil {
return
}
Expand Down Expand Up @@ -249,7 +248,7 @@ func (h *impl) GetRegisteredCoursesId(ctx context.Context, request openapi.GetRe
return
}

apiRegisteredCourses, err := h.getApiRegisteredCourses(ctx, []*timetabledomain.RegisteredCourse{registeredCourse})
apiRegisteredCourses, err := base.MapWithErr([]*timetabledomain.RegisteredCourse{registeredCourse}, toApiRegisteredCourse)
if err != nil {
return
}
Expand Down Expand Up @@ -330,7 +329,7 @@ func (h *impl) PutRegisteredCoursesId(ctx context.Context, request openapi.PutRe
return
}

apiRegisteredCourses, err := h.getApiRegisteredCourses(ctx, []*timetabledomain.RegisteredCourse{registeredCourse})
apiRegisteredCourses, err := base.MapWithErr([]*timetabledomain.RegisteredCourse{registeredCourse}, toApiRegisteredCourse)
if err != nil {
return
}
Expand All @@ -339,26 +338,3 @@ func (h *impl) PutRegisteredCoursesId(ctx context.Context, request openapi.PutRe

return
}

func (h *impl) getApiRegisteredCourses(ctx context.Context, registeredCourses []*timetabledomain.RegisteredCourse) ([]openapi.RegisteredCourse, error) {
courseIDs := make([]idtype.CourseID, 0, len(registeredCourses))
for _, registeredCourse := range registeredCourses {
if registeredCourse.CourseID != nil {
courseIDs = append(courseIDs, *registeredCourse.CourseID)
}
}

courses, err := h.timetableUseCase.GetCoursesByIDs(ctx, courseIDs)
if err != nil {
return nil, err
}
if len(courseIDs) != len(courses) {
return nil, fmt.Errorf("not found courses in getApiRegisteredCourses %+v", courseIDs)
}

idToCourse := lo.SliceToMap(courses, func(course *timetabledomain.Course) (idtype.CourseID, *timetabledomain.Course) {
return course.ID, course
})

return base.MapWithArgAndErr(registeredCourses, idToCourse, toApiRegisteredCourse)
}
4 changes: 2 additions & 2 deletions handler/api/rest/v3/timetable.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
func (h *impl) GetTimetableDate(ctx context.Context, request openapi.GetTimetableDateRequestObject) (res openapi.GetTimetableDateResponseObject, err error) {
date := civil.DateOf(request.Date.Time)

year, err := shareddomain.NewAcademicYear(date.Year, date.Month)
year, err := shareddomain.NewAcademicYearFromDate(date)
if err != nil {
return
}
Expand Down Expand Up @@ -54,7 +54,7 @@ func (h *impl) GetTimetableDate(ctx context.Context, request openapi.GetTimetabl
return
}

apiRegisteredCourses, err := h.getApiRegisteredCourses(ctx, registeredCourses)
apiRegisteredCourses, err := base.MapWithErr(registeredCourses, toApiRegisteredCourse)
if err != nil {
return
}
Expand Down
2 changes: 1 addition & 1 deletion module/announcement/domain/announcement.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func ParseAnnouncementTag(s string) (AnnouncementTag, error) {
if ok {
return ret, nil
}
return AnnouncementTag(0), fmt.Errorf("failed to parse AnnouncementTag %#v", s)
return 0, fmt.Errorf("failed to parse AnnouncementTag %#v", s)
}

var (
Expand Down
27 changes: 27 additions & 0 deletions module/shared/domain/association.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package shareddomain

import "github.com/samber/mo"

type Association[T any] struct {
v mo.Option[T]
}

func (a *Association[T]) IsPresent() bool {
return a.v.IsPresent()
}

func (a *Association[T]) IsAbsent() bool {
return a.v.IsAbsent()
}

func (a *Association[T]) Get() (T, bool) {
return a.v.Get()
}

func (a *Association[T]) MustGet() T {
return a.v.MustGet()
}

func (a *Association[T]) Set(v T) {
a.v = mo.Some(v)
}
111 changes: 103 additions & 8 deletions module/timetable/domain/registered_course.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,28 @@ var (

// RegisteredCourse is identified by one of the following fields.
// - ID
// - UserID and CourseID ( if CourseID is not nil )
// - UserID and CourseID ( if it has based course )
//
// If CourseID is nil, Name, Instructors, Credit, Methods, Schedules are required.
// There are two types of RegisteredCourse.
// - RegisteredCourse created manually
// - RegisteredCourse that has the based course
//
// If RegisteredCourse has the based course, the following fields are always present.
// - CourseID
//
// And the following fields are present only if overwritten.
// - Name
// - Instructors
// - Credit
// - Methods
// - Schedules
//
// If RegisteredCourse is created manually, the following fields are always present.
// - Name
// - Instructors
// - Credit
// - Methods
// - Schedules
type RegisteredCourse struct {
ID idtype.RegisteredCourseID
UserID idtype.UserID
Expand All @@ -37,6 +56,47 @@ type RegisteredCourse struct {
TagIDs []idtype.TagID

EntityBeforeUpdated *RegisteredCourse

CourseAssociation shareddomain.Association[*Course]
}

func (rc *RegisteredCourse) HasBasedCourse() bool {
return rc.CourseID != nil
}

func (rc *RegisteredCourse) GetName() shareddomain.RequiredString {
if rc.HasBasedCourse() {
return lo.FromPtrOr(rc.Name, rc.CourseAssociation.MustGet().Name)
}
return *rc.Name
}

func (rc *RegisteredCourse) GetInstructors() string {
if rc.HasBasedCourse() {
return lo.FromPtrOr(rc.Instructors, rc.CourseAssociation.MustGet().Instructors)
}
return *rc.Instructors
}

func (rc *RegisteredCourse) GetCredit() Credit {
if rc.HasBasedCourse() {
return lo.FromPtrOr(rc.Credit, rc.CourseAssociation.MustGet().Credit)
}
return *rc.Credit
}

func (rc *RegisteredCourse) GetMethods() []CourseMethod {
if rc.HasBasedCourse() {
return lo.FromPtrOr(rc.Methods, rc.CourseAssociation.MustGet().Methods)
}
return *rc.Methods
}

func (rc *RegisteredCourse) GetSchedules() []Schedule {
if rc.HasBasedCourse() {
return lo.FromPtrOr(rc.Schedules, rc.CourseAssociation.MustGet().Schedules)
}
return *rc.Schedules
}

func (rc *RegisteredCourse) Clone() *RegisteredCourse {
Expand Down Expand Up @@ -88,25 +148,60 @@ type RegisteredCourseDataToUpdate struct {
TagIDs *[]idtype.TagID
}

func (rc *RegisteredCourse) updateName(name shareddomain.RequiredString) {
if rc.HasBasedCourse() && rc.Name == nil && rc.CourseAssociation.MustGet().Name == name {
return
}
rc.Name = &name
}

func (rc *RegisteredCourse) updateInstructors(instructors string) {
if rc.HasBasedCourse() && rc.Instructors == nil && rc.CourseAssociation.MustGet().Instructors == instructors {
return
}
rc.Instructors = &instructors
}

func (rc *RegisteredCourse) updateCredit(credit Credit) {
if rc.HasBasedCourse() && rc.Credit == nil && rc.CourseAssociation.MustGet().Credit == credit {
return
}
rc.Credit = &credit
}

func (rc *RegisteredCourse) updateMethods(methods []CourseMethod) {
// if rc.HasBasedCourse() && rc.Methods == nil && rc.CourseAssociation.MustGet().Methods == methods {
// return
// }
rc.Methods = &methods
}

func (rc *RegisteredCourse) updateSchedules(schedules []Schedule) {
// if rc.HasBasedCourse() && rc.Schedules == nil && rc.CourseAssociation.MustGet().Schedules == schedules {
// return
// }
rc.Schedules = &schedules
}

func (rc *RegisteredCourse) Update(data RegisteredCourseDataToUpdate) error {
if data.Name != nil {
rc.Name = data.Name
rc.updateName(*data.Name)
}

if data.Instructors != nil {
rc.Instructors = data.Instructors
rc.updateInstructors(*data.Instructors)
}

if data.Credit != nil {
rc.Credit = data.Credit
rc.updateCredit(*data.Credit)
}

if data.Methods != nil {
rc.Methods = data.Methods
rc.updateMethods(*data.Methods)
}

if data.Schedules != nil {
rc.Schedules = data.Schedules
rc.updateSchedules(*data.Schedules)
}

if data.Memo != nil {
Expand Down Expand Up @@ -139,7 +234,7 @@ func ConstructRegisteredCourse(fn func(rc *RegisteredCourse) (err error)) (*Regi
}

if rc.CourseID == nil && (rc.Name == nil || rc.Instructors == nil || rc.Credit == nil || rc.Methods == nil || rc.Schedules == nil) {
return nil, fmt.Errorf("the registered course, which does not have course id, must have name, instructors, credit, methods, and schedules. %+v", rc)
return nil, fmt.Errorf("the registered course, which does not have the based course, must have name, instructors, credit, methods, and schedules. %+v", rc)
}

if rc.ID.IsZero() || rc.UserID.IsZero() || rc.Year.IsZero() {
Expand Down
1 change: 1 addition & 0 deletions module/timetable/factory/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func (f *impl) NewRegisteredCourseFromCourse(userID idtype.UserID, course *timet
rc.UserID = userID
rc.CourseID = &course.ID
rc.Year = course.Year
rc.CourseAssociation.Set(course)
return nil
})
}
Expand Down
5 changes: 5 additions & 0 deletions module/timetable/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type UseCase interface {
SearchCourses(ctx context.Context, in SearchCoursesIn) ([]*timetabledomain.Course, error)

// CreateRegisteredCoursesByCodes creates new registered courses by the given year and codes.
// And it returns the registered courses, each of which has the course association loaded if it has the based course.
//
// [Authentication] required
//
Expand All @@ -39,21 +40,25 @@ type UseCase interface {
CreateRegisteredCoursesByCodes(ctx context.Context, year shareddomain.AcademicYear, codes []timetabledomain.Code) ([]*timetabledomain.RegisteredCourse, error)

// CreateRegisteredCourseManually creates a new registered course mannually.
// And it returns the registered course, which has the course association loaded if it has the based course.
//
// [Authentication] required
CreateRegisteredCourseManually(ctx context.Context, in CreateRegisteredCourseManuallyIn) (*timetabledomain.RegisteredCourse, error)

// GetRegisteredCourseByID returns the registered course specified by the given id.
// And it returns the registered course, which has the course association loaded if it has the based course.
//
// [Authentication] required
GetRegisteredCourseByID(ctx context.Context, id idtype.RegisteredCourseID) (*timetabledomain.RegisteredCourse, error)

// GetRegisteredCourses returns the registered courses.
// And it returns the registered courses, each of which has the course association loaded if it has the based course.
//
// [Authentication] required
GetRegisteredCourses(ctx context.Context, year *shareddomain.AcademicYear) ([]*timetabledomain.RegisteredCourse, error)

// UpdateRegisteredCourse updates registered course specified by the given id.
// And it returns the registered course, which has the course association loaded if it has the based course.
//
// [Authentication] required
//
Expand Down
2 changes: 2 additions & 0 deletions module/timetable/port/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ type Repository interface {
UpdateRegisteredCourse(ctx context.Context, registeredCourse *timetabledomain.RegisteredCourse) error
DeleteRegisteredCourses(ctx context.Context, conds DeleteRegisteredCoursesConds) (rowsAffected int, err error)

LoadCourseToRegisteredCourse(ctx context.Context, registeredCourses []*timetabledomain.RegisteredCourse, lock sharedport.Lock) error

// Tag

FindTag(ctx context.Context, conds FindTagConds, lock sharedport.Lock) (*timetabledomain.Tag, error)
Expand Down
Loading

0 comments on commit 4566471

Please sign in to comment.