refactor: replace NegationHelper.createNegation with DeltaBuilder.negate
- Remove NegationHelper.createNegation in favor of using DeltaBuilder's fluent API - Update all test cases to use createDelta().negate().buildV1() pattern - Update documentation to reflect the preferred way to create negation deltas - Remove unused isNegationDeltaById helper method
This commit is contained in:
parent
9f27912c4a
commit
f4ea2eca39
@ -21,11 +21,9 @@ describe('Negation System', () => {
|
|||||||
.setProperty('entity1', 'name', 'Alice')
|
.setProperty('entity1', 'name', 'Alice')
|
||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
const negationDelta = NegationHelper.createNegation(
|
const negationDelta = createDelta('moderator', 'host1')
|
||||||
originalDelta.id,
|
.negate(originalDelta.id)
|
||||||
'moderator',
|
.buildV1();
|
||||||
'host1'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(negationDelta.creator).toBe('moderator');
|
expect(negationDelta.creator).toBe('moderator');
|
||||||
expect(negationDelta.pointers).toHaveLength(1);
|
expect(negationDelta.pointers).toHaveLength(1);
|
||||||
@ -42,11 +40,9 @@ describe('Negation System', () => {
|
|||||||
.setProperty('entity1', 'name', 'Entity 1')
|
.setProperty('entity1', 'name', 'Entity 1')
|
||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
const negationDelta = NegationHelper.createNegation(
|
const negationDelta = createDelta('moderator', 'host1')
|
||||||
'delta-to-negate',
|
.negate('delta-to-negate')
|
||||||
'moderator',
|
.buildV1();
|
||||||
'host1'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(NegationHelper.isNegationDelta(regularDelta)).toBe(false);
|
expect(NegationHelper.isNegationDelta(regularDelta)).toBe(false);
|
||||||
expect(NegationHelper.isNegationDelta(negationDelta)).toBe(true);
|
expect(NegationHelper.isNegationDelta(negationDelta)).toBe(true);
|
||||||
@ -54,11 +50,9 @@ describe('Negation System', () => {
|
|||||||
|
|
||||||
it('should extract negated delta ID', () => {
|
it('should extract negated delta ID', () => {
|
||||||
const targetDeltaId = 'target-delta-123';
|
const targetDeltaId = 'target-delta-123';
|
||||||
const negationDelta = NegationHelper.createNegation(
|
const negationDelta = createDelta('moderator', 'host1')
|
||||||
targetDeltaId,
|
.negate(targetDeltaId)
|
||||||
'moderator',
|
.buildV1();
|
||||||
'host1'
|
|
||||||
);
|
|
||||||
|
|
||||||
const extractedId = NegationHelper.getNegatedDeltaId(negationDelta);
|
const extractedId = NegationHelper.getNegatedDeltaId(negationDelta);
|
||||||
expect(extractedId).toBe(targetDeltaId);
|
expect(extractedId).toBe(targetDeltaId);
|
||||||
@ -79,9 +73,9 @@ describe('Negation System', () => {
|
|||||||
.setProperty('entity1', 'age', 25)
|
.setProperty('entity1', 'age', 25)
|
||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
const negation1 = NegationHelper.createNegation(delta1.id, 'mod1', 'host1');
|
const negation1 = createDelta('mod1', 'host1').negate(delta1.id).buildV1();
|
||||||
const negation2 = NegationHelper.createNegation(delta1.id, 'mod2', 'host1');
|
const negation2 = createDelta('mod2', 'host1').negate(delta1.id).buildV1();
|
||||||
const negation3 = NegationHelper.createNegation(delta2.id, 'mod1', 'host1');
|
const negation3 = createDelta('mod1', 'host1').negate(delta2.id).buildV1();
|
||||||
|
|
||||||
const allDeltas = [delta1, delta2, negation1, negation2, negation3];
|
const allDeltas = [delta1, delta2, negation1, negation2, negation3];
|
||||||
|
|
||||||
@ -104,7 +98,7 @@ describe('Negation System', () => {
|
|||||||
.setProperty('entity1', 'age', 25)
|
.setProperty('entity1', 'age', 25)
|
||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
const negation1 = NegationHelper.createNegation(delta1.id, 'mod1', 'host1');
|
const negation1 = createDelta('mod1', 'host1').negate(delta1.id).buildV1();
|
||||||
const allDeltas = [delta1, delta2, negation1];
|
const allDeltas = [delta1, delta2, negation1];
|
||||||
|
|
||||||
expect(NegationHelper.isDeltaNegated(delta1.id, allDeltas)).toBe(true);
|
expect(NegationHelper.isDeltaNegated(delta1.id, allDeltas)).toBe(true);
|
||||||
@ -124,8 +118,8 @@ describe('Negation System', () => {
|
|||||||
.setProperty('entity1', 'email', 'entity1@example.com')
|
.setProperty('entity1', 'email', 'entity1@example.com')
|
||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
const negation1 = NegationHelper.createNegation(delta1.id, 'mod1', 'host1');
|
const negation1 = createDelta('mod1', 'host1').negate(delta1.id).buildV1();
|
||||||
const negation2 = NegationHelper.createNegation(delta2.id, 'mod2', 'host1');
|
const negation2 = createDelta('mod2', 'host1').negate(delta2.id).buildV1();
|
||||||
|
|
||||||
const allDeltas = [delta1, delta2, delta3, negation1, negation2];
|
const allDeltas = [delta1, delta2, delta3, negation1, negation2];
|
||||||
const filtered = NegationHelper.filterNegatedDeltas(allDeltas);
|
const filtered = NegationHelper.filterNegatedDeltas(allDeltas);
|
||||||
@ -144,7 +138,7 @@ describe('Negation System', () => {
|
|||||||
.setProperty('entity1', 'age', 25)
|
.setProperty('entity1', 'age', 25)
|
||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
const negation1 = NegationHelper.createNegation(delta1.id, 'mod1', 'host1');
|
const negation1 = createDelta('mod1', 'host1').negate(delta1.id).buildV1();
|
||||||
const allDeltas = [delta1, delta2, negation1];
|
const allDeltas = [delta1, delta2, negation1];
|
||||||
|
|
||||||
const stats = NegationHelper.getNegationStats(allDeltas);
|
const stats = NegationHelper.getNegationStats(allDeltas);
|
||||||
@ -166,7 +160,7 @@ describe('Negation System', () => {
|
|||||||
.setProperty('entity1', 'status', 'active')
|
.setProperty('entity1', 'status', 'active')
|
||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
const negation1 = NegationHelper.createNegation(delta1.id, 'mod1', 'host1');
|
const negation1 = createDelta('mod1', 'host1').negate(delta1.id).buildV1();
|
||||||
negation1.timeCreated = baseTime + 1000; // 1 second later
|
negation1.timeCreated = baseTime + 1000; // 1 second later
|
||||||
|
|
||||||
const delta2 = createDelta('user1', 'host1')
|
const delta2 = createDelta('user1', 'host1')
|
||||||
@ -174,7 +168,7 @@ describe('Negation System', () => {
|
|||||||
.setProperty('entity1', 'status', 'inactive')
|
.setProperty('entity1', 'status', 'inactive')
|
||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
const negation2 = NegationHelper.createNegation(delta2.id, 'mod1', 'host1');
|
const negation2 = createDelta('mod1', 'host1').negate(delta2.id).buildV1();
|
||||||
negation2.timeCreated = baseTime + 3000; // 3 seconds later
|
negation2.timeCreated = baseTime + 3000; // 3 seconds later
|
||||||
|
|
||||||
const allDeltas = [delta1, negation1, delta2, negation2];
|
const allDeltas = [delta1, negation1, delta2, negation2];
|
||||||
@ -193,11 +187,9 @@ describe('Negation System', () => {
|
|||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
// Create negation delta
|
// Create negation delta
|
||||||
const negationDelta = NegationHelper.createNegation(
|
const negationDelta = createDelta('moderator', 'host1')
|
||||||
originalDelta.id,
|
.negate(originalDelta.id)
|
||||||
'moderator',
|
.buildV1();
|
||||||
'host1'
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// Create another non-negated delta
|
// Create another non-negated delta
|
||||||
@ -225,8 +217,8 @@ describe('Negation System', () => {
|
|||||||
.setProperty('post1', 'content', 'Original content')
|
.setProperty('post1', 'content', 'Original content')
|
||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
const negation1 = NegationHelper.createNegation(originalDelta.id, 'mod1', 'host1');
|
const negation1 = createDelta('mod1', 'host1').negate(originalDelta.id).buildV1();
|
||||||
const negation2 = NegationHelper.createNegation(originalDelta.id, 'mod2', 'host1');
|
const negation2 = createDelta('mod2', 'host1').negate(originalDelta.id).buildV1();
|
||||||
|
|
||||||
lossless.ingestDelta(originalDelta);
|
lossless.ingestDelta(originalDelta);
|
||||||
lossless.ingestDelta(negation1);
|
lossless.ingestDelta(negation1);
|
||||||
@ -247,7 +239,7 @@ describe('Negation System', () => {
|
|||||||
.setProperty('article1', 'content', 'Article content')
|
.setProperty('article1', 'content', 'Article content')
|
||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
const negation1 = NegationHelper.createNegation(delta1.id, 'mod1', 'host1');
|
const negation1 = createDelta('mod1', 'host1').negate(delta1.id).buildV1();
|
||||||
|
|
||||||
lossless.ingestDelta(delta1);
|
lossless.ingestDelta(delta1);
|
||||||
lossless.ingestDelta(delta2);
|
lossless.ingestDelta(delta2);
|
||||||
@ -268,11 +260,7 @@ describe('Negation System', () => {
|
|||||||
.setProperty('task1', 'status', 'pending')
|
.setProperty('task1', 'status', 'pending')
|
||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
const negationDelta = NegationHelper.createNegation(
|
const negationDelta = createDelta('admin', 'host1').negate(originalDelta.id).buildV1();
|
||||||
originalDelta.id,
|
|
||||||
'admin',
|
|
||||||
'host1'
|
|
||||||
);
|
|
||||||
|
|
||||||
lossless.ingestDelta(originalDelta);
|
lossless.ingestDelta(originalDelta);
|
||||||
lossless.ingestDelta(negationDelta);
|
lossless.ingestDelta(negationDelta);
|
||||||
@ -299,7 +287,7 @@ describe('Negation System', () => {
|
|||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
// Create negation delta in same transaction
|
// Create negation delta in same transaction
|
||||||
const negationDelta = NegationHelper.createNegation(originalDelta.id, 'moderator', 'host1');
|
const negationDelta = createDelta('moderator', 'host1').negate(originalDelta.id).buildV1();
|
||||||
negationDelta.pointers.unshift({
|
negationDelta.pointers.unshift({
|
||||||
localContext: '_transaction',
|
localContext: '_transaction',
|
||||||
target: transactionId,
|
target: transactionId,
|
||||||
@ -324,7 +312,7 @@ describe('Negation System', () => {
|
|||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
// Moderator negates it
|
// Moderator negates it
|
||||||
const negationDelta = NegationHelper.createNegation(postDelta.id, 'moderator', 'host1');
|
const negationDelta = createDelta('moderator', 'host1').negate(postDelta.id).buildV1();
|
||||||
negationDelta.timeCreated = baseTime + 1000;
|
negationDelta.timeCreated = baseTime + 1000;
|
||||||
|
|
||||||
// User edits content (after negation)
|
// User edits content (after negation)
|
||||||
@ -351,11 +339,7 @@ describe('Negation System', () => {
|
|||||||
|
|
||||||
describe('Edge Cases', () => {
|
describe('Edge Cases', () => {
|
||||||
it('should handle negation of non-existent deltas', () => {
|
it('should handle negation of non-existent deltas', () => {
|
||||||
const negationDelta = NegationHelper.createNegation(
|
const negationDelta = createDelta('moderator', 'host1').negate('non-existent-delta-id').buildV1();
|
||||||
'non-existent-delta-id',
|
|
||||||
'moderator',
|
|
||||||
'host1'
|
|
||||||
);
|
|
||||||
|
|
||||||
lossless.ingestDelta(negationDelta);
|
lossless.ingestDelta(negationDelta);
|
||||||
|
|
||||||
@ -371,7 +355,7 @@ describe('Negation System', () => {
|
|||||||
.setProperty('node1', 'child', 'node1') // Self-reference
|
.setProperty('node1', 'child', 'node1') // Self-reference
|
||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
const negationDelta = NegationHelper.createNegation(selfRefDelta.id, 'admin', 'host1');
|
const negationDelta = createDelta('admin', 'host1').negate(selfRefDelta.id).buildV1();
|
||||||
|
|
||||||
lossless.ingestDelta(selfRefDelta);
|
lossless.ingestDelta(selfRefDelta);
|
||||||
lossless.ingestDelta(negationDelta);
|
lossless.ingestDelta(negationDelta);
|
||||||
@ -390,8 +374,8 @@ describe('Negation System', () => {
|
|||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
// Create two negations of the same delta
|
// Create two negations of the same delta
|
||||||
const negation1 = NegationHelper.createNegation(originalDelta.id, 'user2', 'host1');
|
const negation1 = createDelta('user2', 'host1').negate(originalDelta.id).buildV1();
|
||||||
const negation2 = NegationHelper.createNegation(originalDelta.id, 'user3', 'host1');
|
const negation2 = createDelta('user3', 'host1').negate(originalDelta.id).buildV1();
|
||||||
|
|
||||||
// Process all deltas
|
// Process all deltas
|
||||||
testLossless.ingestDelta(originalDelta);
|
testLossless.ingestDelta(originalDelta);
|
||||||
@ -421,9 +405,9 @@ describe('Negation System', () => {
|
|||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
// Create a chain of negations: B negates A, C negates B, D negates C
|
// Create a chain of negations: B negates A, C negates B, D negates C
|
||||||
const deltaB = NegationHelper.createNegation(deltaA.id, 'user2', 'host1');
|
const deltaB = createDelta('user2', 'host1').negate(deltaA.id).buildV1();
|
||||||
const deltaC = NegationHelper.createNegation(deltaB.id, 'user3', 'host1');
|
const deltaC = createDelta('user3', 'host1').negate(deltaB.id).buildV1();
|
||||||
const deltaD = NegationHelper.createNegation(deltaC.id, 'user4', 'host1');
|
const deltaD = createDelta('user4', 'host1').negate(deltaC.id).buildV1();
|
||||||
|
|
||||||
debug('Delta A (original): %s', deltaA.id);
|
debug('Delta A (original): %s', deltaA.id);
|
||||||
debug('Delta B (negates A): %s', deltaB.id);
|
debug('Delta B (negates A): %s', deltaB.id);
|
||||||
@ -498,8 +482,8 @@ describe('Negation System', () => {
|
|||||||
.buildV1();
|
.buildV1();
|
||||||
|
|
||||||
// Create negations for both deltas
|
// Create negations for both deltas
|
||||||
const negation1 = NegationHelper.createNegation(delta1.id, 'user3', 'host1');
|
const negation1 = createDelta('user3', 'host1').negate(delta1.id).buildV1();
|
||||||
const negation2 = NegationHelper.createNegation(delta2.id, 'user4', 'host1');
|
const negation2 = createDelta('user4', 'host1').negate(delta2.id).buildV1();
|
||||||
|
|
||||||
// Process all deltas
|
// Process all deltas
|
||||||
testLossless.ingestDelta(delta1);
|
testLossless.ingestDelta(delta1);
|
||||||
|
83
delta-patterns/summary.md
Normal file
83
delta-patterns/summary.md
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Delta Patterns in Rhizome-Node
|
||||||
|
|
||||||
|
This document outlines the distinct delta patterns identified in the Rhizome-Node test suite.
|
||||||
|
|
||||||
|
## 1. Basic Entity Creation
|
||||||
|
```typescript
|
||||||
|
createDelta('creator', 'host')
|
||||||
|
.setProperty('entity1', 'name', 'Alice', 'user')
|
||||||
|
.buildV1();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Relationship Creation
|
||||||
|
```typescript
|
||||||
|
createDelta('creator', 'host')
|
||||||
|
.addPointer('users', 'alice', 'friends')
|
||||||
|
.addPointer('friend', 'bob')
|
||||||
|
.addPointer('type', 'friendship')
|
||||||
|
.buildV1();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Transaction-Enabled Deltas
|
||||||
|
```typescript
|
||||||
|
createDelta('user1', 'host1')
|
||||||
|
.inTransaction('tx123')
|
||||||
|
.setProperty('doc1', 'status', 'draft')
|
||||||
|
.buildV1();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Negation Deltas
|
||||||
|
```typescript
|
||||||
|
// Creating a negation delta
|
||||||
|
const delta = createDelta('user1', 'host1').buildV1();
|
||||||
|
const negation = createDelta('moderator', 'host1').negate(delta.id).buildV1();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Temporal Deltas
|
||||||
|
```typescript
|
||||||
|
createDelta('user1', 'host1')
|
||||||
|
.withTimestamp(1624233600000)
|
||||||
|
.setProperty('entity1', 'score', 100, 'game')
|
||||||
|
.buildV1();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Multi-Property Deltas
|
||||||
|
```typescript
|
||||||
|
createDelta('user1', 'host1')
|
||||||
|
.setProperty('entity1', 'title', 'Hello World', 'post')
|
||||||
|
.setProperty('entity1', 'content', 'This is a test', 'post')
|
||||||
|
.setProperty('entity1', 'published', true, 'post')
|
||||||
|
.buildV1();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Reference-Only Deltas
|
||||||
|
```typescript
|
||||||
|
createDelta('system', 'host1')
|
||||||
|
.addPointer('posts', 'post1', 'recent')
|
||||||
|
.buildV1();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Bulk Operation Deltas
|
||||||
|
```typescript
|
||||||
|
// Multiple entities in a single delta
|
||||||
|
createDelta('batch', 'host1')
|
||||||
|
.setProperty('user1', 'status', 'active', 'user')
|
||||||
|
.setProperty('user2', 'status', 'inactive', 'user')
|
||||||
|
.buildV1();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Versioned Deltas
|
||||||
|
```typescript
|
||||||
|
// V1 format
|
||||||
|
createDelta('a', 'h').buildV1();
|
||||||
|
// V2 format
|
||||||
|
createDelta('a', 'h').buildV2();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Observations
|
||||||
|
- Most deltas follow a fluent builder pattern
|
||||||
|
- Deltas can be composed of multiple operations (setProperty, addPointer, etc.)
|
||||||
|
- Support for both V1 and V2 delta formats
|
||||||
|
- Strong typing and schema validation is commonly used
|
||||||
|
- Transaction support is built into the delta creation process
|
||||||
|
- Temporal aspects can be explicitly controlled
|
90
docs/schema-validation.md
Normal file
90
docs/schema-validation.md
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# Schema Validation in Rhizome-Node
|
||||||
|
|
||||||
|
This document explains how schema validation works with deltas in Rhizome-Node.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Schema validation in Rhizome-Node is enforced at the `TypedCollection` level when using the `put` method, which validates data before creating deltas. This means:
|
||||||
|
|
||||||
|
1. **Local Changes**: When you use `collection.put()`, the data is validated against the schema before any deltas are created and ingested.
|
||||||
|
2. **Peer Changes**: Deltas received from other peers are ingested without validation by default, which means invalid data can enter the system.
|
||||||
|
3. **Validation Tracking**: The system tracks which entities are valid/invalid after ingestion.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 1. Define a schema for users
|
||||||
|
const userSchema = SchemaBuilder
|
||||||
|
.create('user')
|
||||||
|
.name('User')
|
||||||
|
.property('name', PrimitiveSchemas.requiredString())
|
||||||
|
.property('email', PrimitiveSchemas.email())
|
||||||
|
.property('age', PrimitiveSchemas.integer({ minimum: 0 }))
|
||||||
|
.required('name')
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 2. Create a typed collection with strict validation
|
||||||
|
const collection = new TypedCollectionImpl<{
|
||||||
|
name: string;
|
||||||
|
email?: string;
|
||||||
|
age?: number;
|
||||||
|
}>('users', userSchema, schemaRegistry, {
|
||||||
|
strictValidation: true // Enable strict validation
|
||||||
|
});
|
||||||
|
|
||||||
|
// Connect to the node
|
||||||
|
collection.rhizomeConnect(node);
|
||||||
|
|
||||||
|
// 3. Local changes - validated on put()
|
||||||
|
// Valid usage - will pass schema validation
|
||||||
|
await collection.put('user1', {
|
||||||
|
name: 'Alice',
|
||||||
|
email: 'alice@example.com',
|
||||||
|
age: 30
|
||||||
|
});
|
||||||
|
|
||||||
|
// Invalid usage - will throw SchemaValidationError
|
||||||
|
await expect(collection.put('user2', {
|
||||||
|
email: 'invalid-email', // Invalid email format
|
||||||
|
age: -5 // Negative age
|
||||||
|
})).rejects.toThrow(SchemaValidationError);
|
||||||
|
|
||||||
|
// 4. Peer data - ingested without validation by default
|
||||||
|
const unsafeDelta = createDelta('peer1', 'peer1')
|
||||||
|
.setProperty('user3', 'name', 'Bob', 'users')
|
||||||
|
.setProperty('user3', 'age', 'not-a-number', 'users')
|
||||||
|
.buildV1();
|
||||||
|
|
||||||
|
// This will be ingested without validation
|
||||||
|
node.lossless.ingestDelta(unsafeDelta);
|
||||||
|
|
||||||
|
// 5. Check validation status after the fact
|
||||||
|
const stats = collection.getValidationStats();
|
||||||
|
console.log(`Valid: ${stats.validEntities}, Invalid: ${stats.invalidEntities}`);
|
||||||
|
|
||||||
|
// Get details about invalid entities
|
||||||
|
const invalidUsers = collection.getInvalidEntities();
|
||||||
|
invalidUsers.forEach(user => {
|
||||||
|
console.log(`User ${user.entityId} is invalid:`, user.errors);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Points
|
||||||
|
|
||||||
|
### Validation Timing
|
||||||
|
- Schema validation happens in `TypedCollection.put()` before deltas are created
|
||||||
|
- Deltas from peers are ingested without validation by default
|
||||||
|
|
||||||
|
### Validation Modes
|
||||||
|
- `strictValidation: true`: Throws errors on invalid data (recommended for local changes)
|
||||||
|
- `strictValidation: false`: Allows invalid data but tracks it (default)
|
||||||
|
|
||||||
|
### Monitoring
|
||||||
|
- Use `getValidationStats()` to get counts of valid/invalid entities
|
||||||
|
- Use `getInvalidEntities()` to get detailed error information
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
- Always validate data before creating deltas when accepting external input
|
||||||
|
- Use `strictValidation: true` for collections where data integrity is critical
|
||||||
|
- Monitor validation statistics in production to detect data quality issues
|
||||||
|
- Consider implementing a validation layer for peer data if needed
|
@ -14,23 +14,6 @@ export interface NegationPointer {
|
|||||||
|
|
||||||
// Helper functions for creating and identifying negation deltas
|
// Helper functions for creating and identifying negation deltas
|
||||||
export class NegationHelper {
|
export class NegationHelper {
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a negation delta that negates another delta
|
|
||||||
*/
|
|
||||||
static createNegation(
|
|
||||||
deltaToNegate: DeltaID,
|
|
||||||
creator: CreatorID,
|
|
||||||
host: HostID
|
|
||||||
): Delta {
|
|
||||||
const negationDelta = createDelta(creator, host)
|
|
||||||
.negate(deltaToNegate)
|
|
||||||
.buildV1();
|
|
||||||
|
|
||||||
debug(`Created negation delta ${negationDelta.id} negating ${deltaToNegate}`);
|
|
||||||
return negationDelta;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a delta is a negation delta
|
* Check if a delta is a negation delta
|
||||||
*/
|
*/
|
||||||
@ -361,14 +344,6 @@ export class NegationHelper {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to check if a delta with the given ID is a negation delta
|
|
||||||
*/
|
|
||||||
private static isNegationDeltaById(deltaId: DeltaID, deltas: Delta[]): boolean {
|
|
||||||
const delta = deltas.find(d => d.id === deltaId);
|
|
||||||
return delta ? this.isNegationDelta(delta) : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply negations to a delta stream in chronological order
|
* Apply negations to a delta stream in chronological order
|
||||||
* Later negations can override earlier ones
|
* Later negations can override earlier ones
|
||||||
|
Loading…
x
Reference in New Issue
Block a user