feat: further work on stores
Some checks failed
TrafficCue Server CI / check (push) Has been cancelled
TrafficCue Server CD / build (push) Has been cancelled

This commit is contained in:
2025-09-26 19:49:39 +02:00
parent ef3debcdb3
commit 8d2eb1d9da
3 changed files with 61 additions and 146 deletions

View File

@ -1,5 +1,6 @@
import z from "zod";
import type { StoreType } from "./entities/Stores";
import { Store, type StoreType } from "./entities/Stores";
import type { User } from "./entities/User";
export const locationStore = z.object({
lat: z.number().min(-90).max(90),
@ -42,3 +43,46 @@ export const storeTypes: Record<StoreType, z.ZodSchema> = {
vehicle: vehicleStore,
route: routeStore,
};
export const SyncPayload = z.object({
changes: z.array(z.object({
id: z.uuid(),
operation: z.enum(["create", "update", "delete"]),
data: z.string(),
modified_at: z.string().refine(val => !isNaN(Date.parse(val)), { message: "Invalid date" })
})),
stores: z.array(z.object({
id: z.uuid(),
modified_at: z.string().refine(val => !isNaN(Date.parse(val)), { message: "Invalid date" })
}))
})
export type SyncPayload = z.infer<typeof SyncPayload>;
export async function sync(payload: SyncPayload, user: User) {
const changes: Store[] = [];
// Apply changes from client
for(const change of payload.changes) {
const store = await Store.findOneBy({ id: change.id });
if(!store) continue;
if(store.user.id !== user.id) {
// Not the owner of this store
changes.push(store); // Send back the store to the client to overwrite their changes
continue;
}
store.data = change.data;
store.modified_at = new Date(change.modified_at);
await store.save();
}
// Find stores that are out of date on the client
const allStores = await Store.findBy({ user: { id: user.id } }); // TODO: include friends' public stores, TODO: use SQL query to only get modified stores
for(const store of allStores) {
const clientStore = payload.stores.find(s => s.id === store.id);
if(!clientStore || new Date(clientStore.modified_at) < store.modified_at) {
changes.push(store); // Client doesn't have this store or it's out of date
}
}
return { changes };
}