Skip to content

Commit

Permalink
Use Jet Queries in Event and Participant Services (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
ayaanqui authored Nov 1, 2024
1 parent 58c475c commit e9ed9ae
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 52 deletions.
2 changes: 1 addition & 1 deletion src/mappers/event_mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func CreateEventToDbCreateEventParams(input types.CreateEvent) database.CreateEv
Valid: input.Description != "",
},
Budget: fmt.Sprintf("%f", input.Budget),
InvitationMessage: input.InviteMessage,
InvitationMessage: input.InvitationMessage,
DrawAt: input.DrawAt,
CloseAt: input.CloseAt,
}
Expand Down
39 changes: 18 additions & 21 deletions src/services/event_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"

"github.com/giftxtrade/api/src/database/jet/postgres/public/table"
"github.com/giftxtrade/api/src/mappers"
"github.com/giftxtrade/api/src/types"
"github.com/go-jet/jet/v2/postgres"
)
Expand Down Expand Up @@ -83,35 +82,33 @@ func (s *EventService) FindEventById(ctx context.Context, user types.User, event
return event, err
}

func (s *EventService) CreateEvent(ctx context.Context, user *types.User, input types.CreateEvent) (types.Event, error) {
tx, err := s.DB.BeginTx(ctx, nil)
if err != nil {
tx.Rollback()
return types.Event{}, fmt.Errorf("could not process. error with database transaction")
}
q := s.Querier.WithTx(tx)
defer q.Close()
func (s *EventService) CreateEvent(ctx context.Context, user *types.User, input types.CreateEvent) (event types.Event, err error) {
s.TX, err = s.DB.BeginTx(ctx, nil)
defer s.TX.Rollback()

// create new event in transaction scope
new_event, err := q.CreateEvent(ctx, mappers.CreateEventToDbCreateEventParams(input))
if err != nil {
tx.Rollback()
qb := table.Event.INSERT(
table.Event.Name,
table.Event.Description,
table.Event.Budget,
table.Event.InvitationMessage,
table.Event.DrawAt,
table.Event.CloseAt,
).MODEL(input).RETURNING(table.Event.AllColumns)
if err = qb.QueryContext(ctx, s.TX, &event); err != nil {
return types.Event{}, fmt.Errorf("could not create event")
}

// create participants for event in transaction scope
participants, err := s.ParticipantService.BulkCreateParticipant(tx, ctx, user, &new_event, input.Participants)
s.ParticipantService.TX = s.TX
participants, err := s.ParticipantService.BulkCreateParticipant(ctx, user, &event, input.Participants)
if err != nil {
tx.Rollback()
return types.Event{}, err
}

// commit all changes! create event, and all participants
if tx.Commit() != nil {
tx.Rollback()
if s.TX.Commit() != nil {
return types.Event{}, fmt.Errorf("could not commit transaction")
}
// build new event dto
mapped_event := mappers.DbEventToEvent(new_event, participants, nil)
return mapped_event, nil
// TODO: email participants?
event.Participants = participants
return event, nil
}
58 changes: 29 additions & 29 deletions src/services/participant_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,55 @@ package services

import (
"context"
"database/sql"
"fmt"

"github.com/giftxtrade/api/src/database"
"github.com/giftxtrade/api/src/mappers"
"github.com/giftxtrade/api/src/database/jet/postgres/public/table"
"github.com/giftxtrade/api/src/types"
"github.com/go-jet/jet/v2/qrm"
)

type ParticipantService struct {
ServiceBase
}

func (s *ParticipantService) BulkCreateParticipant(
tx *sql.Tx, ctx context.Context,
ctx context.Context,
user *types.User,
event *database.Event,
event *types.Event,
input []types.CreateParticipant,
) ([]types.Participant, error) {
q := s.Querier.WithTx(tx)
defer q.Close()

found_creator_participant := false
participants := make([]types.Participant, len(input))
) (participants []types.Participant, err error) {
found_owner_participant := false
for i, p := range input {
data := mappers.CreateParticipantToDbCreateParticipantParams(p, event)
if p.Organizer && p.Email == user.Email {
found_creator_participant = true
data.UserID = sql.NullInt64{
Valid: true,
Int64: user.ID,
}
data.Accepted = true
}

new_participant, err := q.CreateParticipant(ctx, data)
if err != nil {
tx.Rollback()
return nil, fmt.Errorf("could not create participant %s (%s)", p.Name, p.Email)
found_owner_participant = true
input[i].UserID = &user.ID
}
participants[i] = mappers.DbParticipantToParticipant(new_participant, event, nil)
input[i].EventID = event.ID
}

if !found_creator_participant {
tx.Rollback()
if !found_owner_participant {
return nil, fmt.Errorf(
"%s (%s) must be in the participant list and have the organizer field set to 'true'",
user.Name,
user.Email,
)
}
return participants, nil

qb := table.Participant.
INSERT(
table.Participant.Email,
table.Participant.Name,
table.Participant.Address,
table.Participant.Organizer,
table.Participant.Participates,
table.Participant.UserID,
table.Participant.EventID,
).
MODELS(input).
RETURNING(table.Participant.AllColumns)
var db qrm.Queryable = s.DB
if s.TX != nil {
db = s.TX
}
err = qb.QueryContext(ctx, db, &participants)
return participants, err
}
1 change: 1 addition & 0 deletions src/services/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

type ServiceBase struct {
DB *sql.DB
TX *sql.Tx
Querier *database.Queries
Validator *validator.Validate
Tokens *types.Tokens
Expand Down
19 changes: 19 additions & 0 deletions src/tests/event_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,25 @@ func TestEventService(t *testing.T) {
t.Fatal("event should not be created. main participant was not provided")
}
})

t.Run("no participant user", func(t *testing.T) {
event := types.CreateEvent{
Name: "Event with no matching user",
Budget: 100.00,
DrawAt: time.Now(),
CloseAt: time.Now().Add(time.Hour * 24 * 30),
Participants: append(create_participants(5), types.CreateParticipant{
Name: user_1.Name,
Email: "[email protected]",
Organizer: true,
Participates: true,
}),
}
_, err := event_service.CreateEvent(context.Background(), &user_1, event)
if err == nil {
t.Fatal("event should not be created. main participant is not provided")
}
})
})

t.Run("event authentication", func(t *testing.T) {
Expand Down
4 changes: 3 additions & 1 deletion src/types/dto.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ type CreateParticipant struct {
Address string `json:"address,omitempty" validate:"omitempty"`
Organizer bool `json:"organizer,omitempty" validate:"omitempty"`
Participates bool `json:"participates,omitempty" validate:"omitempty"`
UserID *int64 `json:"-" validate:"omitempty"`
EventID int64 `json:"-" validate:"omitempty"`
}

type PatchParticipant struct {
Expand Down Expand Up @@ -169,7 +171,7 @@ type CreateEvent struct {
Name string `json:"name" validate:"required"`
Description string `json:"description,omitempty"`
Budget float32 `json:"budget" validate:"required,gte=1"`
InviteMessage string `json:"inviteMessage,omitempty"`
InvitationMessage string `json:"invitationMessage,omitempty"`
DrawAt time.Time `json:"drawAt" validate:"required"`
CloseAt time.Time `json:"closeAt" validate:"required"`
Participants []CreateParticipant `json:"participants,omitempty" validate:"omitempty"`
Expand Down

0 comments on commit e9ed9ae

Please sign in to comment.