Skip to content

Native

In this tutorial I'll create a database for the candy store to show the basic AnnaDB features.

Insert primitive

let's start with categories. Let's represent categories as simple string objects. To do so let's insert the first one into the categories collection.

Request:

collection|categories|:insert[
    s|sweets|,
];

collection|categories| shows on which collection the query will be applied. In our case - categories

insert[...] - is a query step. You can insert one or many objects using the insert operation.

s|sweets| - is the object to insert. In this case, it is a string primitive. Prefix s means that it is a string, | wrap the value of the primitive. Other primitive types could be found in the Data Types section.

Response:

result:ok[
    response{
        s|data|:ids[
            categories|b74c8f36-698d-41d5-b0cf-8fcbf92c9e3c|,
        ],
        s|meta|:insert_meta{
            s|count|:n|1|,
        },
    },
];

If everything is ok, in result will be returned ok[...] vector with responses for all the transaction pipelines. Each response contains data and meta information. In our case there is only one response with a vector of ids in data and a number of inserted objects in meta

Insert container

Let's insert a more complicated object now - a chocolate bar. It will have fields:

  • name
  • price
  • category

For the category, I'll use the already created one.

Request:

collection|products|:insert[
    m{
        s|name|:s|Tony's|,
        s|price|:n|5.95|,
        s|category|:categories|b74c8f36-698d-41d5-b0cf-8fcbf92c9e3c|,
    },
];

The query is similar to the previous one, but the object is not a primitive, but a map. The value of the category field is a link, that was received after the previous insert.

Response:

result:ok[
    response{
        s|data|:ids[
            products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|,
        ],
        s|meta|:insert_meta{
            s|count|:n|1|,
        },
    },
];

The response is nearly the same as before - link in data and number of inserted objects in meta.

Get object

Let's retrieve the information about this chocolate bar now. I'll use the get operation for this, to the object by id

Request:

collection|products|:get[
    products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|,
];

This time I use the get[...] query step. Using this step you can retrieve one or many objects using object links.

Response:

result:ok[
    response{
        s|data|:objects{
            products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|:m{
                s|name|:s|Tony's|,
                s|category|:s|sweets|,
                s|price|:n|5.95|,
            },
        },
        s|meta|:get_meta{
            s|count|:n|1|,
        },
    },
];

In the response here you can see the objects{...} map, where keys are links to objects and values are objects. objects{} map keeps the order - it will return objects in the same order as they were requested in the get step, or as they were sorted by the sort step.

The category was fetched automatically and the value was returned.

Let's insert another chocolate bar there to have more objects in the collection:

collection|products|:insert[
    m{
        s|name|:s|Mars|,
        s|price|:n|2|,
        s|category|:categories|b74c8f36-698d-41d5-b0cf-8fcbf92c9e3c|,
    },
];

I use the same category id for this bar.

Modify primitive

Let's modify the category to make it more accurate.

Request:

collection|categories|:q[
    get[
        categories|b74c8f36-698d-41d5-b0cf-8fcbf92c9e3c|,
    ],
    update[
        set{
            root:s|chocolate|,
        },
    ],
];

The query here consists of 2 steps. Get the object by link step and modify this object step. The update[...] operation is a vector of update operators. Read more about the update.

Response:

result:ok[
    response{
        s|data|:ids[
            categories|b74c8f36-698d-41d5-b0cf-8fcbf92c9e3c|,
        ],
        s|meta|:update_meta{
            s|count|:n|1|,
        },
    },
];

The response of the update operation contains the ids of the updated objects as data and the number of the updated objects as meta.

Let's take a look, at how this affected the chocolate objects.

Request:

collection|products|:find[
];

To find objects I use the find[...] operation. It is a vector of find operators. If it is empty, all the collection objects will be returned.

Response:

result:ok[
    response{
        s|data|:objects{
            products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|:m{
                s|category|:s|chocolate|,
                s|price|:n|5.95|,
                s|name|:s|Tony's|,
            },
            products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|:m{
                s|name|:s|Mars|,
                s|price|:n|2|,
                s|category|:s|chocolate|,
            },
        },
        s|meta|:find_meta{
            s|count|:n|2|,
        },
    },
];

