Skip to content

Commit

Permalink
feat: add Brazilian grade context (closes #358)
Browse files Browse the repository at this point in the history
  • Loading branch information
enapupe committed Nov 10, 2023
1 parent 6cdaa12 commit d9df965
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 6 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"@babel/runtime": "^7.17.2",
"@google-cloud/storage": "^6.9.5",
"@graphql-tools/schema": "^8.3.1",
"@openbeta/sandbag": "^0.0.48",
"@openbeta/sandbag": "^0.0.51",
"@turf/area": "^6.5.0",
"@turf/bbox": "^6.5.0",
"@turf/bbox-polygon": "^6.5.0",
Expand Down
17 changes: 17 additions & 0 deletions src/GradeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export enum GradeContexts {
ALSK = 'ALSK',
/** Australia */
AU = 'AU',
/** Brazil */
BRZ = 'BRZ',
FIN = 'FIN',
FR = 'FR',
Expand Down Expand Up @@ -96,6 +97,22 @@ export const gradeContextToGradeScales: Partial<Record<GradeContexts, ClimbGrade
aid: GradeScales.UIAA,
snow: GradeScales.UIAA, // TODO: remove `snow` since it duplicates `ice`
ice: GradeScales.WI
},
[GradeContexts.BRZ]: {
trad: GradeScales.BRAZILIAN_CRUX,
sport: GradeScales.BRAZILIAN_CRUX,
bouldering: GradeScales.VSCALE,
tr: GradeScales.BRAZILIAN_CRUX,
deepwatersolo: GradeScales.BRAZILIAN_CRUX,
alpine: GradeScales.BRAZILIAN_CRUX,
mixed: GradeScales.BRAZILIAN_CRUX,
aid: GradeScales.AID,
// definitely no ice in brazil, however once this guy
// top roped a fragile frozen waterfall with ice picks
// and crampons:
ice: GradeScales.WI,
// whenever it snows in brazil, you see it in the news
snow: GradeScales.WI
}
}

Expand Down
32 changes: 32 additions & 0 deletions src/__tests__/gradeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,36 @@ describe('Test grade utilities', () => {
actual = createGradeObject('5.9', sanitizeDisciplines({ bouldering: true }), context)
expect(actual).toBeUndefined()
})

it('creates grade object correctly in BRZ context', () => {
const context = gradeContextToGradeScales.BRZ
if (context == null) { fail('Bad grade context. Should not happen.') }
let actual = createGradeObject('V', sanitizeDisciplines({ sport: true }), context)
expect(actual).toEqual({
brazilian_crux: 'V'
})
actual = createGradeObject('A2', sanitizeDisciplines({ aid: true }), context)
expect(actual).toEqual({
aid: 'A2'
})
actual = createGradeObject('C1', sanitizeDisciplines({ aid: true }), context)
expect(actual).toEqual({
aid: 'C1'
})
actual = createGradeObject('V5', sanitizeDisciplines({ bouldering: true }), context)
expect(actual).toEqual({
vscale: 'V5'
})
actual = createGradeObject('WI6', sanitizeDisciplines({ ice: true }), context)
expect(actual).toEqual({
wi: 'WI6'
})
actual = createGradeObject('VIIb', sanitizeDisciplines({ deepwatersolo: true }), context)
expect(actual).toEqual({
brazilian_crux: 'VIIb'
})
// Invalid input
actual = createGradeObject('5.9', sanitizeDisciplines({ bouldering: true }), context)
expect(actual).toBeUndefined()
})
})
3 changes: 2 additions & 1 deletion src/graphql/schema/Climb.gql
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ type GradeType {
"""
ewbank: String
french: String
brazilian_crux: String
"""
Fontainebleau grading system, the most widely used grading system in Europe.
Mostly used for bouldering.
Expand Down Expand Up @@ -204,4 +205,4 @@ type Pitch {
length: Int
boltsCount: Int
description: String
}
}
75 changes: 75 additions & 0 deletions src/model/__tests__/MutableClimbDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,81 @@ describe('Climb CRUD', () => {
}
})

