From 01e1f815165e0a1b1dc3ebb55068440ea4f0e765 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Tue, 20 Oct 2026 19:59:25 +0400 Subject: [PATCH] =?UTF-8?q?fix(statements):=20=D0=B2=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D0=B2=D0=BA=D0=B0=20document=5Fissue=20=D0=BF=D0=B0=D0=BA?= =?UTF-8?q?=D0=B5=D1=82=D0=B0=D0=BC=D0=B8=20=D0=BF=D0=BE=20BATCH=20(#142,?= =?UTF-8?q?=20AURORA-1711)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add_issues вставлял все записи документа одним INSERT: 16 параметров на запись, лимит asyncpg 32 767 — потолок около 2 047 замечаний. Лист ОСВ «11.xlsx» (сч. 11, 2 128 строк «Кол. доп.» на парсере контура 40287e1) давал 2 131 предупреждение, маппинг падал с InterfaceError, файл ERROR. Теперь пакеты по BATCH (1000), как у строк и значений форм. Co-Authored-By: Claude Opus 5.5 --- api/src/repositories/statements.py | 55 ++++++++++++------------- api/tests/test_mapping_statements_v2.py | 20 +++++++++ 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/api/src/repositories/statements.py b/api/src/repositories/statements.py index 4e3ef9e..c294bab 100644 --- a/api/src/repositories/statements.py +++ b/api/src/repositories/statements.py @@ -59,7 +59,8 @@ __all__ = [ "value_flags", ] -# строк на один INSERT: у строки формы 15 колонок, у значения 10; 15 × 1000 < 32767 параметров asyncpg +# строк на один INSERT: у строки формы 15 колонок, у значения 10, у `document_issue` 16; 16 × 1000 < 32767 параметров +# asyncpg BATCH = 1000 @@ -151,34 +152,30 @@ async def insert_statement( async def add_issues( session: AsyncSession, document_id: uuid.UUID, drafts: Sequence[IssueDraft], *, now: datetime.datetime ) -> None: - """Записи `document_issue` документа из черновиков (без commit).""" - if not drafts: - return - await session.execute( - insert(DocumentIssue).values( - [ - { - "id": uuid.uuid4(), - "document_id": document_id, - "kind": draft.kind, - "code": draft.code, - "severity": draft.severity, - "message": draft.message, - "line_ids": [str(line_id) for line_id in draft.line_ids] or None, - "column_id": draft.column_id, - "column_index": draft.column_index, - "codes": list(draft.codes) or None, - "field": draft.field, - "source": draft.source, - "relation": draft.relation, - "expected": draft.expected, - "actual": draft.actual, - "created_at": now, - } - for draft in drafts - ] - ) - ) + """Записи `document_issue` документа из черновиков пакетами по `BATCH` (без commit).""" + issues = [ + { + "id": uuid.uuid4(), + "document_id": document_id, + "kind": draft.kind, + "code": draft.code, + "severity": draft.severity, + "message": draft.message, + "line_ids": [str(line_id) for line_id in draft.line_ids] or None, + "column_id": draft.column_id, + "column_index": draft.column_index, + "codes": list(draft.codes) or None, + "field": draft.field, + "source": draft.source, + "relation": draft.relation, + "expected": draft.expected, + "actual": draft.actual, + "created_at": now, + } + for draft in drafts + ] + for start in range(0, len(issues), BATCH): + await session.execute(insert(DocumentIssue).values(issues[start : start + BATCH])) async def delete_issues( # noqa: PLR0913 - фильтры записей независимы diff --git a/api/tests/test_mapping_statements_v2.py b/api/tests/test_mapping_statements_v2.py index c331325..8ffc246 100644 --- a/api/tests/test_mapping_statements_v2.py +++ b/api/tests/test_mapping_statements_v2.py @@ -527,3 +527,23 @@ async def test_osv_v2_sheet_needs_check_blocks_recognized(seeded: AsyncSession) osv["status"] = "needs_check" (document,) = await _map(seeded, entity, [osv]) assert document.status is DocumentStatus.NEEDS_CHECK + + +async def test_osv_v2_many_sheet_warnings_stored(seeded: AsyncSession) -> None: + """AURORA-1711: предупреждений листа больше, чем помещается в один INSERT `document_issue` (16 параметров на + запись, лимит asyncpg 32 767 — ≈ 2 047 записей). Так было на «11.xlsx» (сч. 11, 2 128 строк «Кол. доп.»): + документ создаётся, все предупреждения сохранены.""" + entity = await _entity(seeded) + osv = _osv_doc() + count = 2131 + osv["warnings"] = [ + { + "code": "OSV_ROWS", + "severity": "info", + "message": f"строка {row}: метка «Кол. доп.» в колонке «Показатели» не распознана", + } + for row in range(count) + ] + (document,) = await _map(seeded, entity, [osv]) + assert document.document_type is DocumentType.OSV + assert len(await _issues(seeded, document)) == count -- 2.47.2