-
-
Notifications
You must be signed in to change notification settings - Fork 37
/
Copy pathAreaTransformer.ts
132 lines (120 loc) · 3.98 KB
/
AreaTransformer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import mongoose from 'mongoose'
import { geometry, Point } from '@turf/helpers'
import isoCountries from 'i18n-iso-countries'
import enJson from 'i18n-iso-countries/langs/en.json' assert { type: 'json' }
import { getAreaModel } from '../../AreaSchema.js'
import { AreaType } from '../../AreaTypes'
import { Tree, AreaNode, createRootNode } from './AreaTree.js'
import { MUUID } from 'uuid-mongodb'
isoCountries.registerLocale(enJson)
export const createRoot = async (countryCode: string, shortCode?: string): Promise<AreaNode> => {
if (!isoCountries.isValid(countryCode)) {
throw new Error('ISO code must be alpha 2 or 3')
}
const areaModel = getAreaModel('areas')
const code = isoCountries.toAlpha3(countryCode)?.toUpperCase()
if (code == null) {
throw new Error(`Unexpected look up error for ${countryCode}`)
}
const countryNode = createRootNode(code)
const doc = makeDBArea(countryNode)
if (shortCode != null) {
doc.shortCode = shortCode
}
await areaModel.insertMany(doc, { ordered: false })
return countryNode
}
export const createAreas = async (root: AreaNode, areas: any[], areaModel: mongoose.Model<AreaType>): Promise<number> => {
// Build a tree from each record in the state data file
const tree = new Tree(root)
areas.forEach(record => {
const { path }: { path: string } = record
/* eslint-disable-next-line */
const fullPath = `${record.us_state}|${path}` // 'path' doesn't have a parent (a US state)
tree.insertMany(fullPath, record)
})
// Find the USA node in the db and add USA.children[]
// $push is used here because children[] may already have other states
await areaModel.findOneAndUpdate({ _id: root._id }, { $push: { children: tree.subRoot._id } })
// For each node in the tree, insert it to the database
let count = 0
const chunkSize = 50
let chunk: AreaType[] = []
for await (const node of tree.map.values()) {
const area = makeDBArea(node)
chunk.push(area)
if (chunk.length % chunkSize === 0) {
count = count + chunk.length
await areaModel.insertMany(chunk, { ordered: false })
chunk = []
}
}
if (chunk.length > 0) {
count = count + chunk.length
await areaModel.insertMany(chunk, { ordered: false })
}
return count
}
/**
* Convert simple Area tree node to Mongo Area.
* @param node
*/
export const makeDBArea = (node: AreaNode): AreaType => {
const { key, isLeaf, children, _id, uuid } = node
let areaName: string
if (node.countryName != null) {
areaName = node.countryName
} else {
areaName = isLeaf ? node.jsonLine.area_name : key.substring(key.lastIndexOf('|') + 1)
}
return {
_id,
uuid,
shortCode: '',
area_name: areaName,
children: Array.from(children),
metadata: {
isDestination: false,
leaf: isLeaf,
area_id: uuid,
lnglat: geometry('Point', isLeaf ? node.jsonLine.lnglat : [0, 0]) as Point,
bbox: [-180, -90, 180, 90],
leftRightIndex: -1,
ext_id: isLeaf ? extractMpId(node.jsonLine.url) : ''
},
ancestors: uuidArrayToString(node.getAncestors()),
climbs: [],
pathTokens: node.getPathTokens(),
gradeContext: node.getGradeContext(),
aggregate: {
byGrade: [],
byDiscipline: {},
byGradeBand: {
unknown: 0,
beginner: 0,
intermediate: 0,
advanced: 0,
expert: 0
}
},
density: 0,
totalClimbs: 0,
content: {
description: isLeaf ? (Array.isArray(node.jsonLine.description) ? node.jsonLine.description.join('\n\n') : '') : ''
}
}
}
const URL_REGEX = /area\/(?<id>\d+)\//
export const extractMpId = (url: string): string | undefined => URL_REGEX.exec(url)?.groups?.id
/**
* Similar to String.join(',') but also convert each UUID to string before joining them
* @param a
* @returns
*/
const uuidArrayToString = (a: MUUID[]): string => {
return a.reduce((acc: string, curr: MUUID, index) => {
acc = acc + curr.toUUID().toString()
if (index < a.length - 1) acc = acc + ','
return acc
}, '')
}