Schrijven & offline
Schrijven met hetzelfde model
Section titled “Schrijven met hetzelfde model”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] } },});
// Meerdere schrijfacties, één logregel, alles of nietsawait db.$transaction([ db.task.update({ where: { id: a }, data: { position: 2 } }), db.task.update({ where: { id: b }, data: { position: 1 } }),]);create faalt als de id bestaat; update faalt als de rij ontbreekt; upsert kiest binnen de transactie van de engine, dus het kan niet racen.
Schrijfacties worden optimistisch toegepast, wachten offline in een IndexedDB-outbox en resolven naar { id, status: "applied" | "queued" }. Een schrijfactie die de engine tijdens een achtergrondflush definitief weigert, komt bij onWriteRejected terecht.
Herhalingen worden zonder leeftijdsgrens gededupliceerd op client-transactie-id. Ontvangstbewijzen blijven behouden bij snapshots, logopschoning en herstel uit R2. Elk bewijs bewaart een willekeurige id, volgnummer en tijdstip zolang de workspace bestaat. De hash van de operaties wordt na de helft van de bewaartermijn verwijderd, standaard na 15 dagen. Tot dat moment wordt dezelfde id met andere operaties geweigerd; daarna bevestigt die id de oorspronkelijke transactie zonder nog een write toe te passen.
Bij een upgrade of herstel vanuit een toestand waarin ontvangstbewijzen zijn verwijderd, blijft een vaste tijdsgrens voor ontbrekende bewijzen gelden. Een onbekende herhaling waarvan de oorspronkelijke issuedAt op of vóór die grens ligt, wordt geweigerd met retry_expired (HTTP 410) en komt binnen via onWriteRejected. De app kan deze opnieuw als een nieuwe write indienen. De grens schuift niet op naarmate de tijd verstrijkt.
Gerelateerde rijen
Section titled “Gerelateerde rijen”Gerelateerde rijen kunnen samen met de rij die ze nodig heeft worden aangemaakt:
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" } } } });Het is één transactie, zo geordend dat elke rij bestaat voordat iets ernaar wijst, en één fout draait de hele boom terug. De types volgen elk niveau.
Veel rijen schrijven
Section titled “Veel rijen schrijven”const { count } = await db.task.updateMany({ where: { done: true }, data: { archived: true } });await db.task.deleteMany({ where: { columnId: null } });De engine bepaalt binnen de transactie welke rijen matchen en logt de rijen in plaats van het filter. Een replay moet veranderen wat het origineel veranderde, en een filter later opnieuw draaien kan dat niet beloven. Een bulkwrite raakt alleen rijen die de caller mag lezen, en draait de rijregels voor update en delete nog steeds op elke rij.
Elke matchende rij wordt in één transactie geschreven, hoeveel het er ook zijn: de write commit helemaal of helemaal niet, en één rij die een regel weigert draait alles terug. count is het aantal geschreven rijen.
Net als schrijfacties op één rij worden bulkwrites meteen op de cache toegepast en offline in de wachtrij gezet. De cache wijzigt de rijen die hij heeft en die zeker matchen; een rij waarvan de match afhangt van een relatie, of van een veld dat de cache niet heeft, wacht op de engine. De engine bepaalt het filter wanneer de schrijfactie binnenkomt, dus een offline gewachte schrijfactie geldt voor de rijen die dan matchen. In de wachtrij is het resultaat { count, queued: true }.