Skip to content

Cart with versioned migration

Evolve a persisted cart payload safely.

Cart with versioned migration#

import { createPersistedModel, signal } from "@kamod-ch/signals";

type CartItem = { sku: string; quantity: number; currency: "CHF" | "EUR" };
type CartSnapshot = { items: CartItem[] };

const isCartSnapshot = (value: unknown): value is CartSnapshot =>
  typeof value === "object" && value !== null && Array.isArray((value as CartSnapshot).items);

export const CartModel = createPersistedModel(
  {
    key: "cart",
    storage: "local",
    version: 2,
    migrate(snapshot, fromVersion): CartSnapshot {
      if (fromVersion === 0 || fromVersion === 1) {
        const old = snapshot as { items: Array<{ sku: string; quantity: number }> };
        return { items: old.items.map((item) => ({ ...item, currency: "CHF" })) };
      }
      return snapshot as CartSnapshot;
    },
    validate: isCartSnapshot,
    select: (model): CartSnapshot => ({ items: model.items.value }),
    apply(model, snapshot) {
      model.items.value = snapshot.items;
    },
  },
  () => {
    const items = signal<CartItem[]>([]);
    return {
      items,
      add(sku: string) {
        items.value = [...items.value, { sku, quantity: 1, currency: "CHF" }];
      },
    };
  },
);