Skip to content

Be able to run the afterFind trigger automatically after saving object #7064

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

Closed
AurelienVasseur opened this issue Dec 12, 2020 · 6 comments
Closed
Labels
type:question Support or code-level question

Comments

@AurelienVasseur
Copy link

Is your feature request related to a problem? Please describe.

I would like to be able to execute an afterFind trigger after saving an object on database.

For example, if we change the object before saving it, we will receive these changes on the app automatically.
But maybe in the app we don't want them.

This situation appears when an object don't have the same interface between the app and the database.

  • on beforeSave we adapt / change the object for the database
  • on afterFind we adapt / change the object for the application

So currently, to fix my problem I need to do something like that:

await object.save();
await object.fetch();

So I think it's not good in term of optimization.
And with that I always run the beforeFind trigger while I don't want.

I'm not a Parse expert so there is maybe currently a way to do that (or to do something on the same spirit).
If this is the case please say it to me.

Describe the solution you'd like

  • A solution can be to specify that during the save call as an option
object.save( { runAfterFind: true } );
  • It can also be useful to be able to specify that in the beforeSave trigger as a third parameter
Parse.Cloud.beforeSave("myClass", async () => {
   // some code ....
}, {
   runAfterFind: true
});

An other way to see the problem can be: How can I execute a code which will change the returned value on a beforeSave trigger?

Thanks you in advance 😃

@mtrezza
Copy link
Member

mtrezza commented Dec 12, 2020

Thanks for suggesting.

I don't fully understand your proposal, but this:

I would like to be able to execute an afterFind trigger after saving an object on database.

sounds much like an XY problem. It seems as if you were looking for a solution to a problem that results out of your current app concept. Maybe take another look at that underlying app concept.

If you think your current concept is valid, can you please elaborate your use case with a simple 1. - 2. - 3. steps list in which you describe the suggested feature?

@AurelienVasseur
Copy link
Author

AurelienVasseur commented Dec 12, 2020

@mtrezza Thanks for your feedback! I will describe a case similar to mine to be more understable 😉

The use case is the following:

  1. In my application (so in the user side), I have the class MyClass:
class MyClass {
   attribute_1: any
   attribute_2: any
}
  1. In my database I have these tables 2 tables:
table myClass {
   attribute_1: any
}

table myHiddenClass {
   myClassId: string
   attribute_2: any
}
  1. So, as we can see, on the application side (user side) myHiddenClass doesn't exist. So to deal with that I have to work with triggers.
// I simplified them to go to the essentiel point 

Parse.Cloud.beforeSave("myClass", async (request) => {
   // get myHiddenClass object linked to the object
   let query = new Parse.Query("myHiddenClass");
   query.equalTo("myClassId", request.object.id);
   let myHiddenClass: Parse.Object = await query.find();
   // update
   myHiddenClass.set("attribute_2", request.object.get("attribute_2"));
   await myHiddenClass.save();
   // remove attribute_2 from myClass object
   request.object.unset("attribute_2")  // or set his value to null
});

