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
57 changes: 55 additions & 2 deletions packages/go_router/lib/src/route_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -620,11 +620,42 @@ class NoOpPage extends Page<void> {
throw UnsupportedError('Should never be called');
}

/// Signature of custom query parameter encoding.
///
/// The function takes a parameter value of type `T` and returns a string
/// representation suitable for use in a URI. The returned string is escaped to
/// be URL-safe.
///
/// For example, a parameter value of `'field with space'` will generate a query
/// parameter value of `'field+with+space'`.
typedef QueryParameterEncoder<T> = String Function(T value);

/// Signature for custom query parameter decoding functions.
///
/// Converts an encoded string from the URI into a parameter value of type `T`.
///
/// The [value] parameter contains the encoded string from the URI. if the
/// parameter is absent from the URI.
typedef QueryParameterDecoder<T> = T Function(String value);

/// Annotation to override the URI name for a route parameter.
@optionalTypeArgs
@Target({TargetKind.parameter})
class TypedQueryParameter {
class TypedQueryParameter<T> {
/// Annotation to override the URI name for a route parameter.
const TypedQueryParameter({this.name});
const TypedQueryParameter({
this.name,
this.encoder,
this.decoder,
this.compare,
}) : assert(
(encoder == null) == (decoder == null),
'encoder and decoder must both be provided together',
),
assert(
compare == null || encoder != null,
'compare function requires an encoder to be provided',
);

/// The name of the parameter in the URI.
///
Expand All @@ -647,4 +678,26 @@ class TypedQueryParameter {
/// It is escaped to be URL-safe. For example `'field with space'` will
/// generate a query parameter named `'field+with+space'`.
final String? name;

/// A function that converts a parameter value to a string for use in the URI.
///
/// See [QueryParameterEncoder] for details.
final QueryParameterEncoder<T>? encoder;

/// A function that converts a string from the URI to a parameter value.
///
/// See [QueryParameterDecoder] for details.
final QueryParameterDecoder<T>? decoder;

/// A function that determines if two parameter values differ.
///
/// Returns `true` when the values differ and `false` when they match.
///
/// Used to decide whether to include a parameter in the URI when a default
/// value exists. If the parameter equals its default value, it is omitted
/// from the URI; otherwise, it is included.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should mention this must be provided if the T is not primative type and has default value

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

///
/// This should be provided if the parameter has a default value and is is not
/// a primitive type.
final bool Function(T, T)? compare;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
changelog: |
- Adds `encoder`, `decoder` and `compare` parameters to `TypedQueryParameter` annotation for custom encoding, decoding and comparison of query parameters in `TypedGoRoute` constructors.
version: minor
21 changes: 20 additions & 1 deletion packages/go_router/test/route_data_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ final List<GoRoute> _relativeRoutes = <GoRoute>[
),
];

String _coder(String? value) => '';

bool _compare(String a, String b) => true;

void main() {
group('GoRouteData', () {
testWidgets('It should build the page from the overridden build method', (
Expand Down Expand Up @@ -796,8 +800,23 @@ void main() {
});

test('TypedQueryParameter stores the name', () {
const parameter = TypedQueryParameter(name: 'customName');
const TypedQueryParameter<dynamic> parameter = TypedQueryParameter(
name: 'customName',
);

expect(parameter.name, 'customName');
});

test('TypedQueryParameter stores the encoder, decoder and compare', () {
const TypedQueryParameter<String> parameter = TypedQueryParameter(
name: 'customName',
encoder: _coder,
decoder: _coder,
compare: _compare,
);

expect(parameter.encoder, _coder);
expect(parameter.decoder, _coder);
expect(parameter.compare, _compare);
});
}
Loading