upsertRow method

Future<MssqlWriteOutcome> upsertRow({
  1. required MssqlWriteAssignments matching,
  2. required MssqlWriteAssignments insertValues,
  3. required MssqlWriteAssignments updateValues,
  4. bool readRow = true,
})

Updates the row matching identifies or inserts it, then reads it back.

The readback is a keyed SELECT rather than an OUTPUT clause: the upsert is a multi-statement batch whose branches are chosen at run time, so an OUTPUT on one of them says nothing about whether the other ran. matching is a unique key by definition — that is what makes it an upsert — so selecting by it names the same one row either way.

Implementation

Future<MssqlWriteOutcome> upsertRow({
  required MssqlWriteAssignments matching,
  required MssqlWriteAssignments insertValues,
  required MssqlWriteAssignments updateValues,
  bool readRow = true,
}) async {
  final statement = MssqlUpsert.intoParts(
    binding.nameParts,
    matching: matching.toOperands(),
    insertValues: insertValues.toOperands(),
    updateValues: updateValues.toOperands(),
  ).compile(dialect: dialect);
  if (!readRow) {
    await session.execute(statement.sql, parameters: statement.parameters);
    _note();
    return const MssqlWriteOutcome(
      affectedRows: 1,
      affectedRowsSource: MssqlAffectedRowsSource.singleRowStatement,
    );
  }
  var read = MssqlQuery.fromParts(binding.nameParts, ref: binding.sourceRef)
      .select(
        _readableColumns.map<MssqlExpression>((c) => Col(c.name)).toList(),
      );
  for (final entry in matching.entries) {
    final assigned = entry.value;
    read = read.where(
      assigned is MssqlBoundValue && assigned.value.value == null
          ? Col(entry.key).isNull()
          : Col(entry.key).eq(_matchOperand(assigned)),
    );
  }
  final select = _rebased(read.compile(dialect: dialect));
  final rows = await session.queryTypedRows(
    '${statement.sql} ${select.sql}',
    parameters: <String, Object?>{
      ...statement.parameters,
      ...select.parameters,
    },
  );
  _note();
  return MssqlWriteOutcome(
    affectedRows: 1,
    affectedRowsSource: MssqlAffectedRowsSource.singleRowStatement,
    rows: rows,
  );
}