diff --git a/src/components/periodic-report/dto/periodic-report.dto.ts b/src/components/periodic-report/dto/periodic-report.dto.ts index 41d776e3be..7f56030b19 100644 --- a/src/components/periodic-report/dto/periodic-report.dto.ts +++ b/src/components/periodic-report/dto/periodic-report.dto.ts @@ -1,5 +1,7 @@ import { Field, InterfaceType, ObjectType } from '@nestjs/graphql'; +import { simpleSwitch } from '@seedcompany/common'; import { keys as keysOf } from 'ts-transformer-keys'; +import { MergeExclusive } from 'type-fest'; import { Calculated, CalendarDate, @@ -11,14 +13,29 @@ import { SecuredStringNullable, Sensitivity, SensitivityField, + ServerException, } from '~/common'; import { BaseNode as DbBaseNode } from '~/core/database/results'; import { e } from '~/core/edgedb'; import { RegisterResource } from '~/core/resources'; import { ScopedRole } from '../../authorization/dto'; import { DefinedFile } from '../../file/dto'; +import { ProgressReport } from '../../progress-report/dto'; import { ReportType } from './report-type.enum'; +export type AnyReport = MergeExclusive< + FinancialReport, + MergeExclusive +>; + +export const resolveReportType = (val: Pick) => { + const type = simpleSwitch(val.type, ReportConcretes); + if (!type) { + throw new ServerException(`Could not resolve report type: '${val.type}'`); + } + return type; +}; + @RegisterResource({ db: e.PeriodicReport }) @Calculated() @InterfaceType({ @@ -92,6 +109,12 @@ export class NarrativeReport extends PeriodicReport { }) export class SecuredPeriodicReport extends SecuredProperty(PeriodicReport) {} +export const ReportConcretes = { + Financial: FinancialReport, + Narrative: NarrativeReport, + Progress: ProgressReport, +}; + declare module '~/core/resources/map' { interface ResourceMap { PeriodicReport: typeof PeriodicReport; diff --git a/src/components/periodic-report/periodic-report.edgedb.repository.ts b/src/components/periodic-report/periodic-report.edgedb.repository.ts new file mode 100644 index 0000000000..6a07783db1 --- /dev/null +++ b/src/components/periodic-report/periodic-report.edgedb.repository.ts @@ -0,0 +1,189 @@ +import { Injectable } from '@nestjs/common'; +import { Query } from 'cypher-query-builder'; +import { Without } from 'type-fest/source/merge-exclusive'; +import { + CalendarDate, + ID, + PublicOf, + Range, + Session, + UnsecuredDto, +} from '~/common'; +import { castToEnum, e, RepoFor } from '~/core/edgedb'; +import { Variable } from '../../core/database/query'; +import { ProgressReport } from '../progress-report/dto'; +import { + FinancialReport, + IPeriodicReport, + MergePeriodicReports, + NarrativeReport, + ReportType, + resolveReportType, +} from './dto'; +import { PeriodicReportRepository } from './periodic-report.repository'; + +@Injectable() +export class PeriodicReportEdgeDBRepository + extends RepoFor(IPeriodicReport, { + hydrate: (periodicReport) => ({ + ...periodicReport['*'], + type: castToEnum(periodicReport.__type__.name.slice(9, -7), ReportType), + reportFile: true, + sensitivity: periodicReport.container.is(e.Project.ContextAware) + .sensitivity, + scope: false, + parent: e.tuple({ + identity: periodicReport.id, + labels: e.array_agg(e.set(periodicReport.__type__.name.slice(9, null))), + properties: e.tuple({ + id: periodicReport.id, + createdAt: periodicReport.createdAt, + }), + }), + }), + }) + implements PublicOf +{ + merge( + input: MergePeriodicReports, + ): Promise }>> { + throw new Error('Method not implemented.'); + } + + matchCurrentDue( + parentId: ID | Variable, + reportType: ReportType, + ): (query: Query) => Query { + throw new Error('Method not implemented.'); + } + + getByDate( + parentId: ID, + date: CalendarDate, + reportType: ReportType, + _session: Session, + ) { + const resource = e.cast(e.Resource, e.uuid(parentId)); + + const report = e.select(e.PeriodicReport, (report) => ({ + filter: e.all( + e.set( + e.op(resource.id, '=', report.container.id), + e.op(report.start, '<=', date), + e.op(report.end, '>=', date), + ), + ), + ...report.is(resolveReportType(reportType)), + })); + + return this.db.run(report); + } + + getCurrentDue( + parentId: ID, + reportType: ReportType, + session: Session, + ): Promise< + | UnsecuredDto< + | (Without< + | (Without & NarrativeReport) + | (Without & FinancialReport), + ProgressReport + > & + ProgressReport) + | (Without< + ProgressReport, + | (Without & NarrativeReport) + | (Without & FinancialReport) + > & + ( + | (Without & NarrativeReport) + | (Without & FinancialReport) + )) + > + | undefined + > { + throw new Error('Method not implemented.'); + } + + getNextDue( + parentId: ID, + reportType: ReportType, + session: Session, + ): Promise< + | UnsecuredDto< + | (Without< + | (Without & NarrativeReport) + | (Without & FinancialReport), + ProgressReport + > & + ProgressReport) + | (Without< + ProgressReport, + | (Without & NarrativeReport) + | (Without & FinancialReport) + > & + ( + | (Without & NarrativeReport) + | (Without & FinancialReport) + )) + > + | undefined + > { + throw new Error('Method not implemented.'); + } + + getLatestReportSubmitted( + parentId: ID, + type: ReportType, + session: Session, + ): Promise< + | UnsecuredDto< + | (Without< + | (Without & NarrativeReport) + | (Without & FinancialReport), + ProgressReport + > & + ProgressReport) + | (Without< + ProgressReport, + | (Without & NarrativeReport) + | (Without & FinancialReport) + > & + ( + | (Without & NarrativeReport) + | (Without & FinancialReport) + )) + > + | undefined + > { + throw new Error('Method not implemented.'); + } + + getFinalReport( + parentId: ID, + type: ReportType, + session: Session, + ): Promise< + | UnsecuredDto< + | (Without< + | (Without & NarrativeReport) + | (Without & FinancialReport), + ProgressReport + > & + ProgressReport) + | (Without< + ProgressReport, + | (Without & NarrativeReport) + | (Without & FinancialReport) + > & + ( + | (Without & NarrativeReport) + | (Without & FinancialReport) + )) + > + | undefined + > { + throw new Error('Method not implemented.'); + } +}