feat: add built-in backup decryption

This commit is contained in:
Samuel 2024-12-31 16:16:18 +01:00
parent ad9933903c
commit 58a803b0ce
17 changed files with 641 additions and 437 deletions

View file

@ -1,17 +1,52 @@
import { sql, type NotNull } from "kysely";
import { db, kyselyDb, SELF_ID, setDbHash } from "./db";
import { cached } from "./lib/db-cache";
import { kyselyDb, SELF_ID } from "./db";
import { hashString } from "./lib/hash";
export const loadDb = (
statements: string[],
progressCallback?: (percentage: number) => void,
) => {
const length = statements.length;
let percentage = 0;
for (let i = 0; i < length; i++) {
const statement = statements[i];
const newPercentage = Math.round((i / length) * 100);
try {
db.exec(statement);
if (newPercentage !== percentage) {
progressCallback?.(newPercentage);
percentage = newPercentage;
}
} catch (e) {
throw new Error(`statement failed: ${statement}`, {
cause: e,
});
}
}
setDbHash(hashString(statements.join()));
};
const allThreadsOverviewQueryRaw = () =>
kyselyDb()
?.selectFrom("thread")
kyselyDb
.selectFrom("thread")
.innerJoin(
(eb) =>
eb
.selectFrom("message")
.select((eb) => ["message.thread_id", eb.fn.countAll().as("message_count")])
.select((eb) => [
"message.thread_id",
eb.fn.countAll().as("message_count"),
])
.where((eb) => {
return eb.and([eb("message.body", "is not", null), eb("message.body", "is not", "")]);
return eb.and([
eb("message.body", "is not", null),
eb("message.body", "is not", ""),
]);
})
.groupBy("message.thread_id")
.as("message"),
@ -41,8 +76,8 @@ const allThreadsOverviewQueryRaw = () =>
export const allThreadsOverviewQuery = cached(allThreadsOverviewQueryRaw);
const overallSentMessagesQueryRaw = (recipientId: number) =>
kyselyDb()
?.selectFrom("message")
kyselyDb
.selectFrom("message")
.select((eb) => eb.fn.countAll().as("messageCount"))
.where((eb) =>
eb.and([
@ -56,8 +91,8 @@ const overallSentMessagesQueryRaw = (recipientId: number) =>
export const overallSentMessagesQuery = cached(overallSentMessagesQueryRaw);
const dmPartnerRecipientQueryRaw = (dmId: number) =>
kyselyDb()
?.selectFrom("recipient")
kyselyDb
.selectFrom("recipient")
.select([
"recipient._id",
"recipient.system_joined_name",
@ -65,7 +100,9 @@ const dmPartnerRecipientQueryRaw = (dmId: number) =>
"recipient.nickname_joined_name",
])
.innerJoin("thread", "recipient._id", "thread.recipient_id")
.where((eb) => eb.and([eb("thread._id", "=", dmId), eb("recipient._id", "!=", SELF_ID)]))
.where((eb) =>
eb.and([eb("thread._id", "=", dmId), eb("recipient._id", "!=", SELF_ID)]),
)
.$narrowType<{
_id: number;
}>()
@ -74,30 +111,47 @@ const dmPartnerRecipientQueryRaw = (dmId: number) =>
export const dmPartnerRecipientQuery = cached(dmPartnerRecipientQueryRaw);
const threadSentMessagesOverviewQueryRaw = (threadId: number) =>
kyselyDb()
?.selectFrom("message")
.select(["from_recipient_id", sql<string>`datetime(date_sent / 1000, 'unixepoch')`.as("message_datetime")])
kyselyDb
.selectFrom("message")
.select([
"from_recipient_id",
sql<string>`datetime(date_sent / 1000, 'unixepoch')`.as(
"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),
]),
)
.execute();
export const threadSentMessagesOverviewQuery = cached(threadSentMessagesOverviewQueryRaw);
export const threadSentMessagesOverviewQuery = cached(
threadSentMessagesOverviewQueryRaw,
);
const threadMostUsedWordsQueryRaw = (threadId: number, limit = 10) =>
kyselyDb()
?.withRecursive("words", (eb) => {
kyselyDb
.withRecursive("words", (eb) => {
return eb
.selectFrom("message")
.select([
sql`LOWER(substr(body, 1, instr(body || " ", " ") - 1))`.as("word"),
sql`(substr(body, instr(body || " ", " ") + 1))`.as("rest"),
])
.where((eb) => eb.and([eb("body", "is not", null), eb("thread_id", "=", threadId)]))
.where((eb) =>
eb.and([eb("body", "is not", null), eb("thread_id", "=", threadId)]),
)
.unionAll((ebInner) => {
return ebInner
.selectFrom("words")
.select([
sql`LOWER(substr(rest, 1, instr(rest || " ", " ") - 1))`.as("word"),
sql`LOWER(substr(rest, 1, instr(rest || " ", " ") - 1))`.as(
"word",
),
sql`(substr(rest, instr(rest || " ", " ") + 1))`.as("rest"),
])
.where("rest", "<>", "");