- Implemented DeltaBuilder class with support for both V1 and V2 delta formats - Added comprehensive test coverage for all builder functionality - Included utility function for microsecond-precision timestamps - Added support for transactions and negation via special pointer contexts - Provides type-safe API for creating deltas with proper validation
164 lines
5.2 KiB
TypeScript
164 lines
5.2 KiB
TypeScript
import { createDelta, DeltaBuilder } from '../src/core/delta-builder';
|
|
import { DeltaV1, DeltaV2 } from '../src/core/delta';
|
|
import { Lossless } from '../src/views/lossless';
|
|
import { RhizomeNode } from '../src/node';
|
|
import { LastWriteWins } from '../src/views/resolvers/last-write-wins';
|
|
|
|
describe('DeltaBuilder', () => {
|
|
const creator = 'creator-123';
|
|
const host = 'host-456';
|
|
const node = new RhizomeNode();
|
|
|
|
describe('V1 Deltas', () => {
|
|
it('should create a basic V1 delta', () => {
|
|
const builder = new DeltaBuilder(creator, host, 'v1');
|
|
const delta = builder
|
|
.addPointer('name', 'Test Delta', 'title')
|
|
.addPointer('description', 'A test delta', 'description')
|
|
.build();
|
|
|
|
expect(delta).toBeInstanceOf(DeltaV1);
|
|
expect(delta.id).toBeDefined();
|
|
expect(delta.creator).toBe(creator);
|
|
expect(delta.host).toBe(host);
|
|
expect(delta.pointers).toHaveLength(2);
|
|
expect(delta.pointers[0]).toEqual({
|
|
localContext: 'name',
|
|
target: 'Test Delta',
|
|
targetContext: 'title'
|
|
});
|
|
});
|
|
|
|
it.only('should create a V1 delta with setProperty', () => {
|
|
const delta = createDelta(creator, host, 'v1')
|
|
.setProperty('entity-1', 'name', 'Test Entity')
|
|
.build();
|
|
|
|
expect(delta).toBeInstanceOf(DeltaV1);
|
|
expect(delta.pointers).toContainEqual({
|
|
localContext: 'name',
|
|
target: 'Test Entity',
|
|
targetContext: 'name'
|
|
});
|
|
expect(delta.pointers).toContainEqual({
|
|
localContext: 'entity',
|
|
target: 'entity-1',
|
|
targetContext: 'name'
|
|
});
|
|
|
|
// Verify that the entity property resolves correctly
|
|
const lossless = new Lossless(node);
|
|
lossless.ingestDelta(delta);
|
|
const lossy = new LastWriteWins(lossless);
|
|
const result = lossy.resolve();
|
|
expect(result).toBeDefined();
|
|
expect(result!['entity-1'].properties.name).toBe('Test Entity');
|
|
});
|
|
|
|
it('should create a V1 delta with relationships', () => {
|
|
const delta = createDelta(creator, host, 'v1')
|
|
.relate('user-1', 'follows', 'user-2')
|
|
.build();
|
|
|
|
expect(delta.pointers).toContainEqual({
|
|
localContext: 'follows',
|
|
target: 'user-2',
|
|
targetContext: 'follows'
|
|
});
|
|
expect(delta.pointers).toContainEqual({
|
|
localContext: 'source',
|
|
target: 'user-1',
|
|
targetContext: 'follows'
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('V2 Deltas', () => {
|
|
it('should create a basic V2 delta', () => {
|
|
const builder = new DeltaBuilder(creator, host, 'v2');
|
|
const delta = builder
|
|
.addPointer('name', 'Test Delta V2', 'title')
|
|
.buildV2();
|
|
|
|
expect(delta).toBeInstanceOf(DeltaV2);
|
|
expect(delta.id).toBeDefined();
|
|
expect(delta.creator).toBe(creator);
|
|
expect(delta.host).toBe(host);
|
|
expect(delta.pointers).toHaveProperty('name');
|
|
expect(delta.pointers.name).toEqual({ 'Test Delta V2': 'title' });
|
|
});
|
|
|
|
it('should create a V2 delta with setProperty', () => {
|
|
const delta = createDelta(creator, host, 'v2')
|
|
.setProperty('entity-1', 'name', 'Test Entity')
|
|
.buildV2();
|
|
|
|
expect(delta.pointers).toHaveProperty('name', 'Test Entity');
|
|
expect(delta.pointers).toHaveProperty('entity', { 'entity-1': 'name' });
|
|
});
|
|
|
|
it('should create a V2 delta with relationships', () => {
|
|
const delta = createDelta(creator, host, 'v2')
|
|
.relate('user-1', 'follows', 'user-2')
|
|
.buildV2();
|
|
|
|
expect(delta.pointers).toHaveProperty('follows', { 'user-2': 'follows' });
|
|
expect(delta.pointers).toHaveProperty('source', { 'user-1': 'follows' });
|
|
});
|
|
});
|
|
|
|
describe('Common functionality', () => {
|
|
it('should support custom IDs', () => {
|
|
const customId = 'custom-delta-id';
|
|
const delta = createDelta(creator, host)
|
|
.withId(customId)
|
|
.build();
|
|
|
|
expect(delta.id).toBe(customId);
|
|
});
|
|
|
|
it('should support transactions', () => {
|
|
const txId = 'tx-123';
|
|
const delta = createDelta(creator, host)
|
|
.inTransaction(txId)
|
|
.build();
|
|
|
|
// Check for transaction ID in pointers
|
|
const txPointer = delta.pointers.find(p => p.localContext === '_transaction');
|
|
expect(txPointer).toBeDefined();
|
|
expect(txPointer?.target).toBe(txId);
|
|
});
|
|
|
|
it('should support transactions in V2', () => {
|
|
const txId = 'tx-123';
|
|
const delta = createDelta(creator, host, 'v2')
|
|
.inTransaction(txId)
|
|
.buildV2();
|
|
|
|
// Check for transaction ID in V2 pointers
|
|
expect(delta.pointers['_transaction']).toBe(txId);
|
|
});
|
|
|
|
it('should support negation', () => {
|
|
const negatedId = 'delta-to-negate';
|
|
const delta = createDelta(creator, host)
|
|
.negate(negatedId)
|
|
.build();
|
|
|
|
// Check for negation in pointers
|
|
const negationPointer = delta.pointers.find(p => p.localContext === '_negation');
|
|
expect(negationPointer).toBeDefined();
|
|
expect(negationPointer?.target).toBe(negatedId);
|
|
});
|
|
|
|
it('should support custom timestamps', () => {
|
|
const timestamp = Date.now();
|
|
const delta = createDelta(creator, host)
|
|
.withTimestamp(timestamp)
|
|
.build();
|
|
|
|
expect(delta.timeCreated).toBe(timestamp);
|
|
});
|
|
});
|
|
});
|