Readme

Blob storage but uses SQLite under the hood.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// This implementation uses SQLite to store blob data instead of the Val Town API.
// It creates a 'blobs' table to store key-value pairs, where the key is the blob key
// and the value is the blob data stored as TEXT. This approach allows for persistence
// and querying using SQL, but may have limitations for very large blobs or binary data.
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";
// Initialize the database
await sqlite.execute(`
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> {
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]);
},
async set(key: string, value: BodyInit): Promise<void> {
const valueText = value instanceof ReadableStream ? await new Response(value).text() : String(value);
await sqlite.execute({
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.execute({
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 }[]> {
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],
}));
},
async delete(key: string): Promise<void> {
await sqlite.execute({
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> {
await this.set(key, JSON.stringify(value));
},
};
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Comments
Nobody has commented on this val yet: be the first!
August 1, 2024