Skip to main content

UPDATE Statement

It is only possible to update the value of an attribute that has been explicitly marked with mutable.

entity my_entity {
key my_key: text;
mutable my_mutable: text;
}

If you have a reference to an entity, updating an attribute is as simple as making an assignment:

my_entity_instance.my_mutable = "new value";

This corresponds to the following SQL statement:

UPDATE "c0.my_entity" A00 SET "my_mutable" = ? WHERE A00."rowid" = ?

If you have multiple mutable attributes to update, it may be tempting to assign them one by one causing a new database roundrip for each time. A better approach is to use the update keyword in Rell. It works similar to the at-operator.

       FROM        CARDINALITY  WHERE         WHAT
update entity_name @ { condition } ( .my_mutable = "new value" );

Here, we see that the WHAT part has been replaced with an assignment, and the TAIL part is omitted.

This way, we can update several fields in a single database roundtrip. If we already have a reference to an entity, we can pass it as the condition $ == entity_instance.

Example

Let's have a look at a concrete example.

entity user {
key name;
key pubkey;
mutable address: text;
}

operation update_address(name, new_address: text) {
val user = find_and_check_signer(name);
user.address = new_address;
}

function find_and_check_signer(name): user {
val user_pubkey = user @ { name } (user = $, pubkey = .pubkey);
require(op_context.is_signer(user_pubkey.pubkey), "User must sign operation");
return user_pubkey.user;
}

Here, we have a user entity with a unique key on its name and public key and a mutable address property. In operation update_address, we want to find the user and update the address. The function find_and_check_signer thus retrieves not only the user entity with a specific name in the first at-expression. It also fetches the pubkey property to be able to require a signature matching this key without making an additional SQL select. The new address is then updated with a simple assignment.

But let's say now that we instead want the address to be split into a street name and a zip code. The new model would thus look like:

entity user {
key name;
key pubkey;
mutable street_address: text;
mutable zip_code: integer;
}

We would then update our operation to

operation update_address(name, new_street_address: text, new_zip_code: integer) {
val verified_user = find_and_check_signer(name);
update user @ { $ == verified_user } (
.street_address = new_street_address,
.zip_code = new_zip_code
);
}

In this way, we can update both attributes at once.

tip

Use the update operation in combination with { $ == <instance> } to be able to update several attributes in a single database roundtrip when possible.