Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 38 additions & 8 deletions workers/durableObject/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@ const ALLOWED_SORT_COLUMNS = [

type SortColumn = (typeof ALLOWED_SORT_COLUMNS)[number];

const SQLITE_LIKE_PATTERN_LIMIT = 50;
const LIKE_WILDCARD_PADDING = 2;
const MAX_LIKE_TERM_LENGTH = SQLITE_LIKE_PATTERN_LIMIT - LIKE_WILDCARD_PADDING;

function splitLikeTerm(value: string): string[] {
const trimmed = value.trim();
if (!trimmed) return [];

const chunks: string[] = [];
for (let i = 0; i < trimmed.length; i += MAX_LIKE_TERM_LENGTH) {
chunks.push(trimmed.slice(i, i + MAX_LIKE_TERM_LENGTH));
}
return chunks;
}

/**
* Map SortColumn string names to Drizzle column references for safe
* ORDER BY construction (no string interpolation into SQL).
Expand Down Expand Up @@ -671,20 +686,35 @@ export class MailboxDO extends DurableObject<Env> {
return `?${paramIdx}`;
};

const addLikeConditions = (columns: string[], value: string) => {
for (const term of splitLikeTerm(value)) {
const columnConditions = columns.map(
(column) => `${column} LIKE ${addParam(`%${term}%`)}`,
);
conditions.push(`(${columnConditions.join(" OR ")})`);
}
};

if (query) {
const p1 = addParam(`%${query}%`);
const p2 = addParam(`%${query}%`);
const p3 = addParam(`%${query}%`);
const p4 = addParam(`%${query}%`);
conditions.push(`(${prefix}subject LIKE ${p1} OR ${prefix}body LIKE ${p2} OR ${prefix}sender LIKE ${p3} OR ${prefix}recipient LIKE ${p4} OR ${prefix}cc LIKE ${p4} OR ${prefix}bcc LIKE ${p4})`);
addLikeConditions(
[
`${prefix}subject`,
`${prefix}body`,
`${prefix}sender`,
`${prefix}recipient`,
`${prefix}cc`,
`${prefix}bcc`,
],
query,
);
}
if (folder) {
const p = addParam(folder);
conditions.push(`${prefix}folder_id = (SELECT id FROM folders WHERE name = ${p} OR id = ${p} LIMIT 1)`);
}
if (from) { const p = addParam(`%${from}%`); conditions.push(`${prefix}sender LIKE ${p}`); }
if (to) { const p = addParam(`%${to}%`); conditions.push(`(${prefix}recipient LIKE ${p} OR ${prefix}cc LIKE ${p} OR ${prefix}bcc LIKE ${p})`); }
if (subject) { const p = addParam(`%${subject}%`); conditions.push(`${prefix}subject LIKE ${p}`); }
if (from) addLikeConditions([`${prefix}sender`], from);
if (to) addLikeConditions([`${prefix}recipient`, `${prefix}cc`, `${prefix}bcc`], to);
if (subject) addLikeConditions([`${prefix}subject`], subject);
if (date_start) { const p = addParam(date_start); conditions.push(`${prefix}date >= ${p}`); }
if (date_end) { const p = addParam(date_end); conditions.push(`${prefix}date <= ${p}`); }
if (is_read !== undefined) { const p = addParam(is_read ? 1 : 0); conditions.push(`${prefix}read = ${p}`); }
Expand Down