diff --git a/back/store.go b/back/store.go index 587f594..5df6586 100644 --- a/back/store.go +++ b/back/store.go @@ -91,10 +91,25 @@ const schema = ` CREATE TABLE response_time ( response_id INTEGER PRIMARY KEY, + date DATE NOT NULL, time INTEGER NOT NULL, - CHECK (0 <= time < 24) - );` + CHECK (0 <= time < 24), + UNIQUE (response_id, date, time) + ); + + CREATE TRIGGER enforce_valid_response_dates + BEFORE INSERT ON response_time + BEGIN + SELECT + CASE + WHEN NEW.date BETWEEN event.earliest_date AND event.latest_date + THEN RAISE(ABORT, 'response date is out of range') + END + FROM response + JOIN event ON response.event_id = event.id + WHERE response.id = NEW.response_id; + END;` func (s *Store) createSchema() error { conn := s.pool.Get(context.Background()) @@ -224,3 +239,41 @@ func (s *Store) GetEventResponses(ctx context.Context, query GetEventResponsesQu // TODO return an error if the event does not exist? return result, err } + +type CreateEventResponseCommand struct { + EventAlphaID string + DateHours map[time.Time]int +} + +type CreateEventResponseResult struct { + ResponseAlphaID string +} + +func (s *Store) CreateEventResponse(ctx context.Context, cmd CreateEventResponseCommand) (result CreateEventResponseResult, err error) { + const responseAlphaIDLength = 10 + + conn := s.pool.Get(ctx) + defer s.pool.Put(conn) + + defer sqlitex.Save(conn)(&err) + responseAlphaID, err := s.genString(responseAlphaIDLength) + if err != nil { + return CreateEventResponseResult{}, err + } + + // Create response + const responseQuery = ` + INSERT INTO response(event_id, alpha_id) + SELECT event.id AS event_id, ? AS alpha_id + FROM event + WHERE event.alpha_id = ?;` + err = sqlitex.Exec(conn, responseQuery, nil, responseAlphaID, cmd.EventAlphaID) + if err != nil { + return CreateEventResponseResult{}, err + } + // TODO Create response times + + return CreateEventResponseResult{ + ResponseAlphaID: responseAlphaID, + }, nil +} diff --git a/back/store_test.go b/back/store_test.go index d365d1a..dab1098 100644 --- a/back/store_test.go +++ b/back/store_test.go @@ -44,3 +44,58 @@ func TestCreateEvent(t *testing.T) { is.True(metadataResult.EarliestDate.Equal(earliest)) is.True(metadataResult.LatestDate.Equal(latest)) } + +func TestGetEventResponses(t *testing.T) { + store, err := back.NewMemoryStore(back.SecureGenString) + is.New(t).NoErr(err) + + createEvent := func(is *is.I) (eventID string) { + event, err := store.CreateEvent(context.Background(), back.CreateEventCommand{ + Name: "blah", + Description: "stuff happening", + EarliestDate: time.Now(), + LatestDate: time.Now().AddDate(0,0,1), + }) + is.NoErr(err) + return event.AlphaID + } + + getTotalResponses := func(is *is.I, eventID string) int { + responses, err := store.GetEventResponses(context.Background(), back.GetEventResponsesQuery{ + AlphaID: eventID, + }) + is.NoErr(err) + return responses.TotalResponses + } + + createEmptyResponse := func(is *is.I, eventID string) { + _, err = store.CreateEventResponse(context.Background(), back.CreateEventResponseCommand{ + EventAlphaID: eventID, + }) + is.NoErr(err) + } + + t.Run("TotalResponses counts the number of responses created", func(t *testing.T) { + is := is.New(t) + + eventID := createEvent(is) + is.Equal(getTotalResponses(is, eventID), 0) + const respondTimes = 5 + for i := 1; i <= respondTimes; i++ { + createEmptyResponse(is, eventID) + is.Equal(getTotalResponses(is, eventID), i) + } + }) + + t.Run("TotalResponses does not count responses to other events", func(t *testing.T) { + is := is.New(t) + + eventID := createEvent(is) + createEmptyResponse(is, eventID) + + // Create a response to another event + createEmptyResponse(is, createEvent(is)) + + is.Equal(getTotalResponses(is, eventID), 1) + }) +} \ No newline at end of file