Updating posts
In this chapter, we will be focusing on the process of handling an "update post" message.
To update a post, you need to retrieve the specific post from the store using the "Get" operation, modify the values, and then write the updated post back to the store using the "Set" operation.
Let's first implement a getter and a setter logic.
Getting posts
Implement the GetPost keeper method in post.go:
func (k Keeper) GetPost(ctx sdk.Context, id uint64) (val types.Post, found bool) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PostKey))
b := store.Get(GetPostIDBytes(id))
if b == nil {
return val, false
}
k.cdc.MustUnmarshal(b, &val)
return val, true
}
GetPost takes in two arguments: a context ctx and an id of type uint64
representing the ID of the post to be retrieved. It returns a types.Post
struct containing the values of the post, and a boolean value indicating whether
the post was found in the database.
The function first creates a store using the prefix.NewStore method, passing
in the key-value store from the context and the types.KeyPrefix function
applied to the types.PostKey constant as arguments. It then attempts to
retrieve the post from the store using the store.Get method, passing in the ID
of the post as a byte slice. If the post is not found in the store, it returns
an empty types.Post struct and a boolean value of false.
If the post is found in the store, the function unmarshals the retrieved byte
slice into a types.Post struct using the cdc.MustUnmarshal method, passing
in a pointer to the val variable as an argument. It then returns the val struct
and a boolean value of true to indicate that the post was found in the database.
Setting posts
Implement the SetPost keeper method in post.go:
func (k Keeper) SetPost(ctx sdk.Context, post types.Post) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PostKey))
b := k.cdc.MustMarshal(&post)
store.Set(GetPostIDBytes(post.Id), b)
}
SetPost takes in two arguments: a context ctx and a types.Post struct
containing the updated values for the post. The function does not return
anything.
The function first creates a store using the prefix.NewStore method, passing
in the key-value store from the context and the types.KeyPrefix function
applied to the types.PostKey constant as arguments. It then marshals the
updated post struct into a byte slice using the cdc.MustMarshal method,
passing in a pointer to the post struct as an argument. Finally, it updates the
post in the store using the store.Set method, passing in the ID of the post as
a byte slice and the marshaled post struct as arguments.
Update posts
package keeper
import (
"context"
"fmt"
"blog/x/blog/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
func (k msgServer) UpdatePost(goCtx context.Context, msg *types.MsgUpdatePost) (*types.MsgUpdatePostResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
var post = types.Post{
Creator: msg.Creator,
Id: msg.Id,
Title: msg.Title,
Body: msg.Body,
}
val, found := k.GetPost(ctx, msg.Id)
if !found {
return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, fmt.Sprintf("key %d doesn't exist", msg.Id))
}
if msg.Creator != val.Creator {
return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "incorrect owner")
}
k.SetPost(ctx, post)
return &types.MsgUpdatePostResponse{}, nil
}
UpdatePost takes in a context and a message MsgUpdatePost as input, and
returns a response MsgUpdatePostResponse and an error. The function first
retrieves the current values of the post from the database using the provided
msg.Id, and checks if the post exists and if the msg.Creator is the same as
the current owner of the post. If either of these checks fail, it returns an
error. If both checks pass, it updates the post in the database with the new
values provided in msg, and returns a response without an error.
Summary
Well done! You have successfully implemented a number of important methods for managing posts within a store.
The GetPost method allows you to retrieve a specific post from the store based
on its unique identification number, or post ID. This can be useful for
displaying a specific post to a user, or for updating it.
The SetPost method enables you to update an existing post in the store. This
can be useful for correcting mistakes or updating the content of a post as new
information becomes available.
Finally, you implemented the UpdatePost method, which is called whenever the
blockchain processes a message requesting an update to a post.