Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix nullable QueryMap fails to compile #344

Merged
merged 5 commits into from
Jul 14, 2022

Conversation

techouse
Copy link
Collaborator

@techouse techouse commented Jul 10, 2022

This addresses #343

I've used Expression.ifNullThen to additionally check for a nullable QueryMap.

This should be able to take

@Get(path: 'query_map')
Future<Response> getQueryMapTest4({
  @Query('name') String name = '',
  @Query('number') int? number,
  @QueryMap() Map<String, dynamic>? filters, // <-- nullable / optional filters
});

and generate

@override
Future<Response<dynamic>> getQueryMapTest4(
    {String name = '', int? number, Map<String, dynamic>? filters}) {
  final $url = '/test/query_map';
  final $params = <String, dynamic>{'name': name, 'number': number};
  $params.addAll(filters ?? {}); // <-- because Map.addAll expects a non-nullable Map
  final $request = Request('GET', $url, client.baseUrl, parameters: $params);
  return client.send<dynamic, dynamic>($request);
}

without any subsequent compilation errors.

Before this hotfix one had to use a default const {} like this in order to omit the QueryMap and avoid a compilation error

@Get(path: 'query_map')
Future<Response> getQueryMapTest3({
  @Query('name') String name = '',
  @Query('number') int? number,
  @QueryMap() Map<String, dynamic> filters = const {}, // <-- default
});

which would generate

@override
Future<Response<dynamic>> getQueryMapTest3(
    {String name = '',
    int? number,
    Map<String, dynamic> filters = const {}}) { // <-- default
  final $url = '/test/query_map';
  final $params = <String, dynamic>{'name': name, 'number': number};
  $params.addAll(filters);
  final $request = Request('GET', $url, client.baseUrl, parameters: $params);
  return client.send<dynamic, dynamic>($request);
}

However, this fix will also add a null check ?? when the value is not nullable and that's why I've added the extra ignore flag dead_null_aware_expression in order to silence the linter in a case like this

@Get(path: 'query_map')
Future<Response> getQueryMapTest2(
  @QueryMap() Map<String, dynamic> query, {
  @Query('test') bool? test,
});

which generates

@override
Future<Response<dynamic>> getQueryMapTest2(Map<String, dynamic> query,
    {bool? test}) {
  final $url = '/test/query_map';
  final $params = <String, dynamic>{'test': test};
  $params.addAll(query ?? {}); // <-- dead_null_aware_expression because `query` is not nullable
  final $request = Request('GET', $url, client.baseUrl, parameters: $params);
  return client.send<dynamic, dynamic>($request);
}

As such, this should be regarded more or less as a hotfix as some more robust null checking should be performed on the QueryMap itself. At this point, I lack the expertise to do this with source_gen and would appreciate any further guidance 😊

EDIT: This issue has now been rectified. See #344 (comment)

Oh, and of course, I've added a few test cases. ☑️

@JEuler
Copy link
Collaborator

JEuler commented Jul 10, 2022

Thank you sooooooo much!

@JEuler
Copy link
Collaborator

JEuler commented Jul 10, 2022

Please reformat code :)

@techouse
Copy link
Collaborator Author

Please reformat code :)

Done. My bad :)

@techouse
Copy link
Collaborator Author

techouse commented Jul 11, 2022

I just found out how to do a more precise null check on the parameters.

In essence, I built an Iterable of all the positional optional and named parameters like

// Build an iterable of all the parameters that are nullable
final Iterable<String> optionalNullableParameters = [
  ...m.parameters.where((p) => p.isOptionalPositional),
  ...m.parameters.where((p) => p.isNamed),
].where((el) => el.type.isNullable).map((el) => el.name);

which in the case of building a QueryMap I can simply check

if (optionalNullableParameters.contains(queryMap.keys.first)) {
  // do nullable stuff
} else {
  // do non nullable stuff
}

This way I can remove dead_null_aware_expression as this update to the fix will prevent it from happening.

This means that

@Get(path: 'query_map')
Future<Response> getQueryMapTest2(
  @QueryMap() Map<String, dynamic> query, {
  @Query('test') bool? test,
});

will correctly produce

@override
Future<Response<dynamic>> getQueryMapTest2(Map<String, dynamic> query,
    {bool? test}) {
  final $url = '/test/query_map';
  final $params = <String, dynamic>{'test': test};
  $params.addAll(query);
  final $request = Request('GET', $url, client.baseUrl, parameters: $params);
  return client.send<dynamic, dynamic>($request);
}

and

