From 5ff2aaa02334db38a38057c3de05fa6ad7e786af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F=D1=81=20=D0=A1=D1=83=D0=BB=D1=82?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Thu, 6 Aug 2026 15:10:38 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20RAG=20embedding=5Fqueue=20ON=20CONFLICT?= =?UTF-8?q?=20+=20=D0=BF=D0=B5=D1=80=D0=B5=D1=81=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20finance=20views?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - enqueueEmbedding: onConflictDoNothing без предиката не находил частичный уникальный индекс embedding_queue_pending_entity_idx (WHERE processed_at IS NULL) — каждая постановка в очередь индексации падала. Добавлен where: isNull(processedAt). - finance ensureViews: CREATE OR REPLACE VIEW не умеет менять тип столбца (stavkands text↔varchar во внешней БД omegaprom) — заменено на DROP VIEW IF EXISTS + CREATE VIEW (зависимых объектов нет). --- server/finance/views.ts | 8 ++++++-- server/storage/system.storage.ts | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/server/finance/views.ts b/server/finance/views.ts index e2c31df..171c482 100644 --- a/server/finance/views.ts +++ b/server/finance/views.ts @@ -67,8 +67,11 @@ export async function ensureViews(): Promise { } if (incomeExists) { + // CREATE OR REPLACE VIEW не умеет менять типы столбцов (тип stavkands в источнике + // изменился text ↔ varchar) — пересоздаём view целиком. Зависимых объектов нет. + await query(`DROP VIEW IF EXISTS vw_income_effective`); await query(` - CREATE OR REPLACE VIEW vw_income_effective AS + CREATE VIEW vw_income_effective AS SELECT t.*, o.category_id as _override_category_id FROM "${config.incomeTable}" t LEFT JOIN income_category_overrides o ON o.record_id = t.id::text @@ -76,8 +79,9 @@ export async function ensureViews(): Promise { } if (expenseExists) { + await query(`DROP VIEW IF EXISTS vw_expense_effective`); await query(` - CREATE OR REPLACE VIEW vw_expense_effective AS + CREATE VIEW vw_expense_effective AS SELECT t.*, o.category_id as _override_category_id FROM "${config.expenseTable}" t LEFT JOIN expense_category_overrides o ON o.record_id = t.id::text diff --git a/server/storage/system.storage.ts b/server/storage/system.storage.ts index fba223b..a7dee02 100644 --- a/server/storage/system.storage.ts +++ b/server/storage/system.storage.ts @@ -489,7 +489,13 @@ export class SystemStorage extends RolesStorage { operation, createdAt: new Date(), }) - .onConflictDoNothing({ target: [embeddingQueue.organizationId, embeddingQueue.entityType, embeddingQueue.entityId] }); + .onConflictDoNothing({ + target: [embeddingQueue.organizationId, embeddingQueue.entityType, embeddingQueue.entityId], + // Уникальный индекс embedding_queue_pending_entity_idx частичный + // (WHERE processed_at IS NULL) — без этого предиката Postgres не находит + // подходящий constraint и весь INSERT падает с ошибкой. + where: isNull(embeddingQueue.processedAt), + }); } async getPendingEmbeddingQueue(