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

Support referencing subtypes from other files #28

Open
wants to merge 54 commits into
base: master
Choose a base branch
from

Conversation

arrrrny
Copy link

@arrrrny arrrrny commented Dec 4, 2024

This was an important feature for me to move from freezed to Morphy. dont mind the many git commits and reverts, I was learning the package:

Key changes:

  • support subtypes to be referenced from separate files.
  • followed dart naming convention.
  • implemented fromJsonLean and toJsonLean methods that dont have the _classname argument for easier otuside intregrations.
  • some clean up.

fixes #4

I added the explicitToJson parameter decorator from @miklcct commits. Howver all the __ typedefs to only support a variable named 'Type' is unneccsary. So I removed them.

The tests only fail at the part where I chaged the if else to switch and used interface .fromJson for subtypes. it works smoothly and allow the outside file reference for sub types.

@atreeon thanks for the nice package, if you merge this PR, I will keep contributing to it. I am moving away from freezed to morphy.

Here is my source file app_user.dart

import 'package:morphy_annotation/morphy_annotation.dart';
import '../../../domain/entities/device/device.dart';
import '../../../domain/entities/user/user.dart';

import 'supabase_user.dart';
import 'firebase_user.dart';

part 'app_user.morphy.dart';
part 'app_user.g.dart';

@Morphy(generateJson: true, explicitSubTypes: [$SupabaseUser, $FirebaseUser])
abstract class $AppUser implements $User {
  String get country;
  String get neighborhood;
  String get token;
  $Device get device;
}

and firebase_user.dart

import 'package:morphy_annotation/morphy_annotation.dart';
import '../../../domain/entities/user/user.dart';
import '../../../domain/entities/device/device.dart';

import 'app_user.dart';

part 'firebase_user.morphy.dart';
part 'firebase_user.g.dart';

@Morphy(generateJson: true)
abstract class $FirebaseUser implements $AppUser {
  String get fire;
}

and supabase_user.dart

import 'package:morphy_annotation/morphy_annotation.dart';
import '../../../domain/entities/user/user.dart';
import '../../../domain/entities/device/device.dart';

import 'app_user.dart';

part 'supabase_user.morphy.dart';
part 'supabase_user.g.dart';

@Morphy(generateJson: true)
abstract class $SupabaseUser implements $AppUser {
  String get supa;
}

and here is the beautifully generated app_user.morphy.dart

// ignore_for_file: UNNECESSARY_CAST
// ignore_for_file: type=lint

part of 'app_user.dart';

// **************************************************************************
// Generator: MorphyGenerator<Morphy>
// **************************************************************************

///
///implements [$User]
///

///

@JsonSerializable(
  explicitToJson: true,
)
class AppUser extends $AppUser implements User {
  final String country;
  final String neighborhood;
  final String token;
  final Device device;
  final String id;
  final int age;

  ///
  ///implements [$User]
  ///

  ///
  AppUser({
    required this.country,
    required this.neighborhood,
    required this.token,
    required this.device,
    required this.id,
    required this.age,
  });
  AppUser._({
    required this.country,
    required this.neighborhood,
    required this.token,
    required this.device,
    required this.id,
    required this.age,
  });

  String toString() =>
      "(AppUser-country:${country.toString()}|neighborhood:${neighborhood.toString()}|token:${token.toString()}|device:${device.toString()}|id:${id.toString()}|age:${age.toString()})";

  int get hashCode => hashObjects([
        country.hashCode,
        neighborhood.hashCode,
        token.hashCode,
        device.hashCode,
        id.hashCode,
        age.hashCode
      ]);

  bool operator ==(Object other) =>
      identical(this, other) ||
      other is AppUser &&
          runtimeType == other.runtimeType &&
          country == other.country &&
          neighborhood == other.neighborhood &&
          token == other.token &&
          device == other.device &&
          id == other.id &&
          age == other.age;

  User copyWithUser({
    String Function()? id,
    int Function()? age,
  }) {
    return AppUser._(
      id: id == null ? this.id as String : id() as String,
      age: age == null ? this.age as int : age() as int,
      country: (this as AppUser).country,
      neighborhood: (this as AppUser).neighborhood,
      token: (this as AppUser).token,
      device: (this as AppUser).device,
    ) as User;
  }

  AppUser copyWithAppUser({
    String Function()? country,
    String Function()? neighborhood,
    String Function()? token,
    Device Function()? device,
    String Function()? id,
    int Function()? age,
  }) {
    return AppUser._(
      country: country == null ? this.country as String : country() as String,
      neighborhood: neighborhood == null
          ? this.neighborhood as String
          : neighborhood() as String,
      token: token == null ? this.token as String : token() as String,
      device: device == null ? this.device as Device : device() as Device,
      id: id == null ? this.id as String : id() as String,
      age: age == null ? this.age as int : age() as int,
    ) as AppUser;
  }

//$User|[]|[id:String:$User, age:int:$User]$SupabaseUser|[]|[supa:String:$SupabaseUser, country:String:$AppUser, neighborhood:String:$AppUser, token:String:$AppUser, device:$Device:$AppUser, id:String:$User, age:int:$User, country:String:$AppUser, neighborhood:String:$AppUser, token:String:$AppUser, device:$Device:$AppUser, id:String:$User, age:int:$User]$FirebaseUser|[]|[fire:String:$FirebaseUser, country:String:$AppUser, neighborhood:String:$AppUser, token:String:$AppUser, device:$Device:$AppUser, id:String:$User, age:int:$User, country:String:$AppUser, neighborhood:String:$AppUser, token:String:$AppUser, device:$Device:$AppUser, id:String:$User, age:int:$User]$AppUser|[]|[country:String:null, neighborhood:String:null, token:String:null, device:Device:null, id:String:null, age:int:null]
//$SupabaseUser|[]|[supa:String:$SupabaseUser, country:String:$AppUser, neighborhood:String:$AppUser, token:String:$AppUser, device:$Device:$AppUser, id:String:$User, age:int:$User, country:String:$AppUser, neighborhood:String:$AppUser, token:String:$AppUser, device:$Device:$AppUser, id:String:$User, age:int:$User]
//$FirebaseUser|[]|[fire:String:$FirebaseUser, country:String:$AppUser, neighborhood:String:$AppUser, token:String:$AppUser, device:$Device:$AppUser, id:String:$User, age:int:$User, country:String:$AppUser, neighborhood:String:$AppUser, token:String:$AppUser, device:$Device:$AppUser, id:String:$User, age:int:$User]
  factory AppUser.fromJson(Map<String, dynamic> json) {
    final className = json['_className_'] as String;
    switch (className) {
      case 'AppUser':
        return _$AppUserFromJson(json);
      case 'SupabaseUser':
        return SupabaseUser.fromJson(json);
      case 'FirebaseUser':
        return FirebaseUser.fromJson(json);
      default:
        throw UnsupportedError(
            "The _className_ '$className' is not supported by the AppUser.fromJson constructor.");
    }
  }
  factory AppUser.fromJsonLean(Map<String, dynamic> json) {
    return _$AppUserFromJson(
      json,
    );
  }

