Skip to main content

Perform basic operations

In this section, we'll explore basic operations on the Chromia blockchain. We'll focus on adding data to the blockchain through transactions. By the end of this tutorial, you will understand how to create users, make posts, and manage followers within your dapp.

Add data through transactions

In Chromia, data is added to the blockchain by sending transactions, each of which can contain one or more database operations known as "operations." Let's start by defining the operations for creating users, making posts, and following users.

Create a user

src/main.rell
operation create_user(name, pubkey) {
create user(name, pubkey);
}

The create_user operation creates a new user. It takes two parameters: name (user's name) and pubkey (public key). Then, it inserts data into the user entity using the create keyword.

We use a public key as id, and thanks to Rell's ability to identify types, we can pass these directly to the constructor without specifying the fields explicitly.

  • pubkey is a byte_array with a length of 32 or 64, which is common for public keys.

An alternate, more explicit notation would be:

create user( name = name, id = pubkey );

Make a post

src/main.rell
operation make_post(user_id: byte_array, content: text) {
create post(
user @ { user_id },
content
);
}

The make_post operation allows users to create posts. It requires the user_id (of the user making the post) and the content (text content of the post). Note that we don't need to specify the timestamp because we've set a default value in the entity definition.

Follow a user

src/main.rell
operation follow_user(user_id: byte_array, follow_id: byte_array) {
val user = user @ { user_id };
val follow = user @ { follow_id };
create follower(
user = follow,
follower = user
);
}

The follow_user operation enables one user to follow another user. It requires two parameters: user_id (ID of the user who wants to follow) and follow_id (ID of the user to be followed). We explicitly query the database for both users and then create a follower entity to establish the relationship.

Unfollow a user

To unfollow a user, we want to do the opposite of following. We must, therefore, delete the follower entity

src/main.rell
operation unfollow_user(user_id: byte_array, unfollow_id: byte_array) {
val user = user @ { user_id };
val unfollow = user @ { unfollow_id };
delete follower @? { .user == unfollow, .follower == user };
}

Test the operations

Let's add unit tests to ensure your dapp code works as intended. Testing is crucial to the development to verify that your operations produce the expected results.

Set up the test module

  1. In your project's directory, navigate to the test folder. If the test folder doesn't exist, create one.

  2. Inside the test folder, create a new file named my_news_feed_test.rell. This file will contain your test cases.

  3. Add the following header to my_news_feed_test.rell:

src/test/my_news_feed_test.rell
@test module;

import main.*;
  • The @test module declaration indicates that this module contains test code.
  • The import main.*; line imports everything from the main module, making your dapp code accessible for testing.

Write test cases

Let's write some test cases to ensure your dapp functions correctly. We'll test the creation of users, following relationships, and posts.

src/test/my_news_feed_test.rell
@test module;

import main.*;

val alice = rell.test.pubkeys.alice;
val bob = rell.test.pubkeys.bob;

function test_create_entities() {
// Test the creation of two users: Alice and Bob
rell.test.tx()
.op(create_user("Alice", alice))
.op(create_user("Bob", bob))
.run();

// Check if there are two users in the user table
assert_equals(user @ { } (@sum 1), 2);

// Alice follows Bob and makes a post
rell.test.tx()
.op(follow_user(alice, bob))
.op(make_post(alice, "My post"))
.run();

// Check if there is one follower and one post
assert_equals(follower @ { } (@sum 1), 1);
assert_equals(post @ { } (@sum 1), 1);

// Alice unfollows Bob and no followers should now exist
rell.test.tx()
.op(unfollow_user(alice, bob))
.run();
assert_equals(follower @ { } (@sum 1), 0);
}

In this test case:

  • We use two public keys, alice and bob from the Rell test framework as user IDs.
  • The function test_create_entities is prefixed with test_ to indicate it is a test case and runs a series of transactions to create users, establish a following relationship, and create a post.
  • After each transaction, we use assert_equals to check if the expected number of entities is in the corresponding tables. The @sum is used to aggregate a value from the table. We use 1 as aggregate since we just want the number of entities.

Run the tests

Now that you have written your test, you can run it to verify the functionality of your dapp.

  1. Open a terminal and navigate to your project's root directory.

  2. Run the following command to execute the tests:

chr test

This command will run the tests located in the test: modules in the chromia.yml. If all tests pass, you'll see a confirmation that your dapp's functionality is working as expected.

Congratulations! You've successfully added unit tests to your dapp, helping ensure its reliability and functionality.

In the next part of this tutorial, we'll explore more advanced topics, including handling user input and security considerations in Chromia blockchain development.