sqlite: implement deleteMessages

This is laying the foundation to build a cleaning task that's
sort of database agnostic.
All calls are done by acting on a "DeletionRequest" so interpretation
of the config will go through a single point
This commit is contained in:
Reto Brunner 2023-11-04 17:19:45 +01:00
commit 14d9ff247d
3 changed files with 155 additions and 3 deletions

View file

@ -7,7 +7,7 @@ import Config from "../../config";
import Msg, {Message} from "../../models/msg";
import Chan, {Channel} from "../../models/chan";
import Helper from "../../helper";
import type {SearchResponse, SearchQuery, SearchableMessageStorage} from "./types";
import type {SearchResponse, SearchQuery, SearchableMessageStorage, DeletionRequest} from "./types";
import Network from "../../models/network";
// TODO; type
@ -234,6 +234,11 @@ class SqliteMessageStorage implements SearchableMessageStorage {
await this.serialize_run("VACUUM");
}
// helper method that vacuums the db, meant to be used by migration related cli commands
async vacuum() {
await this.serialize_run("VACUUM");
}
async close() {
if (!this.isEnabled) {
return;
@ -481,6 +486,33 @@ class SqliteMessageStorage implements SearchableMessageStorage {
};
}
async deleteMessages(req: DeletionRequest): Promise<number> {
await this.initDone.promise;
let sql = "delete from messages where id in (select id from messages where\n";
// We roughly get a timestamp from N days before.
// We don't adjust for daylight savings time or other weird time jumps
const millisecondsInDay = 24 * 60 * 60 * 1000;
const deleteBefore = Date.now() - req.olderThanDays * millisecondsInDay;
sql += `time <= ${deleteBefore}\n`;
let typeClause = "";
if (req.messageTypes !== null) {
typeClause = `type in (${req.messageTypes.map((type) => `'${type}'`).join(",")})\n`;
}
if (typeClause) {
sql += `and ${typeClause}`;
}
sql += "order by time asc\n";
sql += `limit ${req.limit}\n`;
sql += ")";
return this.serialize_run(sql);
}
canProvideMessages() {
return this.isEnabled;
}
@ -488,13 +520,13 @@ class SqliteMessageStorage implements SearchableMessageStorage {
private serialize_run(stmt: string, ...params: any[]): Promise<number> {
return new Promise((resolve, reject) => {
this.database.serialize(() => {
this.database.run(stmt, params, (err) => {
this.database.run(stmt, params, function (err) {
if (err) {
reject(err);
return;
}
resolve();
resolve(this.changes); // number of affected rows, `this` is re-bound by sqlite3
});
});
});

View file

@ -4,6 +4,13 @@ import {Channel} from "../../models/channel";
import {Message} from "../../models/message";
import {Network} from "../../models/network";
import Client from "../../client";
import type {MessageType} from "../../models/msg";
export type DeletionRequest = {
olderThanDays: number;
messageTypes: MessageType[] | null; // null means no restriction
limit: number; // -1 means unlimited
};
interface MessageStorage {
isEnabled: boolean;