  // ignore: unused_field
  Map<Type, Object? Function(Never)> _fns = {};

  Map<String, dynamic> toJsonCustom([Map<Type, Object? Function(Never)>? fns]) {
    _fns = fns ?? {};
    return toJson();
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = _$AppUserToJson(
      this,
    );
    // Adding custom key-value pair
    data['_className_'] = 'AppUser';

    return data;
  }

  Map<String, dynamic> toJsonLean() {
    final Map<String, dynamic> data = _$AppUserToJson(
      this,
    );
    return data;
  }
}

extension $AppUserchangeToE on $AppUser {
  AppUser changeToAppUser({
    String Function()? country,
    String Function()? neighborhood,
    String Function()? token,
    Device Function()? device,
    String Function()? id,
    int Function()? age,
  }) {
    return AppUser._(
      country: country == null ? this.country as String : country() as String,
      neighborhood: neighborhood == null
          ? this.neighborhood as String
          : neighborhood() as String,
      token: token == null ? this.token as String : token() as String,
      device: device == null ? this.device as Device : device() as Device,
      id: id == null ? this.id as String : id() as String,
      age: age == null ? this.age as int : age() as int,
    ) as AppUser;
  }

  SupabaseUser changeToSupabaseUser({
    required String supa,
    String Function()? country,
    String Function()? neighborhood,
    String Function()? token,
    Device Function()? device,
    String Function()? id,
    int Function()? age,
  }) {
    return SupabaseUser(
      supa: supa as String,
      country: country == null ? this.country as String : country() as String,
      neighborhood: neighborhood == null
          ? this.neighborhood as String
          : neighborhood() as String,
      token: token == null ? this.token as String : token() as String,
      device: device == null ? this.device as Device : device() as Device,
      id: id == null ? this.id as String : id() as String,
      age: age == null ? this.age as int : age() as int,
    ) as SupabaseUser;
  }

  FirebaseUser changeToFirebaseUser({
    required String fire,
    String Function()? country,
    String Function()? neighborhood,
    String Function()? token,
    Device Function()? device,
    String Function()? id,
    int Function()? age,
  }) {
    return FirebaseUser(
      fire: fire as String,
      country: country == null ? this.country as String : country() as String,
      neighborhood: neighborhood == null
          ? this.neighborhood as String
          : neighborhood() as String,
      token: token == null ? this.token as String : token() as String,
      device: device == null ? this.device as Device : device() as Device,
      id: id == null ? this.id as String : id() as String,
      age: age == null ? this.age as int : age() as int,
    ) as FirebaseUser;
  }
}

enum AppUser$ { country, neighborhood, token, device, id, age }

and the firebase

import 'package:morphy_annotation/morphy_annotation.dart';
import '../../../domain/entities/user/user.dart';
import '../../../domain/entities/device/device.dart';

import 'app_user.dart';

part 'firebase_user.morphy.dart';
part 'firebase_user.g.dart';

@Morphy(generateJson: true)
abstract class $FirebaseUser implements $AppUser {
  String get fire;
}

app_user_g.dart

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'app_user.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

AppUser _$AppUserFromJson(Map json) => AppUser(
      country: json['country'] as String,
      neighborhood: json['neighborhood'] as String,
      token: json['token'] as String,
      device: Device.fromJson(Map<String, dynamic>.from(json['device'] as Map)),
      id: json['id'] as String,
      age: (json['age'] as num).toInt(),
    );

Map<String, dynamic> _$AppUserToJson(AppUser instance) => <String, dynamic>{
      'country': instance.country,
      'neighborhood': instance.neighborhood,
      'token': instance.token,
      'device': instance.device.toJson(),
      'id': instance.id,
      'age': instance.age,
    };

miklcct and others added 30 commits May 16, 2024 14:23
…t, Map

Also preserve type aliases in generated files

Fixes atreeon#15
# Conflicts:
#	morphy/lib/morphy2Builder.dart
#	morphy/lib/morphyBuilder.dart
@atreeon
Copy link
Owner

atreeon commented Dec 5, 2024

Thanks so much for contributing. I'll try to take a proper look over the weekend or next week.

It's really nice to hear people using this package after quite a while of tumbleweed after I first published it!

@arrrrny
Copy link
Author

arrrrny commented Dec 5, 2024

fantastik! I made more improvements. throwing error if missing imports in subclasses that are not obvious to import. added an optional method compareTo method, that compares the object against another object to have Map<String,dynamic> type diff nested. This is needed when you work with big objects and use graphql or firestore to send only delta updates.

@arrrrny
Copy link
Author

arrrrny commented Dec 5, 2024

Here is the output of the compareToX extension I added. I made this as a default method. Since for grahql and firestore entities we need the delta json to send the update not the whole object. it can be turned off with annotation.

@morphy(generateCompareTo: false)

extension $CustomerCompareE on $Customer {
  Map<String, dynamic> compareToCustomer(Customer other) {
    final Map<String, dynamic> diff = {};

    if (device != other.device) {
      diff['device'] = () => device.compareToDevice(other.device);
    }
    if (locale != other.locale) {
      diff['locale'] = () => locale.compareToLocale(other.locale);
    }
    if (id != other.id) {
      diff['id'] = () => other.id;
    }
    if (code != other.code) {
      diff['code'] = () => other.code;
    }
    if (name != other.name) {
      diff['name'] = () => other.name;
    }
    if (description != other.description) {
      diff['description'] = () => other.description;
    }
    if (createdAt != other.createdAt) {
      diff['createdAt'] = () => other.createdAt;
    }
    if (updatedAt != other.updatedAt) {
      diff['updatedAt'] = () => other.updatedAt;
    }

    return diff;
  }
}

