getOrCreate method
Future<TRow>
getOrCreate({
- required MssqlUniqueMatch key,
- required MssqlWriteAssignments create,
- bool restoreExisting = false,
- bool includeDeleted = false,
Inserts create, or returns the row already owning key.
Only conflicts from MssqlUniqueMatch.indexName are recovered. Deleted
matches follow restoreExisting and includeDeleted.
Implementation
Future<TRow> getOrCreate({
required MssqlUniqueMatch key,
required MssqlWriteAssignments create,
bool restoreExisting = false,
bool includeDeleted = false,
}) async {
_checkDecimalAgreement();
var values = create;
for (final entry in key.values.entries) {
final column = binding.column(entry.key);
if (column == null) {
throw ArgumentError.value(
entry.key,
'key',
'${binding.qualifiedName} has no column "${entry.key}".',
);
}
final bound = MssqlBoundValue(column.bind(entry.value));
final existing = values[entry.key];
if (existing is MssqlBoundValue &&
existing.value.value != bound.value.value) {
throw ArgumentError.value(
entry.value,
'create',
'getOrCreate unique "${key.indexName}" is ${entry.key}='
'${entry.value}, but create sets it to ${existing.value.value}.',
);
}
values = values.withValue(column.name, bound);
}
try {
return await _insertAssignments(values, key);
} on MssqlException catch (error) {
if (!duplicateKeyIs(error, key.indexName)) rethrow;
if (sessionIsDoomed(session)) {
throw MssqlUniqueConflictException(
table: binding.qualifiedName,
indexName: key.indexName,
reason:
'the insert collided and the transaction is doomed, so the '
'winning row cannot be read back. Roll it back and retry.',
);
}
return _readUniqueWinner(
key,
restoreExisting: restoreExisting,
includeDeleted: includeDeleted,
);
}
}