diff --git a/lib/query.dart b/lib/query.dart index 5b2f4c8..9fa7b08 100644 --- a/lib/query.dart +++ b/lib/query.dart @@ -1,6 +1,7 @@ library query; export 'package:json_api/src/query/fields.dart'; +export 'package:json_api/src/query/filter.dart'; export 'package:json_api/src/query/include.dart'; export 'package:json_api/src/query/page.dart'; export 'package:json_api/src/query/query_parameters.dart'; diff --git a/lib/src/query/filter.dart b/lib/src/query/filter.dart new file mode 100644 index 0000000..105a6fe --- /dev/null +++ b/lib/src/query/filter.dart @@ -0,0 +1,30 @@ +import 'package:json_api/src/query/query_parameters.dart'; + +/// Query parameters defining Filter +/// @see https://jsonapi.org/recommendations/#filtering +class Filter extends QueryParameters { + /// The [filter] argument maps the resource type to a list of filters. + /// + /// Example: + /// ```dart + /// Filter({'articles': ['title', 'body'], 'people': ['name']}).addTo(url); + /// ``` + /// encodes to + /// ``` + /// ?filter[articles]=title,body&filter[people]=name + /// ``` + Filter(Map> filter) + : _filter = {...filter}, + super(filter.map((k, v) => MapEntry('filter[$k]', v.join(',')))); + + /// Extracts the requested filter from the [uri]. + static Filter fromUri(Uri uri) => Filter(uri.queryParameters + .map((k, v) => MapEntry(_regex.firstMatch(k)?.group(1), v.split(','))) + ..removeWhere((k, v) => k == null)); + + List operator [](String key) => _filter[key]; + + static final _regex = RegExp(r'^filter\[(.+)\]$'); + + final Map> _filter; +} diff --git a/test/unit/query/filter_test.dart b/test/unit/query/filter_test.dart new file mode 100644 index 0000000..3661dd0 --- /dev/null +++ b/test/unit/query/filter_test.dart @@ -0,0 +1,23 @@ +import 'package:json_api/src/query/filter.dart'; +import 'package:test/test.dart'; + +void main() { + test('Can decode url', () { + final uri = Uri.parse( + '/articles?include=author&filter%5Barticles%5D=title%2Cbody&filter%5Bpeople%5D=name'); + final filter = Filter.fromUri(uri); + expect(filter['articles'], ['title', 'body']); + expect(filter['people'], ['name']); + }); + + test('Can add to uri', () { + final filter = Filter({ + 'articles': ['title', 'body'], + 'people': ['name'] + }); + final uri = Uri.parse('/articles'); + + expect(filter.addToUri(uri).toString(), + '/articles?filter%5Barticles%5D=title%2Cbody&filter%5Bpeople%5D=name'); + }); +}