Parse.Cloud.afterFind("myClass", async (request) => {
   // get myHiddenClass object linked to the object
   let query = new Parse.Query("myHiddenClass");
   query.equalTo("myClassId", request.object.id);
   let myHiddenClass: Parse.Object = await query.find();
   // add attribute_2 value in the myClass object
   request.object.set("attribute_2", myHiddenClass.get("attribute_2");

   return request.object
});

  1. Currently, if we do a myClass.save() in the application it will set our object with his database value, but it's not what we want. So to 'solve' the problem I need to do a second request:
// application - user side

await myClass.save();
await myClass.fetch();   

So, my objective is to find a solution to be able to do the same without the fetch request.


My case is more complex but this is the same logic.

To rephrase my question: Is there a way to describe how the object should be retrieve from the database / serve side to the application / user side after a save request?

Previously I mentioned the fact that it can be useful to be able to run the afterFind trigger after a save request but it was not an error of understanding. I think it's logic to say that the role of the afterFind trigger can be to do that.
But if you have a solution without using this trigger I will be happy too 😄


Is my situation / problem more understable?

Thanks in advance 👍

@mtrezza
Copy link
Member

mtrezza commented Dec 18, 2020

Thanks for providing more details, I think I understand what you are trying to do. I never came across the use case of unilateral class synthesis. Thumbs up for creativity 🤓

Currently, if we do a myClass.save() in the application it will set our object with his database value, but it's not what we want. So to 'solve' the problem I need to do a second request...

It seems you decided to solve an original problem P1 with a solution S1, and while trying to implement solution S1, you came across an inherent problem P2 for which you are now trying to find a solution S2.

Maybe it helps to discuss P1 to see whether there is a solution Sx in which you don't face problem P2. For example, why should myHiddenClass be hidden and why are you trying to synthesize a class? If it is to hide certain fields from the client, maybe you want to look into Class Level Permissions and the Parse Server Option protectedFields.

@AurelienVasseur
Copy link
Author

@mtrezza Thanks for your feeback!

I understand what do you mean but I'm not sure that this is going to solve the problem. It can maybe be a solution for this case but I think we can have the same problems with other cases.

My current problem is the following: I totally want to dissociate my server / backend architecture from my application / frontend architecture.
So, in my application I want to have a data structure / classes implementation "optimized" for the application without caring about how the server manages to save data well (as well understand "optimized" for the database).
And on the other side, in the server I want to be able to make the "translation" (by the triggers) between the application classes architecture and the database's tables.

If we take the example of a classic REST API, we can do that. The application side just wants to speak with the server without caring about the database implementation.

So my current problem / issue here is not to find a good way to build my classes architecture to feat with Parse, it's just to say that I think it can be very good to allow developpers to have a flexibility on that.

If a take my previous example, when I do a save request I don't want to have as result what was stored in database. Maybe in other case I would like to have it, but I want to have the choice.

After that we can imagine many dev bahaviors:

  • Dev 1: "Me I want to build my application, my classes and database architectures to feat and to be optimized for Parse" -> the choice of optimization
  • Dev 2: "Me I want to use Parse but I don't want to build my app on a certain way because of Parse, I want to adapt Parse for my application and my current architecture" -> the choice of flexibility and adaptability

I hope that this is clear and understable 😅


My proposition for this issue is to allow devs to define how they want to "received" data from the server after a save.
I spoke about the afterFind trigger because it doesn't seem illogical to me, but it was just a proposition.
We can imagine for example to be able to define a method, or another trigger, to do that.


To conclude, I would say that this issue is just part of a larger one:

Allow developpers to have a huge flexibility with Parse, even if their architecture are not perfectly optimized


I will be happy to read your feedback 😉

@mtrezza
Copy link
Member

mtrezza commented Feb 19, 2021

I'm closing this as it seems to be in an early stage of discussion about Parse Server architecture.

Discussions are better suited in our Community Forum while we expect feature requests on GitHub to be in a more advanced conceptual stage.

Feel free to comment if you have any questions and we can re-open this issue.

@mtrezza mtrezza closed this as completed Feb 19, 2021
@mtrezza mtrezza added type:question Support or code-level question and removed 🔧 troubleshooting labels Jul 11, 2021
@dblythy
Copy link
Member

dblythy commented Mar 21, 2022

Hi @AurelienVasseur, after #7839 is merged, you will be able to use req.object.unset in afterSave, and the keys that you unset won't be returned to the client, and the field will still be saved to the database.

Let's say you have the field "secret" that you want the server to generate when a new object is created, and you don't want to allow users to edit that field:

 Parse.Cloud.beforeSave('TestObject', ({ object }) => {
      if (!object.existed()) {
        object.set('secret', true);
        return object;
      }
      object.revert('secret');
    });

    Parse.Cloud.afterSave('TestObject', ({ object }) => {
      object.unset('secret');
    });

    Parse.Cloud.beforeFind(
      'TestObject',
      ({ query }) => {
        query.exclude('secret');
      },
      {
        skipWithMasterKey: true,
      }
    );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:question Support or code-level question
Projects
None yet
Development

No branches or pull requests

3 participants