Open duckbytes opened 1 year ago
@duckbytes, thank you for opening this issue. I'll review this with our team and get a reply back soon!
I'm having a hard time tracing through the case where a deletion can result in this behavior. I assume your code is landing us into this return
line that filters out "irrelevant" operations. But, I'm not seeing how at the moment.
Can you show us the code use to create, update, and delete the record?
Does the behavior differ based on whether the userId
provided to the condition is a string
, null
, or undefined
?
Hi @svidgen here is the code that I use to create and delete records:
async function addAssignee(user, role) {
setIsPosting(true);
try {
const assignee = await DataStore.query(models.User, user.id);
const task = await DataStore.query(models.Task, props.taskId);
if (!assignee || !task)
throw new Error(
`Can't find assignee or task: ${props.taskId}, userId: ${user.id}`
);
const result = await DataStore.save(
new models.TaskAssignee({
assignee,
task,
role,
tenantId,
})
);
if (role === userRoles.rider) {
const status = await determineTaskStatus(
{
...task,
},
[result]
);
await DataStore.save(
models.Task.copyOf(task, (updated) => {
updated.status = status;
if (assignee.riderResponsibility)
updated.riderResponsibility =
assignee.riderResponsibility;
})
);
if (
task.status === tasksStatus.new &&
status === tasksStatus.active
) {
dispatch(displayInfoNotification("Task moved to ACTIVE"));
}
}
setState({ ...state, [result.id]: result });
setIsPosting(false);
} catch (error) {
console.log(error);
setIsPosting(false);
dispatch(displayErrorNotification(errorMessage));
}
}
async function deleteAssignment(assignmentId) {
setIsDeleting(true);
try {
if (!assignmentId) throw new Error("Assignment ID not provided");
const existingTask = await DataStore.query(
models.Task,
props.taskId
);
if (!existingTask) throw new Error("Task doesn't exist");
const existingAssignment = await DataStore.query(
models.TaskAssignee,
assignmentId
);
if (existingAssignment) await DataStore.delete(existingAssignment);
const status = await determineTaskStatus(
existingTask,
Object.values(_.omit(state, assignmentId)).filter(
(a) => a.role === userRoles.rider
)
);
let riderResponsibility = existingTask.riderResponsibility;
let isRiderUsingOwnVehicle = existingTask.isRiderUsingOwnVehicle;
if (
existingAssignment &&
existingAssignment.role === userRoles.rider
) {
const riders = Object.values(state)
.filter(
(a) =>
a.role === userRoles.rider && a.id !== assignmentId
)
.map((a) => a.assignee);
if (riders.length > 0) {
const rider = riders[riders.length - 1];
if (rider && rider.riderResponsibility) {
riderResponsibility = rider.riderResponsibility;
}
} else {
riderResponsibility = null;
isRiderUsingOwnVehicle = 0;
}
}
await DataStore.save(
models.Task.copyOf(existingTask, (updated) => {
updated.status = status;
updated.riderResponsibility = riderResponsibility;
updated.isRiderUsingOwnVehicle = isRiderUsingOwnVehicle;
})
);
setState((prevState) => _.omit(prevState, assignmentId));
setIsDeleting(false);
} catch (error) {
console.log(error);
setIsDeleting(false);
dispatch(displayErrorNotification(errorMessage));
}
}
There is some extra stuff in there that probably isn't relevant, but the part that queries and deletes the item, which aren't being responded to in the observeQuery is pretty simple:
const existingAssignment = await DataStore.query(
models.TaskAssignee,
assignmentId
);
if (existingAssignment) await DataStore.delete(existingAssignment);
and this is the main code for creating a record:
const assignee = await DataStore.query(models.User, user.id);
const task = await DataStore.query(models.Task, props.taskId);
if (!assignee || !task)
throw new Error(
`Can't find assignee or task: ${props.taskId}, userId: ${user.id}`
);
const result = await DataStore.save(
new models.TaskAssignee({
assignee,
task,
role,
tenantId,
})
);
I don't do any updates to these records, only create and delete them.
assignee
is a non-nullable field. I'm not sure if passing in null or undefined makes a difference, it would be difficult to test it properly. I did add an extra line though if (!whoami) return;
so that it doesn't set up the observer until whoami.id is definitely defined. The behaviour is the same though.
Before opening, please confirm:
JavaScript Framework
React Native
Amplify APIs
Authentication, GraphQL API, DataStore
Amplify Categories
auth, api
Environment information
Describe the bug
When using observeQuery with a nested field predicate, it does not respond to deletions. It seems to work fine with no predicates, or predicates on basic fields.
Expected behavior
I expect observeQuery to always respond to deletions.
Reproduction steps
Initialise a DataStore amplify project. Use optimistic concurrency and cognito for auth.
I use ExpoSQLiteAdapter for storageAdapter, but it seems to happen on default too.
Code Snippet
For example I have this model:
and I want an observer to return all assignments of a particular role for the currently signed in user:
The above code does not respond to deletion events. However if I remove
a.assignee.id.eq(whoami?.id),
then it starts to respond again.Log output
Manual configuration
No response
Additional configuration
No response
Mobile Device
Android Emulator: Samsung_Galaxy_S8_API_30
Mobile Operating System
No response
Mobile Browser
No response
Mobile Browser Version
No response
Additional information and screenshots