# User Quickstart with immudb and immuclient

TIP

To learn interactively and to get started with immudb from the command line and with programming languages, visit the immudb Playground at https://play.codenotary.com (opens new window)

# Getting immudb running

You may download the immudb binary from the latest releases on Github (opens new window). Once you have downloaded immudb, rename it to immudb, make sure to mark it as executable, then run it. The following example shows how to obtain v1.0 for linux amd64:

wget https://github.com/vchain-us/immudb/releases/download/v1.0.0/immudb-v1.0.0-linux-amd64
mv immudb-v1.0.0-linux-amd64 immudb
chmod +x immudb

# run immudb in the foreground to see all output
./immudb

# or run immudb in the background
./immudb -d

Alternatively, you may use Docker to run immudb in a ready-to-use container:

docker run -d --net host -it --rm --name immudb codenotary/immudb:latest

# Connecting with immuclient

You may download the immuclient binary from the latest releases on Github (opens new window). Once you have downloaded immuclient, rename it to immuclient, make sure to mark it as executable, then run it. The following example shows how to obtain v1.0.0 for linux amd64:

wget https://github.com/vchain-us/immudb/releases/download/v1.0.0/immuclient-v1.0.0-linux-amd64
mv immuclient-v1.0.0-linux-amd64 immuclient
chmod +x immuclient

# start the interactive shell
./immuclient

Alternatively, you may use Docker to run immuclient in a ready-to-use container:

docker run -it --rm --net host --name immuclient codenotary/immuclient:latest

# Basic operations with immuclient

Before any operations can be run by immuclient, it is necessary to authenticate against the running immudb server.

When immudb is first run, it is ready to use immediately with the default database and credentials:

  • Database name: defaultdb
  • User: immudb
  • Password: immudb
  • Port: 3322

Running login immudb from within immuclient will use the default database name and port. All you need to supply is the user and password:

immuclient> login immudb
Password: immudb

While immudb supports set and get for key-value storing and retrieving, its immutability means that we can verify the integrity of the underlying Merkle tree. To do this, we use the safeset and safeget commands. Let's try setting a value of 100 for the key balance:

immuclient> safeset balance 100

Then, we can immediately overwrite the key balance with a value of 9001 instead:

immuclient> safeset balance 9001

If we try to retrieve the current value of key balance, we should get 9001:

immuclient> safeget balance

Note that at each step so far, the verified flag is set to true. This ensures that the Merkle tree remains consistent for each transaction.

We can show the history of transactions for key balance using the history command:

immuclient> history balance

# SQL operations with immuclient

In addition to a key-value store, immudb supports the relational model (SQL). For example, to a table:

$ immuclient exec "CREATE TABLE people(id INTEGER, name VARCHAR, salary INTEGER, PRIMARY KEY id);"
sql ok, Ctxs: 1 Dtxs: 0

To insert data, use UPSERT (insert or update), which will add an entry, or overwrite it if already exists (based on the primary key):

$ immuclient exec "UPSERT INTO people(id, name, salary) VALUES (1, 'Joe', 10000);"
sql ok, Ctxs: 0 Dtxs: 1
immuclient exec "UPSERT INTO people(id, name, salary) VALUES (2, 'Bob', 30000);"
sql ok, Ctxs: 0 Dtxs: 1

To query the data you can use the traditional SELECT:

$ immuclient query "SELECT id, name, salary FROM people;"
+-----------------------+-------------------------+---------------------------+
| (DEFAULTDB PEOPLE ID) | (DEFAULTDB PEOPLE NAME) | (DEFAULTDB PEOPLE SALARY) |
+-----------------------+-------------------------+---------------------------+
|                     1 | Joe                     |                     10000 |
|                     2 | Bob                     |                     30000 |
+-----------------------+-------------------------+---------------------------+

If we upsert again on the primary key "1", the value for "Joe" will be overwriten:

immuclient exec "UPSERT INTO people(id, name, salary) VALUES (1, 'Joe', 20000);"
sql ok, Ctxs: 0 Dtxs: 1

immuclient query "SELECT id, name, salary FROM people;"
+-----------------------+-------------------------+---------------------------+
| (DEFAULTDB PEOPLE ID) | (DEFAULTDB PEOPLE NAME) | (DEFAULTDB PEOPLE SALARY) |
+-----------------------+-------------------------+---------------------------+
|                     1 | Joe                     |                     20000 |
|                     2 | Bob                     |                     30000 |
+-----------------------+-------------------------+---------------------------+

# Time travel

immudb is a immutable database. History is always preserved. With immudb you can travel in time!

immuclient query "SELECT id, name, salary FROM people WHERE name='Joe';"
+-----------------------+-------------------------+---------------------------+
| (DEFAULTDB PEOPLE ID) | (DEFAULTDB PEOPLE NAME) | (DEFAULTDB PEOPLE SALARY) |
+-----------------------+-------------------------+---------------------------+
|                     1 | Joe                     |                     20000 |
+-----------------------+-------------------------+---------------------------+

Eg. before the update:

immuclient query "SELECT id, name, salary FROM (people BEFORE TX 3) WHERE name='Joe';"
+-----------------------+-------------------------+---------------------------+
| (DEFAULTDB PEOPLE ID) | (DEFAULTDB PEOPLE NAME) | (DEFAULTDB PEOPLE SALARY) |
+-----------------------+-------------------------+---------------------------+
|                     1 | Joe                     |                     10000 |
+-----------------------+-------------------------+---------------------------+

or even before the first time insert (guess what, it is empty!):

immuclient query "SELECT id, name, salary FROM (people BEFORE TX 1) WHERE name='Joe';"
+-----------------------+-------------------------+---------------------------+
| (DEFAULTDB PEOPLE ID) | (DEFAULTDB PEOPLE NAME) | (DEFAULTDB PEOPLE SALARY) |
+-----------------------+-------------------------+---------------------------+
+-----------------------+-------------------------+---------------------------+

You can even TABLE a table with itself in the past. Imagine you want to see how people salary changed between two points in time:

immuclient query "SELECT peoplenow.id, peoplenow.name, peoplethen.salary, peoplenow.salary FROM (people BEFORE TX 3 AS peoplethen) INNER JOIN (people AS peoplenow) ON peoplenow.id=peoplethen.id;"
+--------------------------+----------------------------+-------------------------------+------------------------------+
| (DEFAULTDB PEOPLENOW ID) | (DEFAULTDB PEOPLENOW NAME) | (DEFAULTDB PEOPLETHEN SALARY) | (DEFAULTDB PEOPLENOW SALARY) |
+--------------------------+----------------------------+-------------------------------+------------------------------+
|                        1 | Joe                        |                         10000 |                        20000 |
|                        2 | Bob                        |                         30000 |                        30000 |
+--------------------------+----------------------------+-------------------------------+------------------------------+