Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support for sql reports without date range #2502

Merged
merged 7 commits into from
Aug 8, 2024
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
2 changes: 1 addition & 1 deletion src/app/core/entity/database-field.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { EntitySchema } from "./schema/entity-schema";
* @param propertySchema (optional) SchemaField definition that configures additional options regarding this field
*/
export function DatabaseField(propertySchema: EntitySchemaField = {}) {
return (target, propertyName: string) => {
return (target: any, propertyName: string) => {
// Retrieve datatype from TypeScript type definition
if (propertySchema.dataType === undefined) {
const type = Reflect.getMetadata("design:type", target, propertyName);
Expand Down
17 changes: 15 additions & 2 deletions src/app/features/reporting/report-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,16 @@ class ReportConfig extends Entity {
*/
@DatabaseField() mode?: string;

/**
* (sql only) list of arguments needed for the sql query. Placeholder "?" will be replaced.
*/
@DatabaseField() neededArgs?: string[] = [];

/** the definitions to calculate the report's aggregations */
@DatabaseField() aggregationDefinitions: any[] = [];

/** (sql only) the definition to calculate the report */
@DatabaseField() aggregationDefinition: string | undefined = undefined;
}

/**
Expand Down Expand Up @@ -62,7 +70,12 @@ export interface ExportingReport extends ReportConfig {
export interface SqlReport extends ReportConfig {
mode: "sql";
/**
* Array of valid SQL SELECT statements
* a valid SQL SELECT statements, can contain "?" placeholder for arguments
*/
aggregationDefinition: string;

/**
* a list of arguments, passed into the sql statement
*/
aggregationDefinitions: string[];
neededArgs: string[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ describe("ReportingComponent", () => {
status: "FINISHED_SUCCESS",
startDate: "2024-06-07T09:26:56.414",
endDate: "2024-06-09T09:26:57.431",
args: new Map<String, String>([
["from", "2024-01-01T00:00:00.000"],
["to", "2024-01-01T23:59:59.999"],
]),
args: { from: "2024-01-01T00:00:00.000", to: "2024-01-01T23:59:59.999" },
outcome: {
result_hash: "000",
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<div *ngIf="reports?.length > 0" class="work-panel">
<div class="flex-row flex-wrap gap-regular">
<mat-form-field>
<mat-form-field class="flex-grow">
<mat-label i18n>Select Report</mat-label>
<mat-select
[(ngModel)]="selectedReport"
Expand All @@ -24,7 +24,7 @@
</mat-select>
</mat-form-field>

<mat-form-field>
<mat-form-field *ngIf="isDateRangeReport">
<mat-label i18n>Enter a date range</mat-label>
<mat-date-range-input [rangePicker]="picker" [disabled]="loading">
<input
Expand Down Expand Up @@ -56,14 +56,12 @@
mat-stroked-button
color="accent"
class="primary-button"
[disabled]="!selectedReport || (!fromDate && !toDate) || loading"
(click)="
calculateClick.emit({
report: selectedReport,
from: fromDate,
to: toDate,
})
[disabled]="
!selectedReport ||
(isDateRangeReport && !fromDate && !toDate) ||
loading
"
(click)="calculate()"
i18n="Calculate the results for a report"
angulartics2On="click"
angularticsCategory="Reporting"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,73 @@ describe("SelectReportComponent", () => {

expect(component.selectedReport).toBe(report);
sleidig marked this conversation as resolved.
Show resolved Hide resolved
});

it("should display date range filter when report mode is reporting", () => {
const report = new ReportEntity();
report.mode = "reporting";
component.reports = [report];

component.ngOnChanges({ reports: undefined });

expect(component.selectedReport).toBe(report);
expect(component.isDateRangeReport).toBeTrue();
});

it("should display date range filter when sql report supports it", () => {
const report = new ReportEntity();
report.mode = "sql";
report.neededArgs = ["from", "to"];
component.reports = [report];

component.ngOnChanges({ reports: undefined });

expect(component.selectedReport).toBe(report);
expect(component.isDateRangeReport).toBeTrue();
});

it("should hide date range filter when sql report does not have these args", () => {
const report = new ReportEntity();
report.mode = "sql";
component.reports = [report];

component.ngOnChanges({ reports: undefined });

expect(component.selectedReport).toBe(report);
expect(component.isDateRangeReport).toBeFalse();
});

it("should reset dates before calculation when sql report is not a DateRangeReport", () => {
const report = new ReportEntity();
report.mode = "sql";
component.reports = [report];

component.ngOnChanges({ reports: undefined });
component.fromDate = new Date();
component.toDate = new Date();

component.calculate();

expect(component.selectedReport).toBe(report);
expect(component.isDateRangeReport).toBeFalse();
expect(component.fromDate).toBeUndefined();
expect(component.toDate).toBeUndefined();
});

it("should not reset dates before calculation when sql report is a DateRangeReport", () => {
const report = new ReportEntity();
report.mode = "sql";
component.reports = [report];
report.neededArgs = ["from", "to"];

component.ngOnChanges({ reports: undefined });
component.fromDate = new Date();
component.toDate = new Date();

component.calculate();

expect(component.selectedReport).toBe(report);
expect(component.isDateRangeReport).toBeTrue();
expect(component.fromDate).toBeDefined();
expect(component.toDate).toBeDefined();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
Output,
SimpleChanges,
} from "@angular/core";
import { NgForOf, NgIf } from "@angular/common";
import { JsonPipe, NgForOf, NgIf } from "@angular/common";
import { MatButtonModule } from "@angular/material/button";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatSelectModule } from "@angular/material/select";
Expand Down Expand Up @@ -36,6 +36,7 @@ import { ReportEntity } from "../../report-config";
FontAwesomeModule,
MatProgressBarModule,
MatTooltipModule,
JsonPipe,
],
standalone: true,
})
Expand All @@ -49,22 +50,49 @@ export class SelectReportComponent implements OnChanges {
selectedReport: ReportEntity;
fromDate: Date;
toDate: Date;
/** whether the currently selected report includes filter parameters for a "from" - "to" date range */
isDateRangeReport: boolean;
tomwwinter marked this conversation as resolved.
Show resolved Hide resolved

ngOnChanges(changes: SimpleChanges): void {
if (changes.hasOwnProperty("reports")) {
if (this.reports?.length === 1) {
this.selectedReport = this.reports[0];
this.checkDateRangeReport();
}
}
}

calculate(): void {
if (!this.isDateRangeReport) {
this.fromDate = undefined;
this.toDate = undefined;
}

this.calculateClick.emit({
report: this.selectedReport,
from: this.fromDate,
to: this.toDate,
});
}

reportChange() {
this.dataChanged.emit();
this.checkDateRangeReport();
}

dateChange() {
this.dataChanged.emit();
}

private checkDateRangeReport(): void {
if (this.selectedReport.mode !== "sql") {
this.isDateRangeReport = true;
} else {
this.isDateRangeReport =
this.selectedReport.neededArgs.indexOf("from") !== -1 ||
this.selectedReport.neededArgs.indexOf("to") !== -1;
}
}
}

interface CalculateReportOptions {
Expand Down
12 changes: 3 additions & 9 deletions src/app/features/reporting/sql-report/sql-report.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe("SqlReportService", () => {
startDate: null,
endDate: null,
status: "PENDING",
args: new Map<String, String>(),
args: {},
outcome: {
result_hash:
"180a94a09c517b24e994aaf8342c58270a775f953eb32af78f06f1c8f61e37b9",
Expand All @@ -39,10 +39,7 @@ describe("SqlReportService", () => {
status: "FINISHED_SUCCESS",
startDate: "2024-06-07T09:26:56.414",
endDate: "2024-06-09T09:26:57.431",
args: new Map<String, String>([
["from", "2024-01-01T00:00:00.000"],
["to", "2024-01-01T23:59:59.999"],
]),
args: { from: "2024-01-01T00:00:00.000", to: "2024-01-01T23:59:59.999" },
outcome: {
result_hash: "000",
},
Expand All @@ -55,10 +52,7 @@ describe("SqlReportService", () => {
status: "FINISHED_SUCCESS",
startDate: "2024-06-07T09:26:56.414",
endDate: "2024-06-07T09:26:57.431",
args: new Map<String, String>([
["from", "2024-01-01T00:00:00.000"],
["to", "2024-01-01T23:59:59.999"],
]),
args: { from: "2024-01-01T00:00:00.000", to: "2024-01-01T23:59:59.999" },
outcome: {
result_hash: "000",
},
Expand Down
19 changes: 12 additions & 7 deletions src/app/features/reporting/sql-report/sql-report.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface ReportCalculation {
};
startDate: string | null;
endDate: string | null;
args: Map<String, String>;
args: { [key: string]: string };
status: "PENDING" | "RUNNING" | "FINISHED_SUCCESS" | "FINISHED_ERROR";
outcome: {
result_hash: string;
Expand Down Expand Up @@ -98,17 +98,22 @@ export class SqlReportService {
from: Date,
to: Date,
): Observable<ReportData> {
let params = {};
if (from && to) {
params = {
from: moment(from).format("YYYY-MM-DD"),
to: moment(to).format("YYYY-MM-DD"),
};
}

return this.http
.post<{
id: string;
}>(
`${SqlReportService.QUERY_PROXY}/api/v1/reporting/report-calculation/report/${reportId}`,
{},
{
params: {
from: moment(from).format("YYYY-MM-DD"),
to: moment(to).format("YYYY-MM-DD"),
},
params: params,
},
)
.pipe(
Expand Down Expand Up @@ -166,8 +171,8 @@ export class SqlReportService {
from: Date,
to: Date,
): boolean {
let argFrom = value.args.get("from");
let argTo = value.args.get("to");
let argFrom = value.args["from"];
let argTo = value.args["to"];

if (!argFrom || !argTo) {
return false;
Expand Down
Loading