Spaces:
Sleeping
Sleeping
import { FieldConfig, History, unpackSampleRecord } from '../../convex/engine/historicalObject'; | |
import { useMemo, useRef } from 'react'; | |
export function useHistoricalValue<T extends Record<string, number>>( | |
fields: FieldConfig, | |
historicalTime: number | undefined, | |
value: T | undefined, | |
history: ArrayBuffer | undefined, | |
): T | undefined { | |
const manager = useRef(new HistoryManager()); | |
const sampleRecord: Record<string, History> | undefined = useMemo(() => { | |
if (!value || !history) { | |
return undefined; | |
} | |
if (!(history instanceof ArrayBuffer)) { | |
throw new Error(`Expected ArrayBuffer, found ${typeof history}`); | |
} | |
return unpackSampleRecord(fields, history); | |
}, [value && history]); | |
if (sampleRecord) { | |
manager.current.receive(sampleRecord); | |
} | |
if (value === undefined) { | |
return undefined; | |
} | |
if (!historicalTime) { | |
return value; | |
} | |
const historicalFields = manager.current.query(historicalTime); | |
return { ...value, ...historicalFields }; | |
} | |
class HistoryManager { | |
histories: Record<string, History[]> = {}; | |
receive(sampleRecord: Record<string, History>) { | |
for (const [fieldName, history] of Object.entries(sampleRecord)) { | |
let histories = this.histories[fieldName]; | |
if (!histories) { | |
histories = []; | |
this.histories[fieldName] = histories; | |
} | |
if (histories[histories.length - 1] == history) { | |
continue; | |
} | |
histories.push(history); | |
} | |
} | |
query(historicalTime: number): Record<string, number> { | |
const result: Record<string, number> = {}; | |
for (const [fieldName, histories] of Object.entries(this.histories)) { | |
if (histories.length == 0) { | |
continue; | |
} | |
let foundIndex = null; | |
let currentValue = histories[0].initialValue; | |
for (let i = 0; i < histories.length; i++) { | |
const history = histories[i]; | |
for (const sample of history.samples) { | |
if (sample.time > historicalTime) { | |
foundIndex = i; | |
break; | |
} | |
currentValue = sample.value; | |
} | |
if (foundIndex !== null) { | |
break; | |
} | |
} | |
if (foundIndex !== null) { | |
this.histories[fieldName] = histories.slice(foundIndex); | |
} | |
result[fieldName] = currentValue; | |
} | |
return result; | |
} | |
} | |