Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ describe('EmailReportWriter', () => {
prompts: [],
}),
};
const consumptionTrackingService = {
registerEmailBasedReportRunConsumption: jest.fn().mockResolvedValue(undefined),
};
const eventDispatcher = {
publishExternal: jest.fn().mockResolvedValue(undefined),
};
Expand Down Expand Up @@ -72,7 +69,6 @@ describe('EmailReportWriter', () => {
markdownParser as never as MarkdownParser,
publicOriginService as never,
insightTemplateFacade as never as DataMartInsightTemplateFacadeImpl,
consumptionTrackingService as never,
eventDispatcher as never,
credentialsResolver as never as DataDestinationCredentialsResolver,
sourceDataService as never as InsightTemplateSourceDataService,
Expand All @@ -86,7 +82,6 @@ describe('EmailReportWriter', () => {
insightTemplateService,
sourceUsageService,
credentialsResolver,
consumptionTrackingService,
eventDispatcher,
};
};
Expand Down Expand Up @@ -134,6 +129,30 @@ describe('EmailReportWriter', () => {
},
}) as Report;

it('finalizes delivery without returning consumption metadata', async () => {
const { writer, emailProvider, eventDispatcher } = createWriter();
const report = createReport();

await writer.prepareToWriteReport(report, new ReportDataDescription([]));
const result = await writer.finalize();

expect(result).toBeUndefined();
expect(emailProvider.sendEmail).toHaveBeenCalledTimes(1);
expect(eventDispatcher.publishExternal).toHaveBeenCalledTimes(1);
const event = eventDispatcher.publishExternal.mock.calls[0][0] as {
name: string;
payload: unknown;
};
expect(event.name).toBe('email.report.run.successfully');
expect(event.payload).toEqual({
dataMartId: 'data-mart-1',
runId: 'report-1',
biProjectId: 'project-1',
userId: 'user-1',
status: 'successfully',
});
});

it('passes preloaded main source to buildRenderContext for insight template reports', async () => {
const { writer, sourceDataService, insightTemplateFacade, emailProvider, sourceUsageService } =
createWriter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import {
ReportRunExecutionContext,
ReportRunLogger,
} from '../../../../report-run-logging/report-run-logger';
import { ConsumptionTrackingService } from '../../../../services/consumption-tracking.service';
import { InsightTemplateSourceDataService } from '../../../../services/insight-template-source-data.service';
import { InsightTemplateService } from '../../../../services/insight-template.service';
import { InsightTemplateSourceUsageService } from '../../../../services/insight-template-source-usage.service';
Expand All @@ -43,6 +42,7 @@ import { TemplateSourceTypeEnum } from '../../../../enums/template-source-type.e
import { ReportCondition } from '../../../enums/report-condition.enum';
import {
DataDestinationReportWriter,
ReportWriteFinalizeResult,
ReportWriteFinalizeMeta,
} from '../../../interfaces/data-destination-report-writer.interface';
import { RowsTruncationInfo } from '../../../../use-cases/report-execution-policy.resolver';
Expand Down Expand Up @@ -83,7 +83,6 @@ abstract class BaseEmailReportWriter implements DataDestinationReportWriter {
private readonly markdownParser: MarkdownParser,
private readonly publicOriginService: PublicOriginService,
private readonly insightTemplateFacade: DataMartInsightTemplateFacadeImpl,
private readonly consumptionTrackingService: ConsumptionTrackingService,
private readonly eventDispatcher: OwoxEventDispatcher,
private readonly credentialsResolver: DataDestinationCredentialsResolver,
private readonly sourceDataService: InsightTemplateSourceDataService,
Expand Down Expand Up @@ -119,7 +118,10 @@ abstract class BaseEmailReportWriter implements DataDestinationReportWriter {
this.reportDataRows.push(...reportDataBatch.dataRows);
}

public async finalize(processingError?: Error, meta?: ReportWriteFinalizeMeta): Promise<void> {
public async finalize(
processingError?: Error,
meta?: ReportWriteFinalizeMeta
): Promise<ReportWriteFinalizeResult | void> {
this.mainRowsTruncationInfo = meta?.mainRowsTruncationInfo ?? null;

if (processingError) {
Expand All @@ -139,7 +141,6 @@ abstract class BaseEmailReportWriter implements DataDestinationReportWriter {
await this.sendEmail(emailHtml);
}

await this.consumptionTrackingService.registerEmailBasedReportRunConsumption(this.report);
await this.produceRunEvent('successfully');
}

Expand Down Expand Up @@ -420,7 +421,6 @@ export class EmailReportWriter extends BaseEmailReportWriter {
markdownParser: MarkdownParser,
publicOriginService: PublicOriginService,
insightTemplateFacade: DataMartInsightTemplateFacadeImpl,
consumptionTrackingService: ConsumptionTrackingService,
eventDispatcher: OwoxEventDispatcher,
credentialsResolver: DataDestinationCredentialsResolver,
sourceDataService: InsightTemplateSourceDataService,
Expand All @@ -432,7 +432,6 @@ export class EmailReportWriter extends BaseEmailReportWriter {
markdownParser,
publicOriginService,
insightTemplateFacade,
consumptionTrackingService,
eventDispatcher,
credentialsResolver,
sourceDataService,
Expand All @@ -452,7 +451,6 @@ export class SlackReportWriter extends BaseEmailReportWriter {
markdownParser: MarkdownParser,
publicOriginService: PublicOriginService,
insightTemplateFacade: DataMartInsightTemplateFacadeImpl,
consumptionTrackingService: ConsumptionTrackingService,
eventDispatcher: OwoxEventDispatcher,
credentialsResolver: DataDestinationCredentialsResolver,
sourceDataService: InsightTemplateSourceDataService,
Expand All @@ -464,7 +462,6 @@ export class SlackReportWriter extends BaseEmailReportWriter {
markdownParser,
publicOriginService,
insightTemplateFacade,
consumptionTrackingService,
eventDispatcher,
credentialsResolver,
sourceDataService,
Expand All @@ -484,7 +481,6 @@ export class MsTeamsReportWriter extends BaseEmailReportWriter {
markdownParser: MarkdownParser,
publicOriginService: PublicOriginService,
insightTemplateFacade: DataMartInsightTemplateFacadeImpl,
consumptionTrackingService: ConsumptionTrackingService,
eventDispatcher: OwoxEventDispatcher,
credentialsResolver: DataDestinationCredentialsResolver,
sourceDataService: InsightTemplateSourceDataService,
Expand All @@ -496,7 +492,6 @@ export class MsTeamsReportWriter extends BaseEmailReportWriter {
markdownParser,
publicOriginService,
insightTemplateFacade,
consumptionTrackingService,
eventDispatcher,
credentialsResolver,
sourceDataService,
Expand All @@ -516,7 +511,6 @@ export class GoogleChatReportWriter extends BaseEmailReportWriter {
markdownParser: MarkdownParser,
publicOriginService: PublicOriginService,
insightTemplateFacade: DataMartInsightTemplateFacadeImpl,
consumptionTrackingService: ConsumptionTrackingService,
eventDispatcher: OwoxEventDispatcher,
credentialsResolver: DataDestinationCredentialsResolver,
sourceDataService: InsightTemplateSourceDataService,
Expand All @@ -528,7 +522,6 @@ export class GoogleChatReportWriter extends BaseEmailReportWriter {
markdownParser,
publicOriginService,
insightTemplateFacade,
consumptionTrackingService,
eventDispatcher,
credentialsResolver,
sourceDataService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,6 @@ function buildWriter(opts: BuildOpts) {
formatRowsValuesByName: jest.fn().mockImplementation((rows: unknown[][]) => rows),
};

const consumptionTrackingService = {
registerSheetsReportRunConsumption: jest.fn().mockResolvedValue(undefined),
};
const appEditionConfig = { isEnterpriseEdition: jest.fn().mockReturnValue(true) };
const publicOriginService = {
getPublicOrigin: jest.fn().mockReturnValue('https://example.test'),
Expand All @@ -151,7 +148,6 @@ function buildWriter(opts: BuildOpts) {
valuesFormatter as never,
columnPlanBuilder as never,
adapterFactory as never,
consumptionTrackingService as never,
appEditionConfig as never,
publicOriginService as never,
eventDispatcher as never
Expand All @@ -176,6 +172,29 @@ const makeHeaders = (...names: string[]): ReportDataHeader[] =>
names.map(n => new ReportDataHeader(n));

describe('GoogleSheetsReportWriter — pre-clears imported rectangle before writing', () => {
it('returns Sheets consumption metadata without registering consumption directly', async () => {
const { writer, report, finalImportedNames } = buildWriter({
availableRowsCount: 11,
});

await writer.prepareToWriteReport(
report as never,
new ReportDataDescription(makeHeaders(...finalImportedNames), 1)
);
await writer.writeReportDataBatch(new ReportDataBatch([['A', '10', '2']]));

const result = await writer.finalize();

expect(result).toEqual({
consumption: {
googleSheets: {
googleSheetsDocumentTitle: 'Test Spreadsheet',
googleSheetsListTitle: SHEET_TITLE,
},
},
});
});

it('pre-clears A2..lastImportedColA1:availableRows on the first batch', async () => {
// Sheet had 11 rows from a previous (larger) refresh; this run will write
// header (row 1) + a single data row (row 2). The pre-clear must wipe
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ReportDataHeader } from '../../../dto/domain/report-data-header.dto';
import { ColumnPlan, PreviousImportedColumn } from '../../../dto/domain/column-plan.dto';
import { ConsumptionTrackingService } from '../../../services/consumption-tracking.service';
import {
DataDestinationReportWriter,
ReportWriteFinalizeMeta,
ReportWriteFinalizeResult,
} from '../../interfaces/data-destination-report-writer.interface';
import { DataDestinationType } from '../../enums/data-destination-type.enum';
import { Injectable, Logger, Scope } from '@nestjs/common';
Expand Down Expand Up @@ -78,7 +78,6 @@ export class GoogleSheetsReportWriter implements DataDestinationReportWriter {
private readonly valuesFormatter: SheetValuesFormatter,
private readonly columnPlanBuilder: ColumnPlanBuilder,
private readonly adapterFactory: GoogleSheetsApiAdapterFactory,
private readonly consumptionTrackingService: ConsumptionTrackingService,
private readonly appEditionConfig: AppEditionConfig,
private readonly publicOriginService: PublicOriginService,
private readonly eventDispatcher: OwoxEventDispatcher
Expand Down Expand Up @@ -321,7 +320,10 @@ export class GoogleSheetsReportWriter implements DataDestinationReportWriter {
* data, and the design contract is that such failures must leave the
* sheet exactly as the user last saw it.
*/
public async finalize(processingError?: Error, _meta?: ReportWriteFinalizeMeta): Promise<void> {
public async finalize(
processingError?: Error,
_meta?: ReportWriteFinalizeMeta
): Promise<ReportWriteFinalizeResult | void> {
await this.executeWithErrorHandling(async () => {
// Zero-batch happy path: the reader finished cleanly but had nothing
// to write. Bring the sheet layout up to date so column changes do
Expand Down Expand Up @@ -477,11 +479,6 @@ export class GoogleSheetsReportWriter implements DataDestinationReportWriter {
}
}, 'Finalizing report with metadata and formatting');
if (!processingError) {
await this.consumptionTrackingService.registerSheetsReportRunConsumption(this.report, {
googleSheetsDocumentTitle: this.spreadsheetTitle,
googleSheetsListTitle: this.sheetTitle,
});

const dataMart = this.report.dataMart;
await this.eventDispatcher.publishExternal(
new SheetsReportRunEvent(
Expand All @@ -492,6 +489,14 @@ export class GoogleSheetsReportWriter implements DataDestinationReportWriter {
'successfully'
)
);
return {
consumption: {
googleSheets: {
googleSheetsDocumentTitle: this.spreadsheetTitle,
googleSheetsListTitle: this.sheetTitle,
},
},
};
} else {
const dataMart = this.report.dataMart;
await this.eventDispatcher.publishExternal(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ export interface ReportWriteFinalizeMeta {
mainRowsTruncationInfo?: RowsTruncationInfo | null;
}

export interface ReportWriteFinalizeResult {
consumption?: {
googleSheets?: {
googleSheetsDocumentTitle: string;
googleSheetsListTitle: string;
};
};
}

/**
* Interface for writing reports to data destinations
* Implementations handle the specifics of writing data to different destination types
Expand Down Expand Up @@ -42,5 +51,8 @@ export interface DataDestinationReportWriter extends TypedComponent<DataDestinat
* @param processingError - Optional error that occurred during report processing
* @param meta - Optional report-level metadata computed during execution
*/
finalize(processingError?: Error, meta?: ReportWriteFinalizeMeta): Promise<void>;
finalize(
processingError?: Error,
meta?: ReportWriteFinalizeMeta
): Promise<ReportWriteFinalizeResult | void>;
}
Loading
Loading