Telegram Bot with Node.js: Implementing CRUD-L Operations Using Command Arguments

Publication date: 2024-10-14

In this post, I’ll share my journey into Telegram bot development, following up on a previous post where I created a basic Node.js bot with standard commands like /start, /help, and /settings using the grammY library. This time, we’ll go a step further by building a bot capable of managing data in a database using the CRUD-L pattern (Create, Read, Update, Delete, and List) through command arguments. While this approach is simple, it offers a great starting point for personal projects.

The demo bot, @flancer64/tg-demo-crudl, allows users to manage a list of contacts and phone numbers in a database using the following commands:

Technologies Used

Creating a Typical Command for the Bot

In this section, I won’t go into the details of how to set up the bot itself. If you need help setting up a basic bot, you can refer to my previous article. Instead, we’ll focus on how to create a typical command for handling CRUD operations. We’ll use /create as an example, and this approach can be easily extended to implement other commands.

Dependency Injection

The ES6 module (./src/Back/Bot/Cmd/Create.js) is written in a way that allows the Object Container to manage dependencies based on the instructions in the module. The following dependencies are injected:

export default class Demo_Crudl_Back_Bot_Cmd_Create {
constructor(
{

TeqFw_Core_Shared_Api_Logger$$: logger,

TeqFw_Db_Back_RDb_IConnect$: conn,

TeqFw_Db_Back_Api_RDb_CrudEngine$: crud,

Demo_Crudl_Back_Store_RDb_Schema_Phone$: rdbPhone,

}
) {}
} * Logger (TeqFw_Core_Shared_Api_Logger): For logging the execution of commands. * Database Connection (TeqFw_Db_Back_RDb_IConnect): To handle database transactions. * CRUD Engine (TeqFw_Db_Back_Api_RDb_CrudEngine): To perform basic database operations. * DTO for Database Structure (Demo_Crudl_Back_Store_RDb_Schema_Phone): A Data Transfer Object (DTO) that defines the database structure.

The first three dependencies are standard tools from my TeqFW toolkit, while the last one is specific to the domain of the project.

DTO for the Database

The Demo_Crudl_Back_Store_RDb_Schema_Phone DTO describes a simple structure with four fields:

class Dto {
date_created;
id;
name;
phone;
}

This DTO corresponds to the following table in an SQLite database:

CREATE TABLE main.phone

(

id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,

name VARCHAR(255) NOT NULL,

phone VARCHAR(255) NOT NULL,

date_created DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL

); This structure is sufficient to give you an idea of how the data is organized in the database. While the demo bot uses SQLite, Knex.js, a database abstraction layer (DBAL), allows you to work with PostgreSQL, MariaDB/MySQL, MS SQL, and Oracle as well. You just need to install the appropriate npm package for the desired database system.

The Knex.js connection settings for the specific database are configured in the ./cfg/local.json file (the configuration template can be found in ./cfg/init.json). In the demo version, SQLite is used, with the database file located at ./var/data.db. The following commands are used to interact with the database:

$ ./bin/tequila.mjs db-init
$ ./bin/tequila.mjs db-export -f ./var/data.json
$ ./bin/tequila.mjs db-import -f ./var/data.json The command names are self-explanatory: db-init initializes the database structure (table), while db-export and db-import handle data export and import in JSON format, respectively.

Template for Handling Telegram Commands

Since our bot uses the grammY framework, a typical command handler works with the platform’s ctx object. Here’s a skeleton of the handler:

const handler = async (ctx) => {
let msg = ‘The command has failed.’;
const from = ctx.message.from;
logger.info(Command has been received from user '${from.username}' (id:${from.id}));
const trx = await conn.startTransaction();

try {

// const parts = ctx.message.text.split(’ ’);
// …
await trx.commit();
} catch (e) {
await trx.rollback();

msg = e.toString();

logger.error(msg);
}
// https://core.telegram.org/bots/api#sendmessage
await ctx.reply(msg, {

parse_mode: ‘HTML’,

});
};

The algorithm for the handler’s execution is as follows:

Executing the Command

The following code demonstrates how the /create command is processed — extracting the data from the command and saving it to the database:

try {

const parts = ctx.message.text.split(’ ’);
const dto = rdbPhone.createDto();
dto.name = parts[1];
dto.phone = parts[2];
const {[A_PHONE.ID]: id} = await crud.create(trx, rdbPhone, dto);
await trx.commit();

msg = New record #${id} has been created.;

logger.info(msg);
} catch (e) {…}

I use my own wrapper for the DBAL Knex.js, which allows me to perform basic operations (CRUD) with DTOs. If you are using a different library for working with the database (e.g., Sequelize or Prisma), the code here will be different. However, the rest of the surrounding logic can remain the same (except for transaction handling).

Example of Bot Operation

After creating the bot in BotFather, obtaining the API key, and configuring the bot (./cfg/local.json), you need to create the database tables:

$ ./bin/tequila.mjs db-init Start the bot in long polling mode:
$ ./bin/tequila.mjs tg-bot-start or
$ npm start ### Get the Help

Accessing bot commands

Create

Adding a new record

Read

Retrieving a record

Update

Modifying a record

List

Listing all records

Delete

Deleting a record

Conclusion

In this article, I covered the process of creating a simple Telegram bot using Node.js and the grammY library, which supports CRUD-L operations (Create, Read, Update, Delete, and List). We explored how command arguments can be used to manipulate data in a database. Despite its simplicity, this approach opens up opportunities for personal projects where complex business logic isn’t required, but ease of implementation is key.

If you are looking for a simple yet powerful solution for working with databases through Telegram bots, this project can be a great starting point for bringing your ideas to life.

Happy coding!

If you enjoyed this article, please give it a clap and follow me for more content!

Stay connected:

Thank you for your support!