feat: add comprehensive zero-config validation system
- Implement self-configuring validation that adapts to system resources
- Add validation for all CRUD operations (add, update, delete, find, relate)
- Auto-configure limits based on available memory (1GB = 10K limit, 8GB = 80K)
- Monitor and auto-tune performance based on query response times
- Fix multiple type filtering with proper anyOf structure
- Enhance type safety by requiring NounType/VerbType enums
- Fix tests to validate correct behavior (no fake implementations)
- Add comprehensive VALIDATION.md documentation
- Update API_REFERENCE.md with validation rules and examples
- Clarify metadata update behavior (null keeps existing, {} clears)
BREAKING CHANGE: getFieldsForType() now requires NounType enum instead of string
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
e9a2c41b0a
commit
7eaf5a9252
12 changed files with 979 additions and 76 deletions
|
|
@ -236,23 +236,18 @@ describe('Brainy.update()', () => {
|
|||
})).rejects.toThrow()
|
||||
})
|
||||
|
||||
it('should allow any entity type on update', async () => {
|
||||
it('should reject invalid entity type on update', async () => {
|
||||
// Arrange
|
||||
const id = await brain.add(createAddParams({
|
||||
data: 'Test',
|
||||
type: 'thing'
|
||||
}))
|
||||
|
||||
// Act - Update doesn't validate type
|
||||
await brain.update({
|
||||
// Act & Assert - Should properly validate type
|
||||
await expect(brain.update({
|
||||
id,
|
||||
type: 'invalid_type' as any
|
||||
})
|
||||
|
||||
// Assert
|
||||
const updated = await brain.get(id)
|
||||
expect(updated).not.toBeNull()
|
||||
expect(updated!.type).toBe('invalid_type')
|
||||
})).rejects.toThrow('invalid NounType')
|
||||
})
|
||||
|
||||
it('should not update vector directly via update method', async () => {
|
||||
|
|
@ -280,7 +275,7 @@ describe('Brainy.update()', () => {
|
|||
expect(updated!.vector).toEqual(originalVector)
|
||||
})
|
||||
|
||||
it('should handle empty update parameters', async () => {
|
||||
it('should reject empty update parameters', async () => {
|
||||
// Arrange
|
||||
const id = await brain.add(createAddParams({
|
||||
data: 'Test',
|
||||
|
|
@ -288,18 +283,13 @@ describe('Brainy.update()', () => {
|
|||
metadata: { original: true }
|
||||
}))
|
||||
|
||||
// Act - Update with empty params (should be no-op)
|
||||
await brain.update({ id })
|
||||
|
||||
// Assert - Nothing should change
|
||||
const entity = await brain.get(id)
|
||||
expect(entity).not.toBeNull()
|
||||
expect(entity!.metadata.original).toBe(true)
|
||||
// Act & Assert - Should require at least one field to update
|
||||
await expect(brain.update({ id })).rejects.toThrow('must specify at least one field to update')
|
||||
})
|
||||
})
|
||||
|
||||
describe('edge cases', () => {
|
||||
it('should handle updating with null metadata (documents actual behavior)', async () => {
|
||||
it('should reject updating with null metadata', async () => {
|
||||
// Arrange
|
||||
const id = await brain.add(createAddParams({
|
||||
data: 'Test',
|
||||
|
|
@ -307,29 +297,18 @@ describe('Brainy.update()', () => {
|
|||
metadata: { existing: 'data', another: 'field' }
|
||||
}))
|
||||
|
||||
// Act
|
||||
await brain.update({
|
||||
// Act & Assert - null metadata is not a valid update
|
||||
// This prevents accidental data loss from null values
|
||||
await expect(brain.update({
|
||||
id,
|
||||
metadata: null as any,
|
||||
merge: false
|
||||
})
|
||||
})).rejects.toThrow('must specify at least one field to update')
|
||||
|
||||
// Assert
|
||||
const updated = await brain.get(id)
|
||||
expect(updated).not.toBeNull()
|
||||
expect(updated!.metadata).toBeDefined()
|
||||
|
||||
// Document the actual API behavior:
|
||||
// 1. Setting metadata to null does NOT clear existing metadata
|
||||
// 2. String data may be spread into metadata as individual characters
|
||||
|
||||
// The original metadata should still be present (actual behavior)
|
||||
expect(updated!.metadata.existing).toBe('data')
|
||||
expect(updated!.metadata.another).toBe('field')
|
||||
|
||||
// Note: This documents that null metadata updates preserve existing fields
|
||||
// This may be intentional to prevent accidental data loss
|
||||
console.log('Documented behavior: null metadata update preserves existing metadata')
|
||||
// Verify original data is untouched
|
||||
const entity = await brain.get(id)
|
||||
expect(entity!.metadata.existing).toBe('data')
|
||||
expect(entity!.metadata.another).toBe('field')
|
||||
})
|
||||
|
||||
it('should handle concurrent updates', async () => {
|
||||
|
|
|
|||
Reference in a new issue