GetDutchie / brick

An intuitive way to work with persistent data in Dart

Home Page:https://getdutchie.github.io/brick/#/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to send the child relation to the server?

hortigado opened this issue · comments

Hello, this is more than an error, it is a query. How could the child relationship be sent to the server? This works locally, but only the main model is sent to the server and I think it is correct because I am establishing that only the id is put on pizza_ids, but there would be a way to make it automatic. This speeds up the sending of data a lot.
For better understanding I give an example. In the image you can see how I create a Customer item and a Pizza item as a child at the same time. I want the two data to be uploaded to the server but each one to its respective table in the parent item (Customer) only the id of the child item (pizza) is saved and vice versa in the child item the id of the parent is saved.
Could you help me with an example of how to do it if possible. Thanks
image
image

#115
my query is similar to this ticket

@hortigado that related ticket is exactly right. If you want to send a full payload (not just the id), simply remove the @OfflineFirst annotation.

The full association is saved to the association's table in SQLite on upsert. When the association is sent to REST while using @OfflineFirst, only the key value of your where argument is sent.

@tshedor Thanks I tried removing the @OfflineFirst and leaving only the @Rest; but when doing them it is saved correctly locally but nothing is sent to the server, not even the Customer item.

@hortigado did you regenerate the adapter? Does your CustomerRequestTransformer have an upsert field?

@tshedor Yes, I am using a remote server (Appwrite) not the local of the example, I don't know if this could also cause a problem

class CustomerRequestTransformer extends RestRequestTransformer {
  // A production code base would not forward to another operation
  // but for testing this is convenient
  @override
  RestRequest get delete => get;

  @override
  RestRequest get get {
    if (query?.where != null) {
      final byId = Where.firstByField('id', query?.where);
      print(byId.toString());
      // member endpoint
      if (byId?.value != null) {
        return RestRequest(
            url:
                "/databases/6436b61c1e67e1fe6d5d/collections/649531713e0d37be7da4/documents/${byId!.value}",
            topLevelKey: "documents");
      }
    }
    return RestRequest(
        url:
            '/databases/6436b61c1e67e1fe6d5d/collections/649531713e0d37be7da4/documents',
        topLevelKey: "documents");
  }

  // A production code base would not forward to another operation
  // but for testing this is convenient
  @override
  RestRequest get upsert {
    final id = query?.providerArgs['id'];
    final method = query?.action == QueryAction.update ? "PATCH" : "POST";
    final url = method == "PATCH"
        ? '/databases/6436b61c1e67e1fe6d5d/collections/649531713e0d37be7da4/documents/$id'
        : '/databases/6436b61c1e67e1fe6d5d/collections/649531713e0d37be7da4/documents';

    return RestRequest(
      supplementalTopLevelData: <String, String>{
        "documentId": id!.toString(),
      },
      method: method,
      url: url,
      topLevelKey: "data",
    );
  }

  RestRequest get update {
    final id = query?.providerArgs['id'];

    return RestRequest(
      supplementalTopLevelData: <String, String>{
        "documentId": id!.toString(),
      },
      method: "PATCH",
      url:
          '/databases/6436b61c1e67e1fe6d5d/collections/649531713e0d37be7da4/documents',
      topLevelKey: "data",
      /*  headers: <String, String>{
            "documentId": id,
          } */
    );
  }

  const CustomerRequestTransformer(Query? query, RestModel? instance)
      : super(query, instance);
}
Future<Customer> _$CustomerFromRest(Map<String, dynamic> data,
    {required RestProvider provider,
    OfflineFirstWithRestRepository? repository}) async {
  return Customer(
      id: data['\$id'] as String?,
      firstName: data['first_name'] as String?,
      lastName: data['last_name'] as String?,
      pizzas: await Future.wait<Pizza>(data['pizzas']
              ?.map((d) => PizzaAdapter()
                  .fromRest(d, provider: provider, repository: repository))
              .toList()
              .cast<Future<Pizza>>() ??
          []));
}

Future<Map<String, dynamic>> _$CustomerToRest(Customer instance,
    {required RestProvider provider,
    OfflineFirstWithRestRepository? repository}) async {
  return {
    'first_name': instance.firstName,
    'last_name': instance.lastName,
    'pizzas': instance.pizzas!.first.id
  };
}

@hortigado I've created a mini example to help illustrate what you'll need to do. When running the server, you'll see upsert request body logged.

Based on what you have in the latest adapter code, your adapter wasn't regenerated for toRest. It looks like there's an override somewhere:

    'pizzas': instance.pizzas!.first.id

Can you supply your model code?

@tshedor Thanks for the example, I had already tried as it is in the example and it didn't work for me. Now I tried again and it works 100%.
Thank you if I have another question I open a new issue