brainy/tests/metadata-filter.test.ts
David Snelling 9c87982a7d 🧠 Brainy 2.0.0 - Zero-Configuration AI Database with Triple Intelligence™
MAJOR RELEASE: Complete evolution of Brainy with groundbreaking features and performance.

🎯 KEY FEATURES:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Triple Intelligence™ Engine
  - Unified Vector + Metadata + Graph search
  - O(log n) performance on all operations
  - 3ms average search latency at any scale

 API Consolidation
  - 15+ search methods → 2 clean APIs
  - search() for vector similarity
  - find() for natural language queries

 Natural Language Processing
  - 220+ pre-computed NLP patterns
  - Instant context understanding
  - "Show me recent React components with tests"

 Zero Configuration
  - Works instantly, no setup required
  - Built-in embedding models (no API keys)
  - Smart defaults for everything
  - Automatic optimization

 Enterprise Features (Free for Everyone)
  - Scales to 10M+ items
  - Write-Ahead Logging (WAL) for durability
  - Distributed architecture with sharding
  - Read/write separation
  - Connection pooling & request deduplication
  - Built-in monitoring & health checks

 Universal Compatibility
  - Node.js, Browser, Edge Workers
  - 4 Storage Adapters (Memory, FileSystem, OPFS, S3)
  - TypeScript with full type safety
  - Worker-based embeddings

📦 WHAT'S INCLUDED:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• Core AI Database with HNSW indexing
• 19 Production-ready augmentations
• Universal Memory Manager
• Complete CLI with all commands
• Brain Cloud integration (soulcraft.com)
• Comprehensive documentation
• 52 test files with 400+ tests
• Migration guide from 1.x

📊 PERFORMANCE:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• Initialize: 450ms (24MB memory)
• Search: 3ms average (up to 10M items)
• Metadata Filter: 0.8ms (O(log n))
• Bulk Import: 2.3s per 1000 items
• Production Scale: 5.8ms at 10M items

🔧 TECHNICAL IMPROVEMENTS:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• TypeScript compilation: 153 errors → 0
• Memory usage: 200MB → 24MB baseline
• Circular dependencies resolved
• Worker thread communication fixed
• Storage adapter consistency
• Request coalescing for 3x performance

🛠️ CLI FEATURES:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• brainy add - Smart data ingestion
• brainy find - Natural language search
• brainy search - Vector similarity
• brainy chat - AI conversation mode
• brainy cloud - Brain Cloud integration
• brainy augment - Manage extensions
• 100% API compatibility

📚 DOCUMENTATION:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• Professional README with examples
• Quick Start guide (5 minutes)
• Enterprise Features guide
• Migration guide from 1.x
• API reference
• Architecture documentation

🌟 USE CASES:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• AI memory layer for chatbots
• Semantic document search
• Code intelligence platforms
• Knowledge management systems
• Real-time recommendation engines
• Customer support automation

MIT License - Enterprise features included free for everyone.
No premium tiers, no paywalls, no limits.

Built with ❤️ by the Brainy community.
Visit https://soulcraft.com for Brain Cloud integration.
2025-08-26 12:32:21 -07:00

269 lines
No EOL
9.2 KiB
TypeScript

