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