learning_ai_notes/backend/src/modules/intake/repository.ts

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);
}