Schreiben & offline
Mit demselben Modell schreiben
Abschnitt betitelt „Mit demselben Modell schreiben“const { id } = await db.task.create({ data: { title: "Ship it", column: { connect: columnId } },});
await db.task.update({ where: { id }, data: { done: true } });await db.task.upsert({ where: { id }, create: { title: "A" }, update: { title: "B" } });await db.task.delete({ where: { id } });
await db.column.update({ where: { id: columnId }, data: { tasks: { connect: [a, b], disconnect: [c] } },});
// Mehrere Schreibvorgänge, ein Logeintrag, alles oder nichtsawait db.$transaction([ db.task.update({ where: { id: a }, data: { position: 2 } }), db.task.update({ where: { id: b }, data: { position: 1 } }),]);create schlägt fehl, wenn die ID existiert; update schlägt fehl, wenn die Zeile fehlt; upsert wählt innerhalb der Engine-Transaktion, kann also nicht racen.
Schreibvorgänge werden optimistisch angewendet, warten offline in einer IndexedDB-Outbox und resolven zu { id, status: "applied" | "queued" }. Einen Schreibvorgang, den die Engine während eines Hintergrund-Flushs endgültig ablehnt, erreicht onWriteRejected.
Wiederholungen werden anhand der Client-Transaktions-ID ohne Altersgrenze dedupliziert. Die Belege bleiben bei Snapshots, Logbereinigung und Wiederherstellung aus R2 erhalten. Jeder Beleg speichert eine zufällige ID, die Sequenznummer und den Zeitpunkt, solange der Workspace besteht. Der Hash der Operationen wird nach der halben Aufbewahrungsdauer entfernt, standardmäßig nach 15 Tagen. Bis dahin wird dieselbe ID mit anderen Operationen abgelehnt; danach bestätigt sie die ursprüngliche Transaktion, ohne einen weiteren Schreibvorgang auszuführen.
Bei einem Upgrade oder einer Wiederherstellung aus einem Zustand mit gelöschten Belegen bleibt eine feste Zeitgrenze für fehlende Belege bestehen. Eine unbekannte Wiederholung, deren ursprünglicher issuedAt-Wert auf oder vor dieser Grenze liegt, wird mit retry_expired (HTTP 410) abgelehnt und über onWriteRejected gemeldet. Die App kann sie als neuen Schreibvorgang erneut senden. Die Grenze verschiebt sich nicht mit der Zeit.
Verknüpfte Zeilen
Abschnitt betitelt „Verknüpfte Zeilen“Verknüpfte Zeilen können zusammen mit der Zeile angelegt werden, die sie braucht:
await db.board.create({ data: { name: "Launch", columns: { create: [{ name: "Todo", position: 1, tasks: { create: { title: "Ship" } } }] }, },});
await db.column.create({ data: { name: "Solo", board: { create: { name: "New board" } } } });Es ist eine Transaktion, so geordnet, dass jede Zeile existiert, bevor etwas darauf zeigt, und ein Fehler rollt den ganzen Baum zurück. Die Typen folgen jeder Ebene.
Viele Zeilen schreiben
Abschnitt betitelt „Viele Zeilen schreiben“const { count } = await db.task.updateMany({ where: { done: true }, data: { archived: true } });await db.task.deleteMany({ where: { columnId: null } });Die Engine ermittelt innerhalb der Transaktion, welche Zeilen passen, und loggt die Zeilen statt des Filters. Ein Replay muss ändern, was das Original geändert hat, und einen Filter später erneut auszuführen kann das nicht versprechen. Ein Bulk-Write erreicht nur Zeilen, die der Aufrufer lesen darf, und führt die Zeilenregeln für update und delete weiterhin pro Zeile aus.
Jede passende Zeile wird in einer Transaktion geschrieben, egal wie viele es sind: der Write committet ganz oder gar nicht, und eine von einer Regel abgelehnte Zeile rollt alles zurück. count ist die Zahl der geschriebenen Zeilen.
Wie Einzelzeilen-Schreibvorgänge werden Bulk-Writes sofort auf den Cache angewendet und offline eingereiht. Der Cache ändert die Zeilen, die er hält und die sicher passen; eine Zeile, deren Treffer von einer Relation oder von einem Feld abhängt, das der Cache nicht hält, wartet auf die Engine. Die Engine wertet den Filter aus, wenn der Schreibvorgang sie erreicht, ein offline eingereihter gilt also für die Zeilen, die dann passen. Eingereiht ist das Ergebnis { count, queued: true }.