102 lines
3.6 KiB
TypeScript
102 lines
3.6 KiB
TypeScript
import { getCollection } from '../../lib/datastore.js';
|
|
import type { FilterMap } from '@bytelyst/datastore';
|
|
import type { IntakeRuleDoc, IntakeJobDoc, IntakeJobStatus } from './types.js';
|
|
|
|
// ── Intake Rules ─────────────────────────────────────────────────
|
|
|
|
function rulesCollection() {
|
|
return getCollection<IntakeRuleDoc>('note_intake_rules', '/userId');
|
|
}
|
|
|
|
export async function createIntakeRule(doc: IntakeRuleDoc): Promise<IntakeRuleDoc> {
|
|
return rulesCollection().create(doc);
|
|
}
|
|
|
|
export async function getIntakeRule(id: string, userId: string): Promise<IntakeRuleDoc | null> {
|
|
return rulesCollection().findById(id, userId);
|
|
}
|
|
|
|
export async function listIntakeRules(
|
|
userId: string,
|
|
productId: string,
|
|
): Promise<IntakeRuleDoc[]> {
|
|
const filter: FilterMap = { productId };
|
|
// Fetch both user rules and built-in rules
|
|
const userRules = await rulesCollection().findMany({ filter: { ...filter, userId }, sort: { priority: 1 }, limit: 100, offset: 0 });
|
|
const builtinRules = await rulesCollection().findMany({ filter: { ...filter, userId: '__builtin__' }, sort: { priority: 1 }, limit: 100, offset: 0 });
|
|
return [...userRules, ...builtinRules];
|
|
}
|
|
|
|
export async function updateIntakeRule(
|
|
id: string,
|
|
userId: string,
|
|
updates: Partial<IntakeRuleDoc>,
|
|
): Promise<IntakeRuleDoc> {
|
|
return rulesCollection().update(id, userId, updates);
|
|
}
|
|
|
|
export async function deleteIntakeRule(id: string, userId: string): Promise<void> {
|
|
await rulesCollection().delete(id, userId);
|
|
}
|
|
|
|
export async function upsertBuiltinIntakeRule(
|
|
rule: Omit<IntakeRuleDoc, 'createdAt' | 'updatedAt' | '_ts' | '_etag'>,
|
|
): Promise<IntakeRuleDoc> {
|
|
const now = new Date().toISOString();
|
|
return rulesCollection().upsert({
|
|
...rule,
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
});
|
|
}
|
|
|
|
// ── Intake Jobs ──────────────────────────────────────────────────
|
|
|
|
function jobsCollection() {
|
|
return getCollection<IntakeJobDoc>('note_intake_jobs', '/userId');
|
|
}
|
|
|
|
export async function createIntakeJob(doc: IntakeJobDoc): Promise<IntakeJobDoc> {
|
|
return jobsCollection().create(doc);
|
|
}
|
|
|
|
export async function getIntakeJob(id: string, userId: string): Promise<IntakeJobDoc | null> {
|
|
return jobsCollection().findById(id, userId);
|
|
}
|
|
|
|
export async function listIntakeJobs(
|
|
userId: string,
|
|
productId: string,
|
|
options?: { statuses?: IntakeJobStatus[]; since?: string; limit?: number; offset?: number },
|
|
): Promise<IntakeJobDoc[]> {
|
|
const filter: FilterMap = { userId, productId };
|
|
// If a single status is provided, use it as a direct filter for efficiency
|
|
if (options?.statuses && options.statuses.length === 1) {
|
|
filter.status = options.statuses[0];
|
|
}
|
|
const limit = options?.limit ?? 20;
|
|
// Fetch more if we need to filter client-side for multiple statuses
|
|
const fetchLimit = options?.statuses && options.statuses.length > 1 ? Math.min(limit * 3, 100) : limit;
|
|
let jobs = await jobsCollection().findMany({
|
|
filter,
|
|
sort: { startedAt: -1 },
|
|
limit: fetchLimit,
|
|
offset: options?.offset ?? 0,
|
|
});
|
|
// Client-side filter for multiple statuses
|
|
if (options?.statuses && options.statuses.length > 1) {
|
|
const statusSet = new Set(options.statuses);
|
|
jobs = jobs.filter((j) => statusSet.has(j.status));
|
|
jobs = jobs.slice(0, limit);
|
|
}
|
|
return jobs;
|
|
}
|
|
|
|
export async function updateIntakeJob(
|
|
id: string,
|
|
userId: string,
|
|
updates: Partial<IntakeJobDoc>,
|
|
): Promise<IntakeJobDoc> {
|
|
return jobsCollection().update(id, userId, updates);
|
|
}
|