Skip to content

Commit e1a1e12

Browse files
authored
perf: use cache to fetch historical velocity aggregation data (#1411)
1 parent ee2386e commit e1a1e12

2 files changed

Lines changed: 65 additions & 20 deletions

File tree

src/pages/velocityHeatmap/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const VelocityHeatmapPage: React.FC = () => {
2525
const [max, setMax] = useState(1)
2626

2727
const handleTimestampChange = (time: dayjs.Dayjs | null) => {
28-
setSearch((current) => ({ ...current, timestamp: time?.valueOf() ?? Date.now() }))
28+
setSearch((current) => ({ ...current, timestamp: time?.valueOf() ?? +new Date('2026-01-01') }))
2929
}
3030

3131
return (
Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { SiriVelocityAggregationPydanticModel } from '@hasadna/open-bus-api-client'
12
import { useQuery } from '@tanstack/react-query'
23
import { SIRI_API } from 'src/api/apiConfig'
34
import dayjs from 'src/dayjs'
@@ -9,31 +10,15 @@ export interface VelocityAggregationBounds {
910
maxLon: number
1011
}
1112

13+
const cacheDomain = 'https://docbuvbfdq5r6.cloudfront.net/'
14+
1215
export function useVelocityAggregationData(
1316
bounds: VelocityAggregationBounds,
1417
timestamp: dayjs.Dayjs,
1518
zoom: number,
1619
) {
1720
const { data, isLoading, error } = useQuery({
18-
queryFn: async () => {
19-
const data =
20-
await SIRI_API.velocityAggregationSiriVelocityAggregationSiriVelocityAggregationGet({
21-
recordedFrom: timestamp.toDate(),
22-
lonMin: bounds.minLon,
23-
lonMax: bounds.maxLon,
24-
latMin: bounds.minLat,
25-
latMax: bounds.maxLat,
26-
roundingPrecision: zoom,
27-
}).then((data) => data.filter((p) => p.totalSampleCount > 4))
28-
29-
if (data.length === 0) {
30-
throw new Error(
31-
'No data points with more than 4 samples found in the specified area. Try expanding the area.',
32-
)
33-
}
34-
35-
return data
36-
},
21+
queryFn: queryFn.bind(null, bounds, timestamp, zoom),
3722
queryKey: [
3823
'velocity_aggregation',
3924
bounds.minLon,
@@ -42,8 +27,68 @@ export function useVelocityAggregationData(
4227
bounds.maxLat,
4328
zoom,
4429
timestamp.toString(),
30+
'v2',
4531
],
4632
})
4733

4834
return { data, loading: isLoading, error, currZoom: zoom }
4935
}
36+
37+
function snakeToCamel(o: SiriVelocityAggregationPydanticModel) {
38+
return Object.fromEntries(
39+
Object.entries(o).map(([k, v]) => {
40+
const newKey = k.replace(/(_\w)/g, (m) => m[1].toUpperCase())
41+
return [newKey, v]
42+
}),
43+
)
44+
}
45+
46+
async function loadFromCache(
47+
bounds: VelocityAggregationBounds,
48+
timestamp: dayjs.Dayjs,
49+
zoom: number,
50+
) {
51+
const dataFromCache = await fetch(
52+
`${cacheDomain}siri_velocity_aggregation/siri_velocity_aggregation?recorded_from=${encodeURIComponent(
53+
timestamp.toISOString(),
54+
)}&lon_min=${bounds.minLon}&lon_max=${bounds.maxLon}&lat_min=${bounds.minLat}&lat_max=${bounds.maxLat}&rounding_precision=${zoom}`,
55+
).then(async (res) => {
56+
if (!res.ok) {
57+
throw new Error('No cached data found')
58+
}
59+
const rawResult = await res.json()
60+
return rawResult.map(snakeToCamel) as SiriVelocityAggregationPydanticModel[]
61+
})
62+
63+
return dataFromCache
64+
}
65+
66+
async function queryFn(bounds: VelocityAggregationBounds, timestamp: dayjs.Dayjs, zoom: number) {
67+
// only try cached data if date is in the past
68+
if (timestamp.isBefore(dayjs('yesterday'))) {
69+
try {
70+
const cachedData = await loadFromCache(bounds, timestamp, zoom)
71+
if (cachedData) {
72+
return cachedData
73+
}
74+
} catch (e) {
75+
console.warn('Failed to load cached velocity aggregation data', e)
76+
}
77+
}
78+
const data = await SIRI_API.velocityAggregationSiriVelocityAggregationSiriVelocityAggregationGet({
79+
recordedFrom: timestamp.toDate(),
80+
lonMin: bounds.minLon,
81+
lonMax: bounds.maxLon,
82+
latMin: bounds.minLat,
83+
latMax: bounds.maxLat,
84+
roundingPrecision: zoom,
85+
}).then((data) => data.filter((p) => p.totalSampleCount > 4))
86+
87+
if (data.length === 0) {
88+
throw new Error(
89+
'No data points with more than 4 samples found in the specified area. Try expanding the area.',
90+
)
91+
}
92+
93+
return data
94+
}

0 commit comments

Comments
 (0)