google / built_value.dart

Immutable value types, enum classes, and serialization.
https://pub.dev/packages/built_value
BSD 3-Clause "New" or "Revised" License
869 stars 184 forks source link

EnumClass: Support using wireName as the discriminated value. #558

Open matanlurey opened 5 years ago

matanlurey commented 5 years ago

For example, here is the current behavior:

import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';

part 'main.g.dart';

class Drink extends EnumClass {
  @BuiltValueEnumConst(wireName: 'gin-and-tonic')
  static const Drink ginAndTonic = _$ginAndTonic;

  @BuiltValueEnumConst(wireName: 'old-fashioned')
  static const Drink oldFashioned = _$oldFashioned;

  const Drink._(String name) : super(name);

  static Serializer<Drink> get serializer => _$drinkSerializer;
  static BuiltSet<Drink> get values => _$values;
  static Drink valueOf(String name) => _$valueOf(name);
}

void main() {
  print(Drink.oldFashioned.name); // oldFashioned
}

It would be nice, as an option, to use wireName: ... as the identity value:

@BuiltValueEnum(useWireNameAsValue: true)
class Drink extends EnumClass {
  // ...
}

void main() {
  print(Drink.oldFashioned.name); // old-fashioned
}

My rationale for this is for the web (and mobile, with deep linking), using hyphenated values is much more common (and easier to read and write). For example, If I wanted to see a recipe, I might visit localhost/drinks/old-fashioned, and it would be nice to do Drinks.valueOf('old-fashioned').

I have found a (hacky) workaround, which is:

class Drink extends EnumClass {
  // ...

  /// Use instead of [valueOf].
  factory Drink.from(String name) {
    final identity = _$DrinkSerializer._fromWire[name];
    return valueOf(identity);
  }

  @override
  String get name => _$DrinkSerializer._toWire[super.name];

  // ...
}

It works for my needs, but it's not perfect. Another option is allowing users to custom implement valueOf (i.e. I could move Drink.from to Drink.valueOf).

davidmorgan commented 5 years ago

Thanks. That makes sense. Will try to take a look at some point.

cpboyd commented 5 years ago

The use of a factory constructor will currently cause the build_runner to throw an error, because only one constructor is expected.

However, this is just fine:

  static Drink from(String name) {
    final identity = _$DrinkSerializer._fromWire[name];
    return valueOf(identity);
  }

I'm not familiar enough with Dart at the moment to know if the factory constructor has any inherent benefits over a static method.

srix55 commented 2 years ago

Any updates on this... i just want to get the exact enum-constant value without having to edit any generated EnumClass code (generated by openapi-generator)...