diff --git a/__tests__/delta-builder.test.ts b/__tests__/delta-builder.test.ts index 5203499..d120ee3 100644 --- a/__tests__/delta-builder.test.ts +++ b/__tests__/delta-builder.test.ts @@ -1,4 +1,4 @@ -import { createDelta, DeltaBuilder } from '../src/core/delta-builder'; +import { createDelta } from '../src/core/delta-builder'; import { DeltaV1, DeltaV2 } from '../src/core/delta'; import { Lossless } from '../src/views/lossless'; import { RhizomeNode } from '../src/node'; @@ -11,11 +11,10 @@ describe('DeltaBuilder', () => { describe('V1 Deltas', () => { it('should create a basic V1 delta', () => { - const builder = new DeltaBuilder(creator, host, 'v1'); - const delta = builder + const delta = createDelta(creator, host) .addPointer('name', 'Test Delta', 'title') .addPointer('description', 'A test delta', 'description') - .build(); + .buildV1(); expect(delta).toBeInstanceOf(DeltaV1); expect(delta.id).toBeDefined(); @@ -29,22 +28,46 @@ describe('DeltaBuilder', () => { }); }); - it.only('should create a V1 delta with setProperty', () => { - const delta = createDelta(creator, host, 'v1') + it('should create a V1 delta with setProperty', () => { + const delta = createDelta(creator, host) .setProperty('entity-1', 'name', 'Test Entity') - .build(); + .buildV1(); 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' }); + expect(delta.pointers).toContainEqual({ + localContext: 'name', + target: 'Test Entity', + }); + + // 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 setProperty and entityLabel', () => { + const delta = createDelta(creator, host) + .setProperty('entity-1', 'name', 'Test Entity', 'user') + .buildV1(); + + expect(delta).toBeInstanceOf(DeltaV1); + expect(delta.pointers).toContainEqual({ + localContext: 'user', + target: 'entity-1', + targetContext: 'name' + }); + expect(delta.pointers).toContainEqual({ + localContext: 'name', + target: 'Test Entity', + }); // Verify that the entity property resolves correctly const lossless = new Lossless(node); @@ -56,9 +79,9 @@ describe('DeltaBuilder', () => { }); it('should create a V1 delta with relationships', () => { - const delta = createDelta(creator, host, 'v1') + const delta = createDelta(creator, host) .relate('user-1', 'follows', 'user-2') - .build(); + .buildV1(); expect(delta.pointers).toContainEqual({ localContext: 'follows', @@ -75,8 +98,7 @@ describe('DeltaBuilder', () => { describe('V2 Deltas', () => { it('should create a basic V2 delta', () => { - const builder = new DeltaBuilder(creator, host, 'v2'); - const delta = builder + const delta = createDelta(creator, host) .addPointer('name', 'Test Delta V2', 'title') .buildV2(); @@ -89,7 +111,7 @@ describe('DeltaBuilder', () => { }); it('should create a V2 delta with setProperty', () => { - const delta = createDelta(creator, host, 'v2') + const delta = createDelta(creator, host) .setProperty('entity-1', 'name', 'Test Entity') .buildV2(); @@ -98,7 +120,7 @@ describe('DeltaBuilder', () => { }); it('should create a V2 delta with relationships', () => { - const delta = createDelta(creator, host, 'v2') + const delta = createDelta(creator, host) .relate('user-1', 'follows', 'user-2') .buildV2(); @@ -112,7 +134,7 @@ describe('DeltaBuilder', () => { const customId = 'custom-delta-id'; const delta = createDelta(creator, host) .withId(customId) - .build(); + .buildV1(); expect(delta.id).toBe(customId); }); @@ -121,7 +143,7 @@ describe('DeltaBuilder', () => { const txId = 'tx-123'; const delta = createDelta(creator, host) .inTransaction(txId) - .build(); + .buildV1(); // Check for transaction ID in pointers const txPointer = delta.pointers.find(p => p.localContext === '_transaction'); @@ -131,7 +153,7 @@ describe('DeltaBuilder', () => { it('should support transactions in V2', () => { const txId = 'tx-123'; - const delta = createDelta(creator, host, 'v2') + const delta = createDelta(creator, host) .inTransaction(txId) .buildV2(); @@ -143,7 +165,7 @@ describe('DeltaBuilder', () => { const negatedId = 'delta-to-negate'; const delta = createDelta(creator, host) .negate(negatedId) - .build(); + .buildV1(); // Check for negation in pointers const negationPointer = delta.pointers.find(p => p.localContext === '_negation'); @@ -155,7 +177,7 @@ describe('DeltaBuilder', () => { const timestamp = Date.now(); const delta = createDelta(creator, host) .withTimestamp(timestamp) - .build(); + .buildV1(); expect(delta.timeCreated).toBe(timestamp); }); diff --git a/src/core/delta-builder.ts b/src/core/delta-builder.ts index 484d915..47d5413 100644 --- a/src/core/delta-builder.ts +++ b/src/core/delta-builder.ts @@ -1,24 +1,7 @@ -import { - DeltaID, - Delta, - DeltaV1, - DeltaV2, - DeltaNetworkImageV1, - DeltaNetworkImageV2, - PointerTarget, - PointersV2 -} from './delta'; +import { DeltaV1, DeltaV2 } from './delta'; import { randomUUID } from 'crypto'; -import { microtime } from '../utils/time'; - -type DeltaVersion = 'v1' | 'v2'; - -// Local type for V1 pointers -interface PointerV1 { - localContext: string; - target: PointerTarget; - targetContext?: string; -} +import Debug from 'debug'; +const debug = Debug('rz:delta-builder'); /** * A fluent builder for creating Delta objects with proper validation and type safety. @@ -26,12 +9,10 @@ interface PointerV1 { */ export class DeltaBuilder { private id: string; - private timeCreated: number; + private timeCreated?: number; private host: string; private creator: string; - private version: DeltaVersion = 'v2'; // Default to V2 - private pointersV1: Array<{ localContext: string; target: PointerTarget; targetContext?: string }> = []; - private pointersV2: Record = {}; + private pointers: Record = {}; private transactionId?: string; private isNegation: boolean = false; private negatedDeltaId?: string; @@ -40,14 +21,11 @@ export class DeltaBuilder { * Create a new DeltaBuilder instance * @param creator - The ID of the entity creating this delta * @param host - The host where this delta is being created - * @param version - The delta version to use ('v1' or 'v2') */ - constructor(creator: string, host: string, version: DeltaVersion = 'v2') { + constructor(creator: string, host: string) { this.id = randomUUID(); - this.timeCreated = microtime.now(); this.creator = creator; this.host = host; - this.version = version; } /** @@ -84,50 +62,23 @@ export class DeltaBuilder { } /** - * Add a pointer to the delta (V1 style) + * Add a pointer to the delta */ addPointer(localContext: string, target: string | number | boolean, targetContext?: string): this { - if (this.version === 'v1') { - this.pointersV1.push({ localContext, target, targetContext }); + if (targetContext && typeof target === 'string') { + this.pointers[localContext] = { [target]: targetContext }; } else { - // For V2, we need to handle the target context differently - if (targetContext && typeof target === 'string') { - this.pointersV2[localContext] = { [target]: targetContext }; - } else { - this.pointersV2[localContext] = target; - } + this.pointers[localContext] = target; } return this; } /** - * Set a property on an entity (shorthand for addPointer with 'value' local context) + * Set a property on an entity */ - setProperty(entityId: string, property: string, value: string | number | boolean, targetContext?: string): this { - if (this.version === 'v1') { - // For V1, we need to ensure target is a valid type - if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { - this.pointersV1.push({ - localContext: property, - target: value, // We've checked it's a valid type - targetContext: property - }); - // Add a reference to the entity - this.pointersV1.push({ - localContext: 'entity', - target: entityId, - targetContext: property - }); - } - } else { - // V2 format - if (targetContext) { - this.pointersV2[property] = { [String(value)]: targetContext }; - } else { - this.pointersV2[property] = value; - } - this.pointersV2.entity = { [entityId]: property }; - } + setProperty(entityId: string, property: string, value: string | number | boolean, entityLabel = "entity"): this { + this.addPointer(entityLabel, entityId, property) + this.addPointer(property, value); return this; } @@ -135,41 +86,17 @@ export class DeltaBuilder { * Create a relationship between two entities */ relate(sourceId: string, relationship: string, targetId: string): this { - if (this.version === 'v1') { - this.pointersV1.push({ - localContext: relationship, - target: targetId, - targetContext: relationship - }); - this.pointersV1.push({ - localContext: 'source', - target: sourceId, - targetContext: relationship - }); - } else { - this.pointersV2[relationship] = { [targetId]: relationship }; - this.pointersV2.source = { [sourceId]: relationship }; - } + this.pointers[relationship] = { [targetId]: relationship }; + this.pointers.source = { [sourceId]: relationship }; return this; } - /** - * Build and return a Delta instance - */ - build(): Delta { - if (this.version === 'v1') { - return this.buildV1(); - } else { - return this.buildV2().toV1(); - } - } - /** * Build and return a DeltaV2 instance */ buildV2(): DeltaV2 { // For V2, we'll store transaction and negation info in the pointers object - const pointers = { ...this.pointersV2 }; + const pointers = { ...this.pointers }; if (this.transactionId) { pointers['_transaction'] = this.transactionId; @@ -182,9 +109,9 @@ export class DeltaBuilder { // Create the delta with all pointers return new DeltaV2({ id: this.id, - timeCreated: this.timeCreated, host: this.host, creator: this.creator, + timeCreated: this.timeCreated, pointers }); } @@ -192,38 +119,14 @@ export class DeltaBuilder { /** * Build and return a DeltaV1 instance */ - private buildV1(): DeltaV1 { - // For V1, we'll store transaction and negation info in the pointers - const pointers = [...this.pointersV1]; - - if (this.transactionId) { - pointers.push({ - localContext: '_transaction', - target: this.transactionId - }); - } - - if (this.isNegation && this.negatedDeltaId) { - pointers.push({ - localContext: '_negation', - target: this.negatedDeltaId - }); - } - - // Create the delta with all pointers - return new DeltaV1({ - id: this.id, - timeCreated: this.timeCreated, - host: this.host, - creator: this.creator, - pointers - }); + buildV1(): DeltaV1 { + return this.buildV2().toV1(); } } /** * Create a new DeltaBuilder instance (convenience function) */ -export function createDelta(creator: string, host: string, version: DeltaVersion = 'v2'): DeltaBuilder { - return new DeltaBuilder(creator, host, version); +export function createDelta(creator: string, host: string): DeltaBuilder { + return new DeltaBuilder(creator, host); } diff --git a/src/utils/time.ts b/src/utils/time.ts deleted file mode 100644 index 3058d8b..0000000 --- a/src/utils/time.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Microsecond-precision timestamp utilities - */ - -/** - * Get current time in microseconds since epoch - */ -export function microtimeNow(): number { - const [seconds, nanoseconds] = process.hrtime(); - return Math.floor(seconds * 1e6 + nanoseconds / 1e3); -} - -export const microtime = { - now: microtimeNow -};