Files
agentic-dev/packages/blog/src/infrastructure/repositories/articles.repository.mock.ts

115 lines
3.4 KiB
TypeScript

import "reflect-metadata";
import { injectable } from "inversify";
import {
NoopTracer,
NoopLogger,
type ITracer,
type ILogger,
} from "@repo/core-shared/instrumentation";
import type { IArticlesRepository } from "../../application/repositories/articles.repository.interface";
import type { Article } from "../../entities/models/article";
@injectable()
export class MockArticlesRepository implements IArticlesRepository {
private _articles: Article[] = [];
private tracer: ITracer;
private logger: ILogger;
constructor(
tracer: ITracer = new NoopTracer(),
logger: ILogger = new NoopLogger(),
) {
this.tracer = tracer;
this.logger = logger;
void this.logger; // currently unused; reserved for future mock-thrown captures
}
async getArticle(id: string): Promise<Article | undefined> {
return this.tracer.startSpan(
{ name: "articles.getArticle", op: "repository", attributes: { id } },
async (span) => {
const found = this._articles.find((a) => a.id === id);
span.setAttribute("found", Boolean(found));
return found;
},
);
}
async getArticleBySlug(slug: string): Promise<Article | undefined> {
return this.tracer.startSpan(
{ name: "articles.getArticleBySlug", op: "repository", attributes: { slug } },
async (span) => {
const found = this._articles.find((a) => a.slug === slug);
span.setAttribute("found", Boolean(found));
return found;
},
);
}
async getArticles(options?: {
status?: string;
authorId?: string;
limit?: number;
offset?: number;
}): Promise<Article[]> {
return this.tracer.startSpan(
{
name: "articles.getArticles",
op: "repository",
attributes: {
status: options?.status ?? null,
authorId: options?.authorId ?? null,
limit: options?.limit ?? null,
offset: options?.offset ?? null,
},
},
async (span) => {
let result = [...this._articles];
if (options?.status) {
result = result.filter((a) => a.status === options.status);
}
if (options?.authorId) {
result = result.filter((a) => a.authorId === options.authorId);
}
const offset = options?.offset ?? 0;
const limit = options?.limit ?? 50;
const sliced = result.slice(offset, offset + limit);
span.setAttribute("count", sliced.length);
return sliced;
},
);
}
async createArticle(input: Article): Promise<Article> {
return this.tracer.startSpan(
{ name: "articles.createArticle", op: "repository", attributes: { slug: input.slug } },
async (span) => {
this._articles.push(input);
span.setAttribute("id", input.id);
return input;
},
);
}
async updateArticle(
id: string,
input: Partial<Article>,
): Promise<Article | undefined> {
return this.tracer.startSpan(
{ name: "articles.updateArticle", op: "repository", attributes: { id } },
async (span) => {
const idx = this._articles.findIndex((a) => a.id === id);
if (idx === -1) {
span.setAttribute("found", false);
return undefined;
}
const merged = { ...this._articles[idx]!, ...input, id } as Article;
this._articles[idx] = merged;
span.setAttribute("found", true);
return merged;
},
);
}
}