diff --git a/coolfacts/cmd/coolfacts_client/main.go b/coolfacts/cmd/coolfacts_client/main.go index 88c246a..409e78d 100644 --- a/coolfacts/cmd/coolfacts_client/main.go +++ b/coolfacts/cmd/coolfacts_client/main.go @@ -9,13 +9,13 @@ import ( "regexp" "strconv" "strings" - + "github.com/FTBpro/go-workshop/coolfacts/coolfact" ) const ( serverEndpoint = "http://127.0.0.1:9002" - + commandGetFacts = "getFacts" createFactCommand = "createFact" commandGetLastFact = "getLastFact" @@ -23,9 +23,9 @@ const ( func main() { fmt.Println("Hello, Client!") - + cl := NewClient(serverEndpoint) - + reader := bufio.NewReader(os.Stdin) for { fmt.Print("> ") @@ -33,27 +33,27 @@ func main() { if err != nil { log.Fatal(err) } - + input = strings.Trim(input, "\n ") tokens := regexp.MustCompile("[ ]+").Split(input, -1) - + cmd, args := tokens[0], tokens[1:] if cmd == "exit" { fmt.Println("Bye, bye!") return } - + res, err := processCmd(cl, cmd, args) if err != nil { fmt.Println("ERROR:", err) continue } - + if res != "" { fmt.Println(res) } } - + } func processCmd(cl *client, cmd string, args []string) (string, error) { @@ -83,38 +83,38 @@ func processCmd(cl *client, cmd string, args []string) (string, error) { if err != nil { return "", err } - + var msg string for i, fact := range facts { msg += fmt.Sprintf("\n**************\nFact %d:", i) msg += fmt.Sprintf("\tTopic: %s\n\tDescription: %s\n\tCreatedAt: %s", fact.Topic, fact.Description, fact.CreatedAt) } - + return msg, nil case commandGetLastFact: lastFact, err := cl.GetLastCreatedFact() if err != nil { return "", err } - + return fmt.Sprintf("\tTopic: %s\n\tDescription: %s\n\tCreatedAt: %s", lastFact.Topic, lastFact.Description, lastFact.CreatedAt), nil case createFactCommand: if len(args) < 2 { return "", errors.New("invalid arguments") } - + fct := coolfact.Fact{ Topic: args[0], Description: strings.Join(args[1:], " "), } - + err := cl.CreateFact(fct) if err != nil { return "", fmt.Errorf("failed to create fact: %v", err) } - + return fmt.Sprintf(" ---> Fact created successfully"), nil - + default: return "", errors.New("unknown command") } diff --git a/coolfacts/cmd/coolfacts_server/server.go b/coolfacts/cmd/coolfacts_server/server.go index bab58f7..efa77de 100644 --- a/coolfacts/cmd/coolfacts_server/server.go +++ b/coolfacts/cmd/coolfacts_server/server.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "net/http" + "strconv" "strings" "time" @@ -12,8 +13,7 @@ import ( ) type FactsService interface { - // TODO: fix signature for GetFacts - GetFacts() ([]coolfact.Fact, error) + GetFacts(filters coolfact.Filters) ([]coolfact.Fact, error) CreateFact(fact coolfact.Fact) error } @@ -79,9 +79,26 @@ func (s *server) HandlePing(w http.ResponseWriter, _ *http.Request) { func (s *server) HandleGetFacts(w http.ResponseWriter, r *http.Request) { log.Println("Handling getFact ...") - facts, err := s.factsService.GetFacts() + limitString := r.URL.Query().Get("limit") + if limitString == "" || limitString == "0" { + err := fmt.Errorf("limit is mandatory int") + s.HandleBadRequest(w, err) + } + + limit, err := strconv.Atoi(limitString) + if err != nil { + err = fmt.Errorf("HandleGetFacts limit not int") + s.HandleBadRequest(w, err) + } + + filters := coolfact.Filters{ + Topic: r.URL.Query().Get("topic"), + Limit: limit, + } + + facts, err := s.factsService.GetFacts(filters) if err != nil { - s.HandleError(w, fmt.Errorf("server.GetFactsHandler: %w", err)) + s.HandleError(w, fmt.Errorf("server.HandleGetFacts: %w", err)) return } @@ -149,7 +166,14 @@ func (s *server) HandleError(w http.ResponseWriter, err error) { func (s *server) HandleBadRequest(w http.ResponseWriter, err error) { log.Println("Handling Bad Request ...") - // TODO: implement + w.WriteHeader(http.StatusBadRequest) + w.Header().Set("Content-Type", "application/json") + response := map[string]string{ + "error": err.Error(), + } + if err := json.NewEncoder(w).Encode(response); err != nil { + fmt.Printf("HandleBadRequest: %s", err) + } } func (s *server) formatGetFactsResponse(facts []coolfact.Fact) map[string]interface{} { diff --git a/coolfacts/coolfact/fact.go b/coolfacts/coolfact/fact.go index 49420f1..c3593eb 100644 --- a/coolfacts/coolfact/fact.go +++ b/coolfacts/coolfact/fact.go @@ -8,6 +8,7 @@ type Fact struct { CreatedAt time.Time } -// TODO: add struct Filters with: -// - Topic -// - Limit +type Filters struct { + Topic string + Limit int +} diff --git a/coolfacts/coolfact/service.go b/coolfacts/coolfact/service.go index 641c588..3e878e1 100644 --- a/coolfacts/coolfact/service.go +++ b/coolfacts/coolfact/service.go @@ -3,8 +3,7 @@ package coolfact import "fmt" type Repository interface { - //TODO: fix signature for GetFacts - GetFacts() ([]Fact, error) + GetFacts(filters Filters) ([]Fact, error) CreateFact(fct Fact) error } @@ -18,9 +17,8 @@ func NewService(factsRepo Repository) *service { } } -//TODO: fix signatur and call to repo -func (s *service) GetFacts() ([]Fact, error) { - facts, err := s.factsRepo.GetFacts() +func (s *service) GetFacts(filters Filters) ([]Fact, error) { + facts, err := s.factsRepo.GetFacts(filters) if err != nil { return nil, fmt.Errorf("factsService.GetFacts: %w", err) } diff --git a/coolfacts/inmem/factsrepo.go b/coolfacts/inmem/factsrepo.go index f943508..06408fb 100644 --- a/coolfacts/inmem/factsrepo.go +++ b/coolfacts/inmem/factsrepo.go @@ -11,26 +11,48 @@ type factsRepo struct { } func NewFactsRepository(facts ...coolfact.Fact) *factsRepo { - // TODO: fix initialization according to the new field type + factsByTopic := map[string][]coolfact.Fact{} + for _, fact := range facts { + factsByTopic[fact.Topic] = append(factsByTopic[fact.Topic], fact) + } + return &factsRepo{ - facts: facts, + factsByTopic: factsByTopic, } } func (r *factsRepo) GetFacts(filters coolfact.Filters) ([]coolfact.Fact, error) { - // TODO: fix method. Return according to the filters. - // note - topic is optional. - sort.Sort(byCreatedAt(r.facts)) + var facts []coolfact.Fact + if filters.Topic != "" { + facts = r.factsByTopic[filters.Topic] + } else { + facts = r.allFacts() + } + + sort.Sort(byCreatedAt(facts)) + + if filters.Limit < len(facts) { + facts = facts[:filters.Limit] + } - return r.facts, nil + return facts, nil } func (r *factsRepo) CreateFact(fact coolfact.Fact) error { - // TODO: fix according to the new field type - r.facts = append(r.facts, fact) + r.factsByTopic[fact.Topic] = append(r.factsByTopic[fact.Topic], fact) + return nil } +func (s *factsRepo) allFacts() []coolfact.Fact { + var allFacts []coolfact.Fact + for _, facts := range s.factsByTopic { + allFacts = append(allFacts, facts...) + } + + return allFacts +} + type byCreatedAt []coolfact.Fact func (s byCreatedAt) Len() int {