From 93a5e3557eee1ec01e62c5944124685f1919d8c4 Mon Sep 17 00:00:00 2001 From: kao Date: Fri, 28 Apr 2023 18:29:02 -0600 Subject: [PATCH] Add more typing for history objects --- src/db/ChangeLogType.ts | 16 ++++++++++---- src/db/edit/streamListener.ts | 22 +++++++++++--------- src/graphql/history/HistoryFieldResolvers.ts | 21 ++++++++++--------- src/graphql/history/HistoryQueries.ts | 4 +++- src/model/ChangeLogDataSource.ts | 2 +- 5 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/db/ChangeLogType.ts b/src/db/ChangeLogType.ts index 49a495b1..8a57b894 100644 --- a/src/db/ChangeLogType.ts +++ b/src/db/ChangeLogType.ts @@ -6,6 +6,11 @@ import { ClimbEditOperationType, ClimbType } from './ClimbTypes.js' import { OperationType as OrganizationOpType, OrganizationType } from './OrganizationTypes.js' export type DBOperation = 'insert' | 'update' | 'delete' +export enum DocumentKind { + areas = 'areas', + climbs = 'climbs', + organizations = 'organizations' +} export interface ChangeLogType { _id: mongose.Types.ObjectId @@ -14,7 +19,7 @@ export interface ChangeLogType { changes: Array> } -// DIY since ResumeToke is defined as unknown in mongo TS +// DIY since ResumeToken is defined as unknown in mongo TS export interface ResumeToken { _data: string } @@ -29,7 +34,7 @@ export interface BaseChangeRecordType @@ -56,7 +61,10 @@ export type AreaChangeRecordType = BaseChangeRecordType export type ClimbChangeLogType = ChangeLogType export type OrganizationChangeLogType = ChangeLogType -export type SupportedCollectionTypes = AreaType & WithDiscriminator | ClimbType & WithDiscriminator +export type SupportedCollectionTypes = + | AreaType & WithDiscriminator + | ClimbType & WithDiscriminator + | OrganizationType & WithDiscriminator export interface GetHistoryInputFilterType { uuidList: string[] diff --git a/src/db/edit/streamListener.ts b/src/db/edit/streamListener.ts index a8223c39..c90771e2 100644 --- a/src/db/edit/streamListener.ts +++ b/src/db/edit/streamListener.ts @@ -4,7 +4,7 @@ import dot from 'dot-object' import { changelogDataSource } from '../../model/ChangeLogDataSource.js' import { logger } from '../../logger.js' -import { BaseChangeRecordType, ResumeToken, UpdateDescription, DBOperation, SupportedCollectionTypes } from '../ChangeLogType.js' +import { BaseChangeRecordType, ResumeToken, UpdateDescription, DBOperation, SupportedCollectionTypes, DocumentKind } from '../ChangeLogType.js' import { checkVar } from '../index.js' import { updateAreaIndex } from '../export/Typesense/Client.js' import { AreaType } from '../AreaTypes.js' @@ -49,7 +49,7 @@ const onChange = (change: ChangeStreamDocument): void => { case 'replace': case 'update': { let dbOp: DBOperation = 'update' - const source = change.ns.coll + const source = DocumentKind[change.ns.coll] const { fullDocument, _id, updateDescription } = change as ChangeStreamUpdateDocument if (fullDocument?._deleting != null) { dbOp = 'delete' @@ -60,7 +60,7 @@ const onChange = (change: ChangeStreamDocument): void => { } case 'insert': { const dbOp = 'insert' - const source = change.ns.coll + const source = DocumentKind[change.ns.coll] const { fullDocument, _id } = change void recordChange({ _id: _id as ResumeToken, source, fullDocument: fullDocument as SupportedCollectionTypes, dbOp }) break @@ -70,7 +70,7 @@ const onChange = (change: ChangeStreamDocument): void => { interface ChangeRecordType { _id: ResumeToken - source: string + source: DocumentKind fullDocument: SupportedCollectionTypes updateDescription?: any dbOp: DBOperation @@ -79,41 +79,43 @@ interface ChangeRecordType { const recordChange = async ({ source, dbOp, fullDocument, updateDescription, _id }: ChangeRecordType): Promise => { fullDocument.kind = source switch (source) { - case 'climbs': { + case DocumentKind.climbs: { const newDocument: BaseChangeRecordType = { _id, dbOp, fullDocument, updateDescription: dotifyUpdateDescription(updateDescription), - kind: 'climbs' + kind: DocumentKind.climbs } void changelogDataSource.record(newDocument) break } - case 'areas': { + case DocumentKind.areas: { const newDocument: BaseChangeRecordType = { _id, dbOp, fullDocument, updateDescription: dotifyUpdateDescription(updateDescription), - kind: 'areas' + kind: DocumentKind.areas } void changelogDataSource.record(newDocument) void updateAreaIndex(fullDocument as AreaType, dbOp) break } - case 'organizations': { + case DocumentKind.organizations: { const newDocument: BaseChangeRecordType = { _id, dbOp, fullDocument, updateDescription: dotifyUpdateDescription(updateDescription), - kind: 'organizations' + kind: DocumentKind.organizations } void changelogDataSource.record(newDocument) break } default: + const exhaustiveCheck: never = source // Type error indicates unhandled enum. + throw new Error(`Unhandled Enum case: ${exhaustiveCheck}`) } } diff --git a/src/graphql/history/HistoryFieldResolvers.ts b/src/graphql/history/HistoryFieldResolvers.ts index a21949d5..3774c46d 100644 --- a/src/graphql/history/HistoryFieldResolvers.ts +++ b/src/graphql/history/HistoryFieldResolvers.ts @@ -1,4 +1,4 @@ -import { ChangeLogType, BaseChangeRecordType, SupportedCollectionTypes } from '../../db/ChangeLogType.js' +import { ChangeLogType, BaseChangeRecordType, SupportedCollectionTypes, DocumentKind } from '../../db/ChangeLogType.js' /** * Customize to resolve individual fields @@ -24,16 +24,17 @@ const resolvers = { Document: { __resolveType (node: SupportedCollectionTypes) { - if (node.kind === 'areas') { - return 'Area' + switch(node.kind) { + case DocumentKind.areas: + return 'Area' + case DocumentKind.climbs: + return 'Climb' + case DocumentKind.organizations: + return 'Organization' + default: + const exhaustiveCheck: never = node.kind // Type error indicates unhandled enum. + throw new Error(`Unhandled Enum case: ${exhaustiveCheck}`) } - if (node.kind === 'climbs') { - return 'Climb' - } - if (node.kind === 'organizations') { - return 'Organization' - } - return null } } } diff --git a/src/graphql/history/HistoryQueries.ts b/src/graphql/history/HistoryQueries.ts index 4af61fa4..5ea9a5e3 100644 --- a/src/graphql/history/HistoryQueries.ts +++ b/src/graphql/history/HistoryQueries.ts @@ -11,8 +11,10 @@ const HistoryQueries = { getChangeHistory: async (_, { filter }, { dataSources }): Promise => { const { history }: DataSourcesType = dataSources const { uuidList }: GetHistoryInputFilterType = filter ?? {} + // Note: userUuid, fromDate, toDate filters don't currently work. + // Note: though we pull uuidList, we don't use it either. - // convert array of uuid in string to UUID[] + // Convert array of uuid in string to UUID[] const muidList = uuidList?.map(entry => muid.from(entry)) ?? [] return await history.getChangeSets(muidList) }, diff --git a/src/model/ChangeLogDataSource.ts b/src/model/ChangeLogDataSource.ts index f8d6af11..7b8f2344 100644 --- a/src/model/ChangeLogDataSource.ts +++ b/src/model/ChangeLogDataSource.ts @@ -69,7 +69,7 @@ export default class ChangeLogDataSource extends MongoDataSource * @param uuidList optional filter * @returns change sets */ - async getChangeSets (uuidList: MUUID[]): Promise> { + async getChangeSets (uuidList: MUUID[]): Promise> { const rs = await this.changeLogModel.aggregate([ { $sort: {