and this is the customer class.It checks for all types that it implements from that has fields so all nesting is guaranteed.

import 'package:morphy_annotation/morphy_annotation.dart';
import '../../../domain/entities/actor/user.dart';
import '../../../domain/entities/actor/person.dart';

import '../../../domain/entities/actor/actor.dart';
import 'package:zikzak/src/domain/entities/actor/participant.dart';
import 'package:zikzak/src/domain/entities/actor/entity.dart';
import '../../../domain/entities/device/device.dart';

import '../../../domain/types/locale.dart';
import 'id.dart';

part 'customer.morphy.dart';
part 'customer.g.dart';

@Morphy(generateJson: true)
abstract class $Customer implements $$Person {
  $Device get device;
  $Locale get locale;
}

arrrrny and others added 4 commits December 5, 2024 20:58
added compareToX to compare object to another object and get nested diff in map
added non null marks for not null field
@arrrrny
Copy link
Author

arrrrny commented Dec 5, 2024

It got even better. My ultimate goal was to achieving a type safe and automated way of implementing patch type.

I can't simply use the class reference for that, since the class has required fields that I might not need and actually dont want to be part of my patch, like 'id'. below is the latest generated code. It creates compareToX and compareToEnumX. I really liked your idea of generering enum X$ from the fields. Thats genius. @atreeon . So I built Patch type safety on top of that.

this type ensures that fields are only class fields.

  CustomerPatch compareToEnumCustomer(Customer other) {
    final CustomerPatch diff = {};

    if (device != other.device) {
      diff[Customer$.device] = () => device.compareToDevice(other.device);
    }
    if (locale != other.locale) {
      diff[Customer$.locale] = () => locale.compareToLocale(other.locale);
    }
    if (id != other.id) {
      diff[Customer$.id] = () => other.id;
    }
    if (code != other.code) {
      diff[Customer$.code] = () => other.code;
    }
    if (name != other.name) {
      diff[Customer$.name] = () => other.name;
    }
    if (description != other.description) {
      diff[Customer$.description] = () => other.description;
    }
    if (createdAt != other.createdAt) {
      diff[Customer$.createdAt] = () => other.createdAt;
    }
    if (updatedAt != other.updatedAt) {
      diff[Customer$.updatedAt] = () => other.updatedAt;
    }

    return diff;
  }

  typedef CustomerPatch = Map<Customer$, dynamic>;

enum Customer$ {
  device,
  locale,
  id,
  code,
  name,
  description,
  createdAt,
  updatedAt
}

and this is How I simply and confidently use in my abstract repo with type safety.

abstract class UserRepository {
  Future<void> update({required UserPatch patch});

@arrrrny
Copy link
Author

arrrrny commented Dec 5, 2024

and nirvana

    Customer x = Customer(
        device: Device(id: 's'),
        locale: Locale(countryCode: 'TR', languageCode: 'tr'),
        name: 'Arny');
    User y = x.copyWithUser(name: () => 'ARRRRNY');
    UserPatch patch = x.compareToEnumUser(y);

@arrrrny
Copy link
Author

arrrrny commented Dec 8, 2024

All tests pass now. I made sligh change to fromJson method to allow data without className key nested and used public constructors referenced from subtypes instead of same file private constructors.

@arrrrny
Copy link
Author

arrrrny commented Dec 14, 2024

@atreeon Adrian, I really like you to check the end result. it is fantastik! I implemented auto generated type safe patching that can beautiful used as this:

// Create and convert to JSON
final patch = CustomerPatch.create()
  .withEmail("[email protected]")
  .withName("John");

// For GraphQL
final json = patch.toJson();

// For internal use
final patchMap = patch.toPatch();

// From JSON
final patch = CustomerPatch.fromJson(jsonData);

and this:

// Create patch from diff
final diff = customer.compareToCustomer(otherCustomer); 
final patch = CustomerPatch.create(diff);

// Create patch using with methods
final patch = CustomerPatch()
  .withProfile(newProfile)
  .withPreferences(newPrefs);

// Apply patch
customer.copyWithCustomer(patch.toPatch());

And here is the generated output with support of nested type patch and convert toJson for graphql:

// ignore_for_file: UNNECESSARY_CAST
// ignore_for_file: type=lint

part of 'customer.dart';

// **************************************************************************
// Generator: MorphyGenerator<Morphy>
// **************************************************************************

///
///implements [User]
///

///
///implements [Actor]
///

///
///implements [Participant]
///

///
///implements [Entity]
///

///

@JsonSerializable(
  explicitToJson: true,
)
class Customer extends $Customer implements User, Actor, Participant, Entity {
  final CustomerProfile? profile;
  final CustomerPreferences? preferences;
  final List<String>? favoriteStores;
  final DateTime? lastPurchaseDate;
  final int? totalPurchases;
  final double? totalSpent;
  final int? yearOfBirth;
  final String? code;
  final String? name;
  final String id;
  final Locale locale;
  final String? firstName;
  final String? lastName;
  final String? phoneNumber;
  final Town? location;
  final DateTime? lastLogin;
  final bool? isAnonymous;
  final String? email;
  final Device? device;
  final String? displayName;
  final String? deviceToken;
  final DateTime? registeredAt;
  final ZipCode? zipCode;
  final bool? isBanned;
  final bool? isVerified;
  final DateTime? verifiedAt;
  final DateTime? bannedAt;

  ///
  ///implements [User]
  ///

  ///
  ///implements [Actor]
  ///

  ///
  ///implements [Participant]
  ///

  ///
  ///implements [Entity]
  ///

  ///
  Customer({
    this.profile,
    this.preferences,
    this.favoriteStores,
    this.lastPurchaseDate,
    this.totalPurchases,
    this.totalSpent,
    this.yearOfBirth,
    this.code,
    this.name,
    required this.id,
    required this.locale,
    this.firstName,
    this.lastName,
    this.phoneNumber,
    this.location,
    this.lastLogin,
    this.isAnonymous,
    this.email,
    this.device,
    this.displayName,
    this.deviceToken,
    this.registeredAt,
    this.zipCode,
    this.isBanned,
    this.isVerified,
    this.verifiedAt,
    this.bannedAt,
  });
  Customer._({
    this.profile,
    this.preferences,
    this.favoriteStores,
    this.lastPurchaseDate,
    this.totalPurchases,
    this.totalSpent,
    this.yearOfBirth,
    this.code,
    this.name,
    required this.id,
    required this.locale,
    this.firstName,
    this.lastName,
    this.phoneNumber,
    this.location,
    this.lastLogin,
    this.isAnonymous,
    this.email,
    this.device,
    this.displayName,
    this.deviceToken,
    this.registeredAt,
    this.zipCode,
    this.isBanned,
    this.isVerified,
    this.verifiedAt,
    this.bannedAt,
  });

