Search code examples
pythondatabasepostgresqltelegram-botasyncpg

asyncpg.exceptions.PostgresSyntaxError: syntax error at or near "=" problem with databese and user


About my telegram bot and error on it:

I wrote a Telegram bot.

Basis: Aiogram

Database: postgreSQL + Django admin panel

Problem: The first time users press /start to use the bot (which adds the user's information to the database), the bot works fine, but after that, when a user added to the database presses /start 2nd time while using the bot, the following error occurs.

postgresql.py

from typing import Union

import asyncpg
from asyncpg import Connection
from asyncpg.pool import Pool

from data import config


class Database:
    def __init__(self):
        self.pool: Union[Pool, None] = None

    async def create(self):
        self.pool = await asyncpg.create_pool(
            user=config.DB_USER,
            password=config.DB_PASS,
            host=config.DB_HOST,
            database=config.DB_NAME
        )

    async def execute(self, command, *args,
                      fetch: bool = False,
                      fetchval: bool = False,
                      fetchrow: bool = False,
                      execute: bool = False
                      ):
        async with self.pool.acquire() as connection:
            connection: Connection
            async with connection.transaction():
                if fetch:
                    result = await connection.fetch(command, *args)
                elif fetchval:
                    result = await connection.fetchval(command, *args)
                elif fetchrow:
                    result = await connection.fetchrow(command, *args)
                elif execute:
                    result = await connection.execute(command, *args)
            return result


    @staticmethod
    def format_args(sql, parameters: dict):
        sql += " AND ".join([
            f"{item} = ${num}" for num, item in enumerate(parameters.keys(),
                                                          start=1)
        ])
        return sql, tuple(parameters.values())

    async def add_user(self, full_name, username, telegram_id):
        sql = "INSERT INTO usersinfo_user (full_name, username, telegram_id) VALUES($1, $2, $3) returning *"
        return await self.execute(sql, full_name, username, telegram_id, fetchrow=True)

    async def select_all_users(self):
        sql = "SELECT * FROM usersinfo_user"
        return await self.execute(sql, fetch=True)

    async def select_user(self, **kwargs):
        sql = "SELECT * FROM usersinfo_user WHERE"
        sql, parameters = self.format_args(sql, parameters=kwargs)
        return await self.execute(sql, *parameters, fetchrow=True)

    async def count_users(self):
        sql = "SELECT COUNT(*) FROM usersinfo_user"
        return await self.execute(sql, fetchval=True)

    async def update_user_username(self, username, telegram_id):
        sql = "UPDATE usersinfo_user SET username=$1 WHERE telegram_id=$2"
        return await self.execute(sql, username, telegram_id, execute=True)


    async def delete_users(self):
        await self.execute("DELETE FROM usersinfo_user WHERE TRUE", execute=True)

    async def drop_users(self):
        await self.execute("DROP TABLE usersinfo_user", execute=True)

start.py

import logging

import asyncpg.exceptions
from aiogram import types
from aiogram.dispatcher.filters.builtin import CommandStart

from data.config import ADMINS
from keyboards.inline.languageKeyboard import choose_language
from states.intro import IntroState
from loader import dp, db, bot


@dp.message_handler(CommandStart(), state=None)
async def bot_start(message: types.Message):
    try:
        user = await db.add_user(telegram_id=message.from_user.id,
                                 full_name=message.from_user.full_name,
                                 username=message.from_user.username)
    except asyncpg.exceptions.UniqueViolationError:
        user = await db.select_user(telegram_id=message.from_user.id)

    await message.answer("Choose language:", reply_markup=choose_language)
    await IntroState.language.set()

    logging.info(message)
    # Notify admin about added usr
    count = await db.count_users()
    msg = f"User<b>{user[1]}</b> added.\n All users:<b>{count}</b> ."
    await bot.send_message(chat_id=ADMINS[0], text=msg)

app.py

from aiogram import executor

from loader import dp, db
import middlewares, filters, handlers
from utils.notify_admins import on_startup_notify
from utils.set_bot_commands import set_default_commands


async def on_startup(dispatcher):
    await db.create()

    # Commands
    await set_default_commands(dispatcher)

    # Notify admin
    await on_startup_notify(dispatcher)


if __name__ == '__main__':
    executor.start_polling(dp, on_startup=on_startup)

Solution

  • try with ON CONFLICT :

    sql = "INSERT INTO vegabot.Resume (telegram_id, language, fullname) VALUES($1, $2, $3) ON CONFLICT (telegram_id) DO NOTHING RETURNING *"