( options: ValidateBatchRowsOptions )
| 99 | * Uses optimized database queries for unique constraint checks to avoid loading all rows into memory. |
| 100 | */ |
| 101 | export async function validateBatchRows( |
| 102 | options: ValidateBatchRowsOptions |
| 103 | ): Promise<ValidationSuccess | ValidationFailure> { |
| 104 | const { rows, schema, tableId, checkUnique = true } = options |
| 105 | const errors: BatchRowError[] = [] |
| 106 | |
| 107 | for (let i = 0; i < rows.length; i++) { |
| 108 | const rowData = rows[i] |
| 109 | |
| 110 | const sizeValidation = validateRowSize(rowData) |
| 111 | if (!sizeValidation.valid) { |
| 112 | errors.push({ row: i, errors: sizeValidation.errors }) |
| 113 | continue |
| 114 | } |
| 115 | |
| 116 | const schemaValidation = coerceRowToSchema(rowData, schema) |
| 117 | if (!schemaValidation.valid) { |
| 118 | errors.push({ row: i, errors: schemaValidation.errors }) |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | if (errors.length > 0) { |
| 123 | return { |
| 124 | valid: false, |
| 125 | response: NextResponse.json( |
| 126 | { error: 'Validation failed for some rows', details: errors }, |
| 127 | { status: 400 } |
| 128 | ), |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | if (checkUnique) { |
| 133 | const uniqueColumns = getUniqueColumns(schema) |
| 134 | if (uniqueColumns.length > 0) { |
| 135 | // Use optimized batch unique constraint check |
| 136 | const uniqueResult = await checkBatchUniqueConstraintsDb(tableId, rows, schema) |
| 137 | |
| 138 | if (!uniqueResult.valid) { |
| 139 | return { |
| 140 | valid: false, |
| 141 | response: NextResponse.json( |
| 142 | { error: 'Unique constraint violations in batch', details: uniqueResult.errors }, |
| 143 | { status: 400 } |
| 144 | ), |
| 145 | } |
| 146 | } |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | return { valid: true } |
| 151 | } |
| 152 | |
| 153 | /** Validates table name format and length. */ |
| 154 | export function validateTableName(name: string): ValidationResult { |
no test coverage detected