(
table: TableDefinition,
additions: { id?: string; name: string; type: string; required?: boolean; unique?: boolean }[],
data: { rows: RowData[]; workspaceId: string; userId?: string },
requestId: string
)
| 193 | * replaces all rows — atomically. Keeps `trx` out of the API route. |
| 194 | */ |
| 195 | export async function importReplaceRows( |
| 196 | table: TableDefinition, |
| 197 | additions: { id?: string; name: string; type: string; required?: boolean; unique?: boolean }[], |
| 198 | data: { rows: RowData[]; workspaceId: string; userId?: string }, |
| 199 | requestId: string |
| 200 | ): Promise<ReplaceRowsResult> { |
| 201 | // Replace deletes all existing rows, so the footprint is just the new set. Gate |
| 202 | // before opening the tx — the plan lookup is a separate pool read. |
| 203 | const rowLimit = await assertRowCapacity({ |
| 204 | workspaceId: data.workspaceId, |
| 205 | currentRowCount: 0, |
| 206 | addedRows: data.rows.length, |
| 207 | }) |
| 208 | const result = await db.transaction(async (trx) => { |
| 209 | let working = table |
| 210 | if (additions.length > 0) { |
| 211 | await acquireRowOrderLock(trx, table.id) |
| 212 | working = await addTableColumnsWithTx(trx, table, additions, requestId) |
| 213 | } |
| 214 | return replaceTableRowsWithTx( |
| 215 | trx, |
| 216 | { tableId: working.id, rows: data.rows, workspaceId: data.workspaceId, userId: data.userId }, |
| 217 | working, |
| 218 | requestId |
| 219 | ) |
| 220 | }) |
| 221 | notifyTableRowUsage({ |
| 222 | workspaceId: data.workspaceId, |
| 223 | currentRowCount: 0, |
| 224 | addedRows: result.insertedCount, |
| 225 | limit: rowLimit, |
| 226 | }) |
| 227 | return result |
| 228 | } |
no test coverage detected