import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Automation, AutomationsRepository, } from '@task-stream/api/tracker/application'; import { Model } from 'mongoose'; import { AutomationDoc, AutomationRunDoc, ReadModels, fromDoc, } from './read-model.schemas'; const DUPLICATE_KEY = 11000; @Injectable() export class MongoAutomationsRepository extends AutomationsRepository { constructor( @InjectModel(ReadModels.Automation) private readonly automations: Model, @InjectModel(ReadModels.AutomationRun) private readonly runs: Model, ) { super(); } async findByProject(projectId: string): Promise { const docs = await this.automations .find({ projectId }) .sort({ createdAt: 1 }) .lean(); return docs.map((doc) => fromDoc(doc) as Automation); } async findActive(projectId: string): Promise { const docs = await this.automations .find({ projectId, active: true }) .lean(); return docs.map((doc) => fromDoc(doc) as Automation); } async findById(id: string): Promise { const doc = await this.automations .findOne({ id: id }) .lean(); return doc ? (fromDoc(doc) as Automation) : null; } async insert({ id, ...rest }: Automation): Promise { await this.automations.create({ id, ...rest }); } async update( id: string, changes: Partial>, ): Promise { if (Object.keys(changes).length) await this.automations.updateOne({ id }, { $set: changes }); } async delete(id: string): Promise { await this.automations.deleteOne({ id }); } async claimRun(ruleId: string, eventKey: string): Promise { try { await this.runs.create({ id: `${ruleId}:${eventKey}`, at: new Date() }); return true; } catch (error) { if ((error as { code?: number }).code === DUPLICATE_KEY) return false; throw error; } } async recordRun(id: string, error: string | null): Promise { await this.automations.updateOne( { id }, { $inc: { runs: 1 }, $set: { lastRunAt: new Date().toISOString(), lastError: error }, }, ); } }