refacto: use @db/sqlite for better usage
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -35,3 +35,5 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
|||||||
|
|
||||||
*.db
|
*.db
|
||||||
*.db-journal
|
*.db-journal
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
|
|||||||
11
deno.json
11
deno.json
@@ -1,12 +1,13 @@
|
|||||||
{
|
{
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"jetstream:prod": "deno run --allow-net --allow-read --allow-write --allow-env jetstream.ts",
|
"jetstream:prod": "deno run --allow-net --allow-read --allow-write --allow-env --allow-ffi --unstable-ffi jetstream.ts",
|
||||||
"jetstream": "deno run --watch --allow-net --allow-read --allow-write --allow-env jetstream.ts",
|
"jetstream": "deno run --watch --allow-net --allow-read --allow-write --allow-env --allow-ffi --unstable-ffi jetstream.ts",
|
||||||
"server": "deno run --watch --allow-net --allow-read --allow-write --allow-env server.ts",
|
"server": "deno run --watch --allow-net --allow-read --allow-write --allow-env --allow-ffi --unstable-ffi server.ts",
|
||||||
"server:prod": "deno run --allow-net --allow-read --allow-write --allow-env server.ts",
|
"server:prod": "deno run --allow-net --allow-read --allow-write --allow-env --allow-ffi --unstable-ffi server.ts",
|
||||||
"migrate": "deno run --allow-read --allow-write --allow-env src/migrations/init.ts"
|
"migrate": "deno run --allow-net --allow-read --allow-write --allow-env --allow-ffi --unstable-ffi src/migrations/init.ts"
|
||||||
},
|
},
|
||||||
"imports": {
|
"imports": {
|
||||||
|
"@db/sqlite": "jsr:@db/sqlite@^0.13.0",
|
||||||
"@oak/oak": "jsr:@oak/oak@^17.2.0",
|
"@oak/oak": "jsr:@oak/oak@^17.2.0",
|
||||||
"@skyware/jetstream": "npm:@skyware/jetstream@^0.2.5",
|
"@skyware/jetstream": "npm:@skyware/jetstream@^0.2.5",
|
||||||
"@std/assert": "jsr:@std/assert@1"
|
"@std/assert": "jsr:@std/assert@1"
|
||||||
|
|||||||
44
deno.lock
generated
44
deno.lock
generated
@@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"version": "5",
|
"version": "5",
|
||||||
"specifiers": {
|
"specifiers": {
|
||||||
|
"jsr:@db/sqlite@*": "0.13.0",
|
||||||
|
"jsr:@db/sqlite@0.13": "0.13.0",
|
||||||
|
"jsr:@denosaurs/plug@1": "1.1.0",
|
||||||
"jsr:@oak/commons@1": "1.0.0",
|
"jsr:@oak/commons@1": "1.0.0",
|
||||||
"jsr:@oak/oak@^17.2.0": "17.2.0",
|
"jsr:@oak/oak@^17.2.0": "17.2.0",
|
||||||
"jsr:@std/assert@1": "1.0.18",
|
"jsr:@std/assert@1": "1.0.18",
|
||||||
@@ -8,14 +11,35 @@
|
|||||||
"jsr:@std/crypto@1": "1.0.3",
|
"jsr:@std/crypto@1": "1.0.3",
|
||||||
"jsr:@std/encoding@1": "1.0.6",
|
"jsr:@std/encoding@1": "1.0.6",
|
||||||
"jsr:@std/encoding@^1.0.5": "1.0.6",
|
"jsr:@std/encoding@^1.0.5": "1.0.6",
|
||||||
|
"jsr:@std/fmt@1": "1.0.9",
|
||||||
|
"jsr:@std/fs@1": "1.0.19",
|
||||||
"jsr:@std/http@1": "1.0.12",
|
"jsr:@std/http@1": "1.0.12",
|
||||||
"jsr:@std/internal@^1.0.12": "1.0.12",
|
"jsr:@std/internal@^1.0.12": "1.0.12",
|
||||||
|
"jsr:@std/internal@^1.0.9": "1.0.12",
|
||||||
"jsr:@std/media-types@1": "1.1.0",
|
"jsr:@std/media-types@1": "1.1.0",
|
||||||
"jsr:@std/path@1": "1.1.4",
|
"jsr:@std/path@1": "1.1.4",
|
||||||
|
"jsr:@std/path@1.0": "1.0.9",
|
||||||
|
"jsr:@std/path@^1.1.1": "1.1.4",
|
||||||
"npm:@skyware/jetstream@~0.2.5": "0.2.5",
|
"npm:@skyware/jetstream@~0.2.5": "0.2.5",
|
||||||
"npm:path-to-regexp@^6.3.0": "6.3.0"
|
"npm:path-to-regexp@^6.3.0": "6.3.0"
|
||||||
},
|
},
|
||||||
"jsr": {
|
"jsr": {
|
||||||
|
"@db/sqlite@0.13.0": {
|
||||||
|
"integrity": "4545c635e0b3d4ddfdc0f2240f932f24b8ad0178e9c2e3a0f9403e7b18ae2fb5",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@denosaurs/plug",
|
||||||
|
"jsr:@std/path@1.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"@denosaurs/plug@1.1.0": {
|
||||||
|
"integrity": "eb2f0b7546c7bca2000d8b0282c54d50d91cf6d75cb26a80df25a6de8c4bc044",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@std/encoding@1",
|
||||||
|
"jsr:@std/fmt",
|
||||||
|
"jsr:@std/fs",
|
||||||
|
"jsr:@std/path@1"
|
||||||
|
]
|
||||||
|
},
|
||||||
"@oak/commons@1.0.0": {
|
"@oak/commons@1.0.0": {
|
||||||
"integrity": "49805b55603c3627a9d6235c0655aa2b6222d3036b3a13ff0380c16368f607ac",
|
"integrity": "49805b55603c3627a9d6235c0655aa2b6222d3036b3a13ff0380c16368f607ac",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
@@ -35,14 +59,14 @@
|
|||||||
"jsr:@std/bytes",
|
"jsr:@std/bytes",
|
||||||
"jsr:@std/http",
|
"jsr:@std/http",
|
||||||
"jsr:@std/media-types",
|
"jsr:@std/media-types",
|
||||||
"jsr:@std/path",
|
"jsr:@std/path@1",
|
||||||
"npm:path-to-regexp"
|
"npm:path-to-regexp"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"@std/assert@1.0.18": {
|
"@std/assert@1.0.18": {
|
||||||
"integrity": "270245e9c2c13b446286de475131dc688ca9abcd94fc5db41d43a219b34d1c78",
|
"integrity": "270245e9c2c13b446286de475131dc688ca9abcd94fc5db41d43a219b34d1c78",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"jsr:@std/internal"
|
"jsr:@std/internal@^1.0.12"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"@std/bytes@1.0.4": {
|
"@std/bytes@1.0.4": {
|
||||||
@@ -54,6 +78,16 @@
|
|||||||
"@std/encoding@1.0.6": {
|
"@std/encoding@1.0.6": {
|
||||||
"integrity": "ca87122c196e8831737d9547acf001766618e78cd8c33920776c7f5885546069"
|
"integrity": "ca87122c196e8831737d9547acf001766618e78cd8c33920776c7f5885546069"
|
||||||
},
|
},
|
||||||
|
"@std/fmt@1.0.9": {
|
||||||
|
"integrity": "2487343e8899fb2be5d0e3d35013e54477ada198854e52dd05ed0422eddcabe0"
|
||||||
|
},
|
||||||
|
"@std/fs@1.0.19": {
|
||||||
|
"integrity": "051968c2b1eae4d2ea9f79a08a3845740ef6af10356aff43d3e2ef11ed09fb06",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@std/internal@^1.0.9",
|
||||||
|
"jsr:@std/path@^1.1.1"
|
||||||
|
]
|
||||||
|
},
|
||||||
"@std/http@1.0.12": {
|
"@std/http@1.0.12": {
|
||||||
"integrity": "85246d8bfe9c8e2538518725b158bdc31f616e0869255f4a8d9e3de919cab2aa",
|
"integrity": "85246d8bfe9c8e2538518725b158bdc31f616e0869255f4a8d9e3de919cab2aa",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
@@ -66,10 +100,13 @@
|
|||||||
"@std/media-types@1.1.0": {
|
"@std/media-types@1.1.0": {
|
||||||
"integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4"
|
"integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4"
|
||||||
},
|
},
|
||||||
|
"@std/path@1.0.9": {
|
||||||
|
"integrity": "260a49f11edd3db93dd38350bf9cd1b4d1366afa98e81b86167b4e3dd750129e"
|
||||||
|
},
|
||||||
"@std/path@1.1.4": {
|
"@std/path@1.1.4": {
|
||||||
"integrity": "1d2d43f39efb1b42f0b1882a25486647cb851481862dc7313390b2bb044314b5",
|
"integrity": "1d2d43f39efb1b42f0b1882a25486647cb851481862dc7313390b2bb044314b5",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"jsr:@std/internal"
|
"jsr:@std/internal@^1.0.12"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -156,6 +193,7 @@
|
|||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
|
"jsr:@db/sqlite@0.13",
|
||||||
"jsr:@oak/oak@^17.2.0",
|
"jsr:@oak/oak@^17.2.0",
|
||||||
"jsr:@std/assert@1",
|
"jsr:@std/assert@1",
|
||||||
"npm:@skyware/jetstream@~0.2.5"
|
"npm:@skyware/jetstream@~0.2.5"
|
||||||
|
|||||||
@@ -77,5 +77,6 @@ jetstream.start();
|
|||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
if (jetstream.cursor) {
|
if (jetstream.cursor) {
|
||||||
saveCursor(jetstream.cursor);
|
saveCursor(jetstream.cursor);
|
||||||
|
console.log(`[jetstream] updated cursor: ${jetstream.cursor}`);
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|||||||
@@ -1,33 +1,32 @@
|
|||||||
import { DB } from "https://deno.land/x/sqlite/mod.ts";
|
import { Database } from "@db/sqlite";
|
||||||
import type { Note } from "./note.ts";
|
import type { Note } from "./note.ts";
|
||||||
|
|
||||||
export const db = new DB(Deno.env.get("SQLITE_PATH") ?? "notes.db");
|
export const db = new Database(Deno.env.get("SQLITE_PATH") ?? "notes.db");
|
||||||
try {
|
try {
|
||||||
const [[journalMode]] = db.query<[string]>("PRAGMA journal_mode=WAL");
|
db.exec("PRAGMA journal_mode=WAL");
|
||||||
db.query("PRAGMA busy_timeout=5000");
|
db.exec("PRAGMA busy_timeout=5000");
|
||||||
console.log(`[db] journal_mode=${journalMode}, busy_timeout=5000`);
|
const [row] = db.prepare("PRAGMA journal_mode").all<{ journal_mode: string }>();
|
||||||
|
console.log(`[db] journal_mode=${row.journal_mode}, busy_timeout=5000`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[db] failed to set PRAGMAs:", e);
|
console.error("[db] failed to set PRAGMAs:", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getNotes = (cursor?: string, limit = 20) => {
|
type NoteRow = {
|
||||||
const rows = cursor
|
did: string;
|
||||||
? db.query<[string, string, string, string, string]>(
|
rkey: string;
|
||||||
"SELECT did, rkey, title, publishedAt, createdAt FROM note WHERE rkey < ? ORDER BY rkey DESC LIMIT ?",
|
title: string;
|
||||||
[cursor, limit],
|
publishedAt: string;
|
||||||
)
|
createdAt: string;
|
||||||
: db.query<[string, string, string, string, string]>(
|
};
|
||||||
"SELECT did, rkey, title, publishedAt, createdAt FROM note ORDER BY rkey DESC LIMIT ?",
|
|
||||||
[limit],
|
|
||||||
);
|
|
||||||
|
|
||||||
const notes = rows.map(([did, rkey, title, publishedAt, createdAt]) => ({
|
export const getNotes = (cursor?: string, limit = 20) => {
|
||||||
did,
|
const notes = cursor
|
||||||
rkey,
|
? db.prepare(
|
||||||
title,
|
"SELECT did, rkey, title, publishedAt, createdAt FROM note WHERE rkey < ? ORDER BY rkey DESC LIMIT ?",
|
||||||
publishedAt,
|
).all<NoteRow>(cursor, limit)
|
||||||
createdAt,
|
: db.prepare(
|
||||||
}));
|
"SELECT did, rkey, title, publishedAt, createdAt FROM note ORDER BY rkey DESC LIMIT ?",
|
||||||
|
).all<NoteRow>(limit);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
notes,
|
notes,
|
||||||
@@ -36,23 +35,13 @@ export const getNotes = (cursor?: string, limit = 20) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getNotesByDid = (did: string, cursor?: string, limit = 20) => {
|
export const getNotesByDid = (did: string, cursor?: string, limit = 20) => {
|
||||||
const rows = cursor
|
const notes = cursor
|
||||||
? db.query<[string, string, string, string, string]>(
|
? db.prepare(
|
||||||
"SELECT did, rkey, title, publishedAt, createdAt FROM note WHERE did = ? AND rkey < ? ORDER BY rkey DESC LIMIT ?",
|
"SELECT did, rkey, title, publishedAt, createdAt FROM note WHERE did = ? AND rkey < ? ORDER BY rkey DESC LIMIT ?",
|
||||||
[did, cursor, limit],
|
).all<NoteRow>(did, cursor, limit)
|
||||||
)
|
: db.prepare(
|
||||||
: db.query<[string, string, string, string, string]>(
|
|
||||||
"SELECT did, rkey, title, publishedAt, createdAt FROM note WHERE did = ? ORDER BY rkey DESC LIMIT ?",
|
"SELECT did, rkey, title, publishedAt, createdAt FROM note WHERE did = ? ORDER BY rkey DESC LIMIT ?",
|
||||||
[did, limit],
|
).all<NoteRow>(did, limit);
|
||||||
);
|
|
||||||
|
|
||||||
const notes = rows.map(([did, rkey, title, publishedAt, createdAt]) => ({
|
|
||||||
did,
|
|
||||||
rkey,
|
|
||||||
title,
|
|
||||||
publishedAt,
|
|
||||||
createdAt,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
notes,
|
notes,
|
||||||
@@ -61,35 +50,26 @@ export const getNotesByDid = (did: string, cursor?: string, limit = 20) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const deleteNote = ({ did, rkey }: { did: string; rkey: string }) => {
|
export const deleteNote = ({ did, rkey }: { did: string; rkey: string }) => {
|
||||||
db.query("DELETE FROM note WHERE did = ? AND rkey = ?", [did, rkey]);
|
db.exec("DELETE FROM note WHERE did = ? AND rkey = ?", did, rkey);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getCursor = (): string | undefined => {
|
export const getCursor = (): string | undefined => {
|
||||||
const rows = db.query<[string]>(
|
const row = db.prepare(
|
||||||
"SELECT value FROM state WHERE key = 'cursor'",
|
"SELECT value FROM state WHERE key = 'cursor'",
|
||||||
);
|
).get<{ value: string }>();
|
||||||
return rows[0]?.[0];
|
return row?.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const saveCursor = (cursor: number) => {
|
export const saveCursor = (cursor: number) => {
|
||||||
db.query(
|
db.exec(
|
||||||
"INSERT OR REPLACE INTO state (key, value) VALUES ('cursor', ?)",
|
"INSERT OR REPLACE INTO state (key, value) VALUES ('cursor', ?)",
|
||||||
[String(cursor)],
|
String(cursor),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const upsertNote = (note: Note) => {
|
export const upsertNote = (note: Note) => {
|
||||||
const now = new Date().toISOString();
|
const now = new Date().toISOString();
|
||||||
const params = [
|
db.exec(
|
||||||
note.title,
|
|
||||||
note.publishedAt ? new Date(note.publishedAt).toISOString() : now,
|
|
||||||
note.createdAt ? new Date(note.createdAt).toISOString() : now,
|
|
||||||
note.did,
|
|
||||||
note.rkey,
|
|
||||||
];
|
|
||||||
console.log(`[db] upsertNote params: ${JSON.stringify(params)}`);
|
|
||||||
|
|
||||||
db.query(
|
|
||||||
`
|
`
|
||||||
INSERT INTO note (
|
INSERT INTO note (
|
||||||
title,
|
title,
|
||||||
@@ -104,6 +84,10 @@ export const upsertNote = (note: Note) => {
|
|||||||
title = excluded.title,
|
title = excluded.title,
|
||||||
publishedAt = excluded.publishedAt
|
publishedAt = excluded.publishedAt
|
||||||
`,
|
`,
|
||||||
params,
|
note.title,
|
||||||
|
note.publishedAt ? new Date(note.publishedAt).toISOString() : now,
|
||||||
|
note.createdAt ? new Date(note.createdAt).toISOString() : now,
|
||||||
|
note.did,
|
||||||
|
note.rkey,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { db } from "../data/db.ts";
|
import { db } from "../data/db.ts";
|
||||||
|
|
||||||
db.execute(`
|
db.exec(`
|
||||||
CREATE TABLE IF NOT EXISTS note (
|
CREATE TABLE IF NOT EXISTS note (
|
||||||
title TEXT NOT NULL,
|
title TEXT NOT NULL,
|
||||||
publishedAt DATETIME,
|
publishedAt DATETIME,
|
||||||
@@ -11,7 +11,7 @@ db.execute(`
|
|||||||
);
|
);
|
||||||
`);
|
`);
|
||||||
|
|
||||||
db.execute(`
|
db.exec(`
|
||||||
CREATE TABLE IF NOT EXISTS state (
|
CREATE TABLE IF NOT EXISTS state (
|
||||||
key TEXT PRIMARY KEY,
|
key TEXT PRIMARY KEY,
|
||||||
value TEXT NOT NULL
|
value TEXT NOT NULL
|
||||||
|
|||||||
Reference in New Issue
Block a user