2025-11-18 15:41:57 -08:00
/ * *
* Unit Tests for brain . get ( ) Metadata - Only Optimization ( v5 . 11.1 )
*
* Verifies :
* - Metadata - only reads are 75 % + faster
* - Full entity reads ( includeVectors : true ) work correctly
* - Vector field is empty array for metadata - only
* - Vector field is populated for full entity
* - Works with all entity types
* - Handles missing entities correctly
*
* NO STUBS , NO MOCKS - Real functionality testing
* /
import { describe , it , expect , beforeEach , afterEach } from 'vitest'
import { Brainy } from '../../src/brainy.js'
import { MemoryStorage } from '../../src/storage/adapters/memoryStorage.js'
import { NounType } from '../../src/types/graphTypes.js'
describe ( 'brain.get() Metadata-Only Optimization (v5.11.1)' , ( ) = > {
let brain : Brainy
let entityId : string
beforeEach ( async ( ) = > {
feat(8.0)!: flip requireSubtype default to true (BRAINY-8.0-SUBTYPE-CONTRACT § C-1)
Brainy 8.0 makes subtype required by default on every public write path
(`add`, `addMany`, `update`, `relate`, `relateMany`, `updateRelation`,
import). Per the locked C-1 contract, every entity and relation gets a
non-empty subtype string by the time the storage layer sees it.
OPT-OUT REMAINS FULLY SUPPORTED
The runtime flag is still consumer-controlled. Three opt-out paths
cover migration / legacy fixtures / typed escape:
- `new Brainy({ requireSubtype: false })` — last-resort: turn off the
contract entirely. Recommended only for migration windows or test
fixtures that legitimately can't supply a subtype.
- `new Brainy({ requireSubtype: { except: [NounType.Thing, ...] } })` —
per-type allowlist: strict everywhere except the listed types.
- `brain.requireSubtype(type, options)` — per-type registration with
optional vocabulary. Composes with the brain-wide flag.
Default is now `true`. Opt-out is explicit and documented; nothing
silently degrades.
TEST SWEEP
Bulk-applied `requireSubtype: false` to every `new Brainy({...})` call
site across 120 test files. Three sed patterns covered the shapes:
- `new Brainy({` → `new Brainy({ requireSubtype: false,`
- `new Brainy<T>({` → `new Brainy<T>({ requireSubtype: false,`
- `new Brainy()` → `new Brainy({ requireSubtype: false })`
tests/helpers/test-factory.ts → createTestConfig() defaults
`requireSubtype: false` so test files using the helper inherit the
opt-out without per-site edits.
The test sites that DO exercise subtype semantics (the
subtype-and-facets suite, the strict-mode-self-test suite, the verb-
subtype-and-enforcement suite, etc.) already pass real subtypes — they
were the 7.30.x acceptance tests for this contract. Those tests
continue to pass unchanged.
CHANGES
src/brainy.ts
- normalizeConfig() — `requireSubtype` default `false` → `true`.
Comment refreshed to document the three opt-out paths.
tests/* (120 files)
- Bulk-edited brain construction sites. No functional test changes; the
opt-out preserves the test author's original intent.
tests/helpers/test-factory.ts
- createTestConfig() base config gains `requireSubtype: false`.
NO-OP for consumers who were already passing subtype on every write.
For consumers who weren't, the upgrade path is one of the three opt-out
forms above. Migration recipe documented in 8.0 release notes (next
commit).
VERIFICATION
- npx tsc --noEmit: clean
- npm test: 1408 / 1409 (same pre-existing race-condition outstanding;
no other regressions from the flip)
2026-06-09 14:58:25 -07:00
brain = new Brainy ( { requireSubtype : false ,
2025-11-18 15:41:57 -08:00
storage : new MemoryStorage ( ) ,
silent : true
} )
await brain . init ( )
// Add test entity
entityId = await brain . add ( {
data : 'test data for optimization' ,
type : NounType . Document ,
metadata : {
title : 'Test Document' ,
priority : 5
}
} )
} )
afterEach ( async ( ) = > {
await brain . close ( )
} )
describe ( 'Metadata-Only Reads (Default)' , ( ) = > {
it ( 'should load metadata-only by default' , async ( ) = > {
const entity = await brain . get ( entityId )
// Entity should exist
expect ( entity ) . toBeTruthy ( )
expect ( entity ! . id ) . toBe ( entityId )
// Data and metadata should be available
expect ( entity ! . data ) . toBe ( 'test data for optimization' )
expect ( entity ! . metadata . title ) . toBe ( 'Test Document' )
expect ( entity ! . metadata . priority ) . toBe ( 5 )
expect ( entity ! . type ) . toBe ( NounType . Document )
// Vector should be empty array (stub - not loaded)
expect ( entity ! . vector ) . toEqual ( [ ] )
expect ( entity ! . vector . length ) . toBe ( 0 )
} )
it ( 'should include standard fields in metadata-only read' , async ( ) = > {
const entity = await brain . get ( entityId )
expect ( entity ) . toBeTruthy ( )
expect ( entity ! . createdAt ) . toBeTypeOf ( 'number' )
expect ( entity ! . updatedAt ) . toBeTypeOf ( 'number' )
expect ( entity ! . createdAt ) . toBeGreaterThan ( 0 )
} )
it ( 'should return null for missing entity' , async ( ) = > {
const entity = await brain . get ( '00000000-0000-0000-0000-999999999999' )
expect ( entity ) . toBeNull ( )
} )
} )
describe ( 'Full Entity Reads (includeVectors: true)' , ( ) = > {
it ( 'should load full entity with includeVectors: true' , async ( ) = > {
const entity = await brain . get ( entityId , { includeVectors : true } )
// Entity should exist
expect ( entity ) . toBeTruthy ( )
expect ( entity ! . id ) . toBe ( entityId )
// Data and metadata should be available
expect ( entity ! . data ) . toBe ( 'test data for optimization' )
expect ( entity ! . metadata . title ) . toBe ( 'Test Document' )
expect ( entity ! . metadata . priority ) . toBe ( 5 )
// Vector should be populated (384 dimensions)
expect ( entity ! . vector ) . toBeDefined ( )
expect ( entity ! . vector . length ) . toBe ( 384 )
expect ( Array . isArray ( entity ! . vector ) ) . toBe ( true )
} )
it ( 'should return null for missing entity with includeVectors: true' , async ( ) = > {
const entity = await brain . get ( '00000000-0000-0000-0000-999999999999' , { includeVectors : true } )
expect ( entity ) . toBeNull ( )
} )
} )
describe ( 'Performance Comparison' , ( ) = > {
it ( 'metadata-only should complete in <15ms (MemoryStorage)' , async ( ) = > {
// Warm up
await brain . get ( entityId )
// Measure
const iterations = 50
const start = performance . now ( )
for ( let i = 0 ; i < iterations ; i ++ ) {
await brain . get ( entityId )
}
const avgTime = ( performance . now ( ) - start ) / iterations
// MemoryStorage should be very fast (<15ms)
expect ( avgTime ) . toBeLessThan ( 15 )
console . log ( ` [Performance] Metadata-only average: ${ avgTime . toFixed ( 2 ) } ms ` )
} )
} )
describe ( 'Entity Type Coverage' , ( ) = > {
it ( 'should work with all NounTypes' , async ( ) = > {
const types = [
NounType . Person ,
NounType . Location ,
NounType . Concept ,
NounType . Organization ,
NounType . Event ,
NounType . Document ,
NounType . File
]
for ( const type of types ) {
const id = await brain . add ( { data : ` test ${ type } ` , type } )
// Metadata-only
const metadataEntity = await brain . get ( id )
expect ( metadataEntity ) . toBeTruthy ( )
expect ( metadataEntity ! . type ) . toBe ( type )
expect ( metadataEntity ! . vector ) . toEqual ( [ ] )
// Full entity
const fullEntity = await brain . get ( id , { includeVectors : true } )
expect ( fullEntity ) . toBeTruthy ( )
expect ( fullEntity ! . type ) . toBe ( type )
expect ( fullEntity ! . vector . length ) . toBe ( 384 )
}
} )
} )
describe ( 'Data Consistency' , ( ) = > {
it ( 'metadata-only and full entity should have same data' , async ( ) = > {
const metadataEntity = await brain . get ( entityId )
const fullEntity = await brain . get ( entityId , { includeVectors : true } )
expect ( metadataEntity ) . toBeTruthy ( )
expect ( fullEntity ) . toBeTruthy ( )
// Same data
expect ( metadataEntity ! . data ) . toBe ( fullEntity ! . data )
expect ( metadataEntity ! . metadata ) . toEqual ( fullEntity ! . metadata )
expect ( metadataEntity ! . type ) . toBe ( fullEntity ! . type )
expect ( metadataEntity ! . id ) . toBe ( fullEntity ! . id )
// Only difference: vector
expect ( metadataEntity ! . vector ) . toEqual ( [ ] )
expect ( fullEntity ! . vector . length ) . toBe ( 384 )
} )
} )
describe ( 'Integration with brain.similar()' , ( ) = > {
it ( 'similar() should work correctly (uses includeVectors internally)' , async ( ) = > {
// Add more entities for similarity search
await brain . add ( { data : 'similar test data' , type : NounType . Document } )
await brain . add ( { data : 'another document' , type : NounType . Document } )
// similar() should work correctly (internally uses includeVectors: true)
const results = await brain . similar ( { to : entityId , limit : 5 } )
expect ( results ) . toBeDefined ( )
expect ( Array . isArray ( results ) ) . toBe ( true )
// Should return at least the source entity (when no other similar entities)
expect ( results . length ) . toBeGreaterThan ( 0 )
} )
} )
describe ( 'Backward Compatibility' , ( ) = > {
it ( 'should handle legacy code that expects vectors' , async ( ) = > {
// Metadata-only: vector is empty array
const metadataEntity = await brain . get ( entityId )
expect ( metadataEntity ! . vector ) . toEqual ( [ ] )
expect ( metadataEntity ! . vector . length ) . toBe ( 0 )
// Full entity: vector is populated
const fullEntity = await brain . get ( entityId , { includeVectors : true } )
expect ( fullEntity ! . vector . length ) . toBe ( 384 )
// Both are valid Entity types (backward compatible)
expect ( typeof metadataEntity ! . id ) . toBe ( 'string' )
expect ( typeof fullEntity ! . id ) . toBe ( 'string' )
} )
} )
} )