simolus3 / drift

Drift is an easy to use, reactive, typesafe persistence library for Dart & Flutter.
https://drift.simonbinder.eu/
MIT License
2.48k stars 354 forks source link

Add Code Generation for json_serializable #3080

Open eraps7 opened 4 weeks ago

eraps7 commented 4 weeks ago

Great package! I really love what you're creating here!

Currently, to use json_serializable and/or freezed, developers have to write duplicate code: one for the Users class and another for the User class. For example:

@UseRowClass(User)
class Users extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get name => text()();
  DateTimeColumn get birthday => dateTime()();
  TextColumn get status => textEnum<StatusType>()();
}

@JsonSerializable()
class User {
  final int id;
  final String name;
  final DateTime birthday;
  final StatusType status;

  User({
    required this.id,
    required this.name,
    required this.birthday,
    required this.status,
  });
}

enum StatusType {
  none,
  running,
  stopped,
  paused
}

It would be fantastic if this code could be generated using build_runner.

I am willing to contribute to implementing this feature and creating a PR if someone can provide guidance or pointers on how to get started.

Thank you!

simolus3 commented 4 weeks ago

I agree with the idea that it should be easier to combine different builders with drift - putting a cheap form of json serialization into drift by default was my lazy workaround because they're not that easy to combine, but I consider that to be a big design flaw in drift.

However, I think the end realization is that users need to have full control over all builders, and the problem is generating APIs instead of implementations. In drift, you define the table structure in your sources, and then drift generates the row classes and companions (or models, which are really part of a public API then). I think this is fundamentally flawed somewhat, and making drift generate json_serializable annotations on the classes it generates doesn't solve this.

The way things should work is that users define the public models / APIs they want to use, an drift wires up all the boring things in the implementation. This is what we have with UseRowClass, but a downside is that you now have to effectively write double the code. I think a model similar to Android's Room library, where we infer the table structure based on pre-defined data classes, is a better approach in the end, e.g.

@JsonSerializable()
@DriftTable()
class User {
  @PrimaryKey(autoIncrement: true)
  final int id;
  final String name;
  final DateTime birthday;

  @TypeConverter.enumText()
  final StatusType status;
}

Obviously we can't turn the whole library inside out right now, but I still think something like that can form a better model because users control the parts that they see. I'm not sure if it's worth it to explore this approach with the current build_runner-based implementation, but that's what I'll prefer as an API for an eventual macro-based implementation. If you still want to help with that or a similar approach then contributions are absolutely welcome and will help validate the future annotation API.

eraps7 commented 3 weeks ago

Thank you @simolus3 for your prompt response.

A api similar to Android's Room library would be great. It looks clean and organized.

The Drift documentation (code below) explains the process of creating a table and implementing JsonSerializable using two different class names, "user" and "users." Is there a way to use the same class name for both JsonSerializable data classes and the drift tables?

@UseRowClass(User)
class Users extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get name => text()();
  DateTimeColumn get birthday => dateTime()();
  TextColumn get status => textEnum<StatusType>()();
}

@JsonSerializable()
class User {
  final int id;
  final String name;
  final DateTime birthday;
  final StatusType status;

  User({
    required this.id,
    required this.name,
    required this.birthday,
  });
}

thank you