refactor use cases
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
import type { GetAnalyticsMetricsOutput } from '@core/analytics/application/use-cases/GetAnalyticsMetricsUseCase';
|
||||
import type { RecordEngagementOutput } from '@core/analytics/application/use-cases/RecordEngagementUseCase';
|
||||
import type { RecordPageViewOutput } from '@core/analytics/application/use-cases/RecordPageViewUseCase';
|
||||
import type { IEngagementRepository } from '@core/analytics/domain/repositories/IEngagementRepository';
|
||||
import type { IPageViewRepository } from '@core/analytics/application/repositories/IPageViewRepository';
|
||||
import type { Logger, UseCaseOutputPort } from '@core/shared/application';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
import { Provider } from '@nestjs/common';
|
||||
|
||||
import {
|
||||
@@ -13,13 +10,8 @@ import {
|
||||
|
||||
const LOGGER_TOKEN = 'Logger';
|
||||
|
||||
const RECORD_PAGE_VIEW_OUTPUT_PORT_TOKEN = 'RecordPageViewOutputPort_TOKEN';
|
||||
const RECORD_ENGAGEMENT_OUTPUT_PORT_TOKEN = 'RecordEngagementOutputPort_TOKEN';
|
||||
const GET_DASHBOARD_DATA_OUTPUT_PORT_TOKEN = 'GetDashboardDataOutputPort_TOKEN';
|
||||
const GET_ANALYTICS_METRICS_OUTPUT_PORT_TOKEN = 'GetAnalyticsMetricsOutputPort_TOKEN';
|
||||
|
||||
import { GetAnalyticsMetricsUseCase } from '@core/analytics/application/use-cases/GetAnalyticsMetricsUseCase';
|
||||
import { GetDashboardDataOutput, GetDashboardDataUseCase } from '@core/analytics/application/use-cases/GetDashboardDataUseCase';
|
||||
import { GetDashboardDataUseCase } from '@core/analytics/application/use-cases/GetDashboardDataUseCase';
|
||||
import { RecordEngagementUseCase } from '@core/analytics/application/use-cases/RecordEngagementUseCase';
|
||||
import { RecordPageViewUseCase } from '@core/analytics/application/use-cases/RecordPageViewUseCase';
|
||||
import { AnalyticsService } from './AnalyticsService';
|
||||
@@ -34,44 +26,28 @@ export const AnalyticsProviders: Provider[] = [
|
||||
RecordEngagementPresenter,
|
||||
GetDashboardDataPresenter,
|
||||
GetAnalyticsMetricsPresenter,
|
||||
{
|
||||
provide: RECORD_PAGE_VIEW_OUTPUT_PORT_TOKEN,
|
||||
useExisting: RecordPageViewPresenter,
|
||||
},
|
||||
{
|
||||
provide: RECORD_ENGAGEMENT_OUTPUT_PORT_TOKEN,
|
||||
useExisting: RecordEngagementPresenter,
|
||||
},
|
||||
{
|
||||
provide: GET_DASHBOARD_DATA_OUTPUT_PORT_TOKEN,
|
||||
useExisting: GetDashboardDataPresenter,
|
||||
},
|
||||
{
|
||||
provide: GET_ANALYTICS_METRICS_OUTPUT_PORT_TOKEN,
|
||||
useExisting: GetAnalyticsMetricsPresenter,
|
||||
},
|
||||
{
|
||||
provide: RecordPageViewUseCase,
|
||||
useFactory: (repo: IPageViewRepository, logger: Logger, output: UseCaseOutputPort<RecordPageViewOutput>) =>
|
||||
new RecordPageViewUseCase(repo, logger, output),
|
||||
inject: [ANALYTICS_PAGE_VIEW_REPOSITORY_TOKEN, LOGGER_TOKEN, RECORD_PAGE_VIEW_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (repo: IPageViewRepository, logger: Logger) =>
|
||||
new RecordPageViewUseCase(repo, logger),
|
||||
inject: [ANALYTICS_PAGE_VIEW_REPOSITORY_TOKEN, LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: RecordEngagementUseCase,
|
||||
useFactory: (repo: IEngagementRepository, logger: Logger, output: UseCaseOutputPort<RecordEngagementOutput>) =>
|
||||
new RecordEngagementUseCase(repo, logger, output),
|
||||
inject: [ANALYTICS_ENGAGEMENT_REPOSITORY_TOKEN, LOGGER_TOKEN, RECORD_ENGAGEMENT_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (repo: IEngagementRepository, logger: Logger) =>
|
||||
new RecordEngagementUseCase(repo, logger),
|
||||
inject: [ANALYTICS_ENGAGEMENT_REPOSITORY_TOKEN, LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: GetDashboardDataUseCase,
|
||||
useFactory: (logger: Logger, output: UseCaseOutputPort<GetDashboardDataOutput>) =>
|
||||
new GetDashboardDataUseCase(logger, output),
|
||||
inject: [LOGGER_TOKEN, GET_DASHBOARD_DATA_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (logger: Logger) =>
|
||||
new GetDashboardDataUseCase(logger),
|
||||
inject: [LOGGER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: GetAnalyticsMetricsUseCase,
|
||||
useFactory: (logger: Logger, output: UseCaseOutputPort<GetAnalyticsMetricsOutput>, repo: IPageViewRepository) =>
|
||||
new GetAnalyticsMetricsUseCase(logger, output, repo),
|
||||
inject: [LOGGER_TOKEN, GET_ANALYTICS_METRICS_OUTPUT_PORT_TOKEN, ANALYTICS_PAGE_VIEW_REPOSITORY_TOKEN],
|
||||
useFactory: (logger: Logger, repo: IPageViewRepository) =>
|
||||
new GetAnalyticsMetricsUseCase(logger, repo),
|
||||
inject: [LOGGER_TOKEN, ANALYTICS_PAGE_VIEW_REPOSITORY_TOKEN],
|
||||
},
|
||||
];
|
||||
@@ -12,8 +12,7 @@ describe('AnalyticsService', () => {
|
||||
|
||||
const recordPageViewUseCase = {
|
||||
execute: vi.fn(async () => {
|
||||
recordPageViewPresenter.present({ pageViewId: 'pv-1' });
|
||||
return Result.ok(undefined);
|
||||
return Result.ok({ pageViewId: 'pv-1' });
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -77,8 +76,7 @@ describe('AnalyticsService', () => {
|
||||
const recordEngagementPresenter = new RecordEngagementPresenter();
|
||||
const recordEngagementUseCase = {
|
||||
execute: vi.fn(async () => {
|
||||
recordEngagementPresenter.present({ eventId: 'e1', engagementWeight: 7 });
|
||||
return Result.ok(undefined);
|
||||
return Result.ok({ eventId: 'e1', engagementWeight: 7 });
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -154,13 +152,12 @@ describe('AnalyticsService', () => {
|
||||
const getDashboardDataPresenter = new GetDashboardDataPresenter();
|
||||
const getDashboardDataUseCase = {
|
||||
execute: vi.fn(async () => {
|
||||
getDashboardDataPresenter.present({
|
||||
return Result.ok({
|
||||
totalUsers: 1,
|
||||
activeUsers: 2,
|
||||
totalRaces: 3,
|
||||
totalLeagues: 4,
|
||||
});
|
||||
return Result.ok(undefined);
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -217,13 +214,12 @@ describe('AnalyticsService', () => {
|
||||
const getAnalyticsMetricsPresenter = new GetAnalyticsMetricsPresenter();
|
||||
const getAnalyticsMetricsUseCase = {
|
||||
execute: vi.fn(async () => {
|
||||
getAnalyticsMetricsPresenter.present({
|
||||
return Result.ok({
|
||||
pageViews: 10,
|
||||
uniqueVisitors: 0,
|
||||
averageSessionDuration: 0,
|
||||
bounceRate: 0,
|
||||
});
|
||||
return Result.ok(undefined);
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -275,4 +271,4 @@ describe('AnalyticsService', () => {
|
||||
|
||||
await expect(service.getAnalyticsMetrics()).rejects.toThrow('Failed to get analytics metrics');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -31,50 +31,42 @@ export class AnalyticsService {
|
||||
) {}
|
||||
|
||||
async recordPageView(input: RecordPageViewInput): Promise<RecordPageViewOutputDTO> {
|
||||
this.recordPageViewPresenter.reset();
|
||||
|
||||
const result = await this.recordPageViewUseCase.execute(input);
|
||||
if (result.isErr()) {
|
||||
const error = result.unwrapErr();
|
||||
throw new Error(error.details?.message ?? 'Failed to record page view');
|
||||
}
|
||||
|
||||
return this.recordPageViewPresenter.responseModel;
|
||||
return this.recordPageViewPresenter.transform(result.unwrap());
|
||||
}
|
||||
|
||||
async recordEngagement(input: RecordEngagementInput): Promise<RecordEngagementOutputDTO> {
|
||||
this.recordEngagementPresenter.reset();
|
||||
|
||||
const result = await this.recordEngagementUseCase.execute(input);
|
||||
if (result.isErr()) {
|
||||
const error = result.unwrapErr();
|
||||
throw new Error(error.details?.message ?? 'Failed to record engagement');
|
||||
}
|
||||
|
||||
return this.recordEngagementPresenter.responseModel;
|
||||
return this.recordEngagementPresenter.transform(result.unwrap());
|
||||
}
|
||||
|
||||
async getDashboardData(): Promise<GetDashboardDataOutputDTO> {
|
||||
this.getDashboardDataPresenter.reset();
|
||||
|
||||
const result = await this.getDashboardDataUseCase.execute();
|
||||
if (result.isErr()) {
|
||||
const error = result.unwrapErr();
|
||||
throw new Error(error.details?.message ?? 'Failed to get dashboard data');
|
||||
}
|
||||
|
||||
return this.getDashboardDataPresenter.responseModel;
|
||||
return this.getDashboardDataPresenter.transform(result.unwrap());
|
||||
}
|
||||
|
||||
async getAnalyticsMetrics(): Promise<GetAnalyticsMetricsOutputDTO> {
|
||||
this.getAnalyticsMetricsPresenter.reset();
|
||||
|
||||
const result = await this.getAnalyticsMetricsUseCase.execute({});
|
||||
if (result.isErr()) {
|
||||
const error = result.unwrapErr();
|
||||
throw new Error(error.details?.message ?? 'Failed to get analytics metrics');
|
||||
}
|
||||
|
||||
return this.getAnalyticsMetricsPresenter.responseModel;
|
||||
return this.getAnalyticsMetricsPresenter.transform(result.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ describe('GetAnalyticsMetricsPresenter', () => {
|
||||
bounceRate: 0.4,
|
||||
};
|
||||
|
||||
presenter.present(output);
|
||||
presenter.transform(output);
|
||||
|
||||
const dto = presenter.getResponseModel();
|
||||
|
||||
@@ -35,11 +35,11 @@ describe('GetAnalyticsMetricsPresenter', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('getResponseModel throws if not presented', () => {
|
||||
expect(() => presenter.getResponseModel()).toThrow('Presenter not presented');
|
||||
it('getResponseModel throws if not transformed', () => {
|
||||
expect(() => presenter.getResponseModel()).toThrow('Presenter not transformed');
|
||||
});
|
||||
|
||||
it('responseModel throws if not presented', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
it('responseModel throws if not transformed', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not transformed');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
import type { GetAnalyticsMetricsOutput } from '@core/analytics/application/use-cases/GetAnalyticsMetricsUseCase';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application';
|
||||
import type { GetAnalyticsMetricsOutputDTO } from '../dtos/GetAnalyticsMetricsOutputDTO';
|
||||
|
||||
export class GetAnalyticsMetricsPresenter implements UseCaseOutputPort<GetAnalyticsMetricsOutput> {
|
||||
export class GetAnalyticsMetricsPresenter {
|
||||
private model: GetAnalyticsMetricsOutputDTO | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.model = null;
|
||||
}
|
||||
|
||||
present(result: GetAnalyticsMetricsOutput): void {
|
||||
transform(result: GetAnalyticsMetricsOutput): GetAnalyticsMetricsOutputDTO {
|
||||
this.model = {
|
||||
pageViews: result.pageViews,
|
||||
uniqueVisitors: result.uniqueVisitors,
|
||||
averageSessionDuration: result.averageSessionDuration,
|
||||
bounceRate: result.bounceRate,
|
||||
};
|
||||
return this.model;
|
||||
}
|
||||
|
||||
get responseModel(): GetAnalyticsMetricsOutputDTO {
|
||||
if (!this.model) throw new Error('Presenter not presented');
|
||||
if (!this.model) throw new Error('Presenter not transformed');
|
||||
return this.model;
|
||||
}
|
||||
|
||||
getResponseModel(): GetAnalyticsMetricsOutputDTO {
|
||||
if (!this.model) throw new Error('Presenter not presented');
|
||||
if (!this.model) throw new Error('Presenter not transformed');
|
||||
return this.model;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ describe('GetDashboardDataPresenter', () => {
|
||||
totalLeagues: 5,
|
||||
};
|
||||
|
||||
presenter.present(output);
|
||||
presenter.transform(output);
|
||||
|
||||
expect(presenter.getResponseModel()).toEqual({
|
||||
totalUsers: 100,
|
||||
@@ -33,11 +33,11 @@ describe('GetDashboardDataPresenter', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('getResponseModel throws if not presented', () => {
|
||||
expect(() => presenter.getResponseModel()).toThrow('Presenter not presented');
|
||||
it('getResponseModel throws if not transformed', () => {
|
||||
expect(() => presenter.getResponseModel()).toThrow('Presenter not transformed');
|
||||
});
|
||||
|
||||
it('responseModel throws if not presented', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
it('responseModel throws if not transformed', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not transformed');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
import type { GetDashboardDataOutput } from '@core/analytics/application/use-cases/GetDashboardDataUseCase';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application';
|
||||
import type { GetDashboardDataOutputDTO } from '../dtos/GetDashboardDataOutputDTO';
|
||||
|
||||
export class GetDashboardDataPresenter implements UseCaseOutputPort<GetDashboardDataOutput> {
|
||||
export class GetDashboardDataPresenter {
|
||||
private model: GetDashboardDataOutputDTO | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.model = null;
|
||||
}
|
||||
|
||||
present(result: GetDashboardDataOutput): void {
|
||||
transform(result: GetDashboardDataOutput): GetDashboardDataOutputDTO {
|
||||
this.model = {
|
||||
totalUsers: result.totalUsers,
|
||||
activeUsers: result.activeUsers,
|
||||
totalRaces: result.totalRaces,
|
||||
totalLeagues: result.totalLeagues,
|
||||
};
|
||||
return this.model;
|
||||
}
|
||||
|
||||
get responseModel(): GetDashboardDataOutputDTO {
|
||||
if (!this.model) throw new Error('Presenter not presented');
|
||||
if (!this.model) throw new Error('Presenter not transformed');
|
||||
return this.model;
|
||||
}
|
||||
|
||||
getResponseModel(): GetDashboardDataOutputDTO {
|
||||
if (!this.model) throw new Error('Presenter not presented');
|
||||
if (!this.model) throw new Error('Presenter not transformed');
|
||||
return this.model;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,23 +15,15 @@ describe('RecordEngagementPresenter', () => {
|
||||
engagementWeight: 10,
|
||||
};
|
||||
|
||||
presenter.present(output);
|
||||
presenter.transform(output);
|
||||
|
||||
expect(presenter.getResponseModel()).toEqual({
|
||||
eventId: 'event-123',
|
||||
engagementWeight: 10,
|
||||
});
|
||||
expect(presenter.responseModel).toEqual({
|
||||
eventId: 'event-123',
|
||||
engagementWeight: 10,
|
||||
});
|
||||
});
|
||||
|
||||
it('getResponseModel throws if not presented', () => {
|
||||
expect(() => presenter.getResponseModel()).toThrow('Presenter not presented');
|
||||
});
|
||||
|
||||
it('responseModel throws if not presented', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
it('responseModel throws if not transformed', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not transformed');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,28 +1,19 @@
|
||||
import type { RecordEngagementOutput } from '@core/analytics/application/use-cases/RecordEngagementUseCase';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application';
|
||||
import type { RecordEngagementOutputDTO } from '../dtos/RecordEngagementOutputDTO';
|
||||
|
||||
export class RecordEngagementPresenter implements UseCaseOutputPort<RecordEngagementOutput> {
|
||||
export class RecordEngagementPresenter {
|
||||
private model: RecordEngagementOutputDTO | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.model = null;
|
||||
}
|
||||
|
||||
present(result: RecordEngagementOutput): void {
|
||||
transform(output: RecordEngagementOutput): RecordEngagementOutputDTO {
|
||||
this.model = {
|
||||
eventId: result.eventId,
|
||||
engagementWeight: result.engagementWeight,
|
||||
eventId: output.eventId,
|
||||
engagementWeight: output.engagementWeight,
|
||||
};
|
||||
return this.model;
|
||||
}
|
||||
|
||||
get responseModel(): RecordEngagementOutputDTO {
|
||||
if (!this.model) throw new Error('Presenter not presented');
|
||||
if (!this.model) throw new Error('Presenter not transformed');
|
||||
return this.model;
|
||||
}
|
||||
|
||||
getResponseModel(): RecordEngagementOutputDTO {
|
||||
if (!this.model) throw new Error('Presenter not presented');
|
||||
return this.model;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,21 +14,14 @@ describe('RecordPageViewPresenter', () => {
|
||||
pageViewId: 'pv-123',
|
||||
};
|
||||
|
||||
presenter.present(output);
|
||||
presenter.transform(output);
|
||||
|
||||
expect(presenter.getResponseModel()).toEqual({
|
||||
pageViewId: 'pv-123',
|
||||
});
|
||||
expect(presenter.responseModel).toEqual({
|
||||
pageViewId: 'pv-123',
|
||||
});
|
||||
});
|
||||
|
||||
it('getResponseModel throws if not presented', () => {
|
||||
expect(() => presenter.getResponseModel()).toThrow('Presenter not presented');
|
||||
});
|
||||
|
||||
it('responseModel throws if not presented', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
it('responseModel throws if not transformed', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not transformed');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,27 +1,18 @@
|
||||
import type { RecordPageViewOutput } from '@core/analytics/application/use-cases/RecordPageViewUseCase';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application';
|
||||
import type { RecordPageViewOutputDTO } from '../dtos/RecordPageViewOutputDTO';
|
||||
|
||||
export class RecordPageViewPresenter implements UseCaseOutputPort<RecordPageViewOutput> {
|
||||
export class RecordPageViewPresenter {
|
||||
private model: RecordPageViewOutputDTO | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.model = null;
|
||||
}
|
||||
|
||||
present(result: RecordPageViewOutput): void {
|
||||
transform(output: RecordPageViewOutput): RecordPageViewOutputDTO {
|
||||
this.model = {
|
||||
pageViewId: result.pageViewId,
|
||||
pageViewId: output.pageViewId,
|
||||
};
|
||||
return this.model;
|
||||
}
|
||||
|
||||
get responseModel(): RecordPageViewOutputDTO {
|
||||
if (!this.model) throw new Error('Presenter not presented');
|
||||
if (!this.model) throw new Error('Presenter not transformed');
|
||||
return this.model;
|
||||
}
|
||||
|
||||
getResponseModel(): RecordPageViewOutputDTO {
|
||||
if (!this.model) throw new Error('Presenter not presented');
|
||||
return this.model;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user