Delta Builder Fluent API #4

Merged
lentil merged 7 commits from chore/delta-format-standardization into main 2025-06-20 22:55:33 -05:00
9 changed files with 83 additions and 150 deletions
Showing only changes of commit 795551c623 - Show all commits

View File

@ -146,9 +146,11 @@ describe('DeltaBuilder', () => {
.buildV1(); .buildV1();
// Check for transaction ID in pointers // Check for transaction ID in pointers
const txPointer = delta.pointers.find(p => p.localContext === '_transaction'); expect(delta.pointers).toContainEqual({
expect(txPointer).toBeDefined(); localContext: '_transaction',
expect(txPointer?.target).toBe(txId); target: txId,
targetContext: 'deltas'
});
}); });
it('should support transactions in V2', () => { it('should support transactions in V2', () => {
@ -168,7 +170,7 @@ describe('DeltaBuilder', () => {
.buildV1(); .buildV1();
// Check for negation in pointers // Check for negation in pointers
const negationPointer = delta.pointers.find(p => p.localContext === '_negation'); const negationPointer = delta.pointers.find(p => p.localContext === '_negates');
expect(negationPointer).toBeDefined(); expect(negationPointer).toBeDefined();
expect(negationPointer?.target).toBe(negatedId); expect(negationPointer?.target).toBe(negatedId);
}); });

View File

@ -248,8 +248,7 @@ describe('Lossless', () => {
losslessT.ingestDelta( losslessT.ingestDelta(
createDelta('A', 'H') createDelta('A', 'H')
.inTransaction(transactionId) .inTransaction(transactionId)
.addPointer('step', 'process1', 'status') .setProperty('process1', 'status', 'started', 'step')
.addPointer('value', 'started')
.buildV1() .buildV1()
); );
@ -257,8 +256,7 @@ describe('Lossless', () => {
losslessT.ingestDelta( losslessT.ingestDelta(
createDelta('B', 'H') createDelta('B', 'H')
.inTransaction(transactionId) .inTransaction(transactionId)
.addPointer('step', 'process1', 'status') .setProperty('process1', 'status', 'processing', 'step')
.addPointer('value', 'processing')
.buildV1() .buildV1()
); );

View File

@ -1,6 +1,5 @@
import Debug from 'debug'; import Debug from 'debug';
import { createDelta } from '../src/core/delta-builder'; import { createDelta } from '../src/core/delta-builder';
import { Delta } from '../src/core';
import { NegationHelper } from '../src/features'; import { NegationHelper } from '../src/features';
import { RhizomeNode } from '../src/node'; import { RhizomeNode } from '../src/node';
import { Lossless } from '../src/views'; import { Lossless } from '../src/views';
@ -28,15 +27,14 @@ describe('Negation System', () => {
'host1' 'host1'
); );
expect(negationDelta.isNegation).toBe(true);
expect(negationDelta.negatedDeltaId).toBe(originalDelta.id);
expect(negationDelta.creator).toBe('moderator'); expect(negationDelta.creator).toBe('moderator');
expect(negationDelta.pointers).toHaveLength(1); expect(negationDelta.pointers).toHaveLength(1);
expect(negationDelta.pointers[0]).toEqual({ expect(negationDelta.pointers[0]).toEqual({
localContext: 'negates', localContext: '_negates',
target: originalDelta.id, target: originalDelta.id,
targetContext: 'negated_by' targetContext: 'negated_by'
}); });
expect(NegationHelper.isNegationDelta(negationDelta)).toBe(true);
}); });
it('should identify negation deltas', () => { it('should identify negation deltas', () => {

View File

@ -194,14 +194,9 @@ describe('Nested Object Resolution Performance', () => {
const currentId = userIds[i]; const currentId = userIds[i];
const nextId = userIds[i + 1]; const nextId = userIds[i + 1];
const linkDelta = new Delta({ const linkDelta = createDelta(node.config.creator, node.config.peerId)
creator: node.config.creator, .setProperty(currentId, 'next', nextId, 'users')
host: node.config.peerId, .buildV1();
pointers: [
{ localContext: 'users', target: currentId, targetContext: 'next' },
{ localContext: 'next', target: nextId }
]
});
node.lossless.ingestDelta(linkDelta); node.lossless.ingestDelta(linkDelta);
} }
@ -293,14 +288,10 @@ describe('Nested Object Resolution Performance', () => {
const connectedIndex = (i + j) % userCount; const connectedIndex = (i + j) % userCount;
const connectedId = userIds[connectedIndex]; const connectedId = userIds[connectedIndex];
const connectionDelta = new Delta({ const connectionDelta = createDelta(node.config.creator, node.config.peerId)
creator: node.config.creator, .addPointer('users', userId, 'connections')
host: node.config.peerId, .addPointer('connections', connectedId)
pointers: [ .buildV1();
{ localContext: 'users', target: userId, targetContext: 'connections' },
{ localContext: 'connections', target: connectedId }
]
});
node.lossless.ingestDelta(connectionDelta); node.lossless.ingestDelta(connectionDelta);
} }
} }

View File

@ -24,15 +24,13 @@ describe('Transactions', () => {
// Create first delta in transaction // Create first delta in transaction
const delta1 = createDelta('user1', 'host1') const delta1 = createDelta('user1', 'host1')
.inTransaction(transactionId) .inTransaction(transactionId)
.addPointer('name', 'user123', 'name') .setProperty('user123', 'name', 'Alice')
.addPointer('value', 'Alice')
.buildV1(); .buildV1();
// Create second delta in transaction // Create second delta in transaction
const delta2 = createDelta('user1', 'host1') const delta2 = createDelta('user1', 'host1')
.inTransaction(transactionId) .inTransaction(transactionId)
.addPointer('age', 'user123', 'age') .setProperty('user123', 'age', 25)
.addPointer('value', 25)
.buildV1(); .buildV1();
// Ingest transaction declaration and first two deltas // Ingest transaction declaration and first two deltas
@ -47,8 +45,7 @@ describe('Transactions', () => {
// Add the third delta to complete the transaction // Add the third delta to complete the transaction
const delta3 = createDelta('user1', 'host1') const delta3 = createDelta('user1', 'host1')
.inTransaction(transactionId) .inTransaction(transactionId)
.addPointer('email', 'user123', 'email') .setProperty('user123', 'email', 'alice@example.com')
.addPointer('value', 'alice@example.com')
.buildV1(); .buildV1();
lossless.ingestDelta(delta3); lossless.ingestDelta(delta3);
@ -79,15 +76,13 @@ describe('Transactions', () => {
// Add deltas for both transactions // Add deltas for both transactions
lossless.ingestDelta(createDelta('user1', 'host1') lossless.ingestDelta(createDelta('user1', 'host1')
.inTransaction(tx1) .inTransaction(tx1)
.addPointer('status', 'order1', 'status') .setProperty('order1', 'status', 'pending')
.addPointer('value', 'pending')
.buildV1() .buildV1()
); );
lossless.ingestDelta(createDelta('user2', 'host2') lossless.ingestDelta(createDelta('user2', 'host2')
.inTransaction(tx2) .inTransaction(tx2)
.addPointer('status', 'order2', 'status') .setProperty('order2', 'status', 'shipped')
.addPointer('value', 'shipped')
.buildV1() .buildV1()
); );
@ -99,8 +94,7 @@ describe('Transactions', () => {
// Complete tx1 // Complete tx1
lossless.ingestDelta(createDelta('user1', 'host1') lossless.ingestDelta(createDelta('user1', 'host1')
.inTransaction(tx1) .inTransaction(tx1)
.addPointer('total', 'order1', 'total') .setProperty('order1', 'total', 100)
.addPointer('value', 100)
.buildV1() .buildV1()
); );
@ -114,8 +108,7 @@ describe('Transactions', () => {
// Complete tx2 // Complete tx2
lossless.ingestDelta(createDelta('user2', 'host2') lossless.ingestDelta(createDelta('user2', 'host2')
.inTransaction(tx2) .inTransaction(tx2)
.addPointer('tracking', 'order2', 'tracking') .setProperty('order2', 'tracking', 'TRACK123')
.addPointer('value', 'TRACK123')
.buildV1() .buildV1()
); );
@ -139,15 +132,13 @@ describe('Transactions', () => {
// Add both deltas // Add both deltas
lossless.ingestDelta(createDelta('user1', 'host1') lossless.ingestDelta(createDelta('user1', 'host1')
.inTransaction(transactionId) .inTransaction(transactionId)
.addPointer('type', 'doc1', 'type') .setProperty('doc1', 'type', 'report')
.addPointer('value', 'report')
.buildV1() .buildV1()
); );
lossless.ingestDelta(createDelta('user2', 'host2') lossless.ingestDelta(createDelta('user2', 'host2')
.inTransaction(transactionId) .inTransaction(transactionId)
.addPointer('author', 'doc1', 'author') .setProperty('doc1', 'author', 'Bob')
.addPointer('value', 'Bob')
.buildV1() .buildV1()
); );
@ -169,14 +160,13 @@ describe('Transactions', () => {
// Transaction that updates multiple entities atomically // Transaction that updates multiple entities atomically
lossless.ingestDelta(createDelta('system', 'host1') lossless.ingestDelta(createDelta('system', 'host1')
.addPointer('_transaction', transactionId, 'size') .declareTransaction(transactionId, 3)
.addPointer('size', 3)
.buildV1() .buildV1()
); );
// Transfer money from account1 to account2 // Transfer money from account1 to account2
lossless.ingestDelta(createDelta('bank', 'host1') lossless.ingestDelta(createDelta('bank', 'host1')
.addPointer('_transaction', transactionId, 'deltas') .inTransaction(transactionId)
.addPointer('balance', 'account1', 'balance') .addPointer('balance', 'account1', 'balance')
.addPointer('value', 900) .addPointer('value', 900)
.addPointer('operation', 'debit') .addPointer('operation', 'debit')
@ -184,7 +174,7 @@ describe('Transactions', () => {
); );
lossless.ingestDelta(createDelta('bank', 'host1') lossless.ingestDelta(createDelta('bank', 'host1')
.addPointer('_transaction', transactionId, 'deltas') .inTransaction(transactionId)
.addPointer('balance', 'account2', 'balance') .addPointer('balance', 'account2', 'balance')
.addPointer('value', 1100) .addPointer('value', 1100)
.addPointer('operation', 'credit') .addPointer('operation', 'credit')
@ -198,7 +188,7 @@ describe('Transactions', () => {
// Complete transaction with audit log // Complete transaction with audit log
lossless.ingestDelta(createDelta('bank', 'host1') lossless.ingestDelta(createDelta('bank', 'host1')
.addPointer('_transaction', transactionId, 'deltas') .inTransaction(transactionId)
.addPointer('transfer', 'transfer123', 'details') .addPointer('transfer', 'transfer123', 'details')
.addPointer('from', 'account1') .addPointer('from', 'account1')
.addPointer('to', 'account2') .addPointer('to', 'account2')
@ -227,16 +217,14 @@ describe('Transactions', () => {
// Create transaction // Create transaction
lossless.ingestDelta(createDelta('system', 'host1') lossless.ingestDelta(createDelta('system', 'host1')
.addPointer('_transaction', transactionId, 'size') .declareTransaction(transactionId, 2)
.addPointer('size', 2)
.buildV1() .buildV1()
); );
// Add first delta // Add first delta
const delta1 = createDelta('user1', 'host1') const delta1 = createDelta('user1', 'host1')
.addPointer('_transaction', transactionId, 'deltas') .inTransaction(transactionId)
.addPointer('field1', 'entity1', 'field1') .setProperty('entity1', 'field1', 'value1')
.addPointer('value', 'value1')
.buildV1(); .buildV1();
lossless.ingestDelta(delta1); lossless.ingestDelta(delta1);
@ -245,9 +233,8 @@ describe('Transactions', () => {
// Add second delta to complete transaction // Add second delta to complete transaction
const delta2 = createDelta('user1', 'host1') const delta2 = createDelta('user1', 'host1')
.addPointer('_transaction', transactionId, 'deltas') .inTransaction(transactionId)
.addPointer('field2', 'entity1', 'field2') .setProperty('entity1', 'field2', 'value2')
.addPointer('value', 'value2')
.buildV1(); .buildV1();
lossless.ingestDelta(delta2); lossless.ingestDelta(delta2);
@ -270,16 +257,14 @@ describe('Transactions', () => {
// Create transaction // Create transaction
lossless.ingestDelta(createDelta('system', 'host1') lossless.ingestDelta(createDelta('system', 'host1')
.addPointer('_transaction', transactionId, 'size') .declareTransaction(transactionId, 2)
.addPointer('size', 2)
.buildV1() .buildV1()
); );
// Add first delta // Add first delta
lossless.ingestDelta(createDelta('user1', 'host1') lossless.ingestDelta(createDelta('user1', 'host1')
.addPointer('_transaction', transactionId, 'deltas') .inTransaction(transactionId)
.addPointer('status', 'job1', 'status') .setProperty('job1', 'status', 'processing')
.addPointer('value', 'processing')
.buildV1() .buildV1()
); );
@ -294,9 +279,8 @@ describe('Transactions', () => {
// Complete transaction // Complete transaction
lossless.ingestDelta(createDelta('user1', 'host1') lossless.ingestDelta(createDelta('user1', 'host1')
.addPointer('_transaction', transactionId, 'deltas') .inTransaction(transactionId)
.addPointer('status', 'job1', 'status') .setProperty('job1', 'status', 'completed')
.addPointer('value', 'completed')
.buildV1() .buildV1()
); );
@ -340,21 +324,20 @@ describe('Transactions', () => {
// Initially declare transaction with size 2 // Initially declare transaction with size 2
lossless.ingestDelta(createDelta('system', 'host1') lossless.ingestDelta(createDelta('system', 'host1')
.addPointer('_transaction', transactionId, 'size') .declareTransaction(transactionId, 2)
.addPointer('size', 2)
.buildV1() .buildV1()
); );
// Add 2 deltas // Add 2 deltas
lossless.ingestDelta(createDelta('user1', 'host1') lossless.ingestDelta(createDelta('user1', 'host1')
.addPointer('_transaction', transactionId, 'deltas') .inTransaction(transactionId)
.addPointer('item1', 'cart1', 'items') .setProperty('cart1', 'items', 'item1')
.buildV1() .buildV1()
); );
lossless.ingestDelta(createDelta('user1', 'host1') lossless.ingestDelta(createDelta('user1', 'host1')
.addPointer('_transaction', transactionId, 'deltas') .inTransaction(transactionId)
.addPointer('item2', 'cart1', 'items') .setProperty('cart1', 'items', 'item2')
.buildV1() .buildV1()
); );
@ -371,9 +354,8 @@ describe('Transactions', () => {
// Add delta with transaction reference but no size declaration // Add delta with transaction reference but no size declaration
lossless.ingestDelta(createDelta('user1', 'host1') lossless.ingestDelta(createDelta('user1', 'host1')
.addPointer('_transaction', transactionId, 'deltas') .inTransaction(transactionId)
.addPointer('data', 'entity1', 'data') .setProperty('entity1', 'data', 'test')
.addPointer('value', 'test')
.buildV1() .buildV1()
); );
@ -386,8 +368,7 @@ describe('Transactions', () => {
// Declare size after the fact // Declare size after the fact
lossless.ingestDelta(createDelta('system', 'host1') lossless.ingestDelta(createDelta('system', 'host1')
.addPointer('_transaction', transactionId, 'size') .declareTransaction(transactionId, 1)
.addPointer('size', 1)
.buildV1() .buildV1()
); );

View File

@ -2,6 +2,7 @@ import Debug from 'debug';
import {randomUUID} from "node:crypto"; import {randomUUID} from "node:crypto";
import EventEmitter from "node:events"; import EventEmitter from "node:events";
import {Delta} from "../core/delta"; import {Delta} from "../core/delta";
import {createDelta} from "../core/delta-builder";
import {Entity, EntityProperties} from "../core/entity"; import {Entity, EntityProperties} from "../core/entity";
import {ResolvedViewOne} from '../views/resolvers/last-write-wins'; import {ResolvedViewOne} from '../views/resolvers/last-write-wins';
import {RhizomeNode} from "../node"; import {RhizomeNode} from "../node";
@ -72,18 +73,11 @@ export abstract class Collection<View> {
if (key === 'id') return; if (key === 'id') return;
if (oldProperties[key] !== value && host && creator) { if (oldProperties[key] !== value && host && creator) {
deltas.push(new Delta({ deltas.push(
creator, createDelta(creator, host)
host, .setProperty(entityId, key, value, this.name)
pointers: [{ .buildV1()
localContext: this.name, );
target: entityId,
targetContext: key
}, {
localContext: key,
target: value
}]
}));
} }
}); });
@ -91,18 +85,10 @@ export abstract class Collection<View> {
if (deltas.length > 1) { if (deltas.length > 1) {
// We can generate a separate delta describing this transaction // We can generate a separate delta describing this transaction
transactionDelta = new Delta({ transactionDelta = createDelta(creator, host)
creator, .addPointer('_transaction', transactionId, 'size')
host, .addPointer('size', deltas.length)
pointers: [{ .buildV1();
localContext: "_transaction",
target: transactionId,
targetContext: "size"
}, {
localContext: "size",
target: deltas.length
}]
});
// Also need to annotate the deltas with the transactionId // Also need to annotate the deltas with the transactionId
for (const delta of deltas) { for (const delta of deltas) {

View File

@ -13,9 +13,6 @@ export class DeltaBuilder {
private host: string; private host: string;
private creator: string; private creator: string;
private pointers: Record<string, any> = {}; private pointers: Record<string, any> = {};
private transactionId?: string;
private isNegation: boolean = false;
private negatedDeltaId?: string;
/** /**
* Create a new DeltaBuilder instance * Create a new DeltaBuilder instance
@ -48,7 +45,7 @@ export class DeltaBuilder {
* Set the transaction ID for this delta * Set the transaction ID for this delta
*/ */
inTransaction(transactionId: string): this { inTransaction(transactionId: string): this {
this.transactionId = transactionId; this.addPointer('_transaction', transactionId, 'deltas');
return this; return this;
} }
@ -59,8 +56,7 @@ export class DeltaBuilder {
* @returns * @returns
*/ */
declareTransaction(transactionId: string, size: number): this { declareTransaction(transactionId: string, size: number): this {
this.addPointer('_transaction', transactionId, 'size'); this.setProperty(transactionId, 'size', size, '_transaction');
this.addPointer('size', size)
return this; return this;
} }
@ -68,15 +64,17 @@ export class DeltaBuilder {
* Mark this delta as a negation of another delta * Mark this delta as a negation of another delta
*/ */
negate(deltaId: string): this { negate(deltaId: string): this {
this.isNegation = true; this.addPointer('_negates', deltaId, 'negated_by');
this.negatedDeltaId = deltaId;
return this; return this;
} }
/** /**
* Add a pointer to the delta * Add a pointer to the delta
* @param localContext The local context for the pointer
* @param target The target value (string, number, boolean, or null)
* @param targetContext Optional target context for the pointer
*/ */
addPointer(localContext: string, target: string | number | boolean, targetContext?: string): this { addPointer(localContext: string, target: string | number | boolean | null, targetContext?: string): this {
if (targetContext && typeof target === 'string') { if (targetContext && typeof target === 'string') {
this.pointers[localContext] = { [target]: targetContext }; this.pointers[localContext] = { [target]: targetContext };
} else { } else {
@ -88,7 +86,7 @@ export class DeltaBuilder {
/** /**
* Set a property on an entity * Set a property on an entity
*/ */
setProperty(entityId: string, property: string, value: string | number | boolean, entityLabel = "entity"): this { setProperty(entityId: string, property: string, value: string | number | boolean | null, entityLabel = "entity"): this {
this.addPointer(entityLabel, entityId, property) this.addPointer(entityLabel, entityId, property)
this.addPointer(property, value); this.addPointer(property, value);
return this; return this;
@ -110,14 +108,6 @@ export class DeltaBuilder {
// For V2, we'll store transaction and negation info in the pointers object // For V2, we'll store transaction and negation info in the pointers object
const pointers = { ...this.pointers }; const pointers = { ...this.pointers };
if (this.transactionId) {
pointers['_transaction'] = { [this.transactionId]: 'deltas' };
}
if (this.isNegation && this.negatedDeltaId) {
pointers['_negation'] = this.negatedDeltaId;
}
// Create the delta with all pointers // Create the delta with all pointers
return new DeltaV2({ return new DeltaV2({
id: this.id, id: this.id,

View File

@ -1,21 +1,17 @@
import Debug from 'debug'; import Debug from 'debug';
import { Delta, DeltaID } from '../core/delta'; import { Delta, DeltaID } from '../core/delta';
import { createDelta } from '../core/delta-builder';
import { CreatorID, HostID } from '../core/types'; import { CreatorID, HostID } from '../core/types';
const debug = Debug('rz:negation'); const debug = Debug('rz:negation');
// Negation-specific types // Negation-specific types
export interface NegationPointer { export interface NegationPointer {
localContext: 'negates'; localContext: '_negates';
target: DeltaID; target: DeltaID;
targetContext: 'negated_by'; targetContext: 'negated_by';
} }
export interface NegationDelta extends Delta {
isNegation: true;
negatedDeltaId: DeltaID;
}
// Helper functions for creating and identifying negation deltas // Helper functions for creating and identifying negation deltas
export class NegationHelper { export class NegationHelper {
@ -26,19 +22,10 @@ export class NegationHelper {
deltaToNegate: DeltaID, deltaToNegate: DeltaID,
creator: CreatorID, creator: CreatorID,
host: HostID host: HostID
): NegationDelta { ): Delta {
const negationDelta = new Delta({ const negationDelta = createDelta(creator, host)
creator, .negate(deltaToNegate)
host, .buildV1();
pointers: [{
localContext: 'negates',
target: deltaToNegate,
targetContext: 'negated_by'
}]
}) as NegationDelta;
negationDelta.isNegation = true;
negationDelta.negatedDeltaId = deltaToNegate;
debug(`Created negation delta ${negationDelta.id} negating ${deltaToNegate}`); debug(`Created negation delta ${negationDelta.id} negating ${deltaToNegate}`);
return negationDelta; return negationDelta;
@ -47,9 +34,9 @@ export class NegationHelper {
/** /**
* Check if a delta is a negation delta * Check if a delta is a negation delta
*/ */
static isNegationDelta(delta: Delta): delta is NegationDelta { static isNegationDelta(delta: Delta): boolean {
return delta.pointers.some(pointer => return delta.pointers.some(pointer =>
pointer.localContext === 'negates' && pointer.localContext === '_negates' &&
pointer.targetContext === 'negated_by' pointer.targetContext === 'negated_by'
); );
} }
@ -59,7 +46,7 @@ export class NegationHelper {
*/ */
static getNegatedDeltaId(negationDelta: Delta): DeltaID | null { static getNegatedDeltaId(negationDelta: Delta): DeltaID | null {
const negationPointer = negationDelta.pointers.find(pointer => const negationPointer = negationDelta.pointers.find(pointer =>
pointer.localContext === 'negates' && pointer.localContext === '_negates' &&
pointer.targetContext === 'negated_by' pointer.targetContext === 'negated_by'
); );
@ -73,10 +60,10 @@ export class NegationHelper {
/** /**
* Find all negation deltas that negate a specific delta * Find all negation deltas that negate a specific delta
*/ */
static findNegationsFor(targetDeltaId: DeltaID, deltas: Delta[]): NegationDelta[] { static findNegationsFor(targetDeltaId: DeltaID, deltas: Delta[]): Delta[] {
return deltas return deltas
.filter(delta => this.isNegationDelta(delta)) .filter(delta => this.isNegationDelta(delta))
.filter(delta => this.getNegatedDeltaId(delta) === targetDeltaId) as NegationDelta[]; .filter(delta => this.getNegatedDeltaId(delta) === targetDeltaId);
} }
/** /**
@ -152,7 +139,7 @@ export class NegationHelper {
// Create a map of delta ID to its negation status // Create a map of delta ID to its negation status
const deltaStatus = new Map<DeltaID, boolean>(); const deltaStatus = new Map<DeltaID, boolean>();
// Create a map of delta ID to its negation deltas // Create a map of delta ID to its negation deltas
const deltaToNegations = new Map<DeltaID, NegationDelta[]>(); const deltaToNegations = new Map<DeltaID, Delta[]>();
// First pass: collect all deltas and their negations // First pass: collect all deltas and their negations
for (const delta of deltas) { for (const delta of deltas) {

View File

@ -124,10 +124,10 @@ export class Lossless {
// Add negation delta to the entity // Add negation delta to the entity
// For negation deltas, we need to add them to a special property // For negation deltas, we need to add them to a special property
// since they don't directly target the entity // since they don't directly target the entity
let negationDeltas = ent.properties.get('_negations'); let negationDeltas = ent.properties.get('_negates');
if (!negationDeltas) { if (!negationDeltas) {
negationDeltas = new Set<Delta>(); negationDeltas = new Set<Delta>();
ent.properties.set('_negations', negationDeltas); ent.properties.set('_negates', negationDeltas);
} }
negationDeltas.add(delta); negationDeltas.add(delta);
} }
@ -363,8 +363,8 @@ export class Lossless {
} }
for (const [property, deltas] of ent.properties.entries()) { for (const [property, deltas] of ent.properties.entries()) {
// Skip the special _negations property in the per-property stats // Skip the special _negates property in the per-property stats
if (property === '_negations') { if (property === '_negates') {
totalDeltas += deltas.size; totalDeltas += deltas.size;
totalNegationDeltas += deltas.size; totalNegationDeltas += deltas.size;
continue; continue;
@ -398,7 +398,7 @@ export class Lossless {
const ent = this.domainEntities.get(entityId); const ent = this.domainEntities.get(entityId);
if (!ent) return []; if (!ent) return [];
const negationProperty = ent.properties.get('_negations'); const negationProperty = ent.properties.get('_negates');
if (!negationProperty) return []; if (!negationProperty) return [];
return Array.from(negationProperty); return Array.from(negationProperty);