Records
A record is a collection of privacy-enforced typed data elements grouped under one name. For instance, we can define a Person record with the following code:
record Person {
public string name;
private int age;
private double balance;
}
The data elements mirror how data is spelled out within the root document; however, a record can be used in multiple ways. For example, a record can be held within another record.
record Relationship {
public Person a;
public Person b;
}
This simple re-use becomes the foundation for building composite types and collections.
See:
- types for more information on which types can go within records.
- privacy policies for how privacy per field is specified within a record.
- bubbles for how data is exposed based on the viewer from the record.
- reactive formulas for how to expose reactively compute data to the viewer of record.
Records also have methods, can declare privacy policies, and hint at indexing for tables.
If a record is used within a table, an implicit field called id
is created with integer type.
Since communication is done with messages, conversion to a message is provided as a free helper.
Methods
We can associate code to a record via a method. For example, a method may mutate a record which is useful for consolidating how records change.
record R {
public int score;
method zero() {
score = 0;
}
}
Methods can be marked as read-only such that they are not allowed to mutate the document and thus become available for reactive formulas.
record R {
public int score;
method double_score() -> int readonly {
return score * 2;
}
public formula ds = double_score();
}
Policies
Records can express policies which are bits of code associated to the record along with @who
.
record R {
private principal owner;
policy is_owner {
return owner == @who;
}
}
A policy can be used to protect fields within a record.
record R {
private principal owner;
use_policy<is_owner> int balance;
policy is_owner {
return owner == @who;
}
}
Alternatively, a policy may be used to protect the entire record.
record R {
private principal owner;
public int balance;
policy is_owner {
return owner == @who;
}
require is_owner;
}
Indexing tables
The best mental model for a record is a row within a table. By default, a row has a primary key index on id
which has a type of int. Additional fields within a record can be indexed to speed up queries.
record R {
private int key;
index key;
}
table<R> _table;
The index keyword will inform _table that it can group records by the key field to reduce the number of candiates considered during a where clause. This will introduce both memory and computational overhead to maintain.
Easily convert to a message for communication
Given a message or record, we can convert it into a message type via the @convert
keyword.
record R {
public int x;
}
R r;
message M {
int x;
}
#sm {
M m = @convert<M>(r);
}
This conversion is useful with channels and futures are outlined as we sometimes want to present people with a list of options derived from a table. It is also useful for sending records to another service.