fix: wrong month stats and db cache undefined handling

This commit is contained in:
Samuel 2024-12-18 18:27:25 +01:00
parent ed9612fce5
commit d87d9fb301
No known key found for this signature in database
4 changed files with 54 additions and 67 deletions

110
src/db.ts
View file

@ -1,6 +1,6 @@
import { type Accessor, createEffect, createMemo, createRoot, createSignal, DEV, type Setter } from "solid-js"; import { createEffect, createMemo, createRoot, createSignal } from "solid-js";
import { Kysely, type NotNull, sql } from "kysely"; import { Kysely, sql, type NotNull } from "kysely";
import type { DB } from "kysely-codegen"; import type { DB } from "kysely-codegen";
import { SqlJsDialect } from "kysely-wasm"; import { SqlJsDialect } from "kysely-wasm";
import initSqlJS, { type Database } from "sql.js"; import initSqlJS, { type Database } from "sql.js";
@ -14,25 +14,10 @@ export const SQL = await initSqlJS({
locateFile: () => wasmURL, locateFile: () => wasmURL,
}); });
let rawDb: Accessor<Database | undefined> = () => undefined, export const [db, setDb] = createSignal<Database | undefined>();
setRawDb: Setter<Database | undefined> = () => undefined;
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 | undefined>(testDb);
} else {
[rawDb, setRawDb] = createSignal<Database | undefined>();
}
export { rawDb as db, setRawDb as setDb };
const sqlJsDialect = () => { const sqlJsDialect = () => {
const currentDb = rawDb(); const currentDb = db();
if (currentDb) { if (currentDb) {
return new SqlJsDialect({ return new SqlJsDialect({
@ -43,10 +28,10 @@ const sqlJsDialect = () => {
const kyselyDb = createRoot(() => { const kyselyDb = createRoot(() => {
createEffect(() => { createEffect(() => {
const db = rawDb(); const currentDb = db();
if (db) { if (currentDb) {
db.create_function("is_not_empty", (str: string | null) => { currentDb.create_function("is_not_empty", (str: string | null) => {
return str !== null && str !== ""; return str !== null && str !== "";
}); });
} }
@ -56,7 +41,7 @@ const kyselyDb = createRoot(() => {
const currentSqlJsDialect = sqlJsDialect(); const currentSqlJsDialect = sqlJsDialect();
if (!currentSqlJsDialect) { if (!currentSqlJsDialect) {
throw new Error("no db selected!"); return;
} }
return new Kysely<DB>({ return new Kysely<DB>({
@ -65,46 +50,47 @@ const kyselyDb = createRoot(() => {
}); });
}); });
const allThreadsOverviewQueryRaw = kyselyDb() const allThreadsOverviewQueryRaw = () =>
.selectFrom("thread") kyselyDb()
.innerJoin( ?.selectFrom("thread")
(eb) => .innerJoin(
eb (eb) =>
.selectFrom("message") eb
.select((eb) => ["message.thread_id", eb.fn.countAll().as("message_count")]) .selectFrom("message")
.where((eb) => { .select((eb) => ["message.thread_id", eb.fn.countAll().as("message_count")])
return eb.and([eb("message.body", "is not", null), eb("message.body", "is not", "")]); .where((eb) => {
}) return eb.and([eb("message.body", "is not", null), eb("message.body", "is not", "")]);
.groupBy("message.thread_id") })
.as("message"), .groupBy("message.thread_id")
(join) => join.onRef("message.thread_id", "=", "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") .innerJoin("recipient", "thread.recipient_id", "recipient._id")
.select([ .leftJoin("groups", "recipient._id", "groups.recipient_id")
"thread._id as thread_id", .select([
"thread.recipient_id", "thread._id as thread_id",
"thread.archived", "thread.recipient_id",
"recipient.profile_joined_name", "thread.archived",
"recipient.system_joined_name", "recipient.profile_joined_name",
"groups.title", "recipient.system_joined_name",
"message_count", "groups.title",
"thread.date as last_message_date", "message_count",
"recipient.nickname_joined_name", "thread.date as last_message_date",
]) "recipient.nickname_joined_name",
.where("message_count", ">", 0) ])
.$narrowType<{ .where("message_count", ">", 0)
thread_id: NotNull; .$narrowType<{
archived: NotNull; thread_id: NotNull;
message_count: number; archived: NotNull;
}>() message_count: number;
.compile(); }>()
.execute();
export const allThreadsOverviewQuery = cached(() => kyselyDb().executeQuery(allThreadsOverviewQueryRaw)); export const allThreadsOverviewQuery = cached(allThreadsOverviewQueryRaw);
const overallSentMessagesQueryRaw = (recipientId: number) => const overallSentMessagesQueryRaw = (recipientId: number) =>
kyselyDb() kyselyDb()
.selectFrom("message") ?.selectFrom("message")
.select((eb) => eb.fn.countAll().as("messageCount")) .select((eb) => eb.fn.countAll().as("messageCount"))
.where((eb) => .where((eb) =>
eb.and([ eb.and([
@ -119,7 +105,7 @@ export const overallSentMessagesQuery = cached(overallSentMessagesQueryRaw);
const dmPartnerRecipientQueryRaw = (dmId: number) => const dmPartnerRecipientQueryRaw = (dmId: number) =>
kyselyDb() kyselyDb()
.selectFrom("recipient") ?.selectFrom("recipient")
.select([ .select([
"recipient._id", "recipient._id",
"recipient.system_joined_name", "recipient.system_joined_name",
@ -137,7 +123,7 @@ export const dmPartnerRecipientQuery = cached(dmPartnerRecipientQueryRaw);
const threadSentMessagesOverviewQueryRaw = (threadId: number) => const threadSentMessagesOverviewQueryRaw = (threadId: number) =>
kyselyDb() kyselyDb()
.selectFrom("message") ?.selectFrom("message")
.select(["from_recipient_id", sql<string>`datetime(date_sent / 1000, 'unixepoch')`.as("message_datetime")]) .select(["from_recipient_id", sql<string>`datetime(date_sent / 1000, 'unixepoch')`.as("message_datetime")])
.orderBy(["message_datetime"]) .orderBy(["message_datetime"])
.where((eb) => eb.and([eb("body", "is not", null), eb("body", "!=", ""), eb("thread_id", "=", threadId)])) .where((eb) => eb.and([eb("body", "is not", null), eb("body", "!=", ""), eb("thread_id", "=", threadId)]))
@ -147,7 +133,7 @@ export const threadSentMessagesOverviewQuery = cached(threadSentMessagesOverview
const threadMostUsedWordsQueryRaw = (threadId: number, limit = 10) => const threadMostUsedWordsQueryRaw = (threadId: number, limit = 10) =>
kyselyDb() kyselyDb()
.withRecursive("words", (eb) => { ?.withRecursive("words", (eb) => {
return eb return eb
.selectFrom("message") .selectFrom("message")
.select([ .select([

View file

@ -142,7 +142,9 @@ export const cached = <T extends unknown[], R, TT>(fn: (...args: T) => R, self?:
isPromise = promisified == newValue; isPromise = promisified == newValue;
void promisified.then((result) => { void promisified.then((result) => {
cache.set(cacheName, cacheKey, result); if (result !== undefined) {
cache.set(cacheName, cacheKey, result);
}
}); });
return newValue; return newValue;

View file

@ -57,8 +57,7 @@ export const createMessageStatsSources = (
person[message.fromRecipientId] += 1; person[message.fromRecipientId] += 1;
// increment the message count of the message's month for this recipient // increment the message count of the message's month for this recipient
// months are an array from 0 - 11 month[messageDate.getMonth()][message.fromRecipientId] += 1;
month[messageDate.getMonth() - 1][message.fromRecipientId] += 1;
// biome-ignore lint/style/noNonNullAssertion: <explanation> // biome-ignore lint/style/noNonNullAssertion: <explanation>
const dateStatsEntry = date.find(({ date }) => isSameDay(date, messageDate))!; const dateStatsEntry = date.find(({ date }) => isSameDay(date, messageDate))!;

View file

@ -10,8 +10,8 @@ import { Title } from "@solidjs/meta";
export const Overview: Component<RouteSectionProps> = () => { export const Overview: Component<RouteSectionProps> = () => {
const [allSelfSentMessagesCount] = createResource(() => overallSentMessagesQuery(SELF_ID)); const [allSelfSentMessagesCount] = createResource(() => overallSentMessagesQuery(SELF_ID));
const [roomOverview] = createResource<RoomOverview[]>(async () => { const [roomOverview] = createResource<RoomOverview[] | undefined>(async () => {
return (await allThreadsOverviewQuery()).rows.map((row) => { return (await allThreadsOverviewQuery())?.map((row) => {
const isGroup = row.title !== null; const isGroup = row.title !== null;
let name = ""; let name = "";