update method

Future<void> update(
  1. Object pkVal,
  2. Map<String, Object?> row
)

Replace an existing row. Throws if the PK doesn't exist. The primary-key value in row must equal pkVal (we don't allow PK rewrites here — do delete + insert if you need that).

Implementation

Future<void> update(Object pkVal, Map<String, Object?> row) async {
  final pkBytes = _encodePrimaryKey(pkVal);
  final rowId = await _index.get(pkBytes);
  if (rowId == null) {
    throw StateError(
        'PagedTable.update: no row with primary key ${jsonEncode(pkVal)}');
  }
  final newPk = row[primaryKey.name];
  if (newPk == null) {
    throw ArgumentError('PagedTable.update: primary-key value is null');
  }
  if (_compareBytes(_encodePrimaryKey(newPk), pkBytes) != 0) {
    throw ArgumentError(
        'PagedTable.update: cannot rewrite primary key (delete + insert instead)');
  }
  // Refresh secondary-index entries: compare the old vs new tuple
  // of indexed-column values; only rewrite indexes whose tuple
  // changed. NULL-containing tuples have no index entry.
  if (_secondary.isNotEmpty) {
    final oldBytes = await _heap.get(rowId);
    if (oldBytes != null) {
      final oldRow = _decodeRow(oldBytes);
      // Uniqueness pre-check before any mutation.
      for (final si in _secondary.values) {
        if (!si.unique) continue;
        final newPrefix = _encodeSecondaryPrefix(si, row);
        if (newPrefix == null) continue;
        final oldPrefix = _encodeSecondaryPrefix(si, oldRow);
        if (oldPrefix != null && _compareBytes(oldPrefix, newPrefix) == 0) {
          continue; // unchanged prefix, no conflict possible
        }
        if (await _uniqueConflict(si, newPrefix, pkBytes)) {
          throw StateError('PagedTable.update: UNIQUE constraint violated on '
              'index ${si.name} (${si.columns.join(", ")})');
        }
      }
      for (final si in _secondary.values) {
        final oldKey = _encodeSecondaryKey(si, oldRow, pkBytes);
        final newKey = _encodeSecondaryKey(si, row, pkBytes);
        if (oldKey == null && newKey == null) continue;
        if (oldKey != null &&
            newKey != null &&
            _compareBytes(oldKey, newKey) == 0) {
          continue;
        }
        if (oldKey != null) await si.btree.remove(oldKey);
        if (newKey != null) await si.btree.put(newKey, rowId);
      }
    }
  }
  final rowBytes = _encodeRow(row);
  await _heap.update(rowId, rowBytes);
}