rhizome/src/lossy.ts

70 lines
2.4 KiB
TypeScript
Raw Normal View History

2024-12-23 23:30:54 -06:00
// We have the lossless transformation of the delta stream.
// We want to enable transformations from the lossless view,
// into various possible "lossy" views that combine or exclude some information.
//
// We can achieve this via functional expression, encoded as JSON-Logic.
// Fields in the output can be described as transformations
import Debug from 'debug';
2024-12-23 23:30:54 -06:00
import {CollapsedDelta, Lossless, LosslessViewMany, LosslessViewOne} from "./lossless";
import {DeltaFilter, DomainEntityID, Properties} from "./types";
const debug = Debug('lossy');
2024-12-23 23:30:54 -06:00
export type LossyViewOne = {
id: DomainEntityID;
properties: Properties;
};
export type LossyViewMany = {
[key: DomainEntityID]: LossyViewOne;
};
type Resolver = (losslessView: LosslessViewMany) => LossyViewMany | unknown;
2024-12-23 23:30:54 -06:00
2024-12-23 23:34:28 -06:00
// Extract a particular value from a delta's pointers
export function valueFromCollapsedDelta(delta: CollapsedDelta, key: string): 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;
}
2024-12-23 23:30:54 -06:00
}
}
}
2024-12-23 23:34:28 -06:00
// Example function for resolving a value for an entity by taking the first value we find
export function firstValueFromLosslessViewOne(ent: LosslessViewOne, key: string): {delta: CollapsedDelta, value: string | number} | undefined {
debug(`trying to get value for ${key} from ${JSON.stringify(ent.properties[key])}`);
2024-12-23 23:30:54 -06:00
for (const delta of ent.properties[key] || []) {
2024-12-23 23:36:38 -06:00
const value = valueFromCollapsedDelta(delta, key);
2024-12-23 23:30:54 -06:00
if (value) return {delta, value};
}
}
export class Lossy {
lossless: Lossless;
constructor(lossless: Lossless) {
this.lossless = lossless;
}
resolve(fn: Resolver, entityIds?: DomainEntityID[], deltaFilter?: DeltaFilter) {
return fn(this.lossless.view(entityIds, deltaFilter));
2024-12-23 23:30:54 -06:00
}
}
2024-12-25 00:42:16 -06:00
// Generate a rule
// Apply the rule -- When?
// - Maybe we shard a set of deltas and map/reduce the results --
// We are trying to implement CRDT, so the results
// must be composable to preserve that feature.
// That also seems to imply we want to stick with
// the lossless view until the delta set is chosen
// - So, in general on a set of deltas
// at times which seem opportune
// the results of which can be recorded
// and indexed such that the results can be reused
// i.e. you want to compute the result of a set which
// contains a prior one