ark_data_layer 0.1.0-dev.1
ark_data_layer: ^0.1.0-dev.1 copied to clipboard
Pure Dart foundations for repositories, data sources, and observable business data.
example/ark_data_layer_example.dart
import 'dart:async';
import 'package:ark_data_layer/ark_data_layer.dart';
Future<void> main() async {
final InMemoryUserDataSource source = InMemoryUserDataSource(<UserDto>[
const UserDto(id: 'ada', displayName: 'Ada'),
const UserDto(id: 'linus', displayName: 'Linus'),
]);
final UserRepositoryImpl repository = UserRepositoryImpl(
dataSources: DataSourceContainer(<DataSource>[source]),
);
final List<UsersData> observed = <UsersData>[];
final StreamSubscription<UsersData> subscription = repository.stream.listen(
observed.add,
);
await repository.refresh();
await Future<void>.delayed(Duration.zero);
if (observed.length != 2 || observed.last.users.length != 2) {
throw StateError('Expected initial and refreshed repository data.');
}
await subscription.cancel();
await repository.close();
if (source.isClosed) {
throw StateError('Repository must not close a scope-owned DataSource.');
}
await source.close();
}
abstract interface class UserRepository {
UsersData get data;
Stream<UsersData> get stream;
Future<void> refresh();
}
abstract interface class UserRemoteDataSource implements DataSource {
Future<List<UserDto>> fetchUsers();
Future<void> close();
}
final class UserRepositoryImpl extends Repository<UsersData>
implements UserRepository {
UserRepositoryImpl({required super.dataSources})
: _remote = dataSources.get<UserRemoteDataSource>(),
super(initialData: const UsersData.empty());
final UserRemoteDataSource _remote;
@override
Future<void> refresh() async {
final List<UserDto> records = await _remote.fetchUsers();
setData(
UsersData(<User>[
for (final UserDto record in records)
User(id: record.id, displayName: record.displayName),
]),
);
}
}
final class InMemoryUserDataSource implements UserRemoteDataSource {
InMemoryUserDataSource(final Iterable<UserDto> records)
: _records = List<UserDto>.unmodifiable(records);
final List<UserDto> _records;
bool isClosed = false;
@override
Future<List<UserDto>> fetchUsers() async {
if (isClosed) {
throw StateError('DataSource is closed.');
}
return _records;
}
@override
Future<void> close() async {
isClosed = true;
}
}
final class UserDto {
const UserDto({required this.id, required this.displayName});
final String id;
final String displayName;
}
final class User {
const User({required this.id, required this.displayName});
final String id;
final String displayName;
}
final class UsersData {
const UsersData.empty() : users = const <User>[];
UsersData(final Iterable<User> users)
: users = List<User>.unmodifiable(users);
final List<User> users;
}