Skip to content

Commit

Permalink
api: added ability to mark recipe as planned
Browse files Browse the repository at this point in the history
This is first step to have recipe planning and cooking history
implemented.
  • Loading branch information
encero committed Mar 30, 2022
1 parent 9128d17 commit 8a4affc
Show file tree
Hide file tree
Showing 12 changed files with 292 additions and 5 deletions.
51 changes: 51 additions & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ func Run(ctx context.Context, entc *ent.Client, lg *zap.Logger, natsURL string)
return fmt.Errorf("recipe.delete subscription: %w", err)
}

_, err = ec.QueueSubscribe(HandlersMarkAsPlanned, workerQueue, h.MarksAsPlanned)
if err != nil {
return fmt.Errorf("recipe.planned.* subscription: %w", err)
}

lg.Info("Api server started")
<-ctx.Done()

Expand Down Expand Up @@ -220,6 +225,52 @@ func (h *handlers) Upsert(subject, reply string, r Recipe) {
logNatsPublishError(lg, err)
}

const HandlersMarkAsPlanned = "recipes.planned.*"

func (h handlers) MarksAsPlanned(subject, reply string, req RequestPlanned) {
lg := h.lg.With(ZapRequestID(), ZapHandler(HandlersMarkAsPlanned))
id := uuid.MustParse(strings.Split(subject, ".")[2])

ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

recipe, err := h.entc.Recipe.Get(ctx, id)
if err != nil {
if ent.IsNotFound(err) {
lg.Info("recipe not found")

err := h.ec.Publish(reply, Ack{Status: StatusNotFound})
logNatsPublishError(lg, err)

return
}

lg.Error("load recipe", zap.Error(err))

err := h.ec.Publish(reply, Ack{Status: StatusError})
logNatsPublishError(lg, err)

return
}

lg.Sugar().Infof("about to set recipe as planned:%v", req.Planned)

_, err = recipe.Update().
SetPlanned(req.Planned).
Save(ctx)
if err != nil {
lg.Error("save updated recipe", zap.Error(err))

err := h.ec.Publish(reply, Ack{Status: StatusError})
logNatsPublishError(lg, err)

return
}

err = h.ec.Publish(reply, Ack{Status: StatusSuccess})
logNatsPublishError(lg, err)
}

func logNatsPublishError(lg *zap.Logger, err error) {
if err != nil {
lg.Error("Publishing to nats", zap.Error(err))
Expand Down
45 changes: 45 additions & 0 deletions api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,51 @@ func TestDeleteRecipe(t *testing.T) {
is.Equal(list[0].ID, id1) // correct recipe remains
}

func TestMarkRecipeAsPlanned(t *testing.T) {
is, conn, cleanup := tests.SetupAPI(t)
defer cleanup()

id := upsertRecipe(is, conn, api.Recipe{
ID: uuid.New(),
Name: "The name",
})

recipes := listRecipes(is, conn)
is.Equal(len(recipes), 1)
is.Equal(recipes[0].Planned, false) // new recipe is unplanned

markAsPlanned(is, conn, id, true) // mark recipe as planned

recipes = listRecipes(is, conn)
is.Equal(len(recipes), 1)
is.True(recipes[0].Planned) // marked recipe is planned

markAsPlanned(is, conn, id, false) // mark recipe as unplanned

recipes = listRecipes(is, conn)
is.Equal(len(recipes), 1)
is.True(!recipes[0].Planned) // marked recipe is UNplanned
}

func markAsPlanned(is *is.I, conn *nats.Conn, id uuid.UUID, planned bool) {
is.Helper()

req := api.RequestPlanned{Planned: planned}

payload, err := json.Marshal(req)
is.NoErr(err) // marshalling recipes planned request

msg, err := conn.Request(fmt.Sprintf("recipes.planned.%s", id.String()), payload, reqTimeout)
is.NoErr(err) // request

resp := api.Ack{}

err = json.Unmarshal(msg.Data, &resp)
is.NoErr(err) // response unmarshall

is.Equal(resp.Status, api.StatusSuccess) // recipes.planned request status
}

func upsertRecipe(is *is.I, conn *nats.Conn, r api.Recipe) uuid.UUID {
is.Helper()

Expand Down
14 changes: 10 additions & 4 deletions api/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,25 @@ type Envelope[T any] struct {
type List []Recipe

type Recipe struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Planned bool `json:"planned"`

CreatedAt time.Time `json:"createdAt"`
}

func EntToRecipe(r *ent.Recipe) Recipe {
return Recipe{
ID: r.ID,
Name: r.Title,
ID: r.ID,
Name: r.Title,
Planned: r.Planned,
}
}

type RequestPlanned struct {
Planned bool `json:"planned"`
}

type Ack struct {
Status string `json:"status"`
}
Expand Down
1 change: 1 addition & 0 deletions ent/migrate/schema.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 55 additions & 1 deletion ent/mutation.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions ent/recipe.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions ent/recipe/recipe.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions ent/recipe/where.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 8a4affc

Please sign in to comment.