Skip to content
Open
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
32 changes: 16 additions & 16 deletions coolfacts/cmd/coolfacts_client/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,51 +9,51 @@ 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"
)

func main() {
fmt.Println("Hello, Client!")

cl := NewClient(serverEndpoint)

reader := bufio.NewReader(os.Stdin)
for {
fmt.Print("> ")
input, err := reader.ReadString('\n')
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) {
Expand Down Expand Up @@ -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")
}
Expand Down
34 changes: 29 additions & 5 deletions coolfacts/cmd/coolfacts_server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import (
"fmt"
"log"
"net/http"
"strconv"
"strings"
"time"

"github.com/FTBpro/go-workshop/coolfacts/coolfact"
)

type FactsService interface {
// TODO: fix signature for GetFacts
GetFacts() ([]coolfact.Fact, error)
GetFacts(filters coolfact.Filters) ([]coolfact.Fact, error)
CreateFact(fact coolfact.Fact) error
}

Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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{} {
Expand Down
7 changes: 4 additions & 3 deletions coolfacts/coolfact/fact.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type Fact struct {
CreatedAt time.Time
}

// TODO: add struct Filters with:
// - Topic
// - Limit
type Filters struct {
Topic string
Limit int
}
8 changes: 3 additions & 5 deletions coolfacts/coolfact/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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)
}
Expand Down
38 changes: 30 additions & 8 deletions coolfacts/inmem/factsrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down