Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions packages/value_state/lib/src/extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,39 @@ import 'perform.dart';
import 'states.dart';

extension ObjectWithValueExtensions<T> on BaseState<T> {
/// Destructuring pattern-matching
///
/// Example :
/// ```dart
/// const String? nullStr = null;
/// final result = nullStr.toState().when(
/// onValue: (state) => 'Value',
/// onError: (error) => 'Error',
/// orElse: () => 'Null value',
/// );
/// ```
R when<R>({
R Function()? onWaiting,
R Function()? onNoValue,
R Function(T value)? onValue,
R Function(Object error)? onError,
required R Function() orElse,
}) {
final state = this;

if (state is WaitingState<T>) {
return onWaiting?.call() ?? orElse();
} else if (state is NoValueState<T>) {
return onNoValue?.call() ?? orElse();
} else if (state is ValueState<T>) {
return onValue?.call(state.value) ?? orElse();
} else if (state is ErrorState<T>) {
return onError?.call(state.error) ?? orElse();
}

return orElse();
}

/// Shortcut on [BaseState] to easily handle [WithValueState] state. It can be used in different case :
/// * To return a value
/// ```dart
Expand All @@ -27,12 +60,10 @@ extension ObjectWithValueExtensions<T> on BaseState<T> {

/// Shorcut to [withValue] with its parameter `onlyValueState` set to `true`. It is equivalent to handle only
/// [ValueState] state.
R? whenValue<R>(R Function(T value) onValue) =>
withValue<R>(onValue, onlyValueState: true);
R? whenValue<R>(R Function(T value) onValue) => withValue<R>(onValue, onlyValueState: true);

/// Shorcut to [withValue] which return the value if avaible. [onlyValueState] is the same as [withValue].
T? toValue({bool onlyValueState = false}) =>
withValue((value) => value, onlyValueState: onlyValueState);
T? toValue({bool onlyValueState = false}) => withValue((value) => value, onlyValueState: onlyValueState);
}

extension OrExtensions<R> on R? {
Expand All @@ -55,9 +86,7 @@ extension ToReadyStateExtensions<T extends Object> on T? {
/// * else it returns a [NoValueState]
ReadyState<T> toState({bool refreshing = false}) {
final state = this;
return state == null
? NoValueState<T>(refreshing: refreshing)
: ValueState<T>(state, refreshing: refreshing);
return state == null ? NoValueState<T>(refreshing: refreshing) : ValueState<T>(state, refreshing: refreshing);
}
}

Expand All @@ -71,6 +100,5 @@ extension FutureValueStateExtension<T> on Future<T?> {
}

/// Generate a stream of [BaseState] during a processing [Future].
Stream<BaseState<T>> toStates() =>
InitState<T>().perform((_) => toFutureState());
Stream<BaseState<T>> toStates() => InitState<T>().perform((_) => toFutureState());
}
79 changes: 52 additions & 27 deletions packages/value_state/test/extensions_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,57 @@ void main() {
const myStr = 'My String';
const myStrOrElse = 'My String orElse';

group('when()', () {
test('on a non null String', () {
final result = myStr.toState().when(
onWaiting: () => 'Waiting',
onNoValue: () => 'No Value',
onValue: (value) => value,
onError: (error) => 'Error',
orElse: () => 'Else',
);

expect(result, 'My String');
});

test('on null', () {
const String? nullStr = null;

final result = nullStr.toState().when(
onWaiting: () => 'Waiting',
onNoValue: () => 'No Value',
onValue: (state) => 'Value',
onError: (error) => 'Error',
orElse: () => 'Else',
);

expect(result, 'No Value');
});

test('orElse', () {
const String? nullStr = null;

final result = nullStr.toState().when(
onValue: (state) => 'Value',
onError: (error) => 'Error',
orElse: () => 'Else',
);

expect(result, 'Else');
});
});

group('toState()', () {
test('on a non null String', () {
expect(myStr.toState(), const ValueState(myStr));
expect(myStr.toState(refreshing: true),
const ValueState(myStr, refreshing: true));
expect(myStr.toState(refreshing: true), const ValueState(myStr, refreshing: true));
});

test('on null', () {
const String? nullStr = null;

expect(nullStr.toState(), const NoValueState<String>());
expect(nullStr.toState(refreshing: true),
const NoValueState<String>(refreshing: true));
expect(nullStr.toState(refreshing: true), const NoValueState<String>(refreshing: true));
});
});

Expand All @@ -42,39 +81,32 @@ void main() {
});

test('on a $InitState with onlyValueState to true', () {
final result =
const InitState<String>().withValue(modifier, onlyValueState: true);
final result = const InitState<String>().withValue(modifier, onlyValueState: true);

expect(result, isNull);
});

test('on a $ErrorState', () {
final result =
ErrorState<String>(error: 'Error', previousState: myStr.toState())
.withValue(modifier);
final result = ErrorState<String>(error: 'Error', previousState: myStr.toState()).withValue(modifier);

expect(result, modifier(myStr));
});

test('on a $ErrorState with onlyValueState to true', () {
final result =
ErrorState<String>(error: 'Error', previousState: myStr.toState())
.withValue(modifier, onlyValueState: true);
ErrorState<String>(error: 'Error', previousState: myStr.toState()).withValue(modifier, onlyValueState: true);

expect(result, isNull);
});

test('orElse on a $ValueState', () {
final result =
myStr.toState().withValue(modifier).orElse(() => myStrOrElse);
final result = myStr.toState().withValue(modifier).orElse(() => myStrOrElse);

expect(result, modifier(myStr));
});

test('orElse on a $InitState', () {
final result = const InitState<String>()
.withValue(modifier)
.orElse(() => myStrOrElse);
final result = const InitState<String>().withValue(modifier).orElse(() => myStrOrElse);

expect(result, myStrOrElse);
});
Expand All @@ -97,9 +129,7 @@ void main() {
});

test('on a $ErrorState', () {
final result =
ErrorState<String>(error: 'Error', previousState: myStr.toState())
.whenValue(modifier);
final result = ErrorState<String>(error: 'Error', previousState: myStr.toState()).whenValue(modifier);

expect(result, isNull);
});
Expand Down Expand Up @@ -131,17 +161,13 @@ void main() {
});

test('on a $ErrorState', () {
final result =
ErrorState<String>(error: 'Error', previousState: myStr.toState())
.toValue();
final result = ErrorState<String>(error: 'Error', previousState: myStr.toState()).toValue();

expect(result, myStr);
});

test('on a $ErrorState with onlyValueState to true', () {
final result =
ErrorState<String>(error: 'Error', previousState: myStr.toState())
.toValue(onlyValueState: true);
final result = ErrorState<String>(error: 'Error', previousState: myStr.toState()).toValue(onlyValueState: true);

expect(result, isNull);
});
Expand All @@ -151,8 +177,7 @@ void main() {
const value = 'Result';

expect(Future.value(value).toFutureState(), completion(value.toState()));
expect(Future<String?>.value(null).toFutureState(),
completion(const NoValueState<String>()));
expect(Future<String?>.value(null).toFutureState(), completion(const NoValueState<String>()));
});

test('toStates', () {
Expand Down