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