it('handles Brazilian grade context correctly', async () => {
await areas.addCountry('bra')

{
// A roped climbing area
const newClimbingArea = await areas.addArea(testUser, 'Climbing area in Brazil', null, 'bra')
if (newClimbingArea == null) fail('Expect new area to be created in Brazil')

const newclimbs = [
{ ...newSportClimb1, grade: 'VIsup' }, // good sport grade
{ ...newSportClimb2, grade: 'VIsup/VIIa', disciplines: { trad: true } }, // good trad and slash grade
{ ...newSportClimb2, grade: '5.9' }, // bad BRZ context grade
{ ...newIceRoute, grade: 'WI4+' }, // good WI BRZ context grade
{ ...newAidRoute, grade: 'A0' } // good aid grade
]

const newIDs = await climbs.addOrUpdateClimbs(
testUser,
newClimbingArea.metadata.area_id,
newclimbs
)
expect(newIDs).toHaveLength(newclimbs.length)

const climb1 = await climbs.findOneClimbByMUUID(muid.from(newIDs[0]))
expect(climb1?.grades).toEqual({ brazilian_crux: 'VIsup' })
expect(climb1?.type.sport).toBe(true)
expect(newSportClimb1?.boltsCount).toEqual(2)

const climb2 = await climbs.findOneClimbByMUUID(muid.from(newIDs[1]))
expect(climb2?.grades).toEqual({ brazilian_crux: 'VIsup/VIIa' })
expect(climb2?.type.sport).toBe(false)
expect(climb2?.type.trad).toBe(true)

const climb3 = await climbs.findOneClimbByMUUID(muid.from(newIDs[2]))
expect(climb3?.grades).toEqual(undefined)

const climb4 = await climbs.findOneClimbByMUUID(muid.from(newIDs[3]))
expect(climb4?.grades).toEqual({ wi: 'WI4+' })
expect(climb4?.type.sport).toBe(false)
expect(climb4?.type.trad).toBe(false)
expect(climb4?.type.bouldering).toBe(false)
expect(climb4?.type.ice).toBe(true)

const climb5 = await climbs.findOneClimbByMUUID(muid.from(newIDs[4]))
expect(climb5?.grades).toEqual({ aid: 'A0' })
expect(climb5?.type.sport).toBe(false)
expect(climb5?.type.trad).toBe(false)
expect(climb5?.type.aid).toBe(true)
}

{
// A bouldering area
const newBoulderingArea = await areas.addArea(testUser, 'Bouldering area 1', null, 'bra')
if (newBoulderingArea == null) fail('Expect new area to be created')

const newIDs = await climbs.addOrUpdateClimbs(
testUser,
newBoulderingArea.metadata.area_id,
[{ ...newBoulderProblem1, grade: 'V3' }, // good grade
{ ...newBoulderProblem2, grade: '23' }, // bad boulder grade
{ ...newBoulderProblem2, grade: '7B' }]) // invalid grade (font grade for a BRZ context boulder problem)

expect(newIDs).toHaveLength(3)

const climb1 = await climbs.findOneClimbByMUUID(muid.from(newIDs[0]))
expect(climb1?.grades).toEqual({ vscale: 'V3' })

const climb2 = await climbs.findOneClimbByMUUID(muid.from(newIDs[1]))
expect(climb2?.grades).toEqual(undefined)

const climb3 = await climbs.findOneClimbByMUUID(muid.from(newIDs[2]))
expect(climb3?.grades).toEqual(undefined)
}
})

it('handles UIAA grades correctly', async () => {
await areas.addCountry('deu') // Assuming Germany since UIAA is dominant grading system

Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1579,10 +1579,10 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"

"@openbeta/sandbag@^0.0.48":
version "0.0.48"
resolved "https://registry.yarnpkg.com/@openbeta/sandbag/-/sandbag-0.0.48.tgz#d876ae47634c287be1f71858576a9f826f8ee270"
integrity sha512-QyTGG9Y+c+2TY+EbdUByAAr1u7qyqZ4H1ZM0TztetJU/a7TLjdMoR32yaRY8uSFvm3f1sP0zn0ffhlLiICDdlg==
"@openbeta/sandbag@^0.0.51":
version "0.0.51"
resolved "https://registry.yarnpkg.com/@openbeta/sandbag/-/sandbag-0.0.51.tgz#21ce618d2414dc0b8d4f31ef260ac2ebad5a43c8"
integrity sha512-qMVohgqRdFjXH8a3aSEZa6zemwSpak/HMttR/pqvclDIXqgPKzWvjFRA3o/YDGieI/19P4dtizLo91TKx0smGQ==

"@panva/asn1.js@^1.0.0":
version "1.0.0"
Expand Down

0 comments on commit d9df965

Please sign in to comment.