Skip to Content
FILE Columns & Uploads

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?):

ts snippetTS
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)

ts snippetTS
// 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:

text snippetTEXT
/v1/files/{namespace}/{table}/{sub}/{stored_name}

Fetch it with the same bearer token you use for SQL calls:

ts snippetTS
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:

ts snippetTS
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 fetch when XHR progress is unavailable

FileRef model

file_ref.ts exposes FileRef and helpers:

ts snippetTS
import { FileRef, parseFileRef, parseFileRefs } from '@kalamdb/client';

Parse and use file metadata

ts snippetTS
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:

ts snippetTS
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

ts snippetTS
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

ts snippetTS
ref.isImage();ref.isVideo();ref.isAudio();ref.isPdf();ref.getTypeDescription();

Storage-path internals documented by source

FileRef includes:

  • id, sub, name, size, mime, sha256, optional shard
  • filename sanitization and extension normalization
  • shared-table shard-aware relativePath() generation

This is useful for building file galleries, attachment viewers, and audit tooling.

Last updated on