Управление данными в базе данных часто требует написания большого количества запросов. Когда одни и те же данные требуются в нескольких местах, это, вероятно, приведет к дублированию кода. Когда эти запросы также необходимо обновить, это может быть, мягко говоря, «неудобством».

При использовании ThingsDB вы можете использовать так называемые процедуры. Официальное определение процедуры: Именованное замыкание, которое присоединяется к области и доступно для использования в вызове API. Но проще говоря, это просто функция, хранящаяся в ThingsDB, которую вы можете запускать сколько угодно раз с любого поддерживаемого клиента. Это не только сэкономит вам много времени, но и обеспечит более четкую кодовую базу и лучшую производительность. Еще одно преимущество использования процедур заключается в том, что они предотвращают проблемы безопасности, связанные с инъекциями.

Цель этого блога - познакомить с процедурами в ThingsDB и продемонстрировать, как их использовать доступным способом.

Примечание. ThingsDB также поддерживает запросы, но во многих случаях желательно использование процедур.

Настраивать

Прежде чем приступить к созданию и запуску процедур, нам нужно запустить и подготовить базу данных ThingsDB. Вы можете легко опробовать ThingsDB, создав игровую площадку по адресу: https://thingsdb.net/. Вот что мы сделали.

Однако также можно настроить ThingsDB вручную. Если вы хотите сделать это, обратитесь к документации ThingsDB для получения дополнительной информации: https://docs.thingsdb.net/v0/getting-started/.

Теперь у нас есть коллекция в ThingsDB, которая называется Talus, и мы получили токен аутентификации. Мы держим этот токен, потому что он нам понадобится в следующем HTTP-запросе, используя CURL с аутентификацией токена.

Сначала мы добавим list в корень коллекции с именем pizzas. Делается это так:

// Add a new list called `pizzas` to the root of the collection 
.pizzas = [];

Во-вторых, мы создадим тип под названием Pizza. Это не обязательно, но позволяет определять свойства данного типа. Экземпляры этого типа, не соответствующие этому определению, не принимаются.

// Create a new type called `Pizza`
set_type('Pizza', {
    name: 'str',
    price: 'float'
});

Теперь, если мы хотим добавить Pizza в список pizzas, все, что нам нужно сделать, это создать для этого процедуру и запустить ее!

Создание нашей первой процедуры

Создать процедуру очень просто. Все, что нам нужно сделать, это вызвать функцию new_procedure, которая является частью API процедуры. Эта функция требует двух аргументов. Первый - это имя, которое вы даете новой процедуре, а второй аргумент - это закрытие. Замыкание - это встроенная функция, которую вы также найдете в других языках программирования, таких как Javascript (функция стрелки) или Python (функция Lambda).

Итак, давайте создадим нашу первую процедуру, которая добавляет Pizza в список pizzas:

// Create a new procedure called `add_pizza`
new_procedure('add_pizza', |name, price| {
    pizza = Pizza{
        name: name,
        price: price
    };
    .pizzas.push(pizza);
});

Примечание. Процедуры могут быть созданы для @thingsdb или @collection области. Поэтому при создании процедур убедитесь, что вы нацеливаетесь на правильный объем.

Теперь нам просто нужно запустить его. Выполнение процедуры также является частью API процедуры. Для этого можно использовать функцию run:

// Run `add_pizza` with a given name and price
run('add_pizza', 'Pepperoni', 7.99);

Вот и все! Теперь вы знаете, как создавать и запускать процедуры.

Если вы хотите попробовать предыдущие шаги, объединенные с помощью команды CURL. Вы можете использовать следующий пример:

curl --location --request POST 'https://playground.thingsdb.net//Talus' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <PLACE_YOUR_TOKEN_HERE>' \
--data-raw '{
    "type": "query",
    "code": ".pizzas = []; set_type(`Pizza`, {name: `str`, price:     `float`}); new_procedure(`add_pizza`, |name, price|{ pizza = Pizza{name: name, price: price}; .pizzas.push(pizza);}); wse(run(`add_pizza`, `Pepperoni`, 7.99));"
}'

