update method
Immediate atomic UPDATE; skip/take/order/rank windows are rejected.
Implementation
Future<OrmWriteResult> update(Map<Column<T, dynamic>, Object?> values,
{List<Column<T, dynamic>> returning = const []}) {
try {
final owner = _directOwner(this);
_writeType(type);
if (_offset != 0 ||
_limit != null ||
_ordering.isNotEmpty ||
_rank ||
_distance) {
throw const OrmStateException(
'Direct UPDATE cannot combine with ordering, skip/take, rank or distance');
}
if (values.isEmpty) {
throw const OrmMappingException(
'UPDATE requires at least one assignment');
}
_writeColumns(type, values.keys);
final selected = _projection(type, returning);
final parameters = <Object?>[];
final assignments = <String>[];
final changed = <Column<T, dynamic>>[];
for (final assignment in values.entries) {
final column = assignment.key;
if (column.keyOrder != null || column.generated || column.version) {
throw const OrmMappingException(
'Keys, generated fields and versions are managed by ORM');
}
final value = assignment.value;
String expression;
if (value is _ArithmeticAssignment<T, dynamic>) {
if (!['INTEGER', 'REAL'].contains(column.codec.sqlType)) {
throw const OrmMappingException(
'Arithmetic assignment requires a numeric target');
}
_writeColumns(type, value._columns);
expression = value._sql(parameters);
} else {
if (value is SqlExpression) {
throw const OrmMappingException(
'Only constants and add/subtract assignments are supported');
}
parameters.add(copyOrmValue(column.encodeValue(value)));
expression = '?';
}
assignments.add('${quoteIdentifier(column.sqlName)}=$expression');
changed.add(column);
}
final version = type.versionColumn;
if (version != null) {
assignments.add(
'${quoteIdentifier(version.sqlName)}=${quoteIdentifier(version.sqlName)}+1');
changed.add(version);
}
final predicate = _predicate?._sql(parameters);
final sql =
'UPDATE ${quoteIdentifier(type.tableName)} SET ${assignments.join(',')}${predicate == null ? '' : ' WHERE $predicate'}';
final bound = List<Object?>.unmodifiable(parameters.map(copyOrmValue));
return owner._directWrite(() async {
final broad = (await owner._triggerTables())
.contains(type.tableName.toLowerCase()) ||
owner.model.foreignKeys.isNotEmpty;
final projected = <Column<T, dynamic>>{
...changed,
...selected,
if (broad) ...type.keys
}.toList();
final mutation = await owner.connection.execute(
'$sql RETURNING ${projected.map((c) => quoteIdentifier(c.sqlName)).join(',')}',
bound);
final rows = await owner._writeRows(type, mutation, projected, selected,
broad: broad);
return OrmWriteResult._(mutation.changes, rows);
});
} catch (error, stack) {
return Future.error(error, stack);
}
}