From 43fc503d9491bca09b2757413a7193ba8aba887e Mon Sep 17 00:00:00 2001 From: CocoisBuggy Date: Thu, 8 May 2025 18:46:24 +0200 Subject: [PATCH] Fix for mising types that the schema promises --- src/GradeUtils.ts | 13 ++++++++++++- src/model/AreaDataSource.ts | 15 +++++++++++++++ src/model/__tests__/MutableClimbDataSource.ts | 9 ++++++++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/GradeUtils.ts b/src/GradeUtils.ts index 42dab36c..ee20ba36 100644 --- a/src/GradeUtils.ts +++ b/src/GradeUtils.ts @@ -238,7 +238,18 @@ export const getCountriesDefaultGradeContext = (): { [x: string]: GradeContexts return countries } -export const validDisciplines = ['trad', 'sport', 'bouldering', 'deepwatersolo', 'alpine', 'snow', 'ice', 'mixed', 'aid', 'tr'] +export const validDisciplines: Array = [ + 'trad', + 'sport', + 'bouldering', + 'deepwatersolo', + 'alpine', + 'snow', + 'ice', + 'mixed', + 'aid', + 'tr' +] /** * Perform runtime validation of climb discipline object diff --git a/src/model/AreaDataSource.ts b/src/model/AreaDataSource.ts index 1ed84c47..a027f3f6 100644 --- a/src/model/AreaDataSource.ts +++ b/src/model/AreaDataSource.ts @@ -20,6 +20,7 @@ import { import { getClimbModel } from '../db/ClimbSchema.js' import { ClimbGQLQueryType } from '../db/ClimbTypes.js' import { logger } from '../logger.js' +import { validDisciplines } from '../GradeUtils.js' export default class AreaDataSource extends MongoDataSource { areaModel = getAreaModel() @@ -152,6 +153,20 @@ export default class AreaDataSource extends MongoDataSource { const rs = await this.climbModel .aggregate([ { $match: { _id: uuid } }, + // Stage to ensure all discipline fields exist and are booleans. This data may not exist + // for chronology reasons and is an easier fix than doing migrations. + { + $addFields: { + ...validDisciplines.reduce((prev, curr) => { + prev[`type.${curr}`] = { $ifNull: [`$type.${curr}`, false] } + return prev + }, {} + ), + // This ensures 'type' is an object, so the above $ifNull + // operations work correctly on their fields. + disciplines: { $ifNull: ['$type', {}] } + } + }, { $lookup: { from: 'areas', // other collection name diff --git a/src/model/__tests__/MutableClimbDataSource.ts b/src/model/__tests__/MutableClimbDataSource.ts index c126350a..f4d4dbd1 100644 --- a/src/model/__tests__/MutableClimbDataSource.ts +++ b/src/model/__tests__/MutableClimbDataSource.ts @@ -7,10 +7,11 @@ import MutableAreaDataSource from '../MutableAreaDataSource.js' import { createIndexes, getAreaModel, getClimbModel } from '../../db/index.js' import { logger } from '../../logger.js' import { ClimbChangeInputType, ClimbType } from '../../db/ClimbTypes.js' -import { sanitizeDisciplines } from '../../GradeUtils.js' +import { sanitizeDisciplines, validDisciplines } from '../../GradeUtils.js' import streamListener from '../../db/edit/streamListener.js' import ChangeLogDataSource from '../ChangeLogDataSource.js' import inMemoryDB from '../../utils/inMemoryDB.js' +import assert from 'assert' export const newSportClimb1: ClimbChangeInputType = { name: 'Cool route 1', @@ -187,6 +188,12 @@ describe('Climb CRUD', () => { for (const [i, climbIn] of newClimbsToAdd.entries()) { const climbOut = await climbs.findOneClimbByMUUID(muid.from(newIDs[i])) + assert(climbOut !== null) + for (const key of validDisciplines) { + expect(climbOut.type[key]).not.toBeNull() + expect(climbOut.type[key]).not.toBeUndefined() + } + // Validate new climb expect(climbOut).toMatchObject({ name: climbIn.name,