feat: typed database with kysely, updated config

This commit is contained in:
Samuel 2024-12-11 16:41:37 +01:00
parent d06e6d913e
commit 0e6f5a24bd
24 changed files with 1656 additions and 434 deletions

156
src/db.ts
View file

@ -1,8 +1,11 @@
import { type Accessor, createMemo, createSignal, DEV, type Setter } from "solid-js";
import { Kysely, type NotNull } from "kysely";
import type { DB } from "kysely-codegen";
import { SqlJsDialect } from "kysely-wasm";
import initSqlJS, { type Database } from "sql.js";
import wasmURL from "./assets/sql-wasm.wasm?url";
import dbURL from "./assets/database.sqlite?url";
import { createMemo, createSignal } from "solid-js";
export const SELF_ID = 2;
@ -10,80 +13,87 @@ export const SQL = await initSqlJS({
locateFile: () => wasmURL,
});
const file = await fetch(dbURL).then((res) => res.arrayBuffer());
let rawDb: Accessor<Database | undefined>, setRawDb: Setter<Database | undefined>;
const testDb = new SQL.Database(new Uint8Array(file));
export const [db, setDb] = createSignal<Database>(testDb);
const createStatement = (sql: string) => {
return createMemo(() => {
return db().prepare(sql);
if (DEV) {
const file = await import("./assets/database.sqlite?url").then((result) => {
return fetch(result.default).then((res) => res.arrayBuffer());
});
const testDb = new SQL.Database(new Uint8Array(file));
[rawDb, setRawDb] = createSignal<Database>(testDb);
} else {
[rawDb, setRawDb] = createSignal<Database>();
}
export { rawDb as db, setRawDb as setDb };
const sqlJsDialect = () => {
const currentDb = rawDb();
if (currentDb) {
return new SqlJsDialect({
database: currentDb,
});
}
};
export const roomOverviewStmt = createStatement(`
SELECT
thread.recipient_id,
thread.active,
thread.archived,
recipient.profile_joined_name,
recipient.system_joined_name,
groups.title,
message_count,
last_message_date
FROM
thread
LEFT JOIN (
SELECT
thread_id,
COUNT(*) AS message_count
FROM
message
WHERE
message.body IS NOT NULL
AND message.body != ''
GROUP BY
thread_id
) message_counts ON message_counts.thread_id = thread._id
LEFT JOIN (
SELECT
thread_id,
max(date_sent) AS last_message_date
FROM
message
GROUP BY
thread_id
) last_messages ON last_messages.thread_id = thread._id
JOIN recipient ON thread.recipient_id = recipient._id
LEFT JOIN groups ON recipient._id = groups.recipient_id
WHERE
message_count > 0
`);
const kyselyDb = createMemo(() => {
const currentSqlJsDialect = sqlJsDialect();
export type RoomOverviewColumn = {
recipient_id: number;
active: 0 | 1;
archived: 0 | 1;
message_count: number;
last_message_date: number;
} & (
| {
profile_joined_name: string;
system_joined_name: string | null;
title: null;
}
| {
profile_joined_name: null;
system_joined_name: null;
title: string;
}
);
if (!currentSqlJsDialect) {
throw new Error("no db selected!");
}
export const overallSentMessagesStmt = createStatement(`
SELECT
COUNT(*) as message_count
FROM
message
WHERE (message.from_recipient_id = :recipient_id AND message.body IS NOT NULL AND message.body != '')
`);
return new Kysely<DB>({
dialect: currentSqlJsDialect,
});
});
export const threadOverviewQuery = kyselyDb()
.selectFrom("thread")
.innerJoin(
(eb) =>
eb
.selectFrom("message")
.select(["thread_id", kyselyDb().fn.countAll().as("message_count")])
.where((eb) => {
return eb.and([eb("message.body", "is not", null), eb("message.body", "is not", "")]);
})
.groupBy("message.thread_id")
.as("message"),
(join) => join.onRef("message.thread_id", "=", "thread._id"),
)
.innerJoin("recipient", "thread.recipient_id", "recipient._id")
.leftJoin("groups", "recipient._id", "groups.recipient_id")
.select([
"thread._id as thread_id",
"thread.recipient_id",
"thread.archived",
"recipient.profile_joined_name",
"recipient.system_joined_name",
"groups.title",
"message_count",
"thread.date as last_message_date",
])
.where("message_count", ">", 0)
.$narrowType<{
thread_id: NotNull;
archived: NotNull;
message_count: number;
}>();
console.log(threadOverviewQuery.compile());
export const overallSentMessagesQuery = (recipientId: number) =>
kyselyDb()
.selectFrom("message")
.select(kyselyDb().fn.countAll().as("message_count"))
.where((eb) =>
eb.and([
eb("message.from_recipient_id", "=", recipientId),
eb("message.body", "is not", null),
eb("message.body", "!=", ""),
]),
);