async def save_import(import_obj: Import,
                      database: Database) -> Union[int, None]:
    """Create import and corresponding citizens and relations."""
    async with database.transaction():
        insert_import_query = imports.insert().values().returning(
            imports.c.import_id)
        import_id = await database.fetch_val(insert_import_query)

        if import_obj:

            max_citizens_per_insert = MAX_QUERY_ARGS // len(citizens.columns)
            citizens_rows = make_citizens_rows(import_obj, import_id)
            chunked_citizens = chunk_list(citizens_rows,
                                          max_citizens_per_insert)
            insert_citizens_query = citizens.insert()
            for chunk in chunked_citizens:
                await database.execute(
                    insert_citizens_query.values(list(chunk)))

            max_relations_per_insert = MAX_QUERY_ARGS // len(relations.columns)
            relations_rows = make_relations_rows(import_obj, import_id)
            chunked_relations = chunk_list(relations_rows,
                                           max_relations_per_insert)
            insert_relations_query = relations.insert()
            for chunk in chunked_relations:
                await database.execute(
                    insert_relations_query.values(list(chunk)))

    return import_id
示例#2
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
示例#3
0
    async def post(self):
        # Транзакция требуется чтобы в случае ошибки (или отключения клиента,
        # не дождавшегося ответа) откатить частично добавленные изменения.
        async with self.pg.transaction() as conn:
            # Создаем выгрузку
            query = imports_table.insert().returning(imports_table.c.import_id)
            import_id = await conn.fetchval(query)

            # Генераторы make_citizens_table_rows и make_relations_table_rows
            # лениво генерируют данные, готовые для вставки в таблицы citizens
            # и relations на основе данных отправленных клиентом.
            citizens = self.request['data']['citizens']
            citizen_rows = self.make_citizens_table_rows(citizens, import_id)
            relation_rows = self.make_relations_table_rows(citizens, import_id)

            # Чтобы уложиться в ограничение кол-ва аргументов в запросе к
            # postgres, а также сэкономить память и избежать создания полной
            # копии данных присланных клиентом во время подготовки - используем
            # генератор chunk_list.
            # Он будет получать из генератора make_citizens_table_rows только
            # необходимый для 1 запроса объем данных.
            chunked_citizen_rows = chunk_list(citizen_rows,
                                              self.MAX_CITIZENS_PER_INSERT)
            chunked_relation_rows = chunk_list(relation_rows,
                                               self.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 Response(body={'data': {'import_id': import_id}},
                        status=HTTPStatus.CREATED)
示例#4
0
def test_chunk_list():
    data = tuple(map(tuple, aiomisc.chunk_list(range(10), 3)))

    assert data == ((0, 1, 2), (3, 4, 5), (6, 7, 8), (9, ))