  String toString() =>
      "(Customer-profile:${profile.toString()}|preferences:${preferences.toString()}|favoriteStores:${favoriteStores.toString()}|lastPurchaseDate:${lastPurchaseDate.toString()}|totalPurchases:${totalPurchases.toString()}|totalSpent:${totalSpent.toString()}|yearOfBirth:${yearOfBirth.toString()}|code:${code.toString()}|name:${name.toString()}|id:${id.toString()}|locale:${locale.toString()}|firstName:${firstName.toString()}|lastName:${lastName.toString()}|phoneNumber:${phoneNumber.toString()}|location:${location.toString()}|lastLogin:${lastLogin.toString()}|isAnonymous:${isAnonymous.toString()}|email:${email.toString()}|device:${device.toString()}|displayName:${displayName.toString()}|deviceToken:${deviceToken.toString()}|registeredAt:${registeredAt.toString()}|zipCode:${zipCode.toString()}|isBanned:${isBanned.toString()}|isVerified:${isVerified.toString()}|verifiedAt:${verifiedAt.toString()}|bannedAt:${bannedAt.toString()})";

  int get hashCode => hashObjects([
        profile.hashCode,
        preferences.hashCode,
        favoriteStores.hashCode,
        lastPurchaseDate.hashCode,
        totalPurchases.hashCode,
        totalSpent.hashCode,
        yearOfBirth.hashCode,
        code.hashCode,
        name.hashCode,
        id.hashCode,
        locale.hashCode,
        firstName.hashCode,
        lastName.hashCode,
        phoneNumber.hashCode,
        location.hashCode,
        lastLogin.hashCode,
        isAnonymous.hashCode,
        email.hashCode,
        device.hashCode,
        displayName.hashCode,
        deviceToken.hashCode,
        registeredAt.hashCode,
        zipCode.hashCode,
        isBanned.hashCode,
        isVerified.hashCode,
        verifiedAt.hashCode,
        bannedAt.hashCode
      ]);

  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Customer &&
          runtimeType == other.runtimeType &&
          profile == other.profile &&
          preferences == other.preferences &&
          (favoriteStores ?? []).equalUnorderedD(other.favoriteStores ?? []) &&
          lastPurchaseDate == other.lastPurchaseDate &&
          totalPurchases == other.totalPurchases &&
          totalSpent == other.totalSpent &&
          yearOfBirth == other.yearOfBirth &&
          code == other.code &&
          name == other.name &&
          id == other.id &&
          locale == other.locale &&
          firstName == other.firstName &&
          lastName == other.lastName &&
          phoneNumber == other.phoneNumber &&
          location == other.location &&
          lastLogin == other.lastLogin &&
          isAnonymous == other.isAnonymous &&
          email == other.email &&
          device == other.device &&
          displayName == other.displayName &&
          deviceToken == other.deviceToken &&
          registeredAt == other.registeredAt &&
          zipCode == other.zipCode &&
          isBanned == other.isBanned &&
          isVerified == other.isVerified &&
          verifiedAt == other.verifiedAt &&
          bannedAt == other.bannedAt;

  User copyWithUser({
    String? Function()? code,
    String? Function()? name,
    String Function()? id,
    Locale Function()? locale,
    String? Function()? firstName,
    String? Function()? lastName,
    String? Function()? phoneNumber,
    Town? Function()? location,
    DateTime? Function()? lastLogin,
    bool? Function()? isAnonymous,
    String? Function()? email,
    Device? Function()? device,
    String? Function()? displayName,
    String? Function()? deviceToken,
    DateTime? Function()? registeredAt,
    ZipCode? Function()? zipCode,
    bool? Function()? isBanned,
    bool? Function()? isVerified,
    DateTime? Function()? verifiedAt,
    DateTime? Function()? bannedAt,
  }) {
    return Customer._(
      code: code == null ? this.code as String? : code() as String?,
      name: name == null ? this.name as String? : name() as String?,
      id: id == null ? this.id as String : id() as String,
      locale: locale == null ? this.locale as Locale : locale() as Locale,
      firstName: firstName == null
          ? this.firstName as String?
          : firstName() as String?,
      lastName:
          lastName == null ? this.lastName as String? : lastName() as String?,
      phoneNumber: phoneNumber == null
          ? this.phoneNumber as String?
          : phoneNumber() as String?,
      location: location == null ? this.location as Town? : location() as Town?,
      lastLogin: lastLogin == null
          ? this.lastLogin as DateTime?
          : lastLogin() as DateTime?,
      isAnonymous: isAnonymous == null
          ? this.isAnonymous as bool?
          : isAnonymous() as bool?,
      email: email == null ? this.email as String? : email() as String?,
      device: device == null ? this.device as Device? : device() as Device?,
      displayName: displayName == null
          ? this.displayName as String?
          : displayName() as String?,
      deviceToken: deviceToken == null
          ? this.deviceToken as String?
          : deviceToken() as String?,
      registeredAt: registeredAt == null
          ? this.registeredAt as DateTime?
          : registeredAt() as DateTime?,
      zipCode:
          zipCode == null ? this.zipCode as ZipCode? : zipCode() as ZipCode?,
      isBanned: isBanned == null ? this.isBanned as bool? : isBanned() as bool?,
      isVerified:
          isVerified == null ? this.isVerified as bool? : isVerified() as bool?,
      verifiedAt: verifiedAt == null
          ? this.verifiedAt as DateTime?
          : verifiedAt() as DateTime?,
      bannedAt: bannedAt == null
          ? this.bannedAt as DateTime?
          : bannedAt() as DateTime?,
      profile: (this as Customer).profile,
      preferences: (this as Customer).preferences,
      favoriteStores: (this as Customer).favoriteStores,
      lastPurchaseDate: (this as Customer).lastPurchaseDate,
      totalPurchases: (this as Customer).totalPurchases,
      totalSpent: (this as Customer).totalSpent,
      yearOfBirth: (this as Customer).yearOfBirth,
    ) as User;
  }

