Skip to main content

Entity

You store values (instances) of an entity in Rell in a database, not in memory. You can create or delete them explicitly using the Rell create and delete expressions. An in-memory equivalent of an entity in Rell is a struct.

A variable of an entity type holds an ID (primary key) of the corresponding database record but not its attribute values.

entity company {
name: text;
address: text;
}

entity user {
first_name: text;
last_name: text;
year_of_birth: integer;
mutable salary: integer;
}

If the attribute type is not specified, it's the same as the attribute name:

entity user {
name; // built-in type "name"
company; // user-defined type "company" (error if no such type)
}

Attributes may have default values:

entity user {
home_city: text = 'New York';
}

You can use the rowid implicit attribute (type rowid) to get an entity value's ID (primary database key).

val u = user @ { .name == 'Bob' };
print(u.rowid);

val alice_id = user @ { .name == 'Alice' } ( .rowid );
print(alice_id);

Keys and indices

Entities in Rell can be associated with key and index clauses, allowing for organized and efficient data access. A key is a unique identifier for an entity, ensuring its distinctiveness within the blockchain. An index, on the other hand, facilitates fast querying of entities based on specific attributes. Simply put, an index is a pointer to data in a table.

entity user {
name: text;
address: text;
key name;
index address;
}

Keys and indices may have multiple attributes:

entity user {
first_name: text;
last_name: text;
key first_name, last_name;
}

In this example, you can have multiple with the same first_name or last_name but not with the combination of both.

You can specify mutability within a key or index clause. Here one can also set a default value:

entity address{
index mutable city: text = 'Rome';
}

You can combine attribute definitions with key or index clauses, but such definition has restrictions (can't specify mutable):

entity user {
key first_name: text, last_name: text;
index address: text;
}

The entity represents a database object. An example to visualize how to maintain relations between objects is as follows:

entity user {
key pubkey;
index name;
}
entity address {
key pubkey;
street: text;
}

entity residence {
key user, address;
}
//both queries will result lists of records, as it is a many-to-many relationships
//they might be of different sizes. The constraint is that the composite of the two keys are unique.
function get_addresses(user): list<address> = residence @* { user }.address;
function get_users(address): list<user> = residence @* { address }.user;

is many-to-many relations, a user can have more than one residence. You can implement many-to-one relations by changing the key:

entity residence {
key user;
index address;
}
//There is a unique constraint on the user key.
function get_addresses(user): list<address> = residence @* { user }.address; //will only return zero or one addresses
function get_users(address): list<user> = residence @* { address }.user; // will return zero to n users

And for completeness, one-to-many would be reverse of many-to-one:

entity residence {
index user;
key address;
}

It also works without making the address an entity, for example:

entity user { key name; }

// allow user to have many tags
entity user_tag {
key user, tag: text;
}

and one-to-one (optional) as:

entity residence {
key user;
key address; //make sure that address can be claimed by at most one user
}

There is a unique constraint on the user key and the address key.

function get_addresses(user): list<address> = residence @* { user }.address; //will only return zero or one addresses
function get_users(address): list<user> = residence @* { address }.user; // will only return zero to one users

Entity annotations

@log entity user {
name: text;
}

The @log annotation has the following effects:

  • adds a special attribute transaction of type transaction to the entity
  • result of op_context.transaction (current transaction) sets the transaction value
  • an entity can't have mutable attributes
  • can't delete the values

Changing existing entities

When you start a Rell app, a database structure update happens: tables for new entities and objects get created, and tables for existing ones get altered. There are limitations on changes that you can make in the existing entities and objects.

What's allowed:

  • Adding an attribute with a default value (a column gets added to the table and initialized with the default value).
  • Adding an attribute without a default value - only if there are no records in the table.
  • Removing an attribute (database column isn't dropped; you can read the attribute later).

What's not allowed:

  • Any changes in keys/indices, including adding a new key/index attribute, making an existing attribute into a key/index, removing an attribute from an index, etc
  • Changing attribute's type
  • Adding/removing the @log annotation