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.