Примечание. Сохраненные замыкания, которые потенциально могут вносить изменения в ThingsDB, называются замыканиями с побочными эффектами и должны быть заключены в оболочку с помощью функции wse (..). Поскольку процедура - это именованное замыкание, присоединенное к области видимости, это также применимо и здесь.

Также существует прямая точка входа для запуска процедур вместо запуска процедуры с использованием синтаксиса run (..). Это можно использовать следующим образом:

curl --location --request POST 'https://playground.thingsdb.net//Talus' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <PLACE_YOUR_TOKEN_HERE>' \
--data-raw '{
    "type": "run",
    "name": "add_pizza",
    "args": ["Pepperoni", 7.99]
}'

Дополнительные процедуры

Теперь, когда мы создали наш список пицц и процедуру для их добавления, мы, конечно, также хотим получить или даже изменить эти данные. Способ сделать это - просто создать больше процедур. Для любого действия, связанного с ThingsDB, может быть создана процедура. Вы можете создать столько процедур, сколько захотите.

Итак, чтобы получить список пицц, мы могли бы написать следующую процедуру:

// Create a new procedure called `get_pizzas`
new_procedure('get_pizzas', || {
    .pizzas;
});

Или, если мы хотим обновить значение свойства определенной пиццы:

// Create a new procedure called `update_pizza_price`
new_procedure('update_pizza_price', |name, new_price| {
    pizza = .pizzas.find(|p| p.name == name);
    pizza.price = new_price;
    nil;
});

И, наконец, если мы хотим убрать пиццу:

// Create a new procedure called `remove_pizza`
new_procedure('remove_pizza', |name| {
    .pizzas.remove(|p| p.name == name);
    nil;
});

Секреты и уловки

Помимо возможности создавать новые процедуры, API-интерфейс процедур также предлагает ряд других полезных функций. Одна из этих функций - procedure_doc. Эта функция возвращает строку документации для данной процедуры. Строку документа можно добавить к процедуре при ее создании.

Вот пример, который показывает, как строку документа можно добавить в процедуру, а затем снова получить:

// Create a new procedure called `count_pizzas`
new_procedure('count_pizzas', || {
"Returns the number of pizzas";
    .pizzas.len();
});
procedure_doc('count_pizzas');

Еще одна полезная функция - has_procedure. С помощью этой функции вы можете быстро определить, существует ли процедура в текущей области.

Пример:

has_procedure('count_pizzas');

Другие варианты использования

Помимо того факта, что вы можете повторно использовать эти процедуры, их использование имеет еще больше преимуществ. Во-первых, они быстрее обычных запросов. На самом деле это связано с «сохраненными закрытиями». Процедура использует сохраненное замыкание, код / ​​синтаксис которого уже скомпилирован, а возможные переменные уже созданы. Значит, уже проделана некоторая работа, которую не нужно переделывать. Это может иметь серьезные преимущества с точки зрения масштабируемости. Во-вторых, вы можете вызывать эти процедуры из любого проекта, который вы подключаетесь к ThingsDB. Это может быть очень полезно, например, при обмене данными между несколькими приложениями или другими системами.

Наконец, как упоминалось ранее, вы можете избежать внедрения кода, используя процедуры. Используя процедуры, вы более или менее вынуждены вводить аргументы. Внедрение переменных используется для предотвращения проблем с внедрением при обычных запросах. Поэтому вам, возможно, придется взглянуть на инъекцию переменных документацию, чтобы сделать обычные запросы безопасными, но процедуры сами по себе заставляют использовать аргументы. Эти аргументы безопасно анализируются ThingsDB, и потенциально исполняемый код не выполняется как таковой.

Заключение

В этом блоге мы показали, насколько доступно и просто использовать процедуры. Мы объяснили, в чем его преимущества и некоторые варианты использования. Теперь у вас есть достаточно информации, чтобы самостоятельно приступить к процедурам!

Если вы хотите узнать больше о ThingsDB или его процедурах, вы можете посетить официальную страницу документации по адресу https://docs.thingsdb.net.