  Actor copyWithActor({
    String? Function()? code,
    String? Function()? name,
    String? Function()? id,
  }) {
    return Customer._(
      code: code == null ? this.code as String? : code() as String?,
      name: name == null ? this.name as String? : name() as String?,
      id: id == null ? this.id as String : id() as String,
      profile: (this as Customer).profile,
      preferences: (this as Customer).preferences,
      favoriteStores: (this as Customer).favoriteStores,
      lastPurchaseDate: (this as Customer).lastPurchaseDate,
      totalPurchases: (this as Customer).totalPurchases,
      totalSpent: (this as Customer).totalSpent,
      yearOfBirth: (this as Customer).yearOfBirth,
      locale: (this as Customer).locale,
      firstName: (this as Customer).firstName,
      lastName: (this as Customer).lastName,
      phoneNumber: (this as Customer).phoneNumber,
      location: (this as Customer).location,
      lastLogin: (this as Customer).lastLogin,
      isAnonymous: (this as Customer).isAnonymous,
      email: (this as Customer).email,
      device: (this as Customer).device,
      displayName: (this as Customer).displayName,
      deviceToken: (this as Customer).deviceToken,
      registeredAt: (this as Customer).registeredAt,
      zipCode: (this as Customer).zipCode,
      isBanned: (this as Customer).isBanned,
      isVerified: (this as Customer).isVerified,
      verifiedAt: (this as Customer).verifiedAt,
      bannedAt: (this as Customer).bannedAt,
    ) as Actor;
  }

  Participant copyWithParticipant({
    String? Function()? code,
    String? Function()? name,
    String? Function()? id,
  }) {
    return Customer._(
      code: code == null ? this.code as String? : code() as String?,
      name: name == null ? this.name as String? : name() as String?,
      id: id == null ? this.id as String : id() as String,
      profile: (this as Customer).profile,
      preferences: (this as Customer).preferences,
      favoriteStores: (this as Customer).favoriteStores,
      lastPurchaseDate: (this as Customer).lastPurchaseDate,
      totalPurchases: (this as Customer).totalPurchases,
      totalSpent: (this as Customer).totalSpent,
      yearOfBirth: (this as Customer).yearOfBirth,
      locale: (this as Customer).locale,
      firstName: (this as Customer).firstName,
      lastName: (this as Customer).lastName,
      phoneNumber: (this as Customer).phoneNumber,
      location: (this as Customer).location,
      lastLogin: (this as Customer).lastLogin,
      isAnonymous: (this as Customer).isAnonymous,
      email: (this as Customer).email,
      device: (this as Customer).device,
      displayName: (this as Customer).displayName,
      deviceToken: (this as Customer).deviceToken,
      registeredAt: (this as Customer).registeredAt,
      zipCode: (this as Customer).zipCode,
      isBanned: (this as Customer).isBanned,
      isVerified: (this as Customer).isVerified,
      verifiedAt: (this as Customer).verifiedAt,
      bannedAt: (this as Customer).bannedAt,
    ) as Participant;
  }

  Entity copyWithEntity({
    String? Function()? code,
    String? Function()? name,
    String? Function()? id,
  }) {
    return Customer._(
      code: code == null ? this.code as String? : code() as String?,
      name: name == null ? this.name as String? : name() as String?,
      id: id == null ? this.id as String : id() as String,
      profile: (this as Customer).profile,
      preferences: (this as Customer).preferences,
      favoriteStores: (this as Customer).favoriteStores,
      lastPurchaseDate: (this as Customer).lastPurchaseDate,
      totalPurchases: (this as Customer).totalPurchases,
      totalSpent: (this as Customer).totalSpent,
      yearOfBirth: (this as Customer).yearOfBirth,
      locale: (this as Customer).locale,
      firstName: (this as Customer).firstName,
      lastName: (this as Customer).lastName,
      phoneNumber: (this as Customer).phoneNumber,
      location: (this as Customer).location,
      lastLogin: (this as Customer).lastLogin,
      isAnonymous: (this as Customer).isAnonymous,
      email: (this as Customer).email,
      device: (this as Customer).device,
      displayName: (this as Customer).displayName,
      deviceToken: (this as Customer).deviceToken,
      registeredAt: (this as Customer).registeredAt,
      zipCode: (this as Customer).zipCode,
      isBanned: (this as Customer).isBanned,
      isVerified: (this as Customer).isVerified,
      verifiedAt: (this as Customer).verifiedAt,
      bannedAt: (this as Customer).bannedAt,
    ) as Entity;
  }

  Customer copyWithCustomer({
    CustomerProfile? Function()? profile,
    CustomerPreferences? Function()? preferences,
    List<String>? Function()? favoriteStores,
    DateTime? Function()? lastPurchaseDate,
    int? Function()? totalPurchases,
    double? Function()? totalSpent,
    int? Function()? yearOfBirth,
    String? Function()? code,
    String? Function()? name,
    String Function()? id,
    Locale Function()? locale,
    String? Function()? firstName,
    String? Function()? lastName,
    String? Function()? phoneNumber,
    Town? Function()? location,
    DateTime? Function()? lastLogin,
    bool? Function()? isAnonymous,
    String? Function()? email,
    Device? Function()? device,
    String? Function()? displayName,
    String? Function()? deviceToken,
    DateTime? Function()? registeredAt,
    ZipCode? Function()? zipCode,
    bool? Function()? isBanned,
    bool? Function()? isVerified,
    DateTime? Function()? verifiedAt,
    DateTime? Function()? bannedAt,
  }) {
    return Customer._(
      profile: profile == null
          ? this.profile as CustomerProfile?
          : profile() as CustomerProfile?,
      preferences: preferences == null
          ? this.preferences as CustomerPreferences?
          : preferences() as CustomerPreferences?,
      favoriteStores: favoriteStores == null
          ? this.favoriteStores as List<String>?
          : favoriteStores() as List<String>?,
      lastPurchaseDate: lastPurchaseDate == null
          ? this.lastPurchaseDate as DateTime?
          : lastPurchaseDate() as DateTime?,
      totalPurchases: totalPurchases == null
          ? this.totalPurchases as int?
          : totalPurchases() as int?,
      totalSpent: totalSpent == null
          ? this.totalSpent as double?
          : totalSpent() as double?,
      yearOfBirth: yearOfBirth == null
          ? this.yearOfBirth as int?
          : yearOfBirth() as int?,
      code: code == null ? this.code as String? : code() as String?,
      name: name == null ? this.name as String? : name() as String?,
      id: id == null ? this.id as String : id() as String,
      locale: locale == null ? this.locale as Locale : locale() as Locale,
      firstName: firstName == null
          ? this.firstName as String?
          : firstName() as String?,
      lastName:
          lastName == null ? this.lastName as String? : lastName() as String?,
      phoneNumber: phoneNumber == null
          ? this.phoneNumber as String?
          : phoneNumber() as String?,
      location: location == null ? this.location as Town? : location() as Town?,
      lastLogin: lastLogin == null
          ? this.lastLogin as DateTime?
          : lastLogin() as DateTime?,
      isAnonymous: isAnonymous == null
          ? this.isAnonymous as bool?
          : isAnonymous() as bool?,
      email: email == null ? this.email as String? : email() as String?,
      device: device == null ? this.device as Device? : device() as Device?,
      displayName: displayName == null
          ? this.displayName as String?
          : displayName() as String?,
      deviceToken: deviceToken == null
          ? this.deviceToken as String?
          : deviceToken() as String?,
      registeredAt: registeredAt == null
          ? this.registeredAt as DateTime?
          : registeredAt() as DateTime?,
      zipCode:
          zipCode == null ? this.zipCode as ZipCode? : zipCode() as ZipCode?,
      isBanned: isBanned == null ? this.isBanned as bool? : isBanned() as bool?,
      isVerified:
          isVerified == null ? this.isVerified as bool? : isVerified() as bool?,
      verifiedAt: verifiedAt == null
          ? this.verifiedAt as DateTime?
          : verifiedAt() as DateTime?,
      bannedAt: bannedAt == null
          ? this.bannedAt as DateTime?
          : bannedAt() as DateTime?,
    ) as Customer;
  }

//$User|[]|[id:String:$User, locale:$Locale:$User, firstName:String?:$User, lastName:String?:$User, phoneNumber:String?:$User, location:$Town?:$User, lastLogin:DateTime?:$User, isAnonymous:bool?:$User, email:String?:$User, device:$Device?:$User, displayName:String?:$User, deviceToken:String?:$User, registeredAt:DateTime?:$User, zipCode:$ZipCode?:$User, isBanned:bool?:$User, isVerified:bool?:$User, verifiedAt:DateTime?:$User, bannedAt:DateTime?:$User, code:String?:$Entity, name:String?:$Entity]$Actor|[]|[code:String?:$Entity, name:String?:$Entity, id:String?:$Entity]$$Participant|[]|[code:String?:$Entity, name:String?:$Entity, id:String?:$Entity]$Entity|[]|[code:String?:$Entity, name:String?:$Entity, id:String?:$Entity]$Customer|[]|[profile:CustomerProfile?:null, preferences:CustomerPreferences?:null, favoriteStores:List<String>?:null, lastPurchaseDate:DateTime?:null, totalPurchases:int?:null, totalSpent:double?:null, yearOfBirth:int?:null, code:String?:null, name:String?:null, id:String:null, locale:Locale:null, firstName:String?:null, lastName:String?:null, phoneNumber:String?:null, location:Town?:null, lastLogin:DateTime?:null, isAnonymous:bool?:null, email:String?:null, device:Device?:null, displayName:String?:null, deviceToken:String?:null, registeredAt:DateTime?:null, zipCode:ZipCode?:null, isBanned:bool?:null, isVerified:bool?:null, verifiedAt:DateTime?:null, bannedAt:DateTime?:null]
//
  factory Customer.fromJson(Map<String, dynamic> json) {
    if (json['_className_'] == null) {
      return _$CustomerFromJson(json);
    }
    if (json['_className_'] == "Customer") {
      return _$CustomerFromJson(json);
    }
    throw UnsupportedError(
        "The _className_ '${json['_className_']}' is not supported by the Customer.fromJson constructor.");
  }
  // ignore: unused_field

  Map<Type, Object? Function(Never)> _fns = {};

  Map<String, dynamic> toJsonCustom([Map<Type, Object? Function(Never)>? fns]) {
    _fns = fns ?? {};
    return toJson();
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = _$CustomerToJson(this);

    data['_className_'] = 'Customer';

    return data;
  }

  Map<String, dynamic> toJsonLean() {
    final Map<String, dynamic> data = _$CustomerToJson(
      this,
    );
    return _sanitizeJson(data);
  }

  dynamic _sanitizeJson(dynamic json) {
    if (json is Map<String, dynamic>) {
      json.remove('_className_');
      return json
        ..forEach((key, value) {
          json[key] = _sanitizeJson(value);
        });
    } else if (json is List) {
      return json.map((e) => _sanitizeJson(e)).toList();
    }
    return json;
  }
}

extension $CustomerCompareE on $Customer {
  Map<String, dynamic> compareToCustomer(Customer other) {
    final Map<String, dynamic> diff = {};

    if (profile != other.profile) {
      diff['profile'] = () => other.profile;
    }
    if (preferences != other.preferences) {
      diff['preferences'] = () => other.preferences;
    }
    if (favoriteStores != other.favoriteStores) {
      if (favoriteStores != null && other.favoriteStores != null) {
        if (favoriteStores!.length != other.favoriteStores!.length) {
          diff['favoriteStores'] = () => other.favoriteStores;
        } else {
          var hasDiff = false;
          for (var i = 0; i < favoriteStores!.length; i++) {
            if (favoriteStores![i] != other.favoriteStores![i]) {
              hasDiff = true;
              break;
            }
          }
          if (hasDiff) {
            diff['favoriteStores'] = () => other.favoriteStores;
          }
        }
      } else {
        diff['favoriteStores'] = () => other.favoriteStores;
      }
    }
    if (lastPurchaseDate != other.lastPurchaseDate) {
      if (lastPurchaseDate != null && other.lastPurchaseDate != null) {
        if (!lastPurchaseDate!.isAtSameMomentAs(other.lastPurchaseDate!)) {
          diff['lastPurchaseDate'] = () => other.lastPurchaseDate;
        }
      } else {
        diff['lastPurchaseDate'] = () => other.lastPurchaseDate;
      }
    }
    if (totalPurchases != other.totalPurchases) {
      diff['totalPurchases'] = () => other.totalPurchases;
    }
    if (totalSpent != other.totalSpent) {
      diff['totalSpent'] = () => other.totalSpent;
    }
    if (yearOfBirth != other.yearOfBirth) {
      diff['yearOfBirth'] = () => other.yearOfBirth;
    }
    if (code != other.code) {
      diff['code'] = () => other.code;
    }
    if (name != other.name) {
      diff['name'] = () => other.name;
    }
    if (id != other.id) {
      diff['id'] = () => other.id;
    }
    if (locale != other.locale) {
      diff['locale'] = () => other.locale;
    }
    if (firstName != other.firstName) {
      diff['firstName'] = () => other.firstName;
    }
    if (lastName != other.lastName) {
      diff['lastName'] = () => other.lastName;
    }
    if (phoneNumber != other.phoneNumber) {
      diff['phoneNumber'] = () => other.phoneNumber;
    }
    if (location != other.location) {
      diff['location'] = () => other.location;
    }
    if (lastLogin != other.lastLogin) {
      if (lastLogin != null && other.lastLogin != null) {
        if (!lastLogin!.isAtSameMomentAs(other.lastLogin!)) {
          diff['lastLogin'] = () => other.lastLogin;
        }
      } else {
        diff['lastLogin'] = () => other.lastLogin;
      }
    }
    if (isAnonymous != other.isAnonymous) {
      diff['isAnonymous'] = () => other.isAnonymous;
    }
    if (email != other.email) {
      diff['email'] = () => other.email;
    }
    if (device != other.device) {
      diff['device'] = () => other.device;
    }
    if (displayName != other.displayName) {
      diff['displayName'] = () => other.displayName;
    }
    if (deviceToken != other.deviceToken) {
      diff['deviceToken'] = () => other.deviceToken;
    }
    if (registeredAt != other.registeredAt) {
      if (registeredAt != null && other.registeredAt != null) {
        if (!registeredAt!.isAtSameMomentAs(other.registeredAt!)) {
          diff['registeredAt'] = () => other.registeredAt;
        }
      } else {
        diff['registeredAt'] = () => other.registeredAt;
      }
    }
    if (zipCode != other.zipCode) {
      diff['zipCode'] = () => other.zipCode;
    }
    if (isBanned != other.isBanned) {
      diff['isBanned'] = () => other.isBanned;
    }
    if (isVerified != other.isVerified) {
      diff['isVerified'] = () => other.isVerified;
    }
    if (verifiedAt != other.verifiedAt) {
      if (verifiedAt != null && other.verifiedAt != null) {
        if (!verifiedAt!.isAtSameMomentAs(other.verifiedAt!)) {
          diff['verifiedAt'] = () => other.verifiedAt;
        }
      } else {
        diff['verifiedAt'] = () => other.verifiedAt;
      }
    }
    if (bannedAt != other.bannedAt) {
      if (bannedAt != null && other.bannedAt != null) {
        if (!bannedAt!.isAtSameMomentAs(other.bannedAt!)) {
          diff['bannedAt'] = () => other.bannedAt;
        }
      } else {
        diff['bannedAt'] = () => other.bannedAt;
      }
    }

    return diff;
  }
}

extension $CustomerchangeToE on $Customer {
  Customer changeToCustomer({
    CustomerProfile? Function()? profile,
    CustomerPreferences? Function()? preferences,
    List<String>? Function()? favoriteStores,
    DateTime? Function()? lastPurchaseDate,
    int? Function()? totalPurchases,
    double? Function()? totalSpent,
    int? Function()? yearOfBirth,
    String? Function()? code,
    String? Function()? name,
    String Function()? id,
    Locale Function()? locale,
    String? Function()? firstName,
    String? Function()? lastName,
    String? Function()? phoneNumber,
    Town? Function()? location,
    DateTime? Function()? lastLogin,
    bool? Function()? isAnonymous,
    String? Function()? email,
    Device? Function()? device,
    String? Function()? displayName,
    String? Function()? deviceToken,
    DateTime? Function()? registeredAt,
    ZipCode? Function()? zipCode,
    bool? Function()? isBanned,
    bool? Function()? isVerified,
    DateTime? Function()? verifiedAt,
    DateTime? Function()? bannedAt,
  }) {
    return Customer._(
      profile: profile == null
          ? this.profile as CustomerProfile?
          : profile() as CustomerProfile?,
      preferences: preferences == null
          ? this.preferences as CustomerPreferences?
          : preferences() as CustomerPreferences?,
      favoriteStores: favoriteStores == null
          ? this.favoriteStores as List<String>?
          : favoriteStores() as List<String>?,
      lastPurchaseDate: lastPurchaseDate == null
          ? this.lastPurchaseDate as DateTime?
          : lastPurchaseDate() as DateTime?,
      totalPurchases: totalPurchases == null
          ? this.totalPurchases as int?
          : totalPurchases() as int?,
      totalSpent: totalSpent == null
          ? this.totalSpent as double?
          : totalSpent() as double?,
      yearOfBirth: yearOfBirth == null
          ? this.yearOfBirth as int?
          : yearOfBirth() as int?,
      code: code == null ? this.code as String? : code() as String?,
      name: name == null ? this.name as String? : name() as String?,
      id: id == null ? this.id as String : id() as String,
      locale: locale == null ? this.locale as Locale : locale() as Locale,
      firstName: firstName == null
          ? this.firstName as String?
          : firstName() as String?,
      lastName:
          lastName == null ? this.lastName as String? : lastName() as String?,
      phoneNumber: phoneNumber == null
          ? this.phoneNumber as String?
          : phoneNumber() as String?,
      location: location == null ? this.location as Town? : location() as Town?,
      lastLogin: lastLogin == null
          ? this.lastLogin as DateTime?
          : lastLogin() as DateTime?,
      isAnonymous: isAnonymous == null
          ? this.isAnonymous as bool?
          : isAnonymous() as bool?,
      email: email == null ? this.email as String? : email() as String?,
      device: device == null ? this.device as Device? : device() as Device?,
      displayName: displayName == null
          ? this.displayName as String?
          : displayName() as String?,
      deviceToken: deviceToken == null
          ? this.deviceToken as String?
          : deviceToken() as String?,
      registeredAt: registeredAt == null
          ? this.registeredAt as DateTime?
          : registeredAt() as DateTime?,
      zipCode:
          zipCode == null ? this.zipCode as ZipCode? : zipCode() as ZipCode?,
      isBanned: isBanned == null ? this.isBanned as bool? : isBanned() as bool?,
      isVerified:
          isVerified == null ? this.isVerified as bool? : isVerified() as bool?,
      verifiedAt: verifiedAt == null
          ? this.verifiedAt as DateTime?
          : verifiedAt() as DateTime?,
      bannedAt: bannedAt == null
          ? this.bannedAt as DateTime?
          : bannedAt() as DateTime?,
    ) as Customer;
  }
}

enum Customer$ {
  profile,
  preferences,
  favoriteStores,
  lastPurchaseDate,
  totalPurchases,
  totalSpent,
  yearOfBirth,
  code,
  name,
  id,
  locale,
  firstName,
  lastName,
  phoneNumber,
  location,
  lastLogin,
  isAnonymous,
  email,
  device,
  displayName,
  deviceToken,
  registeredAt,
  zipCode,
  isBanned,
  isVerified,
  verifiedAt,
  bannedAt
}

class CustomerPatch {
  final Map<Customer$, dynamic> _patch = {};

  static CustomerPatch create([Map<String, dynamic>? diff]) {
    final patch = CustomerPatch();
    if (diff != null) {
      diff.forEach((key, value) {
        try {
          final enumValue = Customer$.values.firstWhere((e) => e.name == key);
          if (value is Function) {
            patch._patch[enumValue] = value();
          } else {
            patch._patch[enumValue] = value;
          }
        } catch (_) {}
      });
    }
    return patch;
  }

  Map<Customer$, dynamic> toPatch() => Map.from(_patch);

  Map<String, dynamic> toJson() {
    final json = <String, dynamic>{};
    _patch.forEach((key, value) {
      if (value != null) {
        if (value is DateTime) {
          json[key.name] = value.toIso8601String();
        } else if (value is List) {
          json[key.name] = value.map((e) => e?.toJson ?? e).toList();
        } else {
          json[key.name] = value?.toJson ?? value;
        }
      }
    });
    return json;
  }

  static CustomerPatch fromJson(Map<String, dynamic> json) {
    return create(json);
  }

  CustomerPatch withprofile(CustomerProfile? value) {
    _patch[Customer$.profile] = value;
    return this;
  }

  CustomerPatch withpreferences(CustomerPreferences? value) {
    _patch[Customer$.preferences] = value;
    return this;
  }

  CustomerPatch withfavoriteStores(List<String>? value) {
    _patch[Customer$.favoriteStores] = value;
    return this;
  }

  CustomerPatch withlastPurchaseDate(DateTime? value) {
    _patch[Customer$.lastPurchaseDate] = value;
    return this;
  }

  CustomerPatch withtotalPurchases(int? value) {
    _patch[Customer$.totalPurchases] = value;
    return this;
  }

  CustomerPatch withtotalSpent(double? value) {
    _patch[Customer$.totalSpent] = value;
    return this;
  }

  CustomerPatch withyearOfBirth(int? value) {
    _patch[Customer$.yearOfBirth] = value;
    return this;
  }

  CustomerPatch withcode(String? value) {
    _patch[Customer$.code] = value;
    return this;
  }

  CustomerPatch withname(String? value) {
    _patch[Customer$.name] = value;
    return this;
  }

  CustomerPatch withid(String value) {
    _patch[Customer$.id] = value;
    return this;
  }

  CustomerPatch withlocale(Locale value) {
    _patch[Customer$.locale] = value;
    return this;
  }

  CustomerPatch withfirstName(String? value) {
    _patch[Customer$.firstName] = value;
    return this;
  }

  CustomerPatch withlastName(String? value) {
    _patch[Customer$.lastName] = value;
    return this;
  }

  CustomerPatch withphoneNumber(String? value) {
    _patch[Customer$.phoneNumber] = value;
    return this;
  }

  CustomerPatch withlocation(Town? value) {
    _patch[Customer$.location] = value;
    return this;
  }

  CustomerPatch withlastLogin(DateTime? value) {
    _patch[Customer$.lastLogin] = value;
    return this;
  }

  CustomerPatch withisAnonymous(bool? value) {
    _patch[Customer$.isAnonymous] = value;
    return this;
  }

  CustomerPatch withemail(String? value) {
    _patch[Customer$.email] = value;
    return this;
  }

  CustomerPatch withdevice(Device? value) {
    _patch[Customer$.device] = value;
    return this;
  }

  CustomerPatch withdisplayName(String? value) {
    _patch[Customer$.displayName] = value;
    return this;
  }

  CustomerPatch withdeviceToken(String? value) {
    _patch[Customer$.deviceToken] = value;
    return this;
  }

  CustomerPatch withregisteredAt(DateTime? value) {
    _patch[Customer$.registeredAt] = value;
    return this;
  }

  CustomerPatch withzipCode(ZipCode? value) {
    _patch[Customer$.zipCode] = value;
    return this;
  }

  CustomerPatch withisBanned(bool? value) {
    _patch[Customer$.isBanned] = value;
    return this;
  }

  CustomerPatch withisVerified(bool? value) {
    _patch[Customer$.isVerified] = value;
    return this;
  }

  CustomerPatch withverifiedAt(DateTime? value) {
    _patch[Customer$.verifiedAt] = value;
    return this;
  }

  CustomerPatch withbannedAt(DateTime? value) {
    _patch[Customer$.bannedAt] = value;
    return this;
  }
}

@atreeon
Copy link
Owner

atreeon commented Dec 16, 2024

Hey @arrrrny I'm gonna try to take a look today or tomorrow. Bit of a backlog of work here but you have been on my mind!

@arrrrny
Copy link
Author

arrrrny commented Dec 16, 2024

Hi @atreeon take your time. I will create another PR for you to see where I am latest. I implemented an amazing patching mechanism, that I just tested and works great. the only issue with that is, I completely neglected the Generic, as I was not in need and I immediately needed a working version. I will show the example of whats new on that branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

SubclassFromJson not defined for Superclass
3 participants