import { describe, it, expect, beforeEach } from 'vitest'
import { BrainyData } from '../src/brainyData.js'
import { matchesMetadataFilter } from '../src/utils/metadataFilter.js'
describe('Metadata Filtering', () => {
let brainy: BrainyData
beforeEach(async () => {
brainy = new BrainyData({
storage: { forceMemoryStorage: true },
hnsw: { M: 8, efConstruction: 50 },
logging: { verbose: false }
})
await brainy.init()
console.log('BrainyData initialized')
})
describe('matchesMetadataFilter', () => {
it('should match simple equality filters', () => {
const metadata = { level: 'senior', location: 'SF' }
expect(matchesMetadataFilter(metadata, { level: 'senior' })).toBe(true)
expect(matchesMetadataFilter(metadata, { level: 'junior' })).toBe(false)
expect(matchesMetadataFilter(metadata, { level: 'senior', location: 'SF' })).toBe(true)
expect(matchesMetadataFilter(metadata, { level: 'senior', location: 'NYC' })).toBe(false)
})
it('should support Brain Pattern operators', () => {
const metadata = { age: 30, skills: ['React', 'Vue'], name: 'John' }
// greaterThan, greaterEqual, lessThan, lessEqual
expect(matchesMetadataFilter(metadata, { age: { greaterThan: 25 } })).toBe(true)
expect(matchesMetadataFilter(metadata, { age: { lessThan: 25 } })).toBe(false)
expect(matchesMetadataFilter(metadata, { age: { greaterEqual: 30 } })).toBe(true)
expect(matchesMetadataFilter(metadata, { age: { lessEqual: 30 } })).toBe(true)
// oneOf, noneOf
expect(matchesMetadataFilter(metadata, { age: { oneOf: [25, 30, 35] } })).toBe(true)
expect(matchesMetadataFilter(metadata, { age: { noneOf: [25, 35] } })).toBe(true)
expect(matchesMetadataFilter(metadata, { age: { noneOf: [30] } })).toBe(false)
// contains for arrays
expect(matchesMetadataFilter(metadata, { skills: { contains: 'React' } })).toBe(true)
expect(matchesMetadataFilter(metadata, { skills: { contains: 'Angular' } })).toBe(false)
// matches (regex)
expect(matchesMetadataFilter(metadata, { name: { matches: '^Jo' } })).toBe(true)
expect(matchesMetadataFilter(metadata, { name: { matches: 'hn$' } })).toBe(true)
expect(matchesMetadataFilter(metadata, { name: { matches: 'Jane' } })).toBe(false)
})
it('should support nested fields with dot notation', () => {
const metadata = {
user: {
profile: {
level: 'senior',
skills: ['React', 'TypeScript']
}
}
}
expect(matchesMetadataFilter(metadata, { 'user.profile.level': 'senior' })).toBe(true)
expect(matchesMetadataFilter(metadata, { 'user.profile.level': 'junior' })).toBe(false)
expect(matchesMetadataFilter(metadata, {
'user.profile.skills': { contains: 'React' }
})).toBe(true)
})
it('should support logical operators', () => {
const metadata = { level: 'senior', location: 'SF', remote: true }
// allOf (AND logic)
expect(matchesMetadataFilter(metadata, {
allOf: [
{ level: 'senior' },
{ location: 'SF' }
]
})).toBe(true)
expect(matchesMetadataFilter(metadata, {
allOf: [
{ level: 'senior' },
{ location: 'NYC' }
]
})).toBe(false)
// anyOf (OR logic)
expect(matchesMetadataFilter(metadata, {
anyOf: [
{ location: 'NYC' },
{ location: 'SF' }
]
})).toBe(true)
expect(matchesMetadataFilter(metadata, {
anyOf: [
{ location: 'NYC' },
{ location: 'LA' }
]
})).toBe(false)
// not
expect(matchesMetadataFilter(metadata, {
not: { location: 'NYC' }
})).toBe(true)
expect(matchesMetadataFilter(metadata, {
not: { location: 'SF' }
})).toBe(false)
})
})
describe('Search with metadata filtering', () => {
beforeEach(async () => {
// Add test data
const developers = [
{ name: 'Alice', level: 'senior', skills: ['React', 'TypeScript'], location: 'SF', available: true },
{ name: 'Bob', level: 'mid', skills: ['Vue', 'JavaScript'], location: 'NYC', available: true },
{ name: 'Charlie', level: 'senior', skills: ['React', 'Python'], location: 'SF', available: false },
{ name: 'David', level: 'junior', skills: ['JavaScript'], location: 'LA', available: true },
{ name: 'Eve', level: 'senior', skills: ['Angular', 'TypeScript'], location: 'NYC', available: true }
]
for (const dev of developers) {
await brainy.add(
`${dev.name} is a ${dev.level} developer with ${dev.skills.join(', ')} skills in ${dev.location}`,
dev
)
}
})
it('should filter by simple metadata fields', async () => {
// First check what we have without filter
const allResults = await brainy.searchText('developer', 10)
console.log('All results:', allResults.map(r => ({
id: r.id.substring(0, 8),
level: r.metadata?.level,
name: r.metadata?.name
})))
// Now with filter
const results = await brainy.searchText('developer', 10, {
metadata: { level: 'senior' }
})
console.log('Filtered results:', results.map(r => ({
id: r.id.substring(0, 8),
level: r.metadata?.level,
name: r.metadata?.name
})))
expect(results.length).toBeGreaterThan(0)
expect(results.every(r => r.metadata?.level === 'senior')).toBe(true)
})
it('should filter by multiple metadata fields', async () => {
const results = await brainy.searchText('developer', 10, {
metadata: {
level: 'senior',
location: 'SF'
}
})
expect(results.length).toBeGreaterThan(0)
expect(results.every(r =>
r.metadata?.level === 'senior' &&
r.metadata?.location === 'SF'
)).toBe(true)
})
it('should filter with Brainy Field Operators', async () => {
// First verify what we have in the index
const allResults = await brainy.searchText('developer', 10)
console.log('All results before filtering:', allResults.map(r => ({
name: r.metadata?.name,
skills: r.metadata?.skills,
available: r.metadata?.available
})))
const results = await brainy.searchText('developer', 10, {
metadata: {
skills: { contains: 'React' },
available: true
}
})
console.log('Filtered results:', results.map(r => ({
name: r.metadata?.name,
skills: r.metadata?.skills,
available: r.metadata?.available
})))
expect(results.length).toBeGreaterThan(0)
// Check each result individually for debugging
for (const r of results) {
const hasReact = r.metadata?.skills?.includes('React')
const isAvailable = r.metadata?.available === true
if (!hasReact || !isAvailable) {
console.log('Failed result:', r.metadata)
}
}
expect(results.every(r =>
r.metadata?.skills?.includes('React') &&
r.metadata?.available === true
)).toBe(true)
})
it('should filter with complex queries', async () => {
const results = await brainy.searchText('developer', 10, {
metadata: {
anyOf: [
{ location: 'SF' },
{ location: 'NYC' }
],
level: { oneOf: ['senior', 'mid'] }
}
})
expect(results.length).toBeGreaterThan(0)
expect(results.every(r => {
const m = r.metadata
return (m?.location === 'SF' || m?.location === 'NYC') &&
(m?.level === 'senior' || m?.level === 'mid')
})).toBe(true)
})
})
describe('searchWithinItems', () => {
let itemIds: string[] = []
beforeEach(async () => {
// Add test data and collect IDs
const items = [
{ content: 'JavaScript programming', category: 'tech' },
{ content: 'TypeScript development', category: 'tech' },
{ content: 'Python data science', category: 'tech' },
{ content: 'React components', category: 'frontend' },
{ content: 'Vue templates', category: 'frontend' }
]
for (const item of items) {
const id = await brainy.add(item.content, item)
if (item.category === 'frontend') {
itemIds.push(id)
}
}
})
it('should search only within specified items', async () => {
// Search within frontend items only
const results = await brainy.searchWithinItems('JavaScript', itemIds, 5)
expect(results.length).toBeLessThanOrEqual(itemIds.length)
expect(results.every(r => itemIds.includes(r.id))).toBe(true)
})
it('should return empty results if no items match', async () => {
const results = await brainy.searchWithinItems('JavaScript', [], 5)
expect(results).toEqual([])
})
it('should limit results to k even if more items are provided', async () => {
const results = await brainy.searchWithinItems('development', itemIds, 1)
expect(results.length).toBe(1)
})
})
})