# How to combine records and attachments Use one xitdb-clj `swap!` to publish an attachment and update its application record. This guide assumes an application with xitdb-clj and xitstash on the classpath. See [the tested adapter revisions](development.adoc#run-adapter-tests). ## Select a separate map for content Load the library and adapter: ```clojure (require '[ol.xitstash :as objects] '[xitdb.common :as xc] '[xitdb.db :as xdb]) (import '[io.github.radarroark.xitdb ReadHashMap] '[java.io Closeable InputStream]) ``` Create an `:objects` map beside the application’s `:status`. Inside `swap!`, unwrap that map and take its native cursor: ```clojure (with-open [^Closeable db (xdb/xit-db :memory) ^Closeable prepared (objects/prepare (byte-array [1 2 3]))] (reset! db {:objects {} :status :draft}) (swap! db (fn [state] (let [store (.cursor ^ReadHashMap (xc/unwrap (:objects state)))] (objects/initialize! store) (objects/put! store prepared) (objects/create! store [{:name "attachment.bin" :digest (:digest prepared)}])) (assoc state :status :published))) (let [store (.cursor ^ReadHashMap (xc/unwrap (:objects @db)))] (with-open [^InputStream input (objects/open store (:digest prepared))] {:status (:status @db) :path (objects/path store 1) :bytes (vec (.readAllBytes input))}))) ``` Result: ```clojure {:status :published :path ["attachment.bin"] :bytes [1 2 3]} ``` If a write fails, let the exception leave `swap!` so both the application change and the binary change abort. Do not catch the error inside the callback and commit a partial result. In xitdb-clj `:compat` mode, use string keys for your application maps. ## Keep the object store separate from collection operations Use `xc/unwrap` and `.cursor` to reach the native subtree. `xdb-cursor` is a path view, not the native cursor required by xitstash. Do not call `xdb/materialize` on the object-store subtree or edit its internal keys with `assoc`. Use ordinary collection operations on application data beside it. Coordinate concurrent access, close and compaction. For direct native access, use the database monitor or an application lock that prevents overlap. The example is single-threaded. ## Read history and compact Use `xdb/deref-at` to get an older application value, then select its object-store subtree. Keep its streams within the database lifetime. Close affected readers before calling `xdb/compact` outside `swap!`. It creates a new database containing the latest value and at most one history entry. It does not replace the original file. Validate and replace that file using the application’s lifecycle policy. See [How to delete content and reclaim space](deletion.adoc).