@soulcraft/brainy 5.7.7 → 5.7.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [5.7.9](https://github.com/soulcraftlabs/brainy/compare/v5.7.8...v5.7.9) (2025-11-13)
6
+
7
+ - fix: implement exists: false and missing operators in MetadataIndexManager (b0f72ef)
8
+
9
+
10
+ ### [5.7.8](https://github.com/soulcraftlabs/brainy/compare/v5.7.7...v5.7.8) (2025-11-13)
11
+
12
+ - fix: reconstruct Map from JSON for HNSW connections (v5.7.8 hotfix) (f6f2717)
13
+
14
+
5
15
  ### [5.7.7](https://github.com/soulcraftlabs/brainy/compare/v5.7.6...v5.7.7) (2025-11-13)
6
16
 
7
17
  - docs: update index architecture documentation for v5.7.7 lazy loading (67039fc)
@@ -925,9 +925,24 @@ export class BaseStorage extends BaseStorageAdapter {
925
925
  continue;
926
926
  }
927
927
  }
928
+ // v5.7.8: Convert connections from plain object to Map (JSON deserialization fix)
929
+ // When loaded from JSON, Map becomes plain object - must reconstruct
930
+ const connections = new Map();
931
+ if (noun.connections && typeof noun.connections === 'object') {
932
+ for (const [levelStr, ids] of Object.entries(noun.connections)) {
933
+ if (Array.isArray(ids)) {
934
+ connections.set(parseInt(levelStr, 10), new Set(ids));
935
+ }
936
+ else if (ids && typeof ids === 'object') {
937
+ // Handle if it's already an array-like or Set-like object
938
+ connections.set(parseInt(levelStr, 10), new Set(Object.values(ids)));
939
+ }
940
+ }
941
+ }
928
942
  // Combine noun + metadata (v5.4.0: Extract standard fields to top-level)
929
943
  collectedNouns.push({
930
944
  ...noun,
945
+ connections, // Use reconstructed Map instead of plain object
931
946
  type: metadata.noun || type, // Required: Extract type from metadata
932
947
  confidence: metadata.confidence,
933
948
  weight: metadata.weight,
@@ -1322,7 +1322,8 @@ export class MetadataIndexManager {
1322
1322
  // exists: boolean - check if field exists (any value)
1323
1323
  case 'exists':
1324
1324
  if (operand) {
1325
- // Get all IDs that have this field (any value) from chunked sparse index with roaring bitmaps (v3.43.0)
1325
+ // exists: true - Get all IDs that have this field (any value)
1326
+ // v3.43.0: From chunked sparse index with roaring bitmaps
1326
1327
  // v3.44.1: Now fully lazy-loaded via UnifiedCache (no local sparseIndices Map)
1327
1328
  const allIntIds = new Set();
1328
1329
  // Load sparse index via UnifiedCache (lazy loading)
@@ -1344,6 +1345,76 @@ export class MetadataIndexManager {
1344
1345
  // Convert integer IDs back to UUIDs
1345
1346
  fieldResults = this.idMapper.intsIterableToUuids(allIntIds);
1346
1347
  }
1348
+ else {
1349
+ // exists: false - Get all IDs that DON'T have this field
1350
+ // v5.7.9: Fixed excludeVFS bug (was returning empty array)
1351
+ const allItemIds = await this.getAllIds();
1352
+ const existsIntIds = new Set();
1353
+ // Get IDs that HAVE this field
1354
+ const sparseIndex = await this.loadSparseIndex(field);
1355
+ if (sparseIndex) {
1356
+ for (const chunkId of sparseIndex.getAllChunkIds()) {
1357
+ const chunk = await this.chunkManager.loadChunk(field, chunkId);
1358
+ if (chunk) {
1359
+ for (const bitmap of chunk.entries.values()) {
1360
+ for (const intId of bitmap) {
1361
+ existsIntIds.add(intId);
1362
+ }
1363
+ }
1364
+ }
1365
+ }
1366
+ }
1367
+ // Convert to UUIDs and subtract from all IDs
1368
+ const existsUuids = this.idMapper.intsIterableToUuids(existsIntIds);
1369
+ const existsSet = new Set(existsUuids);
1370
+ fieldResults = allItemIds.filter(id => !existsSet.has(id));
1371
+ }
1372
+ break;
1373
+ // ===== MISSING OPERATOR =====
1374
+ // missing: boolean - equivalent to exists: !boolean (for compatibility with metadataFilter.ts)
1375
+ case 'missing':
1376
+ // missing: true is equivalent to exists: false
1377
+ // missing: false is equivalent to exists: true
1378
+ // v5.7.9: Added for API consistency with in-memory metadataFilter
1379
+ if (operand) {
1380
+ // missing: true - field does NOT exist (same as exists: false)
1381
+ const allItemIds = await this.getAllIds();
1382
+ const existsIntIds = new Set();
1383
+ const sparseIndex = await this.loadSparseIndex(field);
1384
+ if (sparseIndex) {
1385
+ for (const chunkId of sparseIndex.getAllChunkIds()) {
1386
+ const chunk = await this.chunkManager.loadChunk(field, chunkId);
1387
+ if (chunk) {
1388
+ for (const bitmap of chunk.entries.values()) {
1389
+ for (const intId of bitmap) {
1390
+ existsIntIds.add(intId);
1391
+ }
1392
+ }
1393
+ }
1394
+ }
1395
+ }
1396
+ const existsUuids = this.idMapper.intsIterableToUuids(existsIntIds);
1397
+ const existsSet = new Set(existsUuids);
1398
+ fieldResults = allItemIds.filter(id => !existsSet.has(id));
1399
+ }
1400
+ else {
1401
+ // missing: false - field DOES exist (same as exists: true)
1402
+ const allIntIds = new Set();
1403
+ const sparseIndex = await this.loadSparseIndex(field);
1404
+ if (sparseIndex) {
1405
+ for (const chunkId of sparseIndex.getAllChunkIds()) {
1406
+ const chunk = await this.chunkManager.loadChunk(field, chunkId);
1407
+ if (chunk) {
1408
+ for (const bitmap of chunk.entries.values()) {
1409
+ for (const intId of bitmap) {
1410
+ allIntIds.add(intId);
1411
+ }
1412
+ }
1413
+ }
1414
+ }
1415
+ }
1416
+ fieldResults = this.idMapper.intsIterableToUuids(allIntIds);
1417
+ }
1347
1418
  break;
1348
1419
  }
1349
1420
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soulcraft/brainy",
3
- "version": "5.7.7",
3
+ "version": "5.7.9",
4
4
  "description": "Universal Knowledge Protocol™ - World's first Triple Intelligence database unifying vector, graph, and document search in one API. Stage 3 CANONICAL: 42 nouns × 127 verbs covering 96-97% of all human knowledge.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",