Last active
November 2, 2021 11:48
-
-
Save brunodb3/090a6f3847237959b453b1b9395085f2 to your computer and use it in GitHub Desktop.
Rell Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// notes: | |
// - I like the "query" notation of `@` and `@*`. It's short and simple, and makes so much sense. `user at name equals 'bruno'` is nice | |
// - on an actual project, could be difficult to differentiate `val` and `var` in a glance. I wonder if the linting is smart enough to see that `val` cannot be reassigned (I assume yes) | |
// - I like that Rell doesn't need type declarations, but that it offers it. makes code better to follow and understand for devs | |
// - I don't like that the web UI doesn't have autocomplete or type-check. It's nice when errors are found while I'm typing | |
// | |
entity user { | |
key pubkey; | |
key username: text; | |
} | |
entity channel { | |
key name; | |
admin: user; | |
} | |
entity channel_member { | |
key channel, member: user; | |
} | |
entity message { | |
key channel, timestamp; // only one message at a given timestamp to one channel, as `key` is unique | |
index posted_by: user; | |
text; | |
} | |
entity balance { | |
key user; | |
mutable amount: integer; | |
} | |
// ---------- | |
operation init (founder_pubkey: pubkey) { | |
require( (user@*{} limit 1).size() == 0 ); | |
// nice that Rell assigns values to attributes based on the type (if you have only one attribute of the same type) | |
// so you don't need to do `create user (pubkey = founder_pubkey, username = 'admin');` | |
val founder = create user (founder_pubkey, 'admin'); | |
create balance (founder, 1000000); | |
} | |
operation register_user ( | |
existing_user_pubkey: pubkey, | |
new_user_pubkey: pubkey, | |
new_user_username: text, | |
transfer_amount: integer | |
) { | |
require ( is_signer(existing_user_pubkey) ); | |
val existing_user = user@{existing_user_pubkey}; | |
require ( transfer_amount > 0); | |
val new_user = create user (new_user_pubkey, new_user_username); | |
pay_fee(existing_user, 100); | |
create balance(new_user, 0); | |
transfer_balance(existing_user, new_user, transfer_amount); | |
// I like that if anything fails, it just rolls back and transaction is rejected. no need to check for balance of existing_user :) | |
} | |
operation create_channel (admin_pubkey: pubkey, name) { | |
require ( is_signer(admin_pubkey) ); | |
val admin_user = user@{admin_pubkey}; | |
pay_fee(admin_user, 100); | |
val channel = create channel(admin_user, name); | |
create channel_member(channel, admin_user); | |
} | |
operation add_channel_member (admin_pubkey: pubkey, channel_name: name, member_username: text) { | |
require( is_signer(admin_pubkey) ); | |
val admin_user = user@{admin_pubkey}; | |
pay_fee(admin_user, 1); | |
val channel = channel@{channel_name, .admin==admin_user}; // here the docs say `.admin==user@{admin_pubkey}`. Wouldn't that trigger another "query"? | |
create channel_member(channel, member=user@{.username == member_username}); | |
} | |
operation post_message (channel_name: name, pubkey, message: text) { | |
require ( is_signer(pubkey) ); | |
val channel = channel@{channel_name}; | |
val member = user@{pubkey}; | |
require ( channel_member@?{channel, member} ); | |
pay_fee(member, 1); | |
create message (channel, member, text=message, op_context.last_block_time); // op_context.last_block_time for timestamp. Could be better explained in the docs | |
} | |
// --------- | |
function transfer_balance (from: user, to: user, amount: integer) { | |
require( balance@{from}.amount >= amount ); | |
update balance@{from} (amount -= amount); | |
update balance@{to} (amount += amount); | |
} | |
function pay_fee(user, deduct_amount: integer) { | |
if(user.username != 'admin') { | |
transfer_balance(user, user@{.username == 'admin'}, deduct_amount); | |
} | |
} | |
// --------- | |
query get_channels(pubkey): list<(name: text, admin: text)> { | |
return channel_member@*{.member == user@{pubkey} } | |
(name = .channel.name, admin = .channel.admin.username); | |
} | |
query get_balance(pubkey) { | |
return balance@{ user@{pubkey} }.amount; | |
} | |
query get_last_messages(channel_name: name): list<(text: text, poster: text, timestamp: timestamp)> { | |
return message@*{ channel@{channel_name} } | |
(.text, poster=.posted_by.username, @sort .timestamp); // `sort` seems to be deprecated, running the node asks to use @sort instead | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment