parse-community / Parse-SDK-Flutter

The Dart/Flutter SDK for Parse Platform
https://parseplatform.org
Apache License 2.0
569 stars 185 forks source link

_TypeError on addRelation #999

Open engeen opened 1 month ago

engeen commented 1 month ago

New Issue Checklist

Issue Description

Having:

Order Class

class Order extends ParseObject implements ParseCloneable {
  Order() : super(_keyTableName);
  Order.clone() : this();

  @override
  clone(Map map) => Order.clone()..fromJson(Map<String, dynamic>.from(map));

  static const String _keyTableName = 'Order';
  static const String keyInitialProduct = 'initial_product';
  static const String keyProduct = 'product';
  static const String keyPrice = 'price';
  static const String keyCertainDate = 'certain_date';
  static const String keyState = 'state';
  static const String keyAccount = 'account';

  Product? get initialProduct => get(keyInitialProduct);
  set initialProduct(Product? initialProduct) =>
      set(keyInitialProduct, initialProduct);

  Product? get product => get(keyProduct);
  set product(Product? product) => set(keyProduct, product);

  Account? get account => get(keyAccount);
  set account(Account? account) => set(keyAccount, account);

  DateTime? get certainDate => get<DateTime?>(keyCertainDate);
  set certainDate(DateTime? certainDate) =>
      set<DateTime?>(keyCertainDate, certainDate);

}

Order Schema

{
  "className": "Order",
  "fields": {
    "objectId": {
      "type": "String"
    },
    "createdAt": {
      "type": "Date"
    },
    "updatedAt": {
      "type": "Date"
    },
    "ACL": {
      "type": "ACL"
    },
    "initial_product": {
      "type": "Pointer",
      "targetClass": "Product",
      "required": false
    },
    "receivers": {
      "type": "Relation",
      "targetClass": "Contact",
      "required": false
    },
    "price": {
      "type": "Number",
      "required": false
    },
    "certain_date": {
      "type": "Date",
      "required": false
    },
    "state": {
      "type": "String",
      "required": true,
      "defaultValue": "draft"
    },
    "account": {
      "type": "Pointer",
      "targetClass": "Account",
      "required": true
    },
    "product": {
      "type": "Pointer",
      "targetClass": "Product",
      "required": false
    }
  },
  "classLevelPermissions": {
    "find": {
      "*": true
    },
    "count": {
      "*": true
    },
    "get": {
      "*": true
    },
    "create": {
      "*": true
    },
    "update": {
      "*": true
    },
    "delete": {
      "*": true
    },
    "addField": {
      "*": true
    },
    "protectedFields": {
      "*": []
    }
  },
  "indexes": {
    "_id_": {
      "_id": 1
    }
  }
}

Contact class

class Contact extends ParseObject implements ParseCloneable {
  Contact() : super(_keyTableName);
  Contact.clone() : this();

  /// Mimic a clone due to Flutter not using reflection
  @override
  clone(Map map) => Contact.clone()..fromJson(Map<String, dynamic>.from(map));

  static const String _keyTableName = 'Contact';
  static const String keyName = 'name';
  static const String keyPhone = 'phone';
  static const String keyAddress = 'address';
  static const String keyBirthday = 'birthday';
  static const String keyAccount = 'account';

  String? get name => get<String?>(keyName);
  set name(String? name) => set<String?>(keyName, name);

  String? get phone => get<String?>(keyPhone);
  set phone(String? phone) => set<String?>(keyPhone, phone);

  String? get address => get<String?>(keyAddress);
  set address(String? address) => set<String?>(keyAddress, address);

  DateTime? get birthday => get<DateTime?>(keyBirthday);
  set birthday(DateTime? birthday) => set<DateTime?>(keyBirthday, birthday);

  Account? get account => get<Account?>(keyAccount);
  set account(Account? account) => set<Account?>(keyAccount, account);

}

Steps to reproduce

      List<Contact> contactsObjects = (result as Set)
          .map((key) => Contact()..objectId = key.value)
          .toList();

      var order = widget.order!;
      order.addRelation('receivers', contactsObjects);

Actual Outcome

Screenshot 2024-06-05 at 19 34 45

_TypeError (type '_Set' is not a subtype of type 'Set' in type cast)

_ParseRelation.preformRelationOperation (/Users/yuriy/.pub-cache/hosted/pub.dev/parse_server_sdk-6.4.0/lib/src/objects/parse_relation.dart:96) _ParseOperation._handelRelationOperation (/Users/yuriy/.pub-cache/hosted/pub.dev/parse_server_sdk-6.4.0/lib/src/objects/parse_operation/parse_operation.dart:159) _ParseOperation._handelOperation (/Users/yuriy/.pub-cache/hosted/pub.dev/parse_server_sdk-6.4.0/lib/src/objects/parse_operation/parse_operation.dart:111) _ParseOperation.maybeMergeWithPrevious (/Users/yuriy/.pub-cache/hosted/pub.dev/parse_server_sdk-6.4.0/lib/src/objects/parse_operation/parse_operation.dart:90) ParseBase.set (/Users/yuriy/.pub-cache/hosted/pub.dev/parse_server_sdk-6.4.0/lib/src/objects/parse_base.dart:250) ParseObject.addRelation (/Users/yuriy/.pub-cache/hosted/pub.dev/parse_server_sdk-6.4.0/lib/src/objects/parse_object.dart:571) _SelectReceiversState._selectContacts (/Users/yuriy/dev/gf/gfapp/lib/widgets/order_select_receivers.dart:83)

(Unknown Source:0) ### Expected Outcome Adding relation ### Environment Parse Flutter SDK - SDK version: `8.0` - Flutter version: `3.19.6` - Dart version: `3.3.4` - Operating system version: `MacOS Sonoma 14.4.1` Server - Parse Server version: `4.5.0` ### Logs Debug console: _ParseRelation.preformRelationOperation (package:parse_server_sdk/src/objects/parse_relation.dart:96:58)
parse-github-assistant[bot] commented 1 month ago

Thanks for opening this issue!

mbfakourii commented 1 month ago

Did you register the model classes with registeredSubClassMap?

engeen commented 1 month ago

@mbfakourii , yes, sure.

But, here is an update. The problem is gone if create new one Order instance:

      List<Contact> contactsObjects = (result as Set)
          .map((key) => Contact()..objectId = key.value)
          .toList();

      var order = Order()..set('objectId', widget.order!.objectId);
      order.addRelation('receivers', contactsObjects);