Docs Client library reference Swift
v0.2.6-alpha.3Swift: Attach a file
fromFile copies a file the user picked into the client's attachment sandbox, queues its upload, and writes the resulting reference onto the row's attachment column as an ordinary local update. The bytes never cross the binding: the picker stays in the app and the engine works from the path.
Examples#
Basic#
// TodoApp/TodoListView.swift (excerpt)
import Foundation
import KizunaSync
let result = try await kizunasync.fromFile(
table: "todos",
column: "image_path",
pk: todoId,
sourcePath: pickedURL.path,
mediaType: "image/jpeg"
)Insert the row first#
// TodoApp/TodoListView.swift (excerpt)
import Foundation
import KizunaSync
let todoId = UUID().uuidString
try await kizunasync.apply(
table: "todos",
pk: todoId,
op: .insert,
columns: ["title": "works on a plane", "done": false]
)
let result = try await kizunasync.fromFile(
table: "todos",
column: "image_path",
pk: todoId,
sourcePath: pickedURL.path
)Both writes wake the Host scheduler, whose next run pushes the row and uploads the bytes.
Parameters#
| Name | Type | Required | Description |
|---|---|---|---|
table | String | Yes | Table of the row that owns the file. |
column | String | Yes | Column declared as an attachment for that table in Initializing. |
pk | String | Yes | Primary key of the row. The row has to exist already, because the reference is written onto it. A uuid names the row in any case, because the engine lowercases it as it does for a write. |
sourcePath | String | Yes | Filesystem path of the file to import. It is read once and copied into the sandbox. |
mediaType | String? | No | Content type recorded for the object; it picks the reference's extension. Default: nil, which records application/octet-stream. |
Returns#
KizunaSyncFromFileResult, with these fields.
| Name | Type | Required | Description |
|---|---|---|---|
reference | String | — | The value written onto the column, shaped <owner>/<pk>/<uploadId>.<extension>, where the owner comes from the row's configured owner column. |
sha256 | String | — | Hex digest of the imported bytes. The sandbox is content addressed by this digest, so importing the same bytes twice stores one copy. |
size | Int64 | — | Size of the imported file in bytes. |
mediaType | String | — | The content type that was recorded. |
localPath | String | — | Path of the copy inside the sandbox, which is what a viewer reads until the upload finishes. |
Errors#
| Code | Condition |
|---|---|
ATTACHMENT_PORTS_MISSING | The client was created without attachmentRoot. See ATTACHMENT_PORTS_MISSING. |
UNKNOWN_TABLE | table is not one of the tables the client was created with. |
LOCAL_CONSTRAINT | column is not declared as an attachment on that table, or the row's owner or its pk is not a uuid. |
ATTACHMENT_ROW_GONE | No live row holds pk in that table. Insert the row before importing the file. |
ATTACHMENT_OWNER_MISSING | The row's owner column is missing or empty, so no object key can be derived. |
TRANSFER | The source file could not be read. |
STORE, JSON | The sandbox copy, the queue row, or the column update could not be written. |
ENGINE_UNAVAILABLE | The client has no engine because Initializing has not run. |
Notes#
The import writes the reference through the normal write path, so it is one more entry in the outbox and it is visible to Fetch data at once. The bytes move later: the next Sync pushes the column first and then drives the transfer, so the server never sees a reference to an object that is on its way. Media and attachments walks through the ordering.
Uploads go to the Storage bucket the column declares, using resumable uploads; Kizuna adds the durable queue around them, so an interrupted transfer resumes from its recorded offset instead of starting again. The object key is the reference, so a Storage policy scoped to the owner segment covers it, as access control describes.
If the column update fails after the file was queued, the queued object is evicted, since no server ever saw the reference: Vacuum attachments only deletes its sandbox bytes, and Storage is never asked. The original error from the write is raised.
Related reference#
Found a problem? Edit this page on GitHub