Compare commits

..

2 Commits

Author SHA1 Message Date
5c1c8a23b8
refactor: update delta declarations to use DeltaBuilder in lossless tests
- Refactored delta declarations in __tests__/lossless.ts to use DeltaBuilder
- Added declareTransaction method to DeltaBuilder for better transaction handling
- Updated transaction pointer structure in DeltaBuilder to match expected format
- Fixed related tests to work with the new DeltaBuilder implementation
2025-06-20 11:04:55 -05:00
4542c4ce83
Use deltaBuilder in lossless.decompose 2025-06-20 10:46:34 -05:00
6 changed files with 102 additions and 108 deletions

View File

@ -0,0 +1,6 @@
---
description: Update the current file to use delta builder
---
Replace each deltav2 instantiation with a fluent call to createDelta from delta builder, using the following process:
- pass creator and host as arguments to createDelta

View File

@ -1,7 +0,0 @@
---
description: Update deltas to use the object style for pointers
---
- in the current file, for each v1 delta, rewrite it as a v2 delta
- make sure the new delta is isomorphic to the original
- do not include a timestamp

View File

@ -158,7 +158,7 @@ describe('DeltaBuilder', () => {
.buildV2();
// Check for transaction ID in V2 pointers
expect(delta.pointers['_transaction']).toBe(txId);
expect(delta.pointers['_transaction']).toEqual({ [txId]: 'deltas' });
});
it('should support negation', () => {

View File

@ -1,22 +1,19 @@
import {Delta, DeltaFilter, DeltaV2} from '../src/core';
import {Lossless} from '../src/views';
import {RhizomeNode} from '../src/node';
import {createDelta} from '../src/core/delta-builder';
describe('Lossless', () => {
const node = new RhizomeNode();
it('creates a lossless view of keanu as neo in the matrix', () => {
const delta = new DeltaV2({
creator: 'a',
host: 'h',
pointers: {
actor: {"keanu": "roles"},
role: {"neo": "actor"},
film: {"the_matrix": "cast"},
base_salary: 1000000,
salary_currency: "usd"
}
}).toV1();
const delta = createDelta('a', 'h')
.addPointer('actor', 'keanu', 'roles')
.addPointer('role', 'neo', 'actor')
.addPointer('film', 'the_matrix', 'cast')
.addPointer('base_salary', 1000000)
.addPointer('salary_currency', 'usd')
.buildV1();
expect(delta.pointers).toMatchObject([{
localContext: "actor",
@ -95,17 +92,13 @@ describe('Lossless', () => {
});
it('accepts DeltaV2 instances', () => {
const delta = new DeltaV2({
creator: 'a',
host: 'h',
pointers: {
actor: {"keanu": "roles"},
role: {"neo": "actor"},
film: {"the_matrix": "cast"},
base_salary: 1000000,
salary_currency: "usd"
}
});
const delta = createDelta('a', 'h')
.addPointer('actor', 'keanu', 'roles')
.addPointer('role', 'neo', 'actor')
.addPointer('film', 'the_matrix', 'cast')
.addPointer('base_salary', 1000000)
.addPointer('salary_currency', 'usd')
.buildV2();
const lossless = new Lossless(node);
@ -167,26 +160,20 @@ describe('Lossless', () => {
const lossless = new Lossless(node);
beforeAll(() => {
lossless.ingestDelta(new Delta({
creator: 'A',
host: 'H',
pointers: [{
localContext: "1",
target: "ace",
targetContext: "value"
}]
}));
// First delta
lossless.ingestDelta(
createDelta('A', 'H')
.addPointer('1', 'ace', 'value')
.buildV1()
);
lossless.ingestDelta(new Delta({
creator: 'B',
host: 'H',
pointers: [{
// Second delta
lossless.ingestDelta(
createDelta('B', 'H')
// 10 11j 12q 13k 14a
localContext: "14",
target: "ace",
targetContext: "value"
}]
}));
.addPointer('14', 'ace', 'value')
.buildV1()
);
expect(lossless.view()).toMatchObject({
ace: {
@ -251,51 +238,42 @@ describe('Lossless', () => {
const transactionId = 'tx-filter-test';
// Declare transaction with 3 deltas
losslessT.ingestDelta(new Delta({
creator: 'system',
host: 'H',
pointers: [
{ localContext: '_transaction', target: transactionId, targetContext: 'size' },
{ localContext: 'size', target: 3 }
]
}));
losslessT.ingestDelta(
createDelta('system', 'H')
.declareTransaction(transactionId, 3)
.buildV1()
);
// A1: First delta from creator A
losslessT.ingestDelta(new Delta({
creator: 'A',
host: 'H',
pointers: [
{ localContext: '_transaction', target: transactionId, targetContext: 'deltas' },
{ localContext: 'step', target: 'process1', targetContext: 'status' },
{ localContext: 'value', target: 'started' }
]
}));
losslessT.ingestDelta(
createDelta('A', 'H')
.inTransaction(transactionId)
.addPointer('step', 'process1', 'status')
.addPointer('value', 'started')
.buildV1()
);
// B: Delta from creator B
losslessT.ingestDelta(new Delta({
creator: 'B',
host: 'H',
pointers: [
{ localContext: '_transaction', target: transactionId, targetContext: 'deltas' },
{ localContext: 'step', target: 'process1', targetContext: 'status' },
{ localContext: 'value', target: 'processing' }
]
}));
losslessT.ingestDelta(
createDelta('B', 'H')
.inTransaction(transactionId)
.addPointer('step', 'process1', 'status')
.addPointer('value', 'processing')
.buildV1()
);
// Transaction incomplete - nothing should show
const incompleteView = losslessT.view(['process1']);
expect(incompleteView.process1).toBeUndefined();
// A2: Second delta from creator A completes transaction
losslessT.ingestDelta(new Delta({
creator: 'A',
host: 'H',
pointers: [
{ localContext: '_transaction', target: transactionId, targetContext: 'deltas' },
{ localContext: 'step', target: 'process1', targetContext: 'status' },
{ localContext: 'value', target: 'completed' }
]
}));
losslessT.ingestDelta(
createDelta('A', 'H')
.inTransaction(transactionId)
.addPointer('step', 'process1', 'status')
.addPointer('value', 'completed')
.buildV1()
);
// All deltas visible now
const completeView = losslessT.view(['process1']);

View File

@ -52,6 +52,18 @@ export class DeltaBuilder {
return this;
}
/**
* Declare a transaction with a size
* @param transactionId The ID of the transaction
* @param size The size of the transaction
* @returns
*/
declareTransaction(transactionId: string, size: number): this {
this.addPointer('_transaction', transactionId, 'size');
this.addPointer('size', size)
return this;
}
/**
* Mark this delta as a negation of another delta
*/
@ -99,7 +111,7 @@ export class DeltaBuilder {
const pointers = { ...this.pointers };
if (this.transactionId) {
pointers['_transaction'] = this.transactionId;
pointers['_transaction'] = { [this.transactionId]: 'deltas' };
}
if (this.isNegation && this.negatedDeltaId) {

View File

@ -9,6 +9,7 @@ import {Transactions} from '../features/transactions';
import {DomainEntityID, PropertyID, PropertyTypes, TransactionID, ViewMany} from "../core/types";
import {Negation} from '../features/negation';
import {NegationHelper} from '../features/negation';
import { createDelta } from '../core/delta-builder';
const debug = Debug('rz:lossless');
export type CollapsedPointer = {[key: PropertyID]: PropertyTypes};
@ -199,31 +200,35 @@ export class Lossless {
for (const delta of deltas) {
if (!seenDeltaIds.has(delta.id)) {
seenDeltaIds.add(delta.id);
// Convert CollapsedDelta back to Delta
const fullDelta = new Delta({
id: delta.id,
creator: delta.creator,
host: delta.host,
timeCreated: delta.timeCreated,
pointers: delta.pointers.map(pointer => {
// Convert back to V1 pointer format for Delta constructor
const pointerEntries = Object.entries(pointer);
if (pointerEntries.length === 1) {
const [localContext, target] = pointerEntries[0];
if (typeof target === 'string' && this.domainEntities.has(target)) {
// This is a reference pointer to an entity
// The targetContext is the property ID this delta appears under
return { localContext, target, targetContext: propertyId };
} else {
// Scalar pointer
return { localContext, target: target as PropertyTypes };
}
// Create a new delta using DeltaBuilder
const builder = createDelta(delta.creator, delta.host)
.withId(delta.id)
.withTimestamp(delta.timeCreated);
// Add all pointers from the collapsed delta
for (const pointer of delta.pointers) {
const pointerEntries = Object.entries(pointer);
if (pointerEntries.length === 1) {
const [localContext, target] = pointerEntries[0];
if (target === null || target === undefined) {
continue; // Skip null/undefined targets
}
// Fallback for unexpected pointer structure
return { localContext: 'unknown', target: 'unknown' };
})
});
allDeltas.push(fullDelta);
if (typeof target === 'string' && this.domainEntities.has(target)) {
// This is a reference pointer to an entity
builder.addPointer(localContext, target, propertyId);
} else if (typeof target === 'string' || typeof target === 'number' || typeof target === 'boolean') {
// Scalar pointer with valid type
builder.addPointer(localContext, target);
} else {
// For other types (objects, arrays), convert to string
builder.addPointer(localContext, JSON.stringify(target));
}
}
}
// Build the delta and add to results
allDeltas.push(builder.buildV1());
}
}
}