(table, v)
| 175 | await this.create(table, v.create); |
| 176 | }, |
| 177 | async upsertMany(table, v) { |
| 178 | if (v.target.length === 0) { |
| 179 | // oxlint-disable-next-line executor/no-try-catch-or-throw, executor/no-error-constructor -- boundary: adapter rejects invalid upsert shape |
| 180 | throw new Error("[FumaDB] upsertMany requires at least one target column."); |
| 181 | } |
| 182 | if (v.update.length === 0) { |
| 183 | // oxlint-disable-next-line executor/no-try-catch-or-throw, executor/no-error-constructor -- boundary: adapter rejects invalid upsert shape |
| 184 | throw new Error("[FumaDB] upsertMany requires at least one update column."); |
| 185 | } |
| 186 | for (const value of v.values) { |
| 187 | // Mirror SQL `ON CONFLICT ... DO UPDATE ... WHERE`: the unique |
| 188 | // target alone detects the conflict, and the predicate only |
| 189 | // decides whether the conflicting row may be updated. A |
| 190 | // policy-excluded conflict skips the row; it never inserts a |
| 191 | // duplicate of the unique target. |
| 192 | const conflicting = tableRows(db, table).find((row) => |
| 193 | v.target.every((column) => row[column.ormName] === value[column.ormName]), |
| 194 | ); |
| 195 | if (conflicting) { |
| 196 | if (!matchesCondition(conflicting, v.where)) continue; |
| 197 | Object.assign( |
| 198 | conflicting, |
| 199 | cloneValue( |
| 200 | Object.fromEntries( |
| 201 | v.update.map((column) => [column.ormName, value[column.ormName]]), |
| 202 | ), |
| 203 | ), |
| 204 | ); |
| 205 | continue; |
| 206 | } |
| 207 | await this.create(table, value); |
| 208 | } |
| 209 | }, |
| 210 | async create(table, values) { |
| 211 | const row = applyDefaults(table, values); |
| 212 | tableRows(db, table).push(row); |
nothing calls this directly
no test coverage detected