You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
`@tanstack/powersync-db-collection` ships `TanStackDBAttachmentQueue`, an [`AttachmentQueue`](https://docs.powersync.com/usage/use-case-examples/attachments-files) whose file operations commit inside a TanStack DB collection transaction. This lets you create (or delete) an attachment and mutate a related collection row (for example, setting `lists.photo_id`) atomically in a single transaction, instead of issuing two independent writes.
1107
+
1108
+
The queue extends PowerSync's `AttachmentQueue`, so the generic concepts are unchanged and documented once in the SDK.
1109
+
1110
+
> This section only covers what is specific to the TanStack DB integration. For storage adapters (local and remote), the `AttachmentTable` schema primitive, error-handling/retry semantics, and the `startSync()` / `stopSync()` lifecycle, see the [PowerSync attachments documentation](https://docs.powersync.com/usage/use-case-examples/attachments-files).
1111
+
1112
+
### Prerequisites
1113
+
1114
+
These are standard PowerSync attachment requirements. See the SDK attachments docs for details.
- A local storage adapter (such as `IndexDBFileSystemStorageAdapter` on web) and a remote storage adapter (an implementation of the SDK's `RemoteStorageAdapter`, for example backed by Supabase Storage). Both are generic to all attachment users. See the SDK docs for the available adapters and the remote-adapter contract.
1128
+
1129
+
### 1. Create the attachments collection
1130
+
1131
+
This is the piece that makes the integration TanStack-aware: a normal PowerSync collection over the attachments table. The queue reads and writes attachment records through it.
Pass your collection as `attachmentsCollection` alongside the standard `AttachmentQueue` options. Only `attachmentsCollection` and `watchAttachments` (below) are specific to this package; `db`, `localStorage`, `remoteStorage`, and `errorHandler` are the usual SDK options.
attachmentsCollection, // TanStack DB collection over your AttachmentTable
1155
+
localStorage, // SDK local storage adapter
1156
+
remoteStorage, // your RemoteStorageAdapter (see SDK docs)
1157
+
watchAttachments, // see step 3
1158
+
errorHandler, // standard AttachmentQueue error handler (see SDK docs)
1159
+
})
1160
+
```
1161
+
1162
+
Start and stop syncing with the standard `attachmentQueue.startSync()` / `attachmentQueue.stopSync()` lifecycle (see SDK docs), typically inside a React effect or provider.
1163
+
1164
+
### 3. Tell the queue which attachments exist (`watchAttachments`)
1165
+
1166
+
`watchAttachments` reports the set of attachment IDs your data currently references, so the queue knows what to download and what to archive. With TanStack DB you drive it from a live query: emit the initial state, then re-emit the complete set on every change, and clean up on abort.
> A `watchAttachmentsFromQuery(...)` convenience helper that collapses this boilerplate into a single call is planned. Until then, use the pattern above.
1212
+
1213
+
### 4. Save an attachment atomically with related data
1214
+
1215
+
`saveFileTanStack` writes the file, inserts the attachment record into your collection, and runs your `updateHook` mutations in the same transaction. Use the hook to insert or update the row that references the new attachment, so both land together or not at all.
1216
+
1217
+
```ts
1218
+
awaitattachmentQueue.saveFileTanStack({
1219
+
data, // file bytes (ArrayBuffer / base64, per your local adapter)
1220
+
fileExtension: "jpg",
1221
+
updateHook: async (attachmentRecord) => {
1222
+
// Runs in the same transaction as the attachment insert.
1223
+
listsCollection.insert({
1224
+
id: crypto.randomUUID(),
1225
+
name,
1226
+
created_at: newDate(),
1227
+
owner_id: userID,
1228
+
photo_id: attachmentRecord.id, // associate the row with the attachment
1229
+
})
1230
+
},
1231
+
})
1232
+
```
1233
+
1234
+
### 5. Delete an attachment and detach it from the row
1235
+
1236
+
`deleteFileTanStack` queues the file for deletion and runs your `updateHook` in the same transaction. Clear the foreign key so the row and the attachment stay consistent.
1237
+
1238
+
```ts
1239
+
awaitattachmentQueue.deleteFileTanStack({
1240
+
id: photo_id,
1241
+
updateHook: async () => {
1242
+
listsCollection.update(listId, (draft) => {
1243
+
draft.photo_id=null
1244
+
})
1245
+
},
1246
+
})
1247
+
```
1248
+
1249
+
### 6. Display attachments via a live-query join
1250
+
1251
+
Join your attachments collection into a live query to read the local URI (the locally cached file path) alongside your domain rows:
0 commit comments