Press n or j to go to the next uncovered block, b, p or k for the previous block.
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 | 4x 4x 16x 44x 44x 9x 4x 15x 15x 15x 15x 15x 8x 8x 8x 8x 15x 4x 4x 8x 7x 8x 14x 14x 7x 7x 8x 11x 11x 18x 18x 15x 11x | // import Debug from 'debug'; import {EntityProperties} from "./entity"; import {CollapsedDelta, LosslessViewOne} from "./lossless"; import {Lossy} from './lossy'; import {DomainEntityID, PropertyID, PropertyTypes, Timestamp, ViewMany} from "./types"; // const debug = Debug('rz:lossy:last-write-wins'); type TimestampedProperty = { value: PropertyTypes, timeUpdated: Timestamp }; type TimestampedProperties = { [key: PropertyID]: TimestampedProperty }; export type LossyViewOne<T = TimestampedProperties> = { id: DomainEntityID; properties: T; }; export type LossyViewMany<T = TimestampedProperties> = ViewMany<LossyViewOne<T>>; export type ResolvedViewOne = LossyViewOne<EntityProperties>; export type ResolvedViewMany = ViewMany<ResolvedViewOne>; type Accumulator = LossyViewMany<TimestampedProperties>; type Result = LossyViewMany<EntityProperties>; // Extract a particular value from a delta's pointers export function valueFromCollapsedDelta( key: string, delta: CollapsedDelta ): string | number | undefined { for (const pointer of delta.pointers) { for (const [k, value] of Object.entries(pointer)) { if (k === key && (typeof value === "string" || typeof value === "number")) { return value; } } } } // Resolve a value for an entity by last write wins export function lastValueFromDeltas( key: string, deltas?: CollapsedDelta[] ): { delta?: CollapsedDelta, value?: string | number, timeUpdated?: number } | undefined { const res: { delta?: CollapsedDelta, value?: string | number, timeUpdated?: number } = {}; res.timeUpdated = 0; for (const delta of deltas || []) { const value = valueFromCollapsedDelta(key, delta); if (value === undefined) continue; Iif (res.timeUpdated && delta.timeCreated < res.timeUpdated) continue; res.delta = delta; res.value = value; res.timeUpdated = delta.timeCreated; } return res; } export class LastWriteWins extends Lossy<Accumulator, Result> { initializer(): Accumulator { return {}; } reducer(acc: Accumulator, cur: LosslessViewOne): Accumulator { if (!acc[cur.id]) { acc[cur.id] = {id: cur.id, properties: {}}; } for (const [key, deltas] of Object.entries(cur.propertyDeltas)) { const {value, timeUpdated} = lastValueFromDeltas(key, deltas) || {}; if (!value || !timeUpdated) continue; if (timeUpdated > (acc[cur.id].properties[key]?.timeUpdated || 0)) { acc[cur.id].properties[key] = { value, timeUpdated }; } } return acc; }; resolver(cur: Accumulator): Result { const res: Result = {}; for (const [id, ent] of Object.entries(cur)) { res[id] = {id, properties: {}}; for (const [key, {value}] of Object.entries(ent.properties)) { res[id].properties[key] = value; } } return res; }; } |