brainy/tests/find-comprehensive.test.ts
David Snelling 26c7d61185 CHECKPOINT: Brainy 2.0 API refactor - pre-fixes state
Current state:
- Unified augmentation system to BrainyAugmentation interface
- Changed methods to specific noun/verb naming (addNoun, getNoun, etc)
- Made old methods private
- Combined getNouns into single unified method
- Neural API exists and is complete
- Triple Intelligence uses correct Brainy operators (not MongoDB)

Issues identified:
- Documentation incorrectly shows MongoDB operators (code is correct)
- Need to ensure all features are properly exposed
- Need to verify nothing was lost in simplification

This commit serves as a rollback point before applying fixes.
2025-08-25 09:52:32 -07:00

715 lines
No EOL
20 KiB
TypeScript

import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { BrainyData, VerbType } from '../src/index.js'
describe('find() Method - Comprehensive Triple Intelligence Tests', () => {
let db: BrainyData | null = null
// Helper to create test vectors with semantic meaning
const createTestVector = (seed: number = 0, category: 'tech' | 'food' | 'travel' | 'person' = 'tech') => {
const base = new Array(384).fill(0).map((_, i) => Math.sin(i + seed) * 0.5)
// Add category-specific bias to create semantic clusters
const categoryBias = {
tech: 0.2,
food: -0.2,
travel: 0.1,
person: -0.1
}
return base.map(v => v + categoryBias[category])
}
afterEach(async () => {
if (db) {
await db.cleanup?.()
db = null
}
// Force garbage collection if available
if (global.gc) {
global.gc()
}
})
describe('Natural Language Queries', () => {
beforeEach(async () => {
db = new BrainyData()
await db.init()
// Add diverse test data
// Tech entities
await db.addNoun(createTestVector(1, 'tech'), {
id: 'javascript',
name: 'JavaScript',
type: 'language',
category: 'tech',
popularity: 95
})
await db.addNoun(createTestVector(2, 'tech'), {
id: 'python',
name: 'Python',
type: 'language',
category: 'tech',
popularity: 90
})
await db.addNoun(createTestVector(3, 'tech'), {
id: 'react',
name: 'React',
type: 'framework',
category: 'tech',
popularity: 85
})
// People
await db.addNoun(createTestVector(4, 'person'), {
id: 'alice',
name: 'Alice',
type: 'developer',
category: 'person',
experience: 5
})
await db.addNoun(createTestVector(5, 'person'), {
id: 'bob',
name: 'Bob',
type: 'developer',
category: 'person',
experience: 3
})
// Projects
await db.addNoun(createTestVector(6, 'tech'), {
id: 'webapp',
name: 'Web Application',
type: 'project',
category: 'tech',
status: 'active'
})
// Add relationships
await db.addVerb('alice', 'javascript', VerbType.USES)
await db.addVerb('alice', 'react', VerbType.USES)
await db.addVerb('bob', 'python', VerbType.USES)
await db.addVerb('webapp', 'react', VerbType.USES)
await db.addVerb('alice', 'webapp', VerbType.WORKS_ON)
})
it('should understand simple natural language queries', async () => {
const results = await db!.find('find all developers')
expect(results).toBeDefined()
expect(Array.isArray(results)).toBe(true)
// Should find Alice and Bob
const ids = results.map(r => r.id)
expect(ids).toContain('alice')
expect(ids).toContain('bob')
})
it('should handle complex natural language with intent', async () => {
const results = await db!.find('show me developers who use JavaScript')
// Should find Alice (who uses JavaScript)
const ids = results.map(r => r.id)
expect(ids).toContain('alice')
// Should not include Bob (uses Python)
expect(ids).not.toContain('bob')
})
it('should understand relationship queries', async () => {
const results = await db!.find('what projects is Alice working on')
// Should find webapp
const ids = results.map(r => r.id)
expect(ids).toContain('webapp')
})
it('should handle similarity queries', async () => {
const results = await db!.find('find things similar to React')
// Should find other tech items
expect(results.length).toBeGreaterThan(0)
// JavaScript should be in results (same category)
const ids = results.map(r => r.id)
expect(ids.some(id => ['javascript', 'python', 'webapp'].includes(id))).toBe(true)
})
})
describe('Vector Search (like/similar)', () => {
beforeEach(async () => {
db = new BrainyData()
await db.init()
// Add test data with clear semantic clusters
for (let i = 0; i < 10; i++) {
await db.addNoun(createTestVector(i, 'tech'), {
id: `tech${i}`,
category: 'technology',
relevance: i * 10
})
}
for (let i = 0; i < 10; i++) {
await db.addNoun(createTestVector(i + 100, 'food'), {
id: `food${i}`,
category: 'cuisine',
rating: i
})
}
})
it('should find items similar to a vector', async () => {
const queryVector = createTestVector(5, 'tech')
const results = await db!.find({
like: queryVector,
limit: 5
})
expect(results.length).toBeLessThanOrEqual(5)
// Should find tech items (similar vectors)
const ids = results.map(r => r.id)
expect(ids.some(id => id.startsWith('tech'))).toBe(true)
})
it('should find items similar to text', async () => {
const results = await db!.find({
similar: 'technology and programming',
limit: 3
})
expect(results.length).toBeGreaterThan(0)
expect(results.length).toBeLessThanOrEqual(3)
})
it('should find items similar to an existing ID', async () => {
const results = await db!.find({
like: 'tech5',
limit: 3
})
// Should find other tech items
const ids = results.map(r => r.id)
expect(ids.some(id => id.startsWith('tech') && id !== 'tech5')).toBe(true)
})
it('should respect similarity threshold', async () => {
const results = await db!.find({
similar: createTestVector(5, 'tech'),
threshold: 0.9, // High similarity required
limit: 10
})
// Should only find very similar items
results.forEach(result => {
expect(result.score).toBeGreaterThan(0.9)
})
})
})
describe('Graph Search (connected)', () => {
beforeEach(async () => {
db = new BrainyData()
await db.init()
// Create a graph structure
// Company -> Department -> Team -> Employee
await db.addNoun(createTestVector(1), { id: 'company', name: 'TechCorp' })
await db.addNoun(createTestVector(2), { id: 'engineering', name: 'Engineering Dept' })
await db.addNoun(createTestVector(3), { id: 'frontend', name: 'Frontend Team' })
await db.addNoun(createTestVector(4), { id: 'backend', name: 'Backend Team' })
await db.addNoun(createTestVector(5), { id: 'alice', name: 'Alice', role: 'developer' })
await db.addNoun(createTestVector(6), { id: 'bob', name: 'Bob', role: 'developer' })
await db.addNoun(createTestVector(7), { id: 'charlie', name: 'Charlie', role: 'manager' })
// Create relationships
await db.addVerb('company', 'engineering', VerbType.CONTAINS)
await db.addVerb('engineering', 'frontend', VerbType.CONTAINS)
await db.addVerb('engineering', 'backend', VerbType.CONTAINS)
await db.addVerb('frontend', 'alice', VerbType.CONTAINS)
await db.addVerb('backend', 'bob', VerbType.CONTAINS)
await db.addVerb('charlie', 'engineering', VerbType.MANAGES)
})
it('should find directly connected nodes', async () => {
const results = await db!.find({
connected: {
to: 'engineering',
depth: 1
}
})
// Should find company (parent) and frontend/backend (children)
const ids = results.map(r => r.id)
expect(ids).toContain('company')
expect(ids).toContain('frontend')
expect(ids).toContain('backend')
})
it('should traverse multiple hops', async () => {
const results = await db!.find({
connected: {
to: 'company',
depth: 3,
direction: 'out'
}
})
// Should find entire hierarchy
const ids = results.map(r => r.id)
expect(ids).toContain('engineering')
expect(ids).toContain('frontend')
expect(ids).toContain('backend')
expect(ids).toContain('alice')
expect(ids).toContain('bob')
})
it('should filter by relationship type', async () => {
const results = await db!.find({
connected: {
from: 'charlie',
type: VerbType.MANAGES
}
})
// Should only find engineering (what Charlie manages)
const ids = results.map(r => r.id)
expect(ids).toContain('engineering')
expect(ids.length).toBe(1)
})
it('should handle bidirectional search', async () => {
const results = await db!.find({
connected: {
to: 'frontend',
direction: 'both',
depth: 1
}
})
// Should find parent (engineering) and child (alice)
const ids = results.map(r => r.id)
expect(ids).toContain('engineering')
expect(ids).toContain('alice')
})
it('should find paths between nodes', async () => {
const results = await db!.find({
connected: {
from: 'alice',
to: 'bob',
depth: 4
}
})
// Should find path through the hierarchy
expect(results.length).toBeGreaterThan(0)
})
})
describe('Field Search (where)', () => {
beforeEach(async () => {
db = new BrainyData()
await db.init()
// Add data with various fields
await db.addNoun(createTestVector(1), {
id: 'product1',
name: 'Laptop',
price: 1200,
category: 'electronics',
inStock: true,
tags: ['portable', 'computer']
})
await db.addNoun(createTestVector(2), {
id: 'product2',
name: 'Phone',
price: 800,
category: 'electronics',
inStock: false,
tags: ['mobile', 'smart']
})
await db.addNoun(createTestVector(3), {
id: 'product3',
name: 'Desk',
price: 400,
category: 'furniture',
inStock: true,
tags: ['office', 'wood']
})
await db.addNoun(createTestVector(4), {
id: 'product4',
name: 'Chair',
price: 200,
category: 'furniture',
inStock: true,
tags: ['office', 'ergonomic']
})
})
it('should filter by exact field match', async () => {
const results = await db!.find({
where: {
category: 'electronics'
}
})
const ids = results.map(r => r.id)
expect(ids).toContain('product1')
expect(ids).toContain('product2')
expect(ids).not.toContain('product3')
expect(ids).not.toContain('product4')
})
it('should filter by multiple fields', async () => {
const results = await db!.find({
where: {
category: 'electronics',
inStock: true
}
})
// Only laptop matches both criteria
const ids = results.map(r => r.id)
expect(ids).toContain('product1')
expect(ids).not.toContain('product2') // Not in stock
})
it('should handle range queries', async () => {
const results = await db!.find({
where: {
price: { $gte: 500, $lte: 1000 }
}
})
// Only phone (800) is in this range
const ids = results.map(r => r.id)
expect(ids).toContain('product2')
expect(ids.length).toBe(1)
})
it('should handle array contains queries', async () => {
const results = await db!.find({
where: {
tags: { $contains: 'office' }
}
})
// Desk and Chair have 'office' tag
const ids = results.map(r => r.id)
expect(ids).toContain('product3')
expect(ids).toContain('product4')
})
it('should handle OR conditions', async () => {
const results = await db!.find({
where: {
$or: [
{ category: 'electronics' },
{ price: { $lt: 300 } }
]
}
})
// Electronics OR price < 300 (all except desk)
const ids = results.map(r => r.id)
expect(ids).toContain('product1') // electronics
expect(ids).toContain('product2') // electronics
expect(ids).toContain('product4') // price 200
})
})
describe('Combined Triple Intelligence', () => {
beforeEach(async () => {
db = new BrainyData()
await db.init()
// Create a rich dataset
// Users
await db.addNoun(createTestVector(1, 'person'), {
id: 'user1',
name: 'Alice',
type: 'user',
skills: ['javascript', 'react'],
experience: 5
})
await db.addNoun(createTestVector(2, 'person'), {
id: 'user2',
name: 'Bob',
type: 'user',
skills: ['python', 'django'],
experience: 3
})
await db.addNoun(createTestVector(3, 'person'), {
id: 'user3',
name: 'Charlie',
type: 'user',
skills: ['javascript', 'vue'],
experience: 4
})
// Projects
await db.addNoun(createTestVector(4, 'tech'), {
id: 'project1',
name: 'E-commerce Platform',
type: 'project',
tech: ['javascript', 'react'],
status: 'active'
})
await db.addNoun(createTestVector(5, 'tech'), {
id: 'project2',
name: 'Data Analysis Tool',
type: 'project',
tech: ['python', 'pandas'],
status: 'completed'
})
// Relationships
await db.addVerb('user1', 'project1', VerbType.WORKS_ON)
await db.addVerb('user2', 'project2', VerbType.WORKS_ON)
await db.addVerb('user3', 'project1', VerbType.CONTRIBUTES_TO)
await db.addVerb('project1', 'project2', VerbType.DEPENDS_ON)
})
it('should combine vector and field search', async () => {
const results = await db!.find({
similar: 'JavaScript development',
where: {
experience: { $gte: 4 }
}
})
// Should find experienced JS developers
const ids = results.map(r => r.id)
expect(ids).toContain('user1') // 5 years, JS
expect(ids).toContain('user3') // 4 years, JS
expect(ids).not.toContain('user2') // Only 3 years
})
it('should combine graph and field search', async () => {
const results = await db!.find({
connected: {
to: 'project1',
type: [VerbType.WORKS_ON, VerbType.CONTRIBUTES_TO]
},
where: {
type: 'user'
}
})
// Should find users working on project1
const ids = results.map(r => r.id)
expect(ids).toContain('user1')
expect(ids).toContain('user3')
expect(ids).not.toContain('user2') // Works on project2
})
it('should combine all three intelligence types', async () => {
const results = await db!.find({
similar: 'web development project',
connected: {
depth: 2
},
where: {
status: 'active'
}
})
// Should find active projects and related entities
expect(results.length).toBeGreaterThan(0)
// Project1 should be highly ranked (matches all criteria)
const topResult = results[0]
expect(topResult.id).toBe('project1')
})
it('should handle complex fusion scoring', async () => {
const results = await db!.find({
like: 'user1', // Similar to Alice
connected: {
to: 'project1' // Connected to project1
},
where: {
skills: { $contains: 'javascript' } // Has JS skills
}
})
// User3 (Charlie) should score high:
// - Similar to user1 (both JS developers)
// - Connected to project1
// - Has javascript in skills
const ids = results.map(r => r.id)
expect(ids).toContain('user3')
// Results should have fusion scores
results.forEach(result => {
expect(result).toHaveProperty('score')
expect(result.score).toBeGreaterThan(0)
expect(result.score).toBeLessThanOrEqual(1)
})
})
})
describe('Performance and Edge Cases', () => {
it('should handle empty database gracefully', async () => {
db = new BrainyData()
await db.init()
const results = await db.find('find anything')
expect(Array.isArray(results)).toBe(true)
expect(results.length).toBe(0)
})
it('should handle invalid queries gracefully', async () => {
db = new BrainyData()
await db.init()
// Add some data
await db.addNoun(createTestVector(1), { id: 'test1' })
// Invalid query structures
const results1 = await db.find({
where: null as any
})
expect(Array.isArray(results1)).toBe(true)
const results2 = await db.find({
connected: {
to: 'nonexistent'
}
})
expect(Array.isArray(results2)).toBe(true)
})
it('should handle large result sets with pagination', async () => {
db = new BrainyData()
await db.init()
// Add many items
for (let i = 0; i < 100; i++) {
await db.addNoun(createTestVector(i), {
id: `item${i}`,
index: i
})
}
// Query with limit
const results = await db.find({
where: {
index: { $gte: 0 }
},
limit: 10,
offset: 20
})
expect(results.length).toBeLessThanOrEqual(10)
})
it('should be performant for complex queries', async () => {
db = new BrainyData()
await db.init()
// Add substantial data
for (let i = 0; i < 50; i++) {
await db.addNoun(createTestVector(i), {
id: `node${i}`,
value: i
})
}
// Add relationships
for (let i = 0; i < 49; i++) {
await db.addVerb(`node${i}`, `node${i+1}`, VerbType.CONNECTED_TO)
}
const start = performance.now()
const results = await db.find({
similar: 'node25',
connected: {
depth: 3
},
where: {
value: { $gte: 20, $lte: 30 }
}
})
const elapsed = performance.now() - start
// Should complete in reasonable time
expect(elapsed).toBeLessThan(1000) // Under 1 second
expect(results).toBeDefined()
})
})
describe('Result Structure and Scoring', () => {
beforeEach(async () => {
db = new BrainyData()
await db.init()
// Add test data
await db.addNoun(createTestVector(1), {
id: 'result1',
name: 'Test Result 1'
})
await db.addNoun(createTestVector(2), {
id: 'result2',
name: 'Test Result 2'
})
})
it('should return properly structured results', async () => {
const results = await db!.find({
like: createTestVector(1.5),
limit: 2
})
expect(Array.isArray(results)).toBe(true)
results.forEach(result => {
expect(result).toHaveProperty('id')
expect(result).toHaveProperty('score')
expect(result).toHaveProperty('data')
expect(result).toHaveProperty('metadata')
expect(result).toHaveProperty('vector')
// Score should be normalized
expect(result.score).toBeGreaterThan(0)
expect(result.score).toBeLessThanOrEqual(1)
})
})
it('should sort results by fusion score', async () => {
const results = await db!.find({
like: createTestVector(1)
})
// Results should be sorted by score (descending)
for (let i = 1; i < results.length; i++) {
expect(results[i-1].score).toBeGreaterThanOrEqual(results[i].score)
}
})
it('should include match explanations when requested', async () => {
const results = await db!.find({
similar: 'test',
where: {
name: { $contains: 'Test' }
},
explain: true
})
results.forEach(result => {
if (result.explanation) {
expect(result.explanation).toHaveProperty('vectorMatch')
expect(result.explanation).toHaveProperty('fieldMatch')
expect(result.explanation).toHaveProperty('fusionScore')
}
})
})
})
})