Esempio n. 1
0
async def partially_update_citizen(db: PG, import_id: int, citizen_id: int,
                                   updated_data: dict) -> dict:
    """
    Частичное обновление жителя.

    :param db: объект для взаимодействия с БД
    :param import_id: идентификатор выгрузки
    :param citizen_id: идентификатор жителя
    :param updated_data: актуальные данные для обновления жителя
    :return: обновленное состояние жителя
    """
    async with db.transaction() as conn:
        # Блокировка позволит избежать состояние гонки между конкурентными
        # запросами на изменение родственников
        await acquire_lock(conn=conn, import_id=import_id)

        citizen = await get_citizen(conn=conn,
                                    import_id=import_id,
                                    citizen_id=citizen_id)

        if not citizen:
            raise HTTPNotFound

        return await update_citizen(conn=conn,
                                    import_id=import_id,
                                    citizen=citizen,
                                    updated_data=updated_data)
Esempio n. 2
0
def get_citizens_cursor(db: PG, import_id: int) -> AsyncPGCursor:
    """
    Возвращает курсор для асинхронного получения данных о жителях по определенной выгрузке.

    :param db: объект для взаимодействия с БД
    :param import_id: идентфикатор выгрузки
    :return: объект курсора
    """
    query = CITIZENS_QUERY.where(citizens_table.c.import_id == import_id)
    return AsyncPGCursor(query=query, transaction_ctx=db.transaction())
Esempio n. 3
0
async def create_import(db: PG, citizens: List[dict]) -> int:
    async with db.transaction() as conn:
        query = imports_table.insert().returning(imports_table.c.import_id)
        import_id = await conn.fetchval(query=query)

        citizen_rows = make_citizen_rows(import_id=import_id, citizens=citizens)
        relation_rows = make_relation_rows(import_id=import_id, citizens=citizens)

        chunked_citizen_rows = chunk_list(iterable=citizen_rows, size=MAX_CITIZENS_PER_INSERT)
        chunked_relation_rows = chunk_list(iterable=relation_rows, size=MAX_RELATIONS_PER_INSERT)

        query = citizens_table.insert()
        for chunk in chunked_citizen_rows:
            await conn.execute(query.values(list(chunk)))

        query = relations_table.insert()
        for chunk in chunked_relation_rows:
            await conn.execute(query.values(list(chunk)))

        return import_id
Esempio n. 4
0
class DataBase:
    def __init__(self,
                 *,
                 driver="postgresql",
                 host,
                 login,
                 pwd,
                 db,
                 loop_=None):
        sql_params = f"{driver}://{login}:{pwd}@{host}/{db}"

        if not loop_:
            loop_ = asyncio.get_event_loop()

        self.loop = loop_
        self.pg = PG()

        self.loop.run_until_complete(
            self.pg.init(sql_params, min_size=5, max_size=100))

    async def save_to_db(self, url, title, html_body, *, parent):
        print(f"Save url: {url}")
        async with self.pg.transaction() as conn:

            insert_query = insert(urls_table).values({
                "url":
                str(url),
                "title":
                title,
                "html":
                await files.save_html(url, html_body),
                "parent":
                parent
            })

            update_query = insert_query.on_conflict_do_update(
                constraint="urls_url_key",
                set_={
                    "title": title,
                    "html": await self._update_html(url, html_body, conn),
                    "parent": parent
                })

            await conn.execute(update_query)

    async def get_from_db(self, *, parent, limit=10):
        async with self.pg.transaction() as conn:
            query = select([
                urls_table.c.url, urls_table.c.title
            ]).where(urls_table.c.parent == parent).limit(limit)

            for res in await conn.fetch(query):
                print(f"{res[0]}: \"{res[1]}\"")

    @staticmethod
    async def _update_html(url: URL, html_file_body: str, connection):
        """ Удалять HTML-файлы, ссылки на которые удаляются из БД """

        query = select([
            urls_table.c.html,
        ]).where(urls_table.c.url == str(url))

        old_html = await connection.fetchval(query)

        if old_html:
            files.del_html(old_html)
            print("Delete file: ", old_html)

        html_file_name = await files.save_html(url, html_file_body)

        return html_file_name