Skip to content

Commit

Permalink
Feat: Enable passing in Extras using Custom Annotations (#706)
Browse files Browse the repository at this point in the history
* Implemented TypedExtras

* changed TypedExtra to TypedExtras

* remove publish_to: none

* update TypedExtra to TypedExtras

* reaname _getExtrasFromClass to _getMapFromTypedExtras

* allow nullable properties in TypedExtras

* update docs

* Update docs

* remove pubspec changes

* update dependencies

* update pubspec

* fix retrofit deps

* Update changelogs and version

---------

Co-authored-by: Trevor Wang <[email protected]>
  • Loading branch information
farmery and trevorwang authored Sep 6, 2024
1 parent 8a0d0b5 commit f1409e8
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 8 deletions.
16 changes: 16 additions & 0 deletions generator/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## 9.1.0

- Added `@TypedExtras` to pass extra options to dio requests using custom annotations.

Example :

```dart
@TypedExtrasSubClass(
id: 'abcd',
count: 5,
shouldProceed: true,
)
@http.POST('/path/')
Future<String> myMethod(@Extras() Map<String, dynamic> extras);
```

## 9.0.0

- Require Dart 3.3
Expand Down
44 changes: 43 additions & 1 deletion generator/lib/src/generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2271,6 +2271,46 @@ ${bodyName.displayName} == null
return result;
}

dynamic _getFieldValue(ConstantReader? value) {
if (value?.isBool ?? false) return value?.boolValue;
if (value?.isDouble ?? false) return value?.doubleValue;
if (value?.isInt ?? false) return value?.intValue;
if (value?.isString ?? false) return value?.stringValue;
if (value?.isList ?? false) {
return value?.listValue.map((item) => _getFieldValue(ConstantReader(item))).toList();
}
if (value?.isMap ?? false) {
final mapValue = value?.mapValue.map((key, val) {
return MapEntry(
_getFieldValue(ConstantReader(key)),
_getFieldValue(ConstantReader(val)),
);
});
return mapValue;
}
if (value?.isSet ?? false) {
return value?.setValue.map((item) {
return _getFieldValue(ConstantReader(item));
}).toSet();
}
return null;
}

Map<String, Object> _getMapFromTypedExtras(MethodElement m) {
final annotation = _getMethodAnnotations(m, retrofit.TypedExtras).firstOrNull;
final fields = annotation?.objectValue.type?.element?.children
.whereType<FieldElement>();
Map<String, Object> mapFromTypedExtras = {};
for (var field in fields ?? <FieldElement>[]) {
final value = annotation?.peek(field.name);
final fieldValue = _getFieldValue(value);
if (fieldValue != null) {
mapFromTypedExtras[field.name] = fieldValue;
}
}
return mapFromTypedExtras;
}

void _generateExtra(
MethodElement m,
List<Code> blocks,
Expand Down Expand Up @@ -2306,7 +2346,9 @@ ${bodyName.displayName} == null
),
),
)
.fold<Map<String, Object>>({}, (p, e) => p..addAll(e ?? {})),
.fold<Map<String, Object>>({}, (p, e) {
return p..addAll(e ?? {});
})..addAll(_getMapFromTypedExtras(m)),
refer('String'),
refer('dynamic'),
),
Expand Down
11 changes: 8 additions & 3 deletions generator/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ topics:
- rest
- retrofit
- codegen
version: 9.0.0
version: 9.1.0
environment:
sdk: '>=3.3.0 <4.0.0'

Expand All @@ -19,11 +19,16 @@ dependencies:
code_builder: ^4.4.0
dart_style: ^2.3.0
dio: ^5.0.0
protobuf: ^3.1.0
retrofit: ^4.3.0
source_gen: ^1.5.0
source_gen: ^1.3.0
tuple: ^2.0.1
protobuf: ^3.1.0

dev_dependencies:
lints: ^4.0.0
source_gen_test: ^1.0.6
test: ^1.25.0

dependency_overrides:
retrofit:
path: ../retrofit
70 changes: 67 additions & 3 deletions generator/test/src/generator_test_src.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,75 @@
import 'dart:io';

import 'package:dio/dio.dart' hide Headers;
import 'package:retrofit/retrofit.dart';
import 'package:source_gen_test/annotations.dart';

import 'package:retrofit/retrofit.dart';
import 'query.pb.dart';

class DummyTypedExtras extends TypedExtras {
final String id;
final Map<String, dynamic> config;
final List<String> fileTypes;
final Set<String> sources;
final bool shouldProceed;
final bool? canFly;
const DummyTypedExtras({
required this.id,
required this.config,
required this.fileTypes,
required this.sources,
required this.shouldProceed,
this.canFly,
});
}

@ShouldGenerate(
'''
final _extra = <String, dynamic>{
'id': '1234',
'config': {
'date': '24-10-2024',
'type': 'analytics',
'shouldReplace': true,
'subConfig': {'date': '24-11-2025'},
},
'fileTypes': [
'mp4',
'mp3',
'mkv',
],
'sources': {
'internet',
'local',
},
'shouldProceed': true,
};
''',
contains: true,
)
@RestApi()
abstract class TypedExtrasTest {
@DummyTypedExtras(
id: '1234',
config: {
'date': '24-10-2024',
'type': 'analytics',
'shouldReplace': true,
'subConfig': {'date': '24-11-2025'},
},
fileTypes: [
'mp4',
'mp3',
'mkv',
],
sources: {
'internet',
'local',
},
shouldProceed: true,
)
@GET('path')
Future<void> list();
}

@ShouldGenerate(
'''
// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element
Expand Down
16 changes: 16 additions & 0 deletions retrofit/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## 4.4.0

- Added `@TypedExtras` to pass extra options to dio requests using custom annotations.

Example :

```dart
@TypedExtrasSubClass(
id: 'abcd',
count: 5,
shouldProceed: true,
)
@http.POST('/path/')
Future<String> myMethod(@Extras() Map<String, dynamic> extras);
```

## 4.3.0

- Required Dart 2.19
Expand Down
20 changes: 20 additions & 0 deletions retrofit/lib/dio.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
import 'package:dio/dio.dart';
import 'package:meta/meta.dart';

/// Extra data that will be passed to Dio's request, response, transformer, and interceptors.
/// Extend [TypedExtras] and define fields that correspond to the keys passed into `extras`.
/// The values of these fields will be derived from the data passed into your subclass.
///
/// Example:
///
/// ```dart
/// @TypedExtrasSubClass(
/// id: '1234',
/// fileType: '.json',
/// )
/// @GET("/get")
/// Future<String> foo();
/// ```
///
@immutable
class TypedExtras {
const TypedExtras();
}

/// Extra data that will be passed to dio's request, response, transformer and interceptors.
@immutable
class Extra {
Expand Down
2 changes: 1 addition & 1 deletion retrofit/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ topics:
- rest
- dio
- retrofit
version: 4.3.0
version: 4.4.0
environment:
sdk: '>=2.19.0 <4.0.0'

Expand Down

0 comments on commit f1409e8

Please sign in to comment.