docs: sync from backend 2c5e80d — db audit waves 5-6
This commit is contained in:
@@ -66,6 +66,8 @@ updated: 2026-06-06
|
||||
| H12: `updateReferralStats` count/update outside a transaction → serializable row-lock transaction | `885745e` v2.9.20 |
|
||||
| H26: `processReferralReward` independent points + referralStats writes → one idempotent `grantReferralReward` transaction for points, referralStats, and ledger row | `885745e` v2.9.20 |
|
||||
| H24: `verifyAndMarkDeliveryCodeUsed` read-check-then-write race → one conditional `UPDATE ... RETURNING` decides delivery-code consumption, with post-miss read only for failure reason | `f22794a` / `51ca048` v2.9.21 |
|
||||
| H13: `DrizzleChatRepo.create` insert-then-update welcome message → build initial system message, lastMessage, and unread counts in the INSERT payload | `2c5e80d` v2.9.24 |
|
||||
| H25: `updatePoints` + `createPointTransaction` could run outside one transaction → runtime guard requires a transaction-bound repo or explicit tx for both money writes | `2c5e80d` v2.9.24 |
|
||||
|
||||
---
|
||||
|
||||
@@ -609,7 +611,7 @@ The method reads the current row (line 558), performs an atomic CAS UPDATE with
|
||||
|
||||
### 3. findPaymentById issues two separate SELECT queries for buyer and seller instead of a JOIN
|
||||
|
||||
> **Category:** N+1 Query | **File:** `src/db/repositories/drizzle/DrizzleMarketplaceRepo.ts:490-533`
|
||||
> **Category:** N+1 Query | **File:** `src/db/repositories/drizzle/DrizzleMarketplaceRepo.ts:490-533` | **FIXED** `61aa42a` v2.9.20
|
||||
|
||||
`findPaymentById` does SELECT * FROM payments WHERE id = $1, then conditionally fires one SELECT for the buyer and one for the seller. This is 3 sequential queries per call. Since `findAllPayments` calls this once per row, the cost multiplies to 1 + 2N.
|
||||
|
||||
@@ -679,7 +681,7 @@ The method calls `this.findRows({...})` (full table scan), deserialises every ch
|
||||
|
||||
### 10. ChatService.addParticipant fires N individual userRepo.findById queries for participant validation
|
||||
|
||||
> **Category:** N+1 Query | **File:** `src/services/chat/ChatService.ts:782-788`
|
||||
> **Category:** N+1 Query | **File:** `src/services/chat/ChatService.ts:782-788` | **FIXED**
|
||||
|
||||
`Promise.all(participantIds.map((id) => userRepo.findById(id)))` fires one SELECT per participant concurrently. While Promise.all avoids sequential waits, it still sends N separate queries to the database, opening N statements from the pool.
|
||||
|
||||
@@ -689,7 +691,7 @@ The method calls `this.findRows({...})` (full table scan), deserialises every ch
|
||||
|
||||
### 11. resolveUserUuid issues a separate DB round-trip per legacy ObjectId in payment create and filter paths
|
||||
|
||||
> **Category:** N+1 Query | **File:** `src/db/repositories/drizzle/DrizzlePaymentRepo.ts:88-100, 116-129, 786-793`
|
||||
> **Category:** N+1 Query | **File:** `src/db/repositories/drizzle/DrizzlePaymentRepo.ts:88-100, 116-129, 786-793` | **FIXED**
|
||||
|
||||
`resolveUserUuid()` executes one SELECT per legacy ObjectId. `create()` calls it twice (buyer + seller). `normalizeUserFilter` calls it sequentially for buyerId then sellerId. No batching or caching: creating multiple payments in a loop issues at least two extra round-trips per iteration.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user