@Get(path: 'query_map')
Future<Response> getQueryMapTest4({
  @Query('name') String name = '',
  @Query('number') int? number,
  @QueryMap() Map<String, dynamic>? filters, // <-- nullable / optional filters
});

will correctly produce

@override
Future<Response<dynamic>> getQueryMapTest4(
    {String name = '', int? number, Map<String, dynamic>? filters}) {
  final $url = '/test/query_map';
  final $params = <String, dynamic>{'name': name, 'number': number};
  $params.addAll(filters ?? {});
  final $request = Request('GET', $url, client.baseUrl, parameters: $params);
  return client.send<dynamic, dynamic>($request);
}

@techouse techouse changed the title Hotfix nullable QueryMap fails to compile Fix nullable QueryMap fails to compile Jul 11, 2022
@techouse techouse requested a review from JEuler July 13, 2022 14:16
@JEuler JEuler merged commit e167ba6 into lejard-h:develop Jul 14, 2022
@techouse techouse deleted the fix-nullable-querymap branch July 14, 2022 22:01
JEuler added a commit that referenced this pull request Oct 15, 2022
* Fix Header Option Casting (#260)

Co-authored-by: Ivan Terekhin <i.terhin@gmail.com>

* Fix for #259 (#263)

* 4.0.1 fixes (#264)

* analyzer dependency upgraded (#296)

* fix(generator): fix PartValueFile value not nullable if arg is (#288) (#293)

* Chopper generator release 4.0.2 (#297)

* fix: fix this.body cast of null value when response body is null (#291) (#292)

* Interpolation fixes (#275)

* encodeQueryComponent now encodeComponent (#278)

* Prevent double call on token refreshment (#276)

* Fixes for #309 #308 (#310)

* Remove new keyword from interceptors.md (#312)

* Analyzer upgrade (#320)

Co-authored-by: István Juhos <stewemetal@gmail.com>

* Add unnecessary_brace_in_string_interps to lint ignores (#317)

* Extend pragma to quiet the linter (#318)

Co-authored-by: Ivan Terekhin <i.terhin@gmail.com>

* Fix converter getting called twice if using an authenticator with a JsonConverter on the request (#324)

* migrate example to nullsafety (#331)

* Resolve problem in main_json_serializable example (#328)

* Add @FiledMap @PartMap @PartFileMap (#335)

Co-authored-by: Meysam Karimi <mysmartapply.it4@gmail.com>

* Upgrade of analyzer (#340)

* Fix nullable QueryMap fails to compile (#344)

* Change return type of decodeJson to FutureOr in order to be able to support compute() (#345)

* Migrate from pedantic to lints ^2.0.0 with lints/recommended.yaml (#349)

* Version bumped for release (#352)

* Revert analyzer to ^4.1.0 and silence linters for Element.enclosingElement (#354)

* [chopper_generator] Update analyzer to ^4.4.0 and code_builde to ^4.3.0 and migrate deprecated code (#358)

* Add Makefiles to streamline development (#357)

* Add Bug Report Github issue template (#359)

* [chopper_generator] Add types to the generated variables (#360)

* Provide an example using an Isolate Worker Pool with Squadron (#361)

* mapToQuery changes (#364)

* Version bumped / changelog update (#367)

* Request extends http.BaseRequest (#370)

* Exclude null query vars by default and add new @method annotation includeNullQueryVars (#372)

* 5.1.0 (dev) (#373)

Co-authored-by: Ivan Terekhin <231950+JEuler@users.noreply.github.com>

Co-authored-by: Youssef Raafat <youssefraafatnasry@gmail.com>
Co-authored-by: luis901101 <luis901101@gmail.com>
Co-authored-by: melvspace <ratealt@gmail.com>
Co-authored-by: Michal Šrůtek <35694712+michalsrutek@users.noreply.github.com>
Co-authored-by: István Juhos <stewemetal@gmail.com>
Co-authored-by: Andre <andre.lipke@gmail.com>
Co-authored-by: John Wimer <john@wimer.org>
Co-authored-by: Max Röhrl <max.roehrl11@gmail.com>
Co-authored-by: ipcjs <gipcjs@gmail.com>
Co-authored-by: ibadin <exbatek@gmail.com>
Co-authored-by: Meysam Karimi <31154534+meysam1717@users.noreply.github.com>
Co-authored-by: Meysam Karimi <mysmartapply.it4@gmail.com>
Co-authored-by: Klemen Tusar <techouse@gmail.com>
Co-authored-by: Klemen Tusar <k.tusar@cmcmarkets.com>
Co-authored-by: Ivan Terekhin <231950+JEuler@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants