Zum Inhalt springen

Schreiben & offline

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 nichts
await 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.

Retries werden über die Client-Transaktions-ID dedupliziert. Durable Receipts überleben Snapshots, Logbereinigung und Wiederherstellung aus R2, ein früher angewendeter Request wird also bestätigt, ohne ihn erneut anzuwenden. Dieselbe ID mit anderen Operationen wiederzuverwenden wird abgelehnt.

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 einer Ebene; tiefere Verschachtelung prüft die Engine.

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.

Bis zu 1.000 passende Zeilen committen als eine Transaktion. Darüber schreibt der Client Stapel von 1.000 in ID-Reihenfolge, jeder seine eigene Transaktion, bis der Filter erschöpft ist; count ist die Summe. Schlägt ein Stapel fehl, sagt BulkWriteError.written, wie viele Zeilen die früheren Stapel geändert haben, und derselbe Aufruf erneut ausgeführt macht mit dem weiter, was noch passt.

Anders als Einzelzeilen-Schreibvorgänge werden Bulk-Writes nicht optimistisch angewendet und nicht offline eingereiht: Welche Zeilen passen, ist die Antwort der Engine, nicht des Caches.