feat(TRUEREF-0023): add sqlite-vec search pipeline
This commit is contained in:
@@ -17,6 +17,54 @@ import type { WorkerPool } from './worker-pool.js';
|
||||
|
||||
const JOB_SELECT = `SELECT * FROM indexing_jobs`;
|
||||
|
||||
type JobStatusFilter = IndexingJob['status'] | Array<IndexingJob['status']>;
|
||||
|
||||
function escapeLikePattern(value: string): string {
|
||||
return value.replaceAll('\\', '\\\\').replaceAll('%', '\\%').replaceAll('_', '\\_');
|
||||
}
|
||||
|
||||
function isSpecificRepositoryId(repositoryId: string): boolean {
|
||||
return repositoryId.split('/').filter(Boolean).length >= 2;
|
||||
}
|
||||
|
||||
function normalizeStatuses(status?: JobStatusFilter): Array<IndexingJob['status']> {
|
||||
if (!status) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const statuses = Array.isArray(status) ? status : [status];
|
||||
return [...new Set(statuses)];
|
||||
}
|
||||
|
||||
function buildJobFilterQuery(options?: {
|
||||
repositoryId?: string;
|
||||
status?: JobStatusFilter;
|
||||
}): { where: string; params: unknown[] } {
|
||||
const conditions: string[] = [];
|
||||
const params: unknown[] = [];
|
||||
|
||||
if (options?.repositoryId) {
|
||||
if (isSpecificRepositoryId(options.repositoryId)) {
|
||||
conditions.push('repository_id = ?');
|
||||
params.push(options.repositoryId);
|
||||
} else {
|
||||
conditions.push(`(repository_id = ? OR repository_id LIKE ? ESCAPE '\\')`);
|
||||
params.push(options.repositoryId, `${escapeLikePattern(options.repositoryId)}/%`);
|
||||
}
|
||||
}
|
||||
|
||||
const statuses = normalizeStatuses(options?.status);
|
||||
if (statuses.length > 0) {
|
||||
conditions.push(`status IN (${statuses.map(() => '?').join(', ')})`);
|
||||
params.push(...statuses);
|
||||
}
|
||||
|
||||
return {
|
||||
where: conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '',
|
||||
params
|
||||
};
|
||||
}
|
||||
|
||||
export class JobQueue {
|
||||
private workerPool: WorkerPool | null = null;
|
||||
|
||||
@@ -144,23 +192,11 @@ export class JobQueue {
|
||||
*/
|
||||
listJobs(options?: {
|
||||
repositoryId?: string;
|
||||
status?: IndexingJob['status'];
|
||||
status?: JobStatusFilter;
|
||||
limit?: number;
|
||||
}): IndexingJob[] {
|
||||
const limit = Math.min(options?.limit ?? 20, 200);
|
||||
const conditions: string[] = [];
|
||||
const params: unknown[] = [];
|
||||
|
||||
if (options?.repositoryId) {
|
||||
conditions.push('repository_id = ?');
|
||||
params.push(options.repositoryId);
|
||||
}
|
||||
if (options?.status) {
|
||||
conditions.push('status = ?');
|
||||
params.push(options.status);
|
||||
}
|
||||
|
||||
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
||||
const { where, params } = buildJobFilterQuery(options);
|
||||
const sql = `${JOB_SELECT} ${where} ORDER BY created_at DESC LIMIT ?`;
|
||||
params.push(limit);
|
||||
|
||||
@@ -194,19 +230,7 @@ export class JobQueue {
|
||||
* Count all jobs matching optional filters.
|
||||
*/
|
||||
countJobs(options?: { repositoryId?: string; status?: IndexingJob['status'] }): number {
|
||||
const conditions: string[] = [];
|
||||
const params: unknown[] = [];
|
||||
|
||||
if (options?.repositoryId) {
|
||||
conditions.push('repository_id = ?');
|
||||
params.push(options.repositoryId);
|
||||
}
|
||||
if (options?.status) {
|
||||
conditions.push('status = ?');
|
||||
params.push(options.status);
|
||||
}
|
||||
|
||||
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND')}` : '';
|
||||
const { where, params } = buildJobFilterQuery(options);
|
||||
const sql = `SELECT COUNT(*) as n FROM indexing_jobs ${where}`;
|
||||
const row = this.db.prepare<unknown[], { n: number }>(sql).get(...params);
|
||||
return row?.n ?? 0;
|
||||
|
||||
Reference in New Issue
Block a user