#Offline transactions testing
6 messages · Page 1 of 1 (latest)
Also be sure to play around with the example app
Thanks, I will take a look to the example app tomorrow. My tests are quite simple, I just don't refetch the collection on success and update the cache manually.
Collection
export const organizationCollection = createCollection(
queryCollectionOptions({
queryClient,
queryKey: organizationQueries.getAll().queryKey,
queryFn: organizationQueries.getAll().queryFn,
getKey: (organization) => organization.id,
onUpdate: async ({ transaction }) => {
const responses = await Promise.all(
transaction.mutations.map((mutation) =>
organizationMutations.updateOne({
id: mutation.original.id,
changes: mutation.changes
})
)
);
return { refetch: false };
}
})
);
Offline executor
export const organizationOffline = startOfflineExecutor({
collections: {
organization: organizationCollection
},
mutationFns: {
syncOrganizations: async ({ transaction, idempotencyKey }) => {
for (const mutation of transaction.mutations) {
switch (mutation.type) {
case 'update': {
const response = await organizationMutations.updateOne({
id: mutation.original.id,
changes: mutation.changes
});
// Server directly return data
if (response.success && response.data) {
organizationCollection.utils.writeBatch(() => {
response.data.forEach((serverItem) => {
organizationCollection.utils.writeUpdate(serverItem);
});
});
// Manually update cache
queryClient.setQueryData(['organization'], (oldData) => {
if (!oldData) return response.data;
return oldData.map(org => {
const updated = response.data.find(item => item.id === org.id);
return updated || org;
});
});
}
break;
}
}
}
}
},
onLeadershipChange: (isLeader) => {
if (!isLeader) {
console.warn('Running in online-only mode (another tab is the leader)');
}
}
});
Component
export default function Test() {
const { data: orgs } = useLiveQuery((q) =>
q.from({ org: organizationCollection })
);
async function testOfflineUpdate(orgId) {
const tx = organizationOffline.createOfflineTransaction({
mutationFnName: 'syncOrganizations',
autoCommit: true
});
tx.mutate(() => {
organizationCollection.update(orgId, (draft) => {
const newBrandName = new Date().toLocaleTimeString();
draft.brandName = newBrandName;
});
});
}
return (
<button type="button" onClick={() => testOfflineUpdate(orgs[0].id)}>
Test Update Offline
</button>
);
}
I did a deep dive into the example todo.
Can someone explain to me what is the point of this condition?
if (typeof actions.toggleTodo === `function`)
From TodoDemo.tsx,
https://github.com/TanStack/db/blob/main/examples/react/offline-transactions/src/components/TodoDemo.tsx
const handleToggleTodo = async (id: string) => {
try {
setError(null)
if (typeof actions.toggleTodo === `function`) {
await actions.toggleTodo(id)
} else {
actions.toggleTodo(id)
}
} catch (err) {
setError(err instanceof Error ? err.message : `Failed to toggle todo`)
}
}