atomicWrite method

  1. @override
Future<List<SqlWriteResult>> atomicWrite(
  1. List<BoundSql> statements
)
override

Executes transaction-safe DML statements as one atomic write batch.

Every statement must declare SqlStatementKind.write. An empty batch is valid and returns an empty result without starting a transaction.

Results preserve input order. Either every statement commits or none do. Transaction control, DDL that implicitly commits, and row-returning statements are outside this contract.

Implementation

@override
Future<List<SqlWriteResult>> atomicWrite(List<BoundSql> statements) async {
  final copiedStatements = List<BoundSql>.unmodifiable(statements);
  _ensureOpen();
  _requireAtomicWrites(copiedStatements);
  if (copiedStatements.isEmpty) return const <SqlWriteResult>[];

  final JSArray<_D1PreparedStatement> prepared;
  try {
    prepared = <_D1PreparedStatement>[
      for (final statement in copiedStatements) _prepare(statement),
    ].toJS;
  } on Object catch (error) {
    _throwD1(error);
  }

  final JSAny? results;
  try {
    results = await _database.batch(prepared).toDart;
  } on Object catch (error) {
    _throwD1(error);
  }

  if (results == null || !results.isA<JSArray<JSAny?>>()) {
    throw const SqlException(
      SqlErrorCode.invalidRow,
      'D1 returned an invalid batch result.',
    );
  }
  final values = (results as JSArray<JSAny?>).toDart;
  if (values.length != copiedStatements.length) {
    throw const SqlException(
      SqlErrorCode.invalidRow,
      'D1 returned the wrong number of batch results.',
    );
  }
  return <SqlWriteResult>[
    for (final result in values) _readWriteResult(result),
  ];
}