Delta Builder Fluent API #4
@ -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);
|
||||||
});
|
});
|
||||||
|
@ -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()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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', () => {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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,
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user