FILE Columns & Uploads
@kalamdb/client supports file upload and retrieval patterns for KalamDB FILE columns.
Upload files with SQL
Use queryWithFiles(sql, files, params?, onProgress?):
const avatarFile = fileInput.files?.[0];if (!avatarFile) throw new Error('No file selected'); await client.queryWithFiles( 'INSERT INTO app.users (id, avatar) VALUES ($1, FILE("avatar"))', { avatar: avatarFile }, ['user_123']);Insert + read FileRefs (end-to-end)
// 1) Insert a FILE via multipart uploadawait client.queryWithFiles( 'INSERT INTO app.users (id, avatar) VALUES ($1, FILE("avatar"))', { avatar: avatarFile }, ['user_123'],); // 2) Read rows with FILE-aware wrappersconst rows = await client.queryRows<{ id: string; avatar: unknown }>( 'SELECT id, avatar FROM app.users WHERE id = $1', 'app.users', ['user_123'],); const avatar = rows[0]?.file('avatar');if (avatar) { console.log(avatar.name, avatar.formatSize()); console.log(avatar.downloadUrl());}downloadUrl() returns the authenticated file-download endpoint for the stored
file path:
/v1/files/{namespace}/{table}/{sub}/{stored_name}Fetch it with the same bearer token you use for SQL calls:
const response = await fetch(avatar.downloadUrl(), { headers: { Authorization: `Bearer ${token}`, },}); const bytes = await response.arrayBuffer();For user tables, SDK helpers intentionally generate an owner-scoped URL without
user_id. A normal user can download only files in their own user-table scope.
Service-role clients may upload or write through authorized EXECUTE AS USER
flows, but raw cross-user FILE downloads are reserved for dba and system
tokens that explicitly add an authorized user_id query parameter.
Progress callback
In browser environments (XMLHttpRequest available), pass onProgress:
await client.queryWithFiles(sql, files, params, (progress) => { console.log(progress.file_name, progress.percent);});Auth behavior
From source:
- SDK builds auth header via
buildAuthHeader(auth) - sends multipart request to
POST /v1/api/sql - falls back to
fetchwhen XHR progress is unavailable
FileRef model
file_ref.ts exposes FileRef and helpers:
import { FileRef, parseFileRef, parseFileRefs } from '@kalamdb/client';Parse and use file metadata
const ref = parseFileRef(row.attachment);if (ref) { console.log(ref.name, ref.size, ref.mime); console.log(ref.formatSize()); console.log(ref.relativePath());}When rows come from queryOne/queryAll, FILE values are KalamCellValue:
const row = await client.queryOne('SELECT avatar FROM app.users WHERE id = $1', ['user_123']);const ref = row?.avatar.asFile();if (ref) { console.log(ref.getDownloadUrl('http://localhost:2900', 'app', 'users'));}Build download URL
const url = ref.getDownloadUrl('http://localhost:2900', 'app', 'users');That URL points at /v1/files/.../{stored_name} and uses the sanitized stored
filename, not the raw file id alone.
Type helpers
ref.isImage();ref.isVideo();ref.isAudio();ref.isPdf();ref.getTypeDescription();Storage-path internals documented by source
FileRef includes:
id,sub,name,size,mime,sha256, optionalshard- filename sanitization and extension normalization
- shared-table shard-aware
relativePath()generation
This is useful for building file galleries, attachment viewers, and audit tooling.