putAsync method
Puts the given object in the box (persisting it) asynchronously.
The returned future completes with an ID of the object. If it is a new object (its ID property is 0), a new ID will be assigned to the object argument, after the returned Future completes.
In extreme scenarios (e.g. having hundreds of thousands async operations
per second), this may fail as internal queues fill up if the disk can't
keep up. However, this should not be a concern for typical apps.
The returned future may also complete with an error if the put failed
for another reason, for example a unique constraint violation. In that
case the object
's id field remains unchanged (0 if it was a new object).
See also putQueued which doesn't return a Future but a pre-allocated ID immediately, even though the actual database put operation may fail.
Implementation
Future<int> putAsync(T object, {PutMode mode = PutMode.put}) async =>
// Wrap with [Future.sync] to avoid mixing sync and async errors.
// Note: doesn't seem to decrease performance at all.
// https://dart.dev/guides/libraries/futures-error-handling#potential-problem-accidentally-mixing-synchronous-and-asynchronous-errors
Future.sync(() async {
if (_hasRelations) {
throw UnsupportedError(
'putAsync() is currently not supported on entity '
'${T.toString()} because it has relations.');
}
_async ??= _AsyncBoxHelper(this);
// Note: we can use the shared flatbuffer object, because:
// https://dart.dev/codelabs/async-await#execution-flow-with-async-and-await
// > An async function runs synchronously until the first await keyword.
// > This means that within an async function body, all synchronous code
// > before the first await keyword executes immediately.
_builder.fbb.reset();
var id = _entity.objectToFB(object, _builder.fbb);
final newId = _async!.put(id, _builder, mode);
_builder.resetIfLarge(); // reset before `await`
if (id == 0) {
// Note: if the newId future completes with an error, ID isn't set.
_entity.setId(object, await newId);
}
return newId;
});