The category was changed for both products, as the category object was linked with these objects.

Modify container

Now I'll increase the price of the bars, where it is less than 2

Request:

collection|products|:q[
    find[
        lt{
            value|price|:n|3|,
        },
    ],
    update[
        inc{
            value|price|:n|2|,
        },
    ],
];

The find step can stay before the update step as well. All the found objects will be updated. Read more about find operation and operators here.

Response:

result:ok[
    response{
        s|data|:ids[
            products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|,
        ],
        s|meta|:update_meta{
            s|count|:n|1|,
        },
    },
];

The response is similar to the previous one.

Here is how all the products look like after update:

result:ok[
    response{
        s|data|:objects{
            products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|:m{
                s|name|:s|Tony's|,
                s|category|:s|chocolate|,
                s|price|:n|5.95|,
            },
            products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|:m{
                s|category|:s|chocolate|,
                s|name|:s|Mars|,
                s|price|:n|4|,
            },
        },
        s|meta|:find_meta{
            s|count|:n|2|,
        },
    },
];

Sort objects

To sort objects I'll use the sort operation against the price field

Request:

collection|products|:q[
    find[
    ],
    sort[
        asc(value|price|),
    ],
];

The sort[...] operation is a vector of sort operators - asc and desc. Sort operators are modifiers, that contain paths to the sorting value. The sort operation is not an independent step, it can stay only after find-like operations, that return objects. You can read more about sort here

Response:

result:ok[
    response{
        s|data|:objects{
            products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|:m{
                s|price|:n|4|,
                s|name|:s|Mars|,
                s|category|:s|chocolate|,
            },
            products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|:m{
                s|name|:s|Tony's|,
                s|category|:s|chocolate|,
                s|price|:n|5.95|,
            },
        },
        s|meta|:find_meta{
            s|count|:n|2|,
        },
    },
];

Objects in the response are sorted by price now.

It is useful to use limit and offset operations together with sort. You can read about them in the documentation

Make projections

To get only the name and price fields I'll use the project operation

Request:

collection|products|:q[
    find[
    ],
    project{
        s|name|:keep,
        s|price|:keep,
    },
];

The keep operator is used to keep the value of the field or subfield in the output.

Response:

result:ok[
    response{
        s|data|:objects{
            products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|:m{
                s|price|:n|4|,
                s|name|:s|Mars|,
            },
        },
        s|meta|:find_meta{
            s|count|:n|1|,
        },
    },
];

To set a new field with already existing value I use root operator

Request:

collection|products|:q[
    find[
    ],
    project{
        s|new_field|:value|category|,
    },
];

Response:

result:ok[
    response{
        s|data|:objects{
            products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|:m{
                s|new_field|:s|chocolate|,
            },
        },
        s|meta|:find_meta{
            s|count|:n|1|,
        },
    },
];

It is possible to set any value to the field as well

Request:

collection|products|:q[
    find[
    ],
    project{
        s|new_field|:s|new_value|,
    },
];

Response:

result:ok[
    response{
        s|data|:objects{
            products|160cdd92-703d-4e51-b31d-bfc9e190c1ba|:m{
                s|new_field|:s|new_value|,
            },
        },
        s|meta|:find_meta{
            s|count|:n|1|,
        },
    },
];

Delete objects

You can use delete operation after any find-like step to delete all the found objects. Or it can be used independently to delete the whole collection.

Request:

collection|products|:q[
    find[
        gt{
            value|price|:n|5|,
        },
    ],
    delete,
];

The delete operation is a primitive without value.

Response:

result:ok[
    response{
        s|data|:ids[
            products|4a9e0f43-92f1-4d42-969b-6a148ac5c6ad|,
        ],
        s|meta|:update_meta{
            s|count|:n|1|,
        },
    },
];

The response contains affected ids in data and the number of deleted objects in meta