MCPcopy Index your code
hub / github.com/simstudioai/sim / upsertRow

Function upsertRow

apps/sim/lib/table/rows/service.ts:508–735  ·  view source on GitHub ↗
(
  data: UpsertRowData,
  table: TableDefinition,
  requestId: string
)

Source from the content-addressed store, hash-verified

506 * @throws Error if no unique columns, ambiguous conflict target, or capacity exceeded
507 */
508export async function upsertRow(
509 data: UpsertRowData,
510 table: TableDefinition,
511 requestId: string
512): Promise<UpsertResult> {
513 const schema = table.schema
514 const uniqueColumns = getUniqueColumns(schema)
515
516 if (uniqueColumns.length === 0) {
517 throw new Error(
518 'Upsert requires at least one unique column in the schema. Please add a unique constraint to a column or use insert instead.'
519 )
520 }
521
522 // Determine the single conflict target column, resolving to its stable
523 // storage id (the row-data key). `conflictTarget` may arrive as an id
524 // (first-party) or a name (legacy/internal) — match either.
525 let targetColumnKey: string
526 if (data.conflictTarget) {
527 const col = uniqueColumns.find(
528 (c) => getColumnId(c) === data.conflictTarget || c.name === data.conflictTarget
529 )
530 if (!col) {
531 throw new Error(
532 `Column "${data.conflictTarget}" is not a unique column. Available unique columns: ${uniqueColumns.map((c) => c.name).join(', ')}`
533 )
534 }
535 targetColumnKey = getColumnId(col)
536 } else if (uniqueColumns.length === 1) {
537 targetColumnKey = getColumnId(uniqueColumns[0])
538 } else {
539 throw new Error(
540 `Table has multiple unique columns (${uniqueColumns.map((c) => c.name).join(', ')}). Specify a conflict column to indicate which one to match on.`
541 )
542 }
543
544 // Validate row data
545 const sizeValidation = validateRowSize(data.data)
546 if (!sizeValidation.valid) {
547 throw new Error(sizeValidation.errors.join(', '))
548 }
549
550 const schemaValidation = coerceRowToSchema(data.data, schema)
551 if (!schemaValidation.valid) {
552 throw new Error(`Schema validation failed: ${schemaValidation.errors.join(', ')}`)
553 }
554
555 // Read the conflict-target value *after* coercion so `matchFilter` branches on
556 // the persisted type (e.g. a coerced `"123"` → `123` matches existing rows).
557 const targetValue = data.data[targetColumnKey]
558 if (targetValue === undefined || targetValue === null) {
559 // Surface the display name, not the internal id — v1 callers pass a name.
560 const targetColumnName =
561 uniqueColumns.find((c) => getColumnId(c) === targetColumnKey)?.name ?? targetColumnKey
562 throw new Error(`Upsert requires a value for the conflict target column "${targetColumnName}"`)
563 }
564
565 // `data->` and `data->>` accept the JSON key as a parameterized text value;

Callers 3

update-row.test.tsFile · 0.90
route.tsFile · 0.90
route.tsFile · 0.90

Calls 15

getUniqueColumnsFunction · 0.90
getColumnIdFunction · 0.90
validateRowSizeFunction · 0.90
coerceRowToSchemaFunction · 0.90
getMaxRowsPerTableFunction · 0.90
setTableTxTimeoutsFunction · 0.90
checkUniqueConstraintsDbFunction · 0.90
acquireRowOrderLockFunction · 0.90
loadExecutionsForRowFunction · 0.90
wouldExceedRowLimitFunction · 0.90
generateIdFunction · 0.90
reserveInsertPositionFunction · 0.90

Tested by

no test coverage detected