Assuming the value you want to update is in the list already, then you need some way to know which it is. That is to say, each Post could likely could use an id, then you can get the array of posts from your posts hashmap, then use the map function (which returns each element of a set with a new element of the same type) against matching post id to update it. We use Opt type for each field of the post, and if it is present, overwrite the new post we are going to update the list with; otherwise copy the existing value…
assuming Posts looks like
type Post = {
id: Text; // should probably be a specific Type like Types.PostId even if it is a Text or number
title: Text;
content: Text;
};
Note existingPosts
has ALREADY been retrieved from the postsHashmap
, and converted
from it’s optional type (see below).
// generic function that overwrites any existing values if new values are present
func editPost(
existingPosts: [Types.Post],
targetPostId: Text,
titleIn: ?Text,
contentIn: ?Text,
): [Types.Post] {
// there's probably a better way to do this, but it assumes the [Post] is going to contain a Post with the id given
var throwError: Bool = true;
let updateFcn = func(post: Types.Post): Types.Post {
// so we are iterating over the [Posts] returning each post, if it has the id
// overwrite existing values with given values, or just copy previous values
if (post.id == targetPostId) {
throwError := false;
return {
id = targetPostId;
title = Option.get<Text>(titleIn, post.title);
content = Option.get<Text>(contentIn, post.content);
};
} else { post }; // don't update a post not updated
};
// now using the function above
let updated = Array.map<Types.Post, Types.Post>(existingPosts, updateFcn);
assert(not throwError);
return updated; // since a post was found with the id, don't trap and return the updated list
};
};
To originally get the [Post] you can use this:
public func getPosts(forPrincipal: Principal): [Types.Post] {
assert(principalMaps(forPrincipal));
let exists = postsHashMap.get(forPrincipal);
switch (exists) {
case (null) { Prelude.unreachable(); }; // assumes the principal ALREADY exists in this map as a key
case (?exists) { return exists };
};
};
Now you can pass getPosts into the update function above, with the optional fields that need to be updated. Whatever other fields you want to add, you can just add them to the Post type and then as optional values to the update function, and pass them in if they change otherwise pass null.
Another way to do this is freeze/unfreeze the array, I’m not sure which is more performant though. Also this is from another project, and I was working on the assumption that principals/post ids would be checked and verified as already existing before retrieved from the map/to be updated, which is why I trap above if there’s no post found with corresponding id.