2024-12-23 17:29:38 -06:00
|
|
|
// Deltas target entities.
|
|
|
|
// We can maintain a record of all the targeted entities, and the deltas that targeted them
|
|
|
|
|
2024-12-23 20:44:54 -06:00
|
|
|
import {Delta, DeltaFilter, PropertyTypes} from "./types";
|
2024-12-23 17:29:38 -06:00
|
|
|
|
|
|
|
type DomainEntityID = string;
|
|
|
|
type PropertyID = string;
|
|
|
|
|
|
|
|
export type CollapsedPointer = {[key: string]: PropertyTypes};
|
|
|
|
export type CollapsedDelta = Omit<Delta, 'pointers'> & {
|
|
|
|
pointers: CollapsedPointer[];
|
|
|
|
};
|
2024-12-23 23:30:21 -06:00
|
|
|
export type LosslessViewOne = {
|
|
|
|
referencedAs: string[];
|
|
|
|
properties: {
|
|
|
|
[key: PropertyID]: CollapsedDelta[]
|
|
|
|
}
|
|
|
|
};
|
|
|
|
export type LosslessViewMany = {
|
|
|
|
[key: DomainEntityID]: LosslessViewOne;
|
|
|
|
};
|
2024-12-23 17:29:38 -06:00
|
|
|
|
|
|
|
class DomainEntityMap extends Map<DomainEntityID, DomainEntity> {};
|
|
|
|
|
|
|
|
class DomainEntityProperty {
|
|
|
|
id: PropertyID;
|
|
|
|
deltas = new Set<Delta>();
|
|
|
|
|
|
|
|
constructor(id: PropertyID) {
|
|
|
|
this.id = id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class DomainEntity {
|
|
|
|
id: DomainEntityID;
|
|
|
|
properties = new Map<PropertyID, DomainEntityProperty>();
|
|
|
|
|
|
|
|
constructor(id: DomainEntityID) {
|
|
|
|
this.id = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
addDelta(delta: Delta) {
|
|
|
|
const targetContexts = delta.pointers
|
|
|
|
.filter(({target}) => target === this.id)
|
|
|
|
.map(({targetContext}) => targetContext)
|
|
|
|
.filter((targetContext) => typeof targetContext === 'string');
|
|
|
|
for (const targetContext of targetContexts) {
|
|
|
|
let property = this.properties.get(targetContext);
|
|
|
|
if (!property) {
|
|
|
|
property = new DomainEntityProperty(targetContext);
|
|
|
|
this.properties.set(targetContext, property);
|
|
|
|
}
|
|
|
|
property.deltas.add(delta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class Lossless {
|
|
|
|
domainEntities = new DomainEntityMap();
|
|
|
|
|
|
|
|
ingestDelta(delta: Delta) {
|
|
|
|
const targets = delta.pointers
|
|
|
|
.filter(({targetContext}) => !!targetContext)
|
|
|
|
.map(({target}) => target)
|
|
|
|
.filter((target) => typeof target === 'string')
|
|
|
|
for (const target of targets) {
|
|
|
|
let ent = this.domainEntities.get(target);
|
|
|
|
if (!ent) {
|
|
|
|
ent = new DomainEntity(target);
|
|
|
|
this.domainEntities.set(target, ent);
|
|
|
|
}
|
|
|
|
ent.addDelta(delta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-23 20:44:54 -06:00
|
|
|
//TODO: json logic -- view(deltaFilter?: FilterExpr) {
|
2024-12-23 23:30:21 -06:00
|
|
|
view(deltaFilter?: DeltaFilter): LosslessViewMany {
|
|
|
|
const view: LosslessViewMany = {};
|
2024-12-23 17:29:38 -06:00
|
|
|
for (const ent of this.domainEntities.values()) {
|
2024-12-23 23:30:21 -06:00
|
|
|
const referencedAs = new Set<string>();
|
|
|
|
view[ent.id] = {
|
|
|
|
referencedAs: [],
|
|
|
|
properties: {}
|
|
|
|
};
|
2024-12-23 17:29:38 -06:00
|
|
|
for (const prop of ent.properties.values()) {
|
2024-12-23 23:30:21 -06:00
|
|
|
view[ent.id].properties[prop.id] = view[ent.id].properties[prop.id] || [];
|
2024-12-23 17:29:38 -06:00
|
|
|
for (const delta of prop.deltas) {
|
2024-12-23 20:44:54 -06:00
|
|
|
if (deltaFilter) {
|
|
|
|
const include = deltaFilter(delta);
|
|
|
|
if (!include) continue;
|
|
|
|
}
|
2024-12-23 23:30:21 -06:00
|
|
|
const pointers: CollapsedPointer[] = [];
|
|
|
|
for (const {localContext, target} of delta.pointers) {
|
|
|
|
pointers.push({[localContext]: target});
|
|
|
|
if (target === ent.id) {
|
|
|
|
referencedAs.add(localContext);
|
|
|
|
}
|
|
|
|
}
|
2024-12-23 17:29:38 -06:00
|
|
|
const collapsedDelta: CollapsedDelta = {
|
|
|
|
...delta,
|
2024-12-23 23:30:21 -06:00
|
|
|
pointers
|
2024-12-23 17:29:38 -06:00
|
|
|
};
|
2024-12-23 23:30:21 -06:00
|
|
|
view[ent.id].referencedAs = Array.from(referencedAs.values());
|
|
|
|
view[ent.id].properties[prop.id].push(collapsedDelta);
|
2024-12-23 17:29:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return view;
|
|
|
|
}
|
|
|
|
}
|