# Rell Playground · Chromia Docs (concept)

> Edit Rell in the browser from working examples (main.rell + test.rell), then run them on your machine with the Chromia CLI (chr test, Rell 0.16.7).

Source: https://docs.chromia.com/playground/

Run locally: create a project with chr create-rell-dapp, put main.rell in src/main.rell and test.rell in src/test/, then run chr test.

## Examples
### Hello, Rell

Functions, values and print(). Open: https://docs.chromia.com/playground/#hello

main.rell:

```rell
module;

function greet(name: text): text {
    return "Hello, %s!".format(name);
}

function fib(n: integer): integer {
    if (n < 2) return n;
    return fib(n - 1) + fib(n - 2);
}
```

test.rell:

```rell
@test module;
import main.*;

function test_hello() {
    print(greet("Chromia"));
    val numbers = list<integer>();
    for (i in range(10)) numbers.add(fib(i));
    print("First ten Fibonacci numbers:", numbers);
    assert_equals(fib(10), 55);
}
```

### Entities & queries

Tables you query like a database. Open: https://docs.chromia.com/playground/#entities

main.rell:

```rell
module;

entity author {
    key name;
}

entity book {
    key title: text;
    index author;
    year: integer;
}

operation add_book(author_name: text, title: text, year: integer) {
    val a = author @? { author_name } ?: create author(author_name);
    create book(title, a, year);
}

query books_by(author_name: text) =
    book @* { .author.name == author_name } (@sort .year, .title);

query count_books() = book @* {} (@group .author.name, @sum 1);
```

test.rell:

```rell
@test module;
import main.*;

function test_library() {
    rell.test.tx(
        add_book("Ursula K. Le Guin", "A Wizard of Earthsea", 1968),
        add_book("Ursula K. Le Guin", "The Dispossessed", 1974),
        add_book("Ted Chiang", "Exhalation", 2019)
    ).run();

    print(books_by("Ursula K. Le Guin"));
    print(count_books());
    assert_equals(books_by("Ted Chiang").size(), 1);
}
```

### Operations & require

A token transfer that rejects bad input. Open: https://docs.chromia.com/playground/#bank

main.rell:

```rell
module;

entity account {
    key owner: text;
    mutable balance: integer;
}

operation open(owner: text, amount: integer) {
    create account(owner, amount);
}

operation transfer(from: text, to: text, amount: integer) {
    require(amount > 0, "Amount must be positive");
    val a = account @ { .owner == from };
    val b = account @ { .owner == to };
    require(a.balance >= amount, "Insufficient balance");
    a.balance -= amount;
    b.balance += amount;
}

query balance(owner: text) = account @ { owner } (.balance);
```

test.rell:

```rell
@test module;
import main.*;

function test_transfer() {
    rell.test.tx(open("alice", 100), open("bob", 0)).run();
    rell.test.tx(transfer("alice", "bob", 30)).run();
    print("alice:", balance("alice"), "bob:", balance("bob"));
    assert_equals(balance("bob"), 30);

    // This one must be rejected: alice only has 70 left
    rell.test.tx(transfer("alice", "bob", 500)).run_must_fail("Insufficient balance");
    print("Overdraft rejected, balances unchanged:", balance("alice"), balance("bob"));
}
```

### Signers & auth

Only the key owner may act. Open: https://docs.chromia.com/playground/#signers

main.rell:

```rell
module;

entity profile {
    key pubkey;
    mutable bio: text;
}

operation register(pubkey, bio: text) {
    require(op_context.is_signer(pubkey), "Must be signed by the profile key");
    create profile(pubkey, bio);
}

query bio(pubkey) = profile @? { pubkey } (.bio);
```

test.rell:

```rell
@test module;
import main.*;

function test_signers() {
    val alice = rell.test.keypairs.alice;
    val bob = rell.test.keypairs.bob;

    rell.test.tx().op(register(alice.pub, "I build on Chromia")).sign(alice).run();
    print("alice:", bio(alice.pub));

    // Bob tries to register Alice's key: rejected
    rell.test.tx().op(register(bob.pub, "spoof")).sign(alice).run_must_fail();
    print("bob (signed by alice):", bio(bob.pub));
}
```

### Structs & collections

Structs, enums, lists and maps. Open: https://docs.chromia.com/playground/#collections

main.rell:

```rell
module;

enum level { low, medium, high }

struct reading {
    sensor: text;
    value: decimal;
}

function classify(v: decimal): level =
    when {
        v < 20.0 -> level.low;
        v < 30.0 -> level.medium;
        else -> level.high;
    };

function summarize(rs: list<reading>): map<text, decimal> {
    val m = map<text, decimal>();
    for (r in rs) m[r.sensor] = (m.get_or_default(r.sensor, 0.0)) + r.value;
    return m;
}
```

test.rell:

```rell
@test module;
import main.*;

function test_collections() {
    val rs = [
        reading("north", 18.5),
        reading("south", 31.25),
        reading("north", 22.0)
    ];
    for (r in rs) print(r.sensor, r.value, classify(r.value));
    print("totals:", summarize(rs));
    assert_equals(classify(31.25), level.high);
}
```
