Generate a builder-like method as an alternative to copyWith for modifying immutable Freezed objects
Is your feature request related to a problem? Please describe.
So lets say I am taking input from the user using a form. The input from the form is stored in freezed-object FormData. Now, I want to be able to incrementally create the FormData object. This can easily be done using Builder Pattern. Such a Builder object should also allow to validate the data before actually creating the FormData.
Describe the solution you'd like
Something similar to Builder Pattern which would allow to create the final object from data coming in steps.
Hello! Could you give a clear example of what you would expect Freezed to do?
Consider the following scenario : (using pseudo code below)
/*************************************/
/***** File - data_object.dart *****/
@freezed
DataObject {
String? id;
String name;
String phoneNumber;
DateTime? createdAt;
// createdAt & id can be null as they will be added by the server, when saved
}
/*************************************/
/***** File - some_form.dart *****/
StatelessWidget SomeForm {
final db = Database();
// Temporary variables
String name;
String phoneNumber;
build () => Column [
TextInput("Enter name", onChanged: (input) => name = input),
TextInput("Enter phoneNumber", onChanged: (input) => phoneNumber = input),
Button("Submit", onTap: () => db.save(DataObject(name: name, phoneNumber: phoneNumber)))
]
}
/*************************************/
/********* File - database.dart ************/
class Database () {
save (DataObject data) {
// saves data into DB
// ...
}
}
Now lets focus on the form widget - SomeForm here.
The above code is fine when the DataObject in question is simple enough. However, imagine a DataObject with 10s of properties. The SomeForm for such a data-object will have to create many temporary variables to temporarily save the onChanged data from the inputs. A "builder pattern" (similar to what built_value has, but then built_value has a lot of other problems) which would allow to add data to the builder of the object as we get it from the inputs, can help.
Furthermore, we could add validation logic to such builders, to put specific constraints over the values these objects could contain.
built_value has this mechanism, also AutoValue for Java allows us to extract a builder from an immutable object.
It would be nice to have a PersonBuilder generated for us, if we have a Person freezed object, and a toBuilder that returns that object's mutable Builder. This has to be done carefully as this will demand some customizations, like how can we validate the data before building it. Fortunately there are tons of use cases already documented in AutoValue and built_value.
builders are also really nice when you need to mutate multiple collections (at arbitrary depth), especially beyond simply adding values
pseudocode
@freezed Foo {
Map<String, String> myMap,
List<String> myList,
bool? nullableBool,
}
final foo = Foo({}, ['yo'], true);
foo.build((b) => b
..myMap['addThis'] = 'this was just added'
..myList.remove('yo')
..nullableBool = null,
);
vs
foo.copyWith(
myMap: { ...foo.myMap, 'addThis': 'this was just added' },
myList: List.from(foo.myList)..remove('yo'),
nullableBool: ?????????????
)
I agree with the value. @unfreeezed was released as an in-between step for this.
At some point, this will exist.
Although I'll admit I have other more important things to do. Especially when in the future Dart will have the necessary features to make Freezed redudant.
In the JS world this is handled by ImmerJS which basically creates a copy that then replaces the original data.
import produce from "immer"
const nextState = produce(baseState, draft => {
draft[1].done = true
draft.push({title: "Tweet about it"})
})
Maybe something like this could be made in Dart too, so it's able to work with any type of immutable data, not just freezed.