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

[Annotation Only] Adding case insensitive to enum based on loading JsonEnum config #1323

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 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
22 changes: 20 additions & 2 deletions json_annotation/lib/src/enum_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@

import 'json_key.dart';

/// Compare an enum value against a source using case-insensitive.
///
/// Exposed only for code generated by `package:json_serializable`.
/// Not meant to be used directly by user code.
bool $enumCompareCaseInsensitive(String arg1, Object arg2) =>
arg2 is String && (arg1.toLowerCase() == arg2.toLowerCase());

/// Compare an enum value against a source.
///
/// Exposed only for code generated by `package:json_serializable`.
/// Not meant to be used directly by user code.
bool $enumCompareStandard<V>(V arg1, Object arg2) => arg1 == arg2;

/// Returns the key associated with value [source] from [enumValues], if one
/// exists.
///
Expand All @@ -18,13 +31,16 @@ K? $enumDecodeNullable<K extends Enum, V>(
Map<K, V> enumValues,
Object? source, {
Enum? unknownValue,
bool Function(V arg1, Object arg2)? comparator,
}) {
if (source == null) {
return null;
}

comparator ??= $enumCompareStandard;

for (var entry in enumValues.entries) {
if (entry.value == source) {
if (comparator(entry.value, source)) {
return entry.key;
}
}
Expand Down Expand Up @@ -65,6 +81,7 @@ K $enumDecode<K extends Enum, V>(
Map<K, V> enumValues,
Object? source, {
K? unknownValue,
bool Function(V arg1, Object arg2)? comparator,
}) {
if (source == null) {
throw ArgumentError(
Expand All @@ -73,8 +90,9 @@ K $enumDecode<K extends Enum, V>(
);
}

comparator ??= $enumCompareStandard;
for (var entry in enumValues.entries) {
if (entry.value == source) {
if (comparator(entry.value, source)) {
return entry.key;
}
}
Expand Down
7 changes: 7 additions & 0 deletions json_annotation/lib/src/json_enum.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class JsonEnum {
const JsonEnum({
this.alwaysCreate = false,
this.fieldRename = FieldRename.none,
this.caseInsensitive = false,
this.valueField,
});

Expand All @@ -36,6 +37,12 @@ class JsonEnum {
/// for entries annotated with [JsonValue].
final FieldRename fieldRename;

/// If `true`, enum comparison will be done using case-insensitive.
///
/// The default, `false`, means enum comparison will be done using
/// case-sensitive.
final bool caseInsensitive;

/// Specifies the field within an "enhanced enum" to use as the value
/// to use for serialization.
///
Expand Down
12 changes: 10 additions & 2 deletions json_annotation/lib/src/json_key.dart
Original file line number Diff line number Diff line change
Expand Up @@ -149,19 +149,26 @@ class JsonKey {
/// valid on a nullable enum field.
final Enum? unknownEnumValue;

/// If true, enum will be parsed with case-insensitive.
/// Specifically, both values will be lower-cased and compared.
///
/// Valid only on enum fields with a compatible enum value.
final bool caseInsensitive;

Choose a reason for hiding this comment

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

Why is the option needed on both JsonEnum and JsonKey?

Copy link
Author

Choose a reason for hiding this comment

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

@t-beckmann so it can be used both at the enum level and at the field level.

Your question did make me add tests to the original PR, so I also found an issue and fixed it, and added 3 test cases: case insensitive on enum level, case insensitive on field level, and without any case insensitive (verifying behavior is same without it).

Example from the other PR:


/// Creates a new [JsonKey] instance.
///
/// Only required when the default behavior is not desired.
const JsonKey({
@Deprecated('Has no effect') bool? nullable,
@Deprecated('Has no effect')
bool? nullable,
this.defaultValue,
this.disallowNullValue,
this.fromJson,
@Deprecated(
'Use `includeFromJson` and `includeToJson` with a value of `false` '
'instead.',
)
this.ignore,
this.ignore,
Copy link
Author

Choose a reason for hiding this comment

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

fyi this was done by dart format 🤷

Copy link
Collaborator

Choose a reason for hiding this comment

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

You need to be using a dev release of Dart 3.1 for this.

this.includeFromJson,
this.includeIfNull,
this.includeToJson,
Expand All @@ -170,6 +177,7 @@ class JsonKey {
this.required,
this.toJson,
this.unknownEnumValue,
this.caseInsensitive = false,
});

/// Sentinel value for use with [unknownEnumValue].
Expand Down