Skip to content
Merged
Show file tree
Hide file tree
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
8 changes: 4 additions & 4 deletions apps/server/src/routes/threads/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
listThreadMentionRowsByIds,
listThreadsWithPendingInteractionStateOffThread,
markThreadDeleted,
searchThreadsWithPendingInteractionState,
searchThreadsWithPendingInteractionStateOffThread,
updateThread,
type ThreadSearchResultGroup as DbThreadSearchResultGroup,
type UpdateThreadInput,
Expand Down Expand Up @@ -309,7 +309,7 @@ export function registerThreadBaseRoutes(app: Hono, deps: AppDeps): void {
);
});

get(routes.search, (context, query) => {
get(routes.search, async (context, query) => {
const searchQuery = query.query.trim();
if (countNonWhitespaceChars(searchQuery) < 2) {
throw new ApiError(
Expand All @@ -321,10 +321,10 @@ export function registerThreadBaseRoutes(app: Hono, deps: AppDeps): void {
const limitPerGroup = parseSearchLimitPerGroup(query.limitPerGroup);
return context.json(
buildThreadSearchResponse(deps, {
...searchThreadsWithPendingInteractionState(deps.db, {
...(await searchThreadsWithPendingInteractionStateOffThread(deps.db, {
query: searchQuery,
limitPerGroup,
}),
})),
}) satisfies ThreadSearchResponse,
);
});
Expand Down
1 change: 1 addition & 0 deletions packages/db/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { createConnection } from "./connection.js";
export {
listThreadsWithPendingInteractionStateForProjectsOffThread,
listThreadsWithPendingInteractionStateOffThread,
searchThreadsWithPendingInteractionStateOffThread,
startSqliteReadWorker,
stopSqliteReadWorker,
} from "./sqlite-read-queue.js";
Expand Down
28 changes: 22 additions & 6 deletions packages/db/src/sqlite-read-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import type { DbConnection } from "./connection.js";
import {
listThreadsWithPendingInteractionState,
listThreadsWithPendingInteractionStateForProjects,
searchThreadsWithPendingInteractionState,
type ListThreadsForProjectsOptions,
type ListThreadsOptions,
type SearchThreadsWithPendingInteractionStateArgs,
type ThreadSearchResults,
type ThreadWithPendingInteractionState,
} from "./data/threads.js";
import type {
Expand All @@ -16,7 +19,7 @@ import type {

type PendingRead = {
reject: (error: Error) => void;
resolve: (result: ThreadWithPendingInteractionState[]) => void;
resolve: (result: unknown) => void;
};

let worker: Worker | null = null;
Expand Down Expand Up @@ -74,7 +77,7 @@ export function startSqliteReadWorker(args: {
}
pending.delete(response.id);
if (response.ok) {
request.resolve(response.result as ThreadWithPendingInteractionState[]);
request.resolve(response.result);
return;
}
request.reject(new Error(response.error));
Expand Down Expand Up @@ -102,9 +105,9 @@ export async function stopSqliteReadWorker(): Promise<void> {
await current.terminate();
}

async function request(
async function request<T>(
message: Omit<SqliteReadRequest, "id">,
): Promise<ThreadWithPendingInteractionState[]> {
): Promise<T> {
const current = worker;
if (current === null) {
throw new Error("sqlite read worker is not running");
Expand All @@ -124,7 +127,7 @@ export async function listThreadsWithPendingInteractionStateOffThread(
if (worker === null) {
return listThreadsWithPendingInteractionState(db, options);
}
return request({
return request<ThreadWithPendingInteractionState[]>({
name: "listThreadsWithPendingInteractionState",
args: options,
});
Expand All @@ -137,8 +140,21 @@ export async function listThreadsWithPendingInteractionStateForProjectsOffThread
if (worker === null) {
return listThreadsWithPendingInteractionStateForProjects(db, options);
}
return request({
return request<ThreadWithPendingInteractionState[]>({
name: "listThreadsWithPendingInteractionStateForProjects",
args: options,
});
}

export async function searchThreadsWithPendingInteractionStateOffThread(
db: DbConnection,
args: SearchThreadsWithPendingInteractionStateArgs,
): Promise<ThreadSearchResults> {
if (worker === null) {
return searchThreadsWithPendingInteractionState(db, args);
}
return request<ThreadSearchResults>({
name: "searchThreadsWithPendingInteractionState",
args,
});
}
11 changes: 10 additions & 1 deletion packages/db/src/sqlite-read-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { createConnection } from "./connection.js";
import {
listThreadsWithPendingInteractionState,
listThreadsWithPendingInteractionStateForProjects,
searchThreadsWithPendingInteractionState,
type ListThreadsForProjectsOptions,
type ListThreadsOptions,
type SearchThreadsWithPendingInteractionStateArgs,
} from "./data/threads.js";

export type SqliteReadRequest =
Expand All @@ -17,6 +19,11 @@ export type SqliteReadRequest =
id: number;
name: "listThreadsWithPendingInteractionStateForProjects";
args: ListThreadsForProjectsOptions;
}
| {
id: number;
name: "searchThreadsWithPendingInteractionState";
args: SearchThreadsWithPendingInteractionStateArgs;
};

export type SqliteReadResponse =
Expand All @@ -36,7 +43,9 @@ port.on("message", (request: SqliteReadRequest) => {
const result =
request.name === "listThreadsWithPendingInteractionState"
? listThreadsWithPendingInteractionState(db, request.args)
: listThreadsWithPendingInteractionStateForProjects(db, request.args);
: request.name === "listThreadsWithPendingInteractionStateForProjects"
? listThreadsWithPendingInteractionStateForProjects(db, request.args)
: searchThreadsWithPendingInteractionState(db, request.args);
const response: SqliteReadResponse = { id: request.id, ok: true, result };
port.postMessage(response);
} catch (error) {
Expand Down
17 changes: 17 additions & 0 deletions packages/db/test/sqlite-read-queue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@ import {
createThread,
listThreadsWithPendingInteractionState,
listThreadsWithPendingInteractionStateForProjects,
searchThreadsWithPendingInteractionState,
updateThread,
} from "../src/data/threads.js";
import { migrate } from "../src/migrate.js";
import { noopNotifier } from "../src/notifier.js";
import {
isSqliteReadWorkerActive,
listThreadsWithPendingInteractionStateForProjectsOffThread,
listThreadsWithPendingInteractionStateOffThread,
searchThreadsWithPendingInteractionStateOffThread,
startSqliteReadWorker,
stopSqliteReadWorker,
} from "../src/sqlite-read-queue.js";
Expand Down Expand Up @@ -101,4 +104,18 @@ describe("sqlite read queue", () => {
expect(fromWorker).toEqual(fromServing);
expect(fromProjectsWorker).toEqual(fromProjectsServing);
});

it("returns the same thread search from a file-backed worker as the serving connection", async () => {
const { db, source, thread } = createFileDatabase();
updateThread(db, noopNotifier, thread.id, {
title: "alpha search target",
});
startSqliteReadWorker({ source });
expect(isSqliteReadWorkerActive()).toBe(true);

const args = { query: "alpha", limitPerGroup: 10 };
await expect(
searchThreadsWithPendingInteractionStateOffThread(db, args),
).resolves.toEqual(searchThreadsWithPendingInteractionState(db, args));
});
});