I was trying to save in afterSave trigger with option silent: true. But it’s still causing beforeSave to trigger and thus causing infinite loop. I am on beta branch, I see silent save option in typescript definition but not in docs.
Would you mind to share the code that you are using?
Thanks for getting back @davimacedo .
Here is the problematic code.
Parse.Cloud.beforeSave( 'Post', async request =>
{
// Guards
protectWriteFields( request, [ 'createdBy', 'likesCount', 'commentsCount' ] );
protectWriteRow( request, 'user_post_write' );
// Create operation
if ( !request.object.id )
{
if ( !request.user )
{
throw new Parse.Error( Parse.Error.OPERATION_FORBIDDEN, 'Missing user' );
}
request.object.set( 'createdBy', request.user );
request.object.set( 'likeCount', 0 );
request.object.set( 'commentCount', 0 );
}
} );
Parse.Cloud.afterSave( 'Post', async request =>
{
request.object.set( 'likeCount', await request.object.relation( 'likes' ).query().count( { useMasterKey: true } ) );
request.object.set( 'commentCount', await request.object.relation( 'comments' ).query().count( { useMasterKey: true } ) );
request.object.save( null, { useMasterKey: true, silent: true} )
} );
The below code is actually a workaround, it’s passing signal in context if an update is required. But I was expecting that if I use the silent option in afterSave it should not trigger beforeSave.
Parse.Cloud.beforeSave( 'Post', async request =>
{
// Guards
protectWriteFields( request, [ 'createdBy', 'likesCount', 'commentsCount' ] );
protectWriteRow( request, 'user_post_write' );
if ( !request.object.id )
{
if ( !request.user )
{
throw new Parse.Error( Parse.Error.OPERATION_FORBIDDEN, 'Missing user' );
}
request.object.set( 'createdBy', request.user );
request.object.set( 'likeCount', 0 );
request.object.set( 'commentCount', 0 );
}
request.context.updateCount = request.object.op( 'likes' ) != undefined || request.object.op( 'comments' ) != undefined;
} );
Parse.Cloud.afterSave( 'Post', async request =>
{
if ( request.context.updateCount )
{
request.object.set( 'likeCount', await request.object.relation( 'likes' ).query().count( { useMasterKey: true } ) );
request.object.set( 'commentCount', await request.object.relation( 'comments' ).query().count( { useMasterKey: true } ) );
request.object.save( null, { useMasterKey: true } )
}
} );
I don’t think this silent object when saving an object exists. Where did you find it?
The way to go is something like what you are doing: creating a stop condition. But in your specific case, I don’t see the advantage on saving it using an after save trigger. Why don’t you set this properties on beforeSave?
In typescript type definition, including docs.
Because with beforesave I have no way to check that the object that is being added is already in comments/likes relation. In that case, the relation count will remain the same.
@davimacedo If you think I am wrong about that, feel free to share your solution.
And these fields are computed for livequery.
Yes. I got your point. Maybe that’s the only way.
I think the silent
option is a mistake in the typescript docs. Clients don’t get to decide whether to skip a cloud trigger or not by passing a parameter, that could be very problematic and lead to security implications.
Generally, I add this to the save hooks if I’m calling save
in afterSave:
Parse.Cloud.beforeSave('TestObject', () => {
}, {
skipWithMasterKey: true
})
Parse.Cloud.afterSave('TestObject', () => {
}, {
skipWithMasterKey: true
})
Also count
operation is not recommended. I would use increment
.
First of all many thanks @dblythy for replying.
Completely agree, I was thinking the same when I saw this option.
Great idea, but doesn’t skip for me. Not completely sure why?
I have no way to check that the object that is being added is already in comments/likes relation. So that’s why using count. If you disagree, can you share your solution?