Field Decorators

FieldDecorator lets you hook into a document's read/write path per field — wrap what's written before it reaches storage, unwrap it after it comes back. Use it for per-field encryption, compression, checksums, or logging.

Attaching decorators

Decorators can be configured at the collection level, the document level, or both:

val notes = Documents.collection("notes") {
    decorators = listOf(LoggingDecorator())
}

val note = notes.document<Note>("note-1") {
    decorators = listOf(ChecksumDecorator())
}
// note's effective decorator list, in order: [LoggingDecorator(), ChecksumDecorator()]

Collection-level decorators apply to every document opened in that collection; document-level decorators are appended after them for that one document.

Order matters

Writes fold through the decorator list left-to-right; reads fold right-to-left. Whichever decorator ran last on write runs first on read, so each wrap is undone in the reverse order it was applied:

// decorators = listOf(Compress, Encrypt)
// write:  bytes  -> Compress.wrap   -> Encrypt.wrap   -> stored
// read:   stored -> Encrypt.unwrap  -> Compress.unwrap -> bytes

This is why compress-then-encrypt — not the reverse — is the order that actually works: encrypted bytes are high-entropy and don't meaningfully compress. See Decorations for why the library folds the list this way.

Where else this applies

Decorators also apply under field delegates — see Field Delegates — and sit immediately next to where CBOR encode/decode happens, see Serialization (CBOR) and Field Decomposition. A decorator's unwrap failing surfaces as DocumentDecodingException, the same as any other decode failure — see Error Handling.