index.ts
Raw
1import { Database as BunDatabase } from "bun:sqlite";
2import { type Generated, Kysely, type Selectable } from "kysely";
3import { BunSqliteDialect } from "kysely-bun-sqlite";
4
5import { DB_PATH } from "../constants.ts";
6
7interface UserTable {
8 id: Generated<number>;
9 username: string;
10 password_hash: string | null;
11 created_at: string;
12 avatar_version: Generated<number>;
13}
14
15interface PasskeyTable {
16 id: Generated<number>;
17 user_id: number;
18 credential_id: string;
19 public_key: string;
20 counter: number;
21 created_at: string;
22}
23
24interface SessionTable {
25 id: string;
26 user_id: number;
27 expires_at: string;
28 created_at: string;
29}
30
31interface RepositoryTable {
32 id: Generated<number>;
33 name: string;
34 description: string | null;
35 is_private: number;
36 is_pinned: Generated<number>;
37 default_branch: string;
38 created_at: string;
39 issue_seq: Generated<number>;
40 patch_seq: Generated<number>;
41 issue_template: string | null;
42 patch_template: string | null;
43}
44
45interface IssueTable {
46 id: Generated<number>;
47 repo_id: number;
48 author_id: number | null;
49 number: number;
50 title: string;
51 body: string;
52 status: string;
53 created_at: string;
54 updated_at: string;
55 edited_at: string | null;
56}
57
58interface IssueCommentTable {
59 id: Generated<number>;
60 issue_id: number;
61 author_id: number | null;
62 body: string;
63 created_at: string;
64 edited_at: string | null;
65}
66
67interface IssueReactionTable {
68 id: Generated<number>;
69 issue_id: number;
70 comment_id: number | null;
71 user_id: number;
72 emoji: string;
73}
74
75interface PatchTable {
76 id: Generated<number>;
77 repo_id: number;
78 author_id: number | null;
79 number: number;
80 title: string;
81 description: string;
82 patch_content: string;
83 status: string;
84 author_name: string;
85 author_email: string;
86 created_at: string;
87 updated_at: string;
88 edited_at: string | null;
89}
90
91interface PatchCommentTable {
92 id: Generated<number>;
93 patch_id: number;
94 author_id: number | null;
95 body: string;
96 created_at: string;
97 edited_at: string | null;
98}
99
100interface PatchReactionTable {
101 id: Generated<number>;
102 patch_id: number;
103 comment_id: number | null;
104 user_id: number;
105 emoji: string;
106}
107
108interface SshKeyTable {
109 id: Generated<number>;
110 user_id: number;
111 name: string;
112 public_key: string;
113 fingerprint: string;
114 created_at: string;
115}
116
117interface ReleaseTable {
118 id: Generated<number>;
119 repo_id: number;
120 tag_name: string | null;
121 name: string;
122 notes: string | null;
123 include_source_code: number;
124 created_at: string;
125}
126
127interface ReleaseAssetTable {
128 id: Generated<number>;
129 release_id: number;
130 filename: string;
131 size: number;
132 content_type: string;
133 created_at: string;
134}
135
136export interface Database {
137 users: UserTable;
138 passkeys: PasskeyTable;
139 sessions: SessionTable;
140 repositories: RepositoryTable;
141 issues: IssueTable;
142 issue_comments: IssueCommentTable;
143 issue_reactions: IssueReactionTable;
144 patches: PatchTable;
145 patch_comments: PatchCommentTable;
146 patch_reactions: PatchReactionTable;
147 ssh_keys: SshKeyTable;
148 releases: ReleaseTable;
149 release_assets: ReleaseAssetTable;
150}
151
152// Selectable row types (id is plain number, as returned by queries)
153export type UserRow = Selectable<UserTable>;
154export type PasskeyRow = Selectable<PasskeyTable>;
155export type SessionRow = Selectable<SessionTable>;
156export type RepositoryRow = Selectable<RepositoryTable>;
157export type IssueRow = Selectable<IssueTable>;
158export type IssueCommentRow = Selectable<IssueCommentTable>;
159export type IssueReactionRow = Selectable<IssueReactionTable>;
160export type PatchRow = Selectable<PatchTable>;
161export type PatchCommentRow = Selectable<PatchCommentTable>;
162export type PatchReactionRow = Selectable<PatchReactionTable>;
163export type SshKeyRow = Selectable<SshKeyTable>;
164export type ReleaseRow = Selectable<ReleaseTable>;
165export type ReleaseAssetRow = Selectable<ReleaseAssetTable>;
166
167const sqlite = new BunDatabase(DB_PATH);
168sqlite.run("PRAGMA journal_mode=WAL");
169sqlite.run("PRAGMA foreign_keys=ON");
170
171export const db = new Kysely<Database>({
172 dialect: new BunSqliteDialect({ database: sqlite }),
173});
174
175export async function getRepo(name: string, isAdmin: boolean) {
176 const repo = await db
177 .selectFrom("repositories")
178 .selectAll()
179 .where("name", "=", name)
180 .executeTakeFirst();
181 if (!repo) return null;
182 if (repo.is_private && !isAdmin) return null;
183 return repo;
184}
185