import { sqlite } from "https://esm.town/v/std/sqlite";
import { ValTownBlobError } from "https://esm.town/v/std/ValTownBlobError";
import { ValTownBlobNotFoundError } from "https://esm.town/v/std/ValTownBlobNotFoundError";
const createTableStatement = `
CREATE TABLE IF NOT EXISTS blobs (
key TEXT PRIMARY KEY,
value TEXT,
size INTEGER,
lastModified TEXT
)
`;
export const blob = {
async get(key: string): Promise<Response> {
try {
const result = await sqlite.execute({
sql: "SELECT value FROM blobs WHERE key = :key",
args: { key },
});
if (result.rows.length === 0) {
throw new ValTownBlobNotFoundError();
}
return new Response(result.rows[0][0]);
} catch (_) {
throw new ValTownBlobNotFoundError();
}
},
async set(key: string, value: BodyInit): Promise<void> {
const valueText = value instanceof ReadableStream ? await new Response(value).text() : String(value);
await sqlite.batch([
createTableStatement,
{
sql:
"INSERT OR REPLACE INTO blobs (key, value, size, lastModified) VALUES (:key, :value, :size, :lastModified)",
args: {
key,
value: valueText,
size: valueText.length,
lastModified: new Date().toISOString(),
},
},
]);
},
async copy(previous: string, next: string): Promise<void> {
await sqlite.batch([createTableStatement, {
sql:
"INSERT OR REPLACE INTO blobs (key, value, size, lastModified) SELECT :next, value, size, :lastModified FROM blobs WHERE key = :previous",
args: { previous, next, lastModified: new Date().toISOString() },
}]);
},
async move(previous: string, next: string): Promise<void> {
await this.copy(previous, next);
await this.delete(previous);
},
async list(prefix?: string): Promise<{ key: string; size: number; lastModified: string }[]> {
try {
const sql = prefix
? "SELECT key, size, lastModified FROM blobs WHERE key LIKE :prefix || '%'"
: "SELECT key, size, lastModified FROM blobs";
const result = await sqlite.execute({ sql, args: { prefix } });
return result.rows.map((row) => ({
key: row[0],
size: row[1],
lastModified: row[2],
}));
} catch {
return [];
}
},
async delete(key: string): Promise<void> {
await sqlite.batch([createTableStatement, {
sql: "DELETE FROM blobs WHERE key = :key",
args: { key },
}]);
},
async getJSON(key: string): Promise<any | undefined> {
try {
const response = await this.get(key);
return JSON.parse(await response.text());
} catch (e) {
if (e instanceof ValTownBlobNotFoundError) {
return undefined;
}
throw e;
}
},
async setJSON(key: string, value: any): Promise<void> {