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