codevault 1.8.4 → 1.8.5
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/README.md +3 -2
- package/dist/chunking/token-counter.d.ts.map +1 -1
- package/dist/chunking/token-counter.js +16 -10
- package/dist/chunking/token-counter.js.map +1 -1
- package/dist/cli/commands/index-cmd.d.ts.map +1 -1
- package/dist/cli/commands/index-cmd.js +108 -97
- package/dist/cli/commands/index-cmd.js.map +1 -1
- package/dist/cli/commands/interactive-config.d.ts.map +1 -1
- package/dist/cli/commands/interactive-config.js +40 -3
- package/dist/cli/commands/interactive-config.js.map +1 -1
- package/dist/cli/commands/search-cmd.d.ts.map +1 -1
- package/dist/cli/commands/search-cmd.js +11 -7
- package/dist/cli/commands/search-cmd.js.map +1 -1
- package/dist/cli/commands/search-with-code-cmd.d.ts.map +1 -1
- package/dist/cli/commands/search-with-code-cmd.js +3 -1
- package/dist/cli/commands/search-with-code-cmd.js.map +1 -1
- package/dist/cli/utils.d.ts +56 -0
- package/dist/cli/utils.d.ts.map +1 -0
- package/dist/cli/utils.js +98 -0
- package/dist/cli/utils.js.map +1 -0
- package/dist/config/constants.d.ts +4 -0
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/config/constants.js +2 -0
- package/dist/config/constants.js.map +1 -1
- package/dist/context/packs.d.ts.map +1 -1
- package/dist/context/packs.js +3 -1
- package/dist/context/packs.js.map +1 -1
- package/dist/core/IndexerEngine.d.ts +2 -0
- package/dist/core/IndexerEngine.d.ts.map +1 -1
- package/dist/core/IndexerEngine.js +34 -26
- package/dist/core/IndexerEngine.js.map +1 -1
- package/dist/core/SearchService.d.ts +1 -0
- package/dist/core/SearchService.d.ts.map +1 -1
- package/dist/core/SearchService.js +18 -12
- package/dist/core/SearchService.js.map +1 -1
- package/dist/core/batch-indexer.d.ts.map +1 -1
- package/dist/core/batch-indexer.js +5 -13
- package/dist/core/batch-indexer.js.map +1 -1
- package/dist/core/indexing/IndexFinalizationStage.d.ts.map +1 -1
- package/dist/core/indexing/IndexFinalizationStage.js +21 -2
- package/dist/core/indexing/IndexFinalizationStage.js.map +1 -1
- package/dist/core/indexing/IndexState.d.ts +3 -8
- package/dist/core/indexing/IndexState.d.ts.map +1 -1
- package/dist/core/indexing/IndexState.js.map +1 -1
- package/dist/core/indexing/PersistManager.d.ts +1 -1
- package/dist/core/indexing/PersistManager.d.ts.map +1 -1
- package/dist/core/indexing/PersistManager.js +17 -17
- package/dist/core/indexing/PersistManager.js.map +1 -1
- package/dist/core/search/HybridFusion.d.ts +0 -1
- package/dist/core/search/HybridFusion.d.ts.map +1 -1
- package/dist/core/search/HybridFusion.js +2 -14
- package/dist/core/search/HybridFusion.js.map +1 -1
- package/dist/core/search/ResultMapper.d.ts +0 -1
- package/dist/core/search/ResultMapper.d.ts.map +1 -1
- package/dist/core/search/ResultMapper.js +2 -13
- package/dist/core/search/ResultMapper.js.map +1 -1
- package/dist/core/search/SearchContextManager.d.ts +3 -0
- package/dist/core/search/SearchContextManager.d.ts.map +1 -1
- package/dist/core/search/SearchContextManager.js +15 -2
- package/dist/core/search/SearchContextManager.js.map +1 -1
- package/dist/core/search.d.ts.map +1 -1
- package/dist/core/search.js +9 -4
- package/dist/core/search.js.map +1 -1
- package/dist/languages/rules.d.ts.map +1 -1
- package/dist/languages/rules.js +14 -5
- package/dist/languages/rules.js.map +1 -1
- package/dist/mcp/schemas.d.ts +2 -2
- package/dist/mcp-server.d.ts +1 -0
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +32 -21
- package/dist/mcp-server.js.map +1 -1
- package/dist/providers/base.d.ts +3 -2
- package/dist/providers/base.d.ts.map +1 -1
- package/dist/providers/base.js +3 -1
- package/dist/providers/base.js.map +1 -1
- package/dist/providers/chat-llm.d.ts +2 -2
- package/dist/providers/chat-llm.d.ts.map +1 -1
- package/dist/providers/chat-llm.js +4 -1
- package/dist/providers/chat-llm.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +4 -1
- package/dist/providers/openai.js.map +1 -1
- package/dist/ranking/api-reranker.d.ts.map +1 -1
- package/dist/ranking/api-reranker.js +27 -8
- package/dist/ranking/api-reranker.js.map +1 -1
- package/dist/ranking/symbol-boost.d.ts.map +1 -1
- package/dist/ranking/symbol-boost.js +4 -11
- package/dist/ranking/symbol-boost.js.map +1 -1
- package/dist/search/bm25.d.ts +10 -0
- package/dist/search/bm25.d.ts.map +1 -1
- package/dist/search/bm25.js +16 -0
- package/dist/search/bm25.js.map +1 -1
- package/dist/storage/encrypted-chunks.d.ts +3 -0
- package/dist/storage/encrypted-chunks.d.ts.map +1 -1
- package/dist/storage/encrypted-chunks.js +108 -16
- package/dist/storage/encrypted-chunks.js.map +1 -1
- package/dist/synthesis/conversational-synthesizer.d.ts +2 -1
- package/dist/synthesis/conversational-synthesizer.d.ts.map +1 -1
- package/dist/synthesis/conversational-synthesizer.js +6 -1
- package/dist/synthesis/conversational-synthesizer.js.map +1 -1
- package/dist/synthesis/prompt-builder.d.ts.map +1 -1
- package/dist/synthesis/prompt-builder.js +40 -13
- package/dist/synthesis/prompt-builder.js.map +1 -1
- package/dist/synthesis/synthesizer.d.ts.map +1 -1
- package/dist/synthesis/synthesizer.js +14 -2
- package/dist/synthesis/synthesizer.js.map +1 -1
- package/dist/tests/api-reranker.test.d.ts +2 -0
- package/dist/tests/api-reranker.test.d.ts.map +1 -0
- package/dist/tests/api-reranker.test.js +575 -0
- package/dist/tests/api-reranker.test.js.map +1 -0
- package/dist/tests/bm25.test.d.ts +2 -0
- package/dist/tests/bm25.test.d.ts.map +1 -0
- package/dist/tests/bm25.test.js +340 -0
- package/dist/tests/bm25.test.js.map +1 -0
- package/dist/tests/chunking/file-grouper.test.d.ts +2 -0
- package/dist/tests/chunking/file-grouper.test.d.ts.map +1 -0
- package/dist/tests/chunking/file-grouper.test.js +495 -0
- package/dist/tests/chunking/file-grouper.test.js.map +1 -0
- package/dist/tests/chunking/semantic-chunker.test.d.ts +2 -0
- package/dist/tests/chunking/semantic-chunker.test.d.ts.map +1 -0
- package/dist/tests/chunking/semantic-chunker.test.js +509 -0
- package/dist/tests/chunking/semantic-chunker.test.js.map +1 -0
- package/dist/tests/chunking/token-counter.test.d.ts +2 -0
- package/dist/tests/chunking/token-counter.test.d.ts.map +1 -0
- package/dist/tests/chunking/token-counter.test.js +441 -0
- package/dist/tests/chunking/token-counter.test.js.map +1 -0
- package/dist/tests/cli/ask-cmd.test.d.ts +2 -0
- package/dist/tests/cli/ask-cmd.test.d.ts.map +1 -0
- package/dist/tests/cli/ask-cmd.test.js +152 -0
- package/dist/tests/cli/ask-cmd.test.js.map +1 -0
- package/dist/tests/cli/chat-cmd.test.d.ts +2 -0
- package/dist/tests/cli/chat-cmd.test.d.ts.map +1 -0
- package/dist/tests/cli/chat-cmd.test.js +118 -0
- package/dist/tests/cli/chat-cmd.test.js.map +1 -0
- package/dist/tests/cli/config-cmd.test.d.ts +2 -0
- package/dist/tests/cli/config-cmd.test.d.ts.map +1 -0
- package/dist/tests/cli/config-cmd.test.js +226 -0
- package/dist/tests/cli/config-cmd.test.js.map +1 -0
- package/dist/tests/cli/context.test.d.ts +2 -0
- package/dist/tests/cli/context.test.d.ts.map +1 -0
- package/dist/tests/cli/context.test.js +158 -0
- package/dist/tests/cli/context.test.js.map +1 -0
- package/dist/tests/cli/index-cmd.test.d.ts +2 -0
- package/dist/tests/cli/index-cmd.test.d.ts.map +1 -0
- package/dist/tests/cli/index-cmd.test.js +89 -0
- package/dist/tests/cli/index-cmd.test.js.map +1 -0
- package/dist/tests/cli/index.test.d.ts +2 -0
- package/dist/tests/cli/index.test.d.ts.map +1 -0
- package/dist/tests/cli/index.test.js +167 -0
- package/dist/tests/cli/index.test.js.map +1 -0
- package/dist/tests/cli/info-cmd.test.d.ts +2 -0
- package/dist/tests/cli/info-cmd.test.d.ts.map +1 -0
- package/dist/tests/cli/info-cmd.test.js +47 -0
- package/dist/tests/cli/info-cmd.test.js.map +1 -0
- package/dist/tests/cli/interactive-config.test.d.ts +2 -0
- package/dist/tests/cli/interactive-config.test.d.ts.map +1 -0
- package/dist/tests/cli/interactive-config.test.js +30 -0
- package/dist/tests/cli/interactive-config.test.js.map +1 -0
- package/dist/tests/cli/mcp-cmd.test.d.ts +2 -0
- package/dist/tests/cli/mcp-cmd.test.d.ts.map +1 -0
- package/dist/tests/cli/mcp-cmd.test.js +47 -0
- package/dist/tests/cli/mcp-cmd.test.js.map +1 -0
- package/dist/tests/cli/search-cmd.test.d.ts +2 -0
- package/dist/tests/cli/search-cmd.test.d.ts.map +1 -0
- package/dist/tests/cli/search-cmd.test.js +120 -0
- package/dist/tests/cli/search-cmd.test.js.map +1 -0
- package/dist/tests/cli/search-with-code-cmd.test.d.ts +2 -0
- package/dist/tests/cli/search-with-code-cmd.test.d.ts.map +1 -0
- package/dist/tests/cli/search-with-code-cmd.test.js +140 -0
- package/dist/tests/cli/search-with-code-cmd.test.js.map +1 -0
- package/dist/tests/cli/update-cmd.test.d.ts +2 -0
- package/dist/tests/cli/update-cmd.test.d.ts.map +1 -0
- package/dist/tests/cli/update-cmd.test.js +75 -0
- package/dist/tests/cli/update-cmd.test.js.map +1 -0
- package/dist/tests/cli/utils.test.d.ts +2 -0
- package/dist/tests/cli/utils.test.d.ts.map +1 -0
- package/dist/tests/cli/utils.test.js +119 -0
- package/dist/tests/cli/utils.test.js.map +1 -0
- package/dist/tests/cli/watch-cmd.test.d.ts +2 -0
- package/dist/tests/cli/watch-cmd.test.d.ts.map +1 -0
- package/dist/tests/cli/watch-cmd.test.js +84 -0
- package/dist/tests/cli/watch-cmd.test.js.map +1 -0
- package/dist/tests/cli-ui.test.d.ts +2 -0
- package/dist/tests/cli-ui.test.d.ts.map +1 -0
- package/dist/tests/cli-ui.test.js +608 -0
- package/dist/tests/cli-ui.test.js.map +1 -0
- package/dist/tests/codemap-io.test.d.ts +2 -0
- package/dist/tests/codemap-io.test.d.ts.map +1 -0
- package/dist/tests/codemap-io.test.js +992 -0
- package/dist/tests/codemap-io.test.js.map +1 -0
- package/dist/tests/config/apply-env.test.d.ts +2 -0
- package/dist/tests/config/apply-env.test.d.ts.map +1 -0
- package/dist/tests/config/apply-env.test.js +717 -0
- package/dist/tests/config/apply-env.test.js.map +1 -0
- package/dist/tests/config/constants.test.d.ts +2 -0
- package/dist/tests/config/constants.test.d.ts.map +1 -0
- package/dist/tests/config/constants.test.js +406 -0
- package/dist/tests/config/constants.test.js.map +1 -0
- package/dist/tests/config/loader.test.d.ts +2 -0
- package/dist/tests/config/loader.test.d.ts.map +1 -0
- package/dist/tests/config/loader.test.js +716 -0
- package/dist/tests/config/loader.test.js.map +1 -0
- package/dist/tests/config/resolver.test.d.ts +2 -0
- package/dist/tests/config/resolver.test.d.ts.map +1 -0
- package/dist/tests/config/resolver.test.js +402 -0
- package/dist/tests/config/resolver.test.js.map +1 -0
- package/dist/tests/config/types.test.d.ts +2 -0
- package/dist/tests/config/types.test.d.ts.map +1 -0
- package/dist/tests/config/types.test.js +460 -0
- package/dist/tests/config/types.test.js.map +1 -0
- package/dist/tests/context-packs.test.d.ts +2 -0
- package/dist/tests/context-packs.test.d.ts.map +1 -0
- package/dist/tests/context-packs.test.js +826 -0
- package/dist/tests/context-packs.test.js.map +1 -0
- package/dist/tests/conversational-synthesizer.test.d.ts +2 -0
- package/dist/tests/conversational-synthesizer.test.d.ts.map +1 -0
- package/dist/tests/conversational-synthesizer.test.js +595 -0
- package/dist/tests/conversational-synthesizer.test.js.map +1 -0
- package/dist/tests/database.test.d.ts +2 -0
- package/dist/tests/database.test.d.ts.map +1 -0
- package/dist/tests/database.test.js +965 -0
- package/dist/tests/database.test.js.map +1 -0
- package/dist/tests/encrypted-chunks.test.d.ts +2 -0
- package/dist/tests/encrypted-chunks.test.d.ts.map +1 -0
- package/dist/tests/encrypted-chunks.test.js +1470 -0
- package/dist/tests/encrypted-chunks.test.js.map +1 -0
- package/dist/tests/hybrid.test.d.ts +2 -0
- package/dist/tests/hybrid.test.d.ts.map +1 -0
- package/dist/tests/hybrid.test.js +456 -0
- package/dist/tests/hybrid.test.js.map +1 -0
- package/dist/tests/indexer/ChangeQueue.test.d.ts +12 -0
- package/dist/tests/indexer/ChangeQueue.test.d.ts.map +1 -0
- package/dist/tests/indexer/ChangeQueue.test.js +441 -0
- package/dist/tests/indexer/ChangeQueue.test.js.map +1 -0
- package/dist/tests/indexer/ProviderManager.test.d.ts +12 -0
- package/dist/tests/indexer/ProviderManager.test.d.ts.map +1 -0
- package/dist/tests/indexer/ProviderManager.test.js +290 -0
- package/dist/tests/indexer/ProviderManager.test.js.map +1 -0
- package/dist/tests/indexer/WatchService.test.d.ts +14 -0
- package/dist/tests/indexer/WatchService.test.d.ts.map +1 -0
- package/dist/tests/indexer/WatchService.test.js +667 -0
- package/dist/tests/indexer/WatchService.test.js.map +1 -0
- package/dist/tests/indexer/merkle.test.d.ts +11 -0
- package/dist/tests/indexer/merkle.test.d.ts.map +1 -0
- package/dist/tests/indexer/merkle.test.js +497 -0
- package/dist/tests/indexer/merkle.test.js.map +1 -0
- package/dist/tests/indexer/update.test.d.ts +10 -0
- package/dist/tests/indexer/update.test.d.ts.map +1 -0
- package/dist/tests/indexer/update.test.js +317 -0
- package/dist/tests/indexer/update.test.js.map +1 -0
- package/dist/tests/indexer/watch.test.d.ts +8 -0
- package/dist/tests/indexer/watch.test.d.ts.map +1 -0
- package/dist/tests/indexer/watch.test.js +95 -0
- package/dist/tests/indexer/watch.test.js.map +1 -0
- package/dist/tests/integration/index-search.integration.test.js +1 -0
- package/dist/tests/integration/index-search.integration.test.js.map +1 -1
- package/dist/tests/languages.test.d.ts +2 -0
- package/dist/tests/languages.test.d.ts.map +1 -0
- package/dist/tests/languages.test.js +575 -0
- package/dist/tests/languages.test.js.map +1 -0
- package/dist/tests/logger-redaction.test.d.ts +2 -0
- package/dist/tests/logger-redaction.test.d.ts.map +1 -0
- package/dist/tests/logger-redaction.test.js +48 -0
- package/dist/tests/logger-redaction.test.js.map +1 -0
- package/dist/tests/logger.test.d.ts +2 -0
- package/dist/tests/logger.test.d.ts.map +1 -0
- package/dist/tests/logger.test.js +468 -0
- package/dist/tests/logger.test.js.map +1 -0
- package/dist/tests/markdown-formatter.test.d.ts +2 -0
- package/dist/tests/markdown-formatter.test.d.ts.map +1 -0
- package/dist/tests/markdown-formatter.test.js +453 -0
- package/dist/tests/markdown-formatter.test.js.map +1 -0
- package/dist/tests/mcp/tools/use-context-pack.test.d.ts +7 -0
- package/dist/tests/mcp/tools/use-context-pack.test.d.ts.map +1 -0
- package/dist/tests/mcp/tools/use-context-pack.test.js +505 -0
- package/dist/tests/mcp/tools/use-context-pack.test.js.map +1 -0
- package/dist/tests/mutex.test.d.ts +2 -0
- package/dist/tests/mutex.test.d.ts.map +1 -0
- package/dist/tests/mutex.test.js +489 -0
- package/dist/tests/mutex.test.js.map +1 -0
- package/dist/tests/path-helpers.test.d.ts +2 -0
- package/dist/tests/path-helpers.test.d.ts.map +1 -0
- package/dist/tests/path-helpers.test.js +332 -0
- package/dist/tests/path-helpers.test.js.map +1 -0
- package/dist/tests/prompt-builder.test.d.ts +2 -0
- package/dist/tests/prompt-builder.test.d.ts.map +1 -0
- package/dist/tests/prompt-builder.test.js +417 -0
- package/dist/tests/prompt-builder.test.js.map +1 -0
- package/dist/tests/providers/base.test.d.ts +2 -0
- package/dist/tests/providers/base.test.d.ts.map +1 -0
- package/dist/tests/providers/base.test.js +299 -0
- package/dist/tests/providers/base.test.js.map +1 -0
- package/dist/tests/providers/chat-llm.test.d.ts +2 -0
- package/dist/tests/providers/chat-llm.test.d.ts.map +1 -0
- package/dist/tests/providers/chat-llm.test.js +435 -0
- package/dist/tests/providers/chat-llm.test.js.map +1 -0
- package/dist/tests/providers/index.test.d.ts +2 -0
- package/dist/tests/providers/index.test.d.ts.map +1 -0
- package/dist/tests/providers/index.test.js +204 -0
- package/dist/tests/providers/index.test.js.map +1 -0
- package/dist/tests/providers/mock.test.d.ts +2 -0
- package/dist/tests/providers/mock.test.d.ts.map +1 -0
- package/dist/tests/providers/mock.test.js +225 -0
- package/dist/tests/providers/mock.test.js.map +1 -0
- package/dist/tests/providers/openai.test.d.ts +2 -0
- package/dist/tests/providers/openai.test.d.ts.map +1 -0
- package/dist/tests/providers/openai.test.js +408 -0
- package/dist/tests/providers/openai.test.js.map +1 -0
- package/dist/tests/providers/token-counter.test.d.ts +2 -0
- package/dist/tests/providers/token-counter.test.d.ts.map +1 -0
- package/dist/tests/providers/token-counter.test.js +247 -0
- package/dist/tests/providers/token-counter.test.js.map +1 -0
- package/dist/tests/rate-limiter.test.js +392 -1
- package/dist/tests/rate-limiter.test.js.map +1 -1
- package/dist/tests/scope.test.d.ts +2 -0
- package/dist/tests/scope.test.d.ts.map +1 -0
- package/dist/tests/scope.test.js +529 -0
- package/dist/tests/scope.test.js.map +1 -0
- package/dist/tests/simple-lru.test.js +377 -0
- package/dist/tests/simple-lru.test.js.map +1 -1
- package/dist/tests/symbol-boost.test.js +730 -10
- package/dist/tests/symbol-boost.test.js.map +1 -1
- package/dist/tests/symbols-extract.test.d.ts +2 -0
- package/dist/tests/symbols-extract.test.d.ts.map +1 -0
- package/dist/tests/symbols-extract.test.js +536 -0
- package/dist/tests/symbols-extract.test.js.map +1 -0
- package/dist/tests/symbols-graph.test.d.ts +2 -0
- package/dist/tests/symbols-graph.test.d.ts.map +1 -0
- package/dist/tests/symbols-graph.test.js +656 -0
- package/dist/tests/symbols-graph.test.js.map +1 -0
- package/dist/tests/synthesizer.test.d.ts +2 -0
- package/dist/tests/synthesizer.test.d.ts.map +1 -0
- package/dist/tests/synthesizer.test.js +381 -0
- package/dist/tests/synthesizer.test.js.map +1 -0
- package/dist/types/context-pack.d.ts +3 -3
- package/dist/utils/logger.d.ts +5 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +149 -4
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/mutex.d.ts +7 -2
- package/dist/utils/mutex.d.ts.map +1 -1
- package/dist/utils/mutex.js +31 -7
- package/dist/utils/mutex.js.map +1 -1
- package/dist/utils/path-helpers.d.ts.map +1 -1
- package/dist/utils/path-helpers.js +5 -2
- package/dist/utils/path-helpers.js.map +1 -1
- package/dist/utils/simple-lru.d.ts +6 -0
- package/dist/utils/simple-lru.d.ts.map +1 -1
- package/dist/utils/simple-lru.js +26 -0
- package/dist/utils/simple-lru.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,965 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { CodeVaultDatabase, decodeEmbedding, initDatabase } from '../database/db.js';
|
|
6
|
+
/**
|
|
7
|
+
* Comprehensive unit tests for the CodeVault database module.
|
|
8
|
+
* Tests cover CRUD operations, binary embedding handling, transaction management,
|
|
9
|
+
* SQL injection prevention, and connection lifecycle.
|
|
10
|
+
*/
|
|
11
|
+
// Helper to create a temporary database for tests
|
|
12
|
+
async function createTempDb() {
|
|
13
|
+
const tmpDir = await fs.mkdtemp(path.join(process.cwd(), 'tmp-db-test-'));
|
|
14
|
+
const dbPath = path.join(tmpDir, 'test.db');
|
|
15
|
+
const db = new CodeVaultDatabase(dbPath);
|
|
16
|
+
db.initialize(1536);
|
|
17
|
+
return {
|
|
18
|
+
db,
|
|
19
|
+
dbPath,
|
|
20
|
+
cleanup: async () => {
|
|
21
|
+
db.close();
|
|
22
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// Helper to create a valid chunk for testing
|
|
27
|
+
function createTestChunk(overrides = {}) {
|
|
28
|
+
return {
|
|
29
|
+
id: 'test-chunk-1',
|
|
30
|
+
file_path: '/src/example.ts',
|
|
31
|
+
symbol: 'testFunction',
|
|
32
|
+
sha: 'abc123def456',
|
|
33
|
+
lang: 'typescript',
|
|
34
|
+
chunk_type: 'function',
|
|
35
|
+
embedding: new Float32Array([0.1, 0.2, 0.3, 0.4, 0.5]),
|
|
36
|
+
embedding_provider: 'openai',
|
|
37
|
+
embedding_dimensions: 5,
|
|
38
|
+
codevault_tags: ['utility', 'helper'],
|
|
39
|
+
codevault_intent: 'Test function for unit tests',
|
|
40
|
+
codevault_description: 'A test function that does nothing',
|
|
41
|
+
doc_comments: '/** Test documentation */',
|
|
42
|
+
variables_used: ['foo', 'bar'],
|
|
43
|
+
context_info: { tested: true, coverage: 100 },
|
|
44
|
+
...overrides
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// Embedding Encoding/Decoding Tests
|
|
49
|
+
// ============================================================================
|
|
50
|
+
test('decodeEmbedding handles empty buffer', () => {
|
|
51
|
+
const result = decodeEmbedding(Buffer.alloc(0));
|
|
52
|
+
assert.equal(result.length, 0);
|
|
53
|
+
});
|
|
54
|
+
test('decodeEmbedding handles null/undefined buffer', () => {
|
|
55
|
+
// @ts-expect-error Testing null handling
|
|
56
|
+
const resultNull = decodeEmbedding(null);
|
|
57
|
+
assert.equal(resultNull.length, 0);
|
|
58
|
+
// @ts-expect-error Testing undefined handling
|
|
59
|
+
const resultUndefined = decodeEmbedding(undefined);
|
|
60
|
+
assert.equal(resultUndefined.length, 0);
|
|
61
|
+
});
|
|
62
|
+
test('decodeEmbedding handles buffer with incorrect size (not divisible by 4)', () => {
|
|
63
|
+
const result = decodeEmbedding(Buffer.from([1, 2, 3]));
|
|
64
|
+
assert.equal(result.length, 0);
|
|
65
|
+
});
|
|
66
|
+
test('decodeEmbedding handles buffer too small (less than 4 bytes)', () => {
|
|
67
|
+
const result = decodeEmbedding(Buffer.from([1, 2]));
|
|
68
|
+
assert.equal(result.length, 0);
|
|
69
|
+
});
|
|
70
|
+
test('decodeEmbedding correctly decodes binary Float32 buffer', () => {
|
|
71
|
+
// Create a buffer with known float values
|
|
72
|
+
const originalValues = [1.5, -2.5, 0.0, 3.14159];
|
|
73
|
+
const buffer = Buffer.allocUnsafe(originalValues.length * 4);
|
|
74
|
+
for (let i = 0; i < originalValues.length; i++) {
|
|
75
|
+
buffer.writeFloatLE(originalValues[i], i * 4);
|
|
76
|
+
}
|
|
77
|
+
const result = decodeEmbedding(buffer);
|
|
78
|
+
assert.equal(result.length, 4);
|
|
79
|
+
assert.ok(Math.abs(result[0] - 1.5) < 0.0001);
|
|
80
|
+
assert.ok(Math.abs(result[1] - (-2.5)) < 0.0001);
|
|
81
|
+
assert.ok(Math.abs(result[2] - 0.0) < 0.0001);
|
|
82
|
+
assert.ok(Math.abs(result[3] - 3.14159) < 0.0001);
|
|
83
|
+
});
|
|
84
|
+
test('decodeEmbedding respects dimensions parameter', () => {
|
|
85
|
+
const buffer = Buffer.allocUnsafe(16); // 4 floats
|
|
86
|
+
for (let i = 0; i < 4; i++) {
|
|
87
|
+
buffer.writeFloatLE(i * 1.0, i * 4);
|
|
88
|
+
}
|
|
89
|
+
// Request only 2 dimensions
|
|
90
|
+
const result = decodeEmbedding(buffer, 2);
|
|
91
|
+
assert.equal(result.length, 2);
|
|
92
|
+
assert.ok(Math.abs(result[0] - 0.0) < 0.0001);
|
|
93
|
+
assert.ok(Math.abs(result[1] - 1.0) < 0.0001);
|
|
94
|
+
});
|
|
95
|
+
test('decodeEmbedding handles dimensions larger than buffer', () => {
|
|
96
|
+
const buffer = Buffer.allocUnsafe(8); // 2 floats
|
|
97
|
+
buffer.writeFloatLE(1.0, 0);
|
|
98
|
+
buffer.writeFloatLE(2.0, 4);
|
|
99
|
+
// Request 10 dimensions but only 2 available
|
|
100
|
+
const result = decodeEmbedding(buffer, 10);
|
|
101
|
+
assert.equal(result.length, 2);
|
|
102
|
+
});
|
|
103
|
+
test('decodeEmbedding parses JSON array format', () => {
|
|
104
|
+
const jsonArray = [0.1, 0.2, 0.3];
|
|
105
|
+
const buffer = Buffer.from(JSON.stringify(jsonArray), 'utf8');
|
|
106
|
+
const result = decodeEmbedding(buffer);
|
|
107
|
+
assert.equal(result.length, 3);
|
|
108
|
+
assert.ok(Math.abs(result[0] - 0.1) < 0.0001);
|
|
109
|
+
assert.ok(Math.abs(result[1] - 0.2) < 0.0001);
|
|
110
|
+
assert.ok(Math.abs(result[2] - 0.3) < 0.0001);
|
|
111
|
+
});
|
|
112
|
+
test('decodeEmbedding handles JSON with negative numbers', () => {
|
|
113
|
+
const jsonArray = [-0.5, -1.0];
|
|
114
|
+
const buffer = Buffer.from(JSON.stringify(jsonArray), 'utf8');
|
|
115
|
+
const result = decodeEmbedding(buffer);
|
|
116
|
+
assert.equal(result.length, 2);
|
|
117
|
+
assert.ok(Math.abs(result[0] - (-0.5)) < 0.0001);
|
|
118
|
+
});
|
|
119
|
+
test('decodeEmbedding rejects non-array JSON', () => {
|
|
120
|
+
const jsonObject = { embedding: [1, 2, 3] };
|
|
121
|
+
const buffer = Buffer.from(JSON.stringify(jsonObject), 'utf8');
|
|
122
|
+
// Should fall back to binary parsing which will fail due to size
|
|
123
|
+
const result = decodeEmbedding(buffer);
|
|
124
|
+
// Since the buffer starts with '{', it will try JSON parse, fail to get array, return null
|
|
125
|
+
// Then binary decode will check size and likely return empty
|
|
126
|
+
assert.equal(result.length, 0);
|
|
127
|
+
});
|
|
128
|
+
test('decodeEmbedding handles malformed JSON gracefully', () => {
|
|
129
|
+
const buffer = Buffer.from('[1, 2, 3', 'utf8'); // Invalid JSON
|
|
130
|
+
const result = decodeEmbedding(buffer);
|
|
131
|
+
// Falls back to binary parsing
|
|
132
|
+
assert.ok(result.length >= 0); // Should not throw
|
|
133
|
+
});
|
|
134
|
+
// ============================================================================
|
|
135
|
+
// Database Initialization and Schema Tests
|
|
136
|
+
// ============================================================================
|
|
137
|
+
test('CodeVaultDatabase creates tables on construction', async () => {
|
|
138
|
+
const { db, cleanup } = await createTempDb();
|
|
139
|
+
try {
|
|
140
|
+
// Verify code_chunks table exists by attempting to query it
|
|
141
|
+
const chunks = db.getChunks('openai', 1536);
|
|
142
|
+
assert.ok(Array.isArray(chunks));
|
|
143
|
+
assert.equal(chunks.length, 0);
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
await cleanup();
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
test('CodeVaultDatabase initialization creates additional tables and indexes', async () => {
|
|
150
|
+
const { db, cleanup } = await createTempDb();
|
|
151
|
+
try {
|
|
152
|
+
// After initialization, intention_cache and query_patterns should exist
|
|
153
|
+
// We can verify by attempting operations that use them
|
|
154
|
+
db.recordQueryPattern('test-pattern');
|
|
155
|
+
db.recordIntention('normalized', 'original', 'sha123', 0.95);
|
|
156
|
+
// Should not throw
|
|
157
|
+
assert.ok(true);
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
await cleanup();
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
test('initDatabase creates directory structure if missing', async () => {
|
|
164
|
+
const tmpDir = await fs.mkdtemp(path.join(process.cwd(), 'tmp-init-'));
|
|
165
|
+
const testPath = path.join(tmpDir, 'nested', 'project');
|
|
166
|
+
try {
|
|
167
|
+
await fs.mkdir(testPath, { recursive: true });
|
|
168
|
+
initDatabase(1536, testPath);
|
|
169
|
+
// Verify the .codevault directory was created
|
|
170
|
+
const codevaultDir = path.join(testPath, '.codevault');
|
|
171
|
+
const stat = await fs.stat(codevaultDir);
|
|
172
|
+
assert.ok(stat.isDirectory());
|
|
173
|
+
// Verify database file exists
|
|
174
|
+
const dbPath = path.join(codevaultDir, 'codevault.db');
|
|
175
|
+
const dbStat = await fs.stat(dbPath);
|
|
176
|
+
assert.ok(dbStat.isFile());
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
// ============================================================================
|
|
183
|
+
// Chunk CRUD Operations Tests
|
|
184
|
+
// ============================================================================
|
|
185
|
+
test('insertChunk inserts a single chunk successfully', async () => {
|
|
186
|
+
const { db, cleanup } = await createTempDb();
|
|
187
|
+
try {
|
|
188
|
+
const chunk = createTestChunk();
|
|
189
|
+
db.insertChunk(chunk);
|
|
190
|
+
const chunks = db.getChunks('openai', 5);
|
|
191
|
+
assert.equal(chunks.length, 1);
|
|
192
|
+
assert.equal(chunks[0].id, 'test-chunk-1');
|
|
193
|
+
assert.equal(chunks[0].file_path, '/src/example.ts');
|
|
194
|
+
assert.equal(chunks[0].symbol, 'testFunction');
|
|
195
|
+
assert.equal(chunks[0].lang, 'typescript');
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
await cleanup();
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
test('insertChunk updates existing chunk on conflict (REPLACE)', async () => {
|
|
202
|
+
const { db, cleanup } = await createTempDb();
|
|
203
|
+
try {
|
|
204
|
+
const chunk1 = createTestChunk({ symbol: 'originalSymbol' });
|
|
205
|
+
db.insertChunk(chunk1);
|
|
206
|
+
const chunk2 = createTestChunk({ symbol: 'updatedSymbol' });
|
|
207
|
+
db.insertChunk(chunk2);
|
|
208
|
+
const chunks = db.getChunks('openai', 5);
|
|
209
|
+
assert.equal(chunks.length, 1);
|
|
210
|
+
assert.equal(chunks[0].symbol, 'updatedSymbol');
|
|
211
|
+
}
|
|
212
|
+
finally {
|
|
213
|
+
await cleanup();
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
test('insertChunk encodes embeddings as binary Float32', async () => {
|
|
217
|
+
const { db, cleanup } = await createTempDb();
|
|
218
|
+
try {
|
|
219
|
+
const originalEmbedding = new Float32Array([1.5, -2.5, 0.0, 3.14]);
|
|
220
|
+
const chunk = createTestChunk({
|
|
221
|
+
embedding: originalEmbedding,
|
|
222
|
+
embedding_dimensions: 4
|
|
223
|
+
});
|
|
224
|
+
db.insertChunk(chunk);
|
|
225
|
+
const chunks = db.getChunks('openai', 4);
|
|
226
|
+
assert.equal(chunks.length, 1);
|
|
227
|
+
// Decode the embedding and verify values
|
|
228
|
+
const decoded = decodeEmbedding(chunks[0].embedding, 4);
|
|
229
|
+
assert.equal(decoded.length, 4);
|
|
230
|
+
assert.ok(Math.abs(decoded[0] - 1.5) < 0.0001);
|
|
231
|
+
assert.ok(Math.abs(decoded[1] - (-2.5)) < 0.0001);
|
|
232
|
+
assert.ok(Math.abs(decoded[2] - 0.0) < 0.0001);
|
|
233
|
+
assert.ok(Math.abs(decoded[3] - 3.14) < 0.01);
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
await cleanup();
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
test('insertChunk handles NaN and special values in embeddings', async () => {
|
|
240
|
+
const { db, cleanup } = await createTempDb();
|
|
241
|
+
try {
|
|
242
|
+
// The encoding function uses `Number(x) || 0` which:
|
|
243
|
+
// - NaN becomes 0 (falsy)
|
|
244
|
+
// - Infinity passes through (truthy)
|
|
245
|
+
// - -Infinity passes through (truthy)
|
|
246
|
+
const embedding = [NaN, Infinity, -Infinity, 1.0];
|
|
247
|
+
const chunk = createTestChunk({
|
|
248
|
+
embedding,
|
|
249
|
+
embedding_dimensions: 4
|
|
250
|
+
});
|
|
251
|
+
db.insertChunk(chunk);
|
|
252
|
+
const chunks = db.getChunks('openai', 4);
|
|
253
|
+
const decoded = decodeEmbedding(chunks[0].embedding, 4);
|
|
254
|
+
// NaN becomes 0 (falsy value triggers || 0)
|
|
255
|
+
assert.equal(decoded[0], 0);
|
|
256
|
+
// Infinity and -Infinity pass through (truthy values)
|
|
257
|
+
assert.equal(decoded[1], Infinity);
|
|
258
|
+
assert.equal(decoded[2], -Infinity);
|
|
259
|
+
assert.ok(Math.abs(decoded[3] - 1.0) < 0.0001);
|
|
260
|
+
}
|
|
261
|
+
finally {
|
|
262
|
+
await cleanup();
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
test('insertChunks inserts multiple chunks in a batch', async () => {
|
|
266
|
+
const { db, cleanup } = await createTempDb();
|
|
267
|
+
try {
|
|
268
|
+
const chunks = [
|
|
269
|
+
createTestChunk({ id: 'chunk-1', symbol: 'func1' }),
|
|
270
|
+
createTestChunk({ id: 'chunk-2', symbol: 'func2' }),
|
|
271
|
+
createTestChunk({ id: 'chunk-3', symbol: 'func3' })
|
|
272
|
+
];
|
|
273
|
+
db.insertChunks(chunks);
|
|
274
|
+
const result = db.getChunks('openai', 5);
|
|
275
|
+
assert.equal(result.length, 3);
|
|
276
|
+
}
|
|
277
|
+
finally {
|
|
278
|
+
await cleanup();
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
test('insertChunks handles empty array gracefully', async () => {
|
|
282
|
+
const { db, cleanup } = await createTempDb();
|
|
283
|
+
try {
|
|
284
|
+
db.insertChunks([]);
|
|
285
|
+
const result = db.getChunks('openai', 5);
|
|
286
|
+
assert.equal(result.length, 0);
|
|
287
|
+
}
|
|
288
|
+
finally {
|
|
289
|
+
await cleanup();
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
test('insertChunks handles non-array input gracefully', async () => {
|
|
293
|
+
const { db, cleanup } = await createTempDb();
|
|
294
|
+
try {
|
|
295
|
+
// @ts-expect-error Testing non-array input
|
|
296
|
+
db.insertChunks(null);
|
|
297
|
+
// @ts-expect-error Testing undefined input
|
|
298
|
+
db.insertChunks(undefined);
|
|
299
|
+
const result = db.getChunks('openai', 5);
|
|
300
|
+
assert.equal(result.length, 0);
|
|
301
|
+
}
|
|
302
|
+
finally {
|
|
303
|
+
await cleanup();
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
test('deleteChunks removes specified chunks by ID', async () => {
|
|
307
|
+
const { db, cleanup } = await createTempDb();
|
|
308
|
+
try {
|
|
309
|
+
const chunks = [
|
|
310
|
+
createTestChunk({ id: 'chunk-1', symbol: 'func1' }),
|
|
311
|
+
createTestChunk({ id: 'chunk-2', symbol: 'func2' }),
|
|
312
|
+
createTestChunk({ id: 'chunk-3', symbol: 'func3' })
|
|
313
|
+
];
|
|
314
|
+
db.insertChunks(chunks);
|
|
315
|
+
db.deleteChunks(['chunk-1', 'chunk-3']);
|
|
316
|
+
const result = db.getChunks('openai', 5);
|
|
317
|
+
assert.equal(result.length, 1);
|
|
318
|
+
assert.equal(result[0].id, 'chunk-2');
|
|
319
|
+
}
|
|
320
|
+
finally {
|
|
321
|
+
await cleanup();
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
test('deleteChunks handles empty array gracefully', async () => {
|
|
325
|
+
const { db, cleanup } = await createTempDb();
|
|
326
|
+
try {
|
|
327
|
+
db.insertChunk(createTestChunk());
|
|
328
|
+
db.deleteChunks([]);
|
|
329
|
+
const result = db.getChunks('openai', 5);
|
|
330
|
+
assert.equal(result.length, 1);
|
|
331
|
+
}
|
|
332
|
+
finally {
|
|
333
|
+
await cleanup();
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
test('deleteChunks handles non-existent IDs gracefully', async () => {
|
|
337
|
+
const { db, cleanup } = await createTempDb();
|
|
338
|
+
try {
|
|
339
|
+
db.insertChunk(createTestChunk({ id: 'existing-chunk' }));
|
|
340
|
+
db.deleteChunks(['non-existent-1', 'non-existent-2']);
|
|
341
|
+
const result = db.getChunks('openai', 5);
|
|
342
|
+
assert.equal(result.length, 1);
|
|
343
|
+
}
|
|
344
|
+
finally {
|
|
345
|
+
await cleanup();
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
test('getChunks filters by provider and dimensions', async () => {
|
|
349
|
+
const { db, cleanup } = await createTempDb();
|
|
350
|
+
try {
|
|
351
|
+
db.insertChunk(createTestChunk({
|
|
352
|
+
id: 'openai-chunk',
|
|
353
|
+
embedding_provider: 'openai',
|
|
354
|
+
embedding_dimensions: 1536
|
|
355
|
+
}));
|
|
356
|
+
db.insertChunk(createTestChunk({
|
|
357
|
+
id: 'anthropic-chunk',
|
|
358
|
+
embedding_provider: 'anthropic',
|
|
359
|
+
embedding_dimensions: 1024
|
|
360
|
+
}));
|
|
361
|
+
const openaiChunks = db.getChunks('openai', 1536);
|
|
362
|
+
assert.equal(openaiChunks.length, 1);
|
|
363
|
+
assert.equal(openaiChunks[0].id, 'openai-chunk');
|
|
364
|
+
const anthropicChunks = db.getChunks('anthropic', 1024);
|
|
365
|
+
assert.equal(anthropicChunks.length, 1);
|
|
366
|
+
assert.equal(anthropicChunks[0].id, 'anthropic-chunk');
|
|
367
|
+
// No match
|
|
368
|
+
const noMatch = db.getChunks('openai', 1024);
|
|
369
|
+
assert.equal(noMatch.length, 0);
|
|
370
|
+
}
|
|
371
|
+
finally {
|
|
372
|
+
await cleanup();
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
test('getOverviewChunks returns limited chunk overview', async () => {
|
|
376
|
+
const { db, cleanup } = await createTempDb();
|
|
377
|
+
try {
|
|
378
|
+
for (let i = 0; i < 10; i++) {
|
|
379
|
+
db.insertChunk(createTestChunk({
|
|
380
|
+
id: `chunk-${i}`,
|
|
381
|
+
symbol: `func${i}`,
|
|
382
|
+
file_path: `/src/file${i}.ts`
|
|
383
|
+
}));
|
|
384
|
+
}
|
|
385
|
+
const overview = db.getOverviewChunks(5);
|
|
386
|
+
assert.equal(overview.length, 5);
|
|
387
|
+
assert.ok(overview[0].id);
|
|
388
|
+
assert.ok(overview[0].file_path);
|
|
389
|
+
assert.ok(overview[0].symbol);
|
|
390
|
+
assert.ok(overview[0].sha);
|
|
391
|
+
assert.ok(overview[0].lang);
|
|
392
|
+
}
|
|
393
|
+
finally {
|
|
394
|
+
await cleanup();
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
test('getExistingDimensions returns distinct provider/dimension pairs', async () => {
|
|
398
|
+
const { db, cleanup } = await createTempDb();
|
|
399
|
+
try {
|
|
400
|
+
db.insertChunk(createTestChunk({
|
|
401
|
+
id: 'chunk-1',
|
|
402
|
+
embedding_provider: 'openai',
|
|
403
|
+
embedding_dimensions: 1536
|
|
404
|
+
}));
|
|
405
|
+
db.insertChunk(createTestChunk({
|
|
406
|
+
id: 'chunk-2',
|
|
407
|
+
embedding_provider: 'openai',
|
|
408
|
+
embedding_dimensions: 1536
|
|
409
|
+
}));
|
|
410
|
+
db.insertChunk(createTestChunk({
|
|
411
|
+
id: 'chunk-3',
|
|
412
|
+
embedding_provider: 'anthropic',
|
|
413
|
+
embedding_dimensions: 1024
|
|
414
|
+
}));
|
|
415
|
+
const dims = db.getExistingDimensions();
|
|
416
|
+
assert.equal(dims.length, 2);
|
|
417
|
+
const openaiDim = dims.find(d => d.embedding_provider === 'openai');
|
|
418
|
+
const anthropicDim = dims.find(d => d.embedding_provider === 'anthropic');
|
|
419
|
+
assert.ok(openaiDim);
|
|
420
|
+
assert.equal(openaiDim.embedding_dimensions, 1536);
|
|
421
|
+
assert.ok(anthropicDim);
|
|
422
|
+
assert.equal(anthropicDim.embedding_dimensions, 1024);
|
|
423
|
+
}
|
|
424
|
+
finally {
|
|
425
|
+
await cleanup();
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
// ============================================================================
|
|
429
|
+
// File Path Operations Tests
|
|
430
|
+
// ============================================================================
|
|
431
|
+
test('getAllFilePaths returns distinct file paths', async () => {
|
|
432
|
+
const { db, cleanup } = await createTempDb();
|
|
433
|
+
try {
|
|
434
|
+
db.insertChunk(createTestChunk({ id: 'c1', file_path: '/src/a.ts' }));
|
|
435
|
+
db.insertChunk(createTestChunk({ id: 'c2', file_path: '/src/a.ts' }));
|
|
436
|
+
db.insertChunk(createTestChunk({ id: 'c3', file_path: '/src/b.ts' }));
|
|
437
|
+
const paths = db.getAllFilePaths();
|
|
438
|
+
assert.equal(paths.length, 2);
|
|
439
|
+
assert.ok(paths.includes('/src/a.ts'));
|
|
440
|
+
assert.ok(paths.includes('/src/b.ts'));
|
|
441
|
+
}
|
|
442
|
+
finally {
|
|
443
|
+
await cleanup();
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
test('deleteChunksByFilePath removes all chunks for a file', async () => {
|
|
447
|
+
const { db, cleanup } = await createTempDb();
|
|
448
|
+
try {
|
|
449
|
+
db.insertChunk(createTestChunk({ id: 'c1', file_path: '/src/a.ts' }));
|
|
450
|
+
db.insertChunk(createTestChunk({ id: 'c2', file_path: '/src/a.ts' }));
|
|
451
|
+
db.insertChunk(createTestChunk({ id: 'c3', file_path: '/src/b.ts' }));
|
|
452
|
+
db.deleteChunksByFilePath('/src/a.ts');
|
|
453
|
+
const paths = db.getAllFilePaths();
|
|
454
|
+
assert.equal(paths.length, 1);
|
|
455
|
+
assert.ok(paths.includes('/src/b.ts'));
|
|
456
|
+
}
|
|
457
|
+
finally {
|
|
458
|
+
await cleanup();
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
// ============================================================================
|
|
462
|
+
// Intention Cache Tests
|
|
463
|
+
// ============================================================================
|
|
464
|
+
test('recordIntention inserts new intention record', async () => {
|
|
465
|
+
const { db, cleanup } = await createTempDb();
|
|
466
|
+
try {
|
|
467
|
+
db.recordIntention('find auth', 'find authentication code', 'sha-123', 0.95);
|
|
468
|
+
const result = db.searchByIntention('find auth');
|
|
469
|
+
assert.ok(result);
|
|
470
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
471
|
+
const typedResult = result;
|
|
472
|
+
assert.equal(typedResult.target_sha, 'sha-123');
|
|
473
|
+
assert.ok(Math.abs(typedResult.confidence - 0.95) < 0.001);
|
|
474
|
+
assert.equal(typedResult.original_query, 'find authentication code');
|
|
475
|
+
}
|
|
476
|
+
finally {
|
|
477
|
+
await cleanup();
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
test('recordIntention updates existing intention with same query/sha', async () => {
|
|
481
|
+
const { db, cleanup } = await createTempDb();
|
|
482
|
+
try {
|
|
483
|
+
db.recordIntention('find auth', 'original', 'sha-123', 0.8);
|
|
484
|
+
db.recordIntention('find auth', 'updated', 'sha-123', 0.95);
|
|
485
|
+
const result = db.searchByIntention('find auth');
|
|
486
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
487
|
+
const typedResult = result;
|
|
488
|
+
// Confidence should be updated
|
|
489
|
+
assert.ok(Math.abs(typedResult.confidence - 0.95) < 0.001);
|
|
490
|
+
// Usage count should be incremented
|
|
491
|
+
assert.equal(typedResult.usage_count, 2);
|
|
492
|
+
}
|
|
493
|
+
finally {
|
|
494
|
+
await cleanup();
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
test('searchByIntention returns null for non-existent query', async () => {
|
|
498
|
+
const { db, cleanup } = await createTempDb();
|
|
499
|
+
try {
|
|
500
|
+
const result = db.searchByIntention('non-existent query');
|
|
501
|
+
assert.equal(result, undefined);
|
|
502
|
+
}
|
|
503
|
+
finally {
|
|
504
|
+
await cleanup();
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
test('searchByIntention joins with code_chunks table', async () => {
|
|
508
|
+
const { db, cleanup } = await createTempDb();
|
|
509
|
+
try {
|
|
510
|
+
db.insertChunk(createTestChunk({
|
|
511
|
+
id: 'chunk-1',
|
|
512
|
+
sha: 'matched-sha',
|
|
513
|
+
file_path: '/src/auth.ts',
|
|
514
|
+
symbol: 'authenticate'
|
|
515
|
+
}));
|
|
516
|
+
db.recordIntention('auth code', 'find auth code', 'matched-sha', 0.9);
|
|
517
|
+
const result = db.searchByIntention('auth code');
|
|
518
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
519
|
+
const typedResult = result;
|
|
520
|
+
assert.equal(typedResult.file_path, '/src/auth.ts');
|
|
521
|
+
assert.equal(typedResult.symbol, 'authenticate');
|
|
522
|
+
}
|
|
523
|
+
finally {
|
|
524
|
+
await cleanup();
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
// ============================================================================
|
|
528
|
+
// Query Pattern Tests
|
|
529
|
+
// ============================================================================
|
|
530
|
+
test('recordQueryPattern inserts new pattern', async () => {
|
|
531
|
+
const { db, cleanup } = await createTempDb();
|
|
532
|
+
try {
|
|
533
|
+
db.recordQueryPattern('authentication');
|
|
534
|
+
db.recordQueryPattern('database query');
|
|
535
|
+
// No direct getter, but should not throw
|
|
536
|
+
assert.ok(true);
|
|
537
|
+
}
|
|
538
|
+
finally {
|
|
539
|
+
await cleanup();
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
test('recordQueryPattern increments frequency for existing pattern', async () => {
|
|
543
|
+
const { db, cleanup } = await createTempDb();
|
|
544
|
+
try {
|
|
545
|
+
db.recordQueryPattern('auth');
|
|
546
|
+
db.recordQueryPattern('auth');
|
|
547
|
+
db.recordQueryPattern('auth');
|
|
548
|
+
// No direct getter, but should not throw
|
|
549
|
+
assert.ok(true);
|
|
550
|
+
}
|
|
551
|
+
finally {
|
|
552
|
+
await cleanup();
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
// ============================================================================
|
|
556
|
+
// Transaction Management Tests
|
|
557
|
+
// ============================================================================
|
|
558
|
+
test('transaction commits on success', async () => {
|
|
559
|
+
const { db, cleanup } = await createTempDb();
|
|
560
|
+
try {
|
|
561
|
+
db.transaction(() => {
|
|
562
|
+
db.insertChunk(createTestChunk({ id: 'tx-chunk-1' }));
|
|
563
|
+
db.insertChunk(createTestChunk({ id: 'tx-chunk-2' }));
|
|
564
|
+
});
|
|
565
|
+
const chunks = db.getChunks('openai', 5);
|
|
566
|
+
assert.equal(chunks.length, 2);
|
|
567
|
+
}
|
|
568
|
+
finally {
|
|
569
|
+
await cleanup();
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
test('transaction rolls back on error', async () => {
|
|
573
|
+
const { db, cleanup } = await createTempDb();
|
|
574
|
+
try {
|
|
575
|
+
try {
|
|
576
|
+
db.transaction(() => {
|
|
577
|
+
db.insertChunk(createTestChunk({ id: 'rollback-chunk' }));
|
|
578
|
+
throw new Error('Intentional error for rollback');
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
catch {
|
|
582
|
+
// Expected
|
|
583
|
+
}
|
|
584
|
+
const chunks = db.getChunks('openai', 5);
|
|
585
|
+
assert.equal(chunks.length, 0);
|
|
586
|
+
}
|
|
587
|
+
finally {
|
|
588
|
+
await cleanup();
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
test('transaction rejects async functions', async () => {
|
|
592
|
+
const { db, cleanup } = await createTempDb();
|
|
593
|
+
try {
|
|
594
|
+
assert.throws(() => {
|
|
595
|
+
db.transaction(() => {
|
|
596
|
+
// Return a promise-like object
|
|
597
|
+
return Promise.resolve('async result');
|
|
598
|
+
});
|
|
599
|
+
}, /better-sqlite3 transactions must be synchronous/);
|
|
600
|
+
}
|
|
601
|
+
finally {
|
|
602
|
+
await cleanup();
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
test('manual transaction control (beginTransaction/commit)', async () => {
|
|
606
|
+
const { db, cleanup } = await createTempDb();
|
|
607
|
+
try {
|
|
608
|
+
db.beginTransaction();
|
|
609
|
+
db.insertChunk(createTestChunk({ id: 'manual-tx-chunk' }));
|
|
610
|
+
db.commit();
|
|
611
|
+
const chunks = db.getChunks('openai', 5);
|
|
612
|
+
assert.equal(chunks.length, 1);
|
|
613
|
+
}
|
|
614
|
+
finally {
|
|
615
|
+
await cleanup();
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
test('manual transaction rollback', async () => {
|
|
619
|
+
const { db, cleanup } = await createTempDb();
|
|
620
|
+
try {
|
|
621
|
+
db.beginTransaction();
|
|
622
|
+
db.insertChunk(createTestChunk({ id: 'rollback-chunk' }));
|
|
623
|
+
db.rollback();
|
|
624
|
+
const chunks = db.getChunks('openai', 5);
|
|
625
|
+
assert.equal(chunks.length, 0);
|
|
626
|
+
}
|
|
627
|
+
finally {
|
|
628
|
+
await cleanup();
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
// ============================================================================
|
|
632
|
+
// Database Statistics and Connection Tests
|
|
633
|
+
// ============================================================================
|
|
634
|
+
test('getStats returns correct database state', async () => {
|
|
635
|
+
const { db, cleanup } = await createTempDb();
|
|
636
|
+
try {
|
|
637
|
+
const stats = db.getStats();
|
|
638
|
+
assert.equal(stats.isOpen, true);
|
|
639
|
+
assert.equal(stats.inTransaction, false);
|
|
640
|
+
assert.equal(stats.readonly, false);
|
|
641
|
+
assert.equal(stats.memory, false); // We're using a file-based DB
|
|
642
|
+
}
|
|
643
|
+
finally {
|
|
644
|
+
await cleanup();
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
test('getStats reflects transaction state', async () => {
|
|
648
|
+
const { db, cleanup } = await createTempDb();
|
|
649
|
+
try {
|
|
650
|
+
db.beginTransaction();
|
|
651
|
+
const stats = db.getStats();
|
|
652
|
+
assert.equal(stats.inTransaction, true);
|
|
653
|
+
db.rollback();
|
|
654
|
+
}
|
|
655
|
+
finally {
|
|
656
|
+
await cleanup();
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
test('close properly closes database connection', async () => {
|
|
660
|
+
const { db, dbPath, cleanup } = await createTempDb();
|
|
661
|
+
try {
|
|
662
|
+
const statsBefore = db.getStats();
|
|
663
|
+
assert.equal(statsBefore.isOpen, true);
|
|
664
|
+
db.close();
|
|
665
|
+
const statsAfter = db.getStats();
|
|
666
|
+
assert.equal(statsAfter.isOpen, false);
|
|
667
|
+
}
|
|
668
|
+
finally {
|
|
669
|
+
// cleanup will try to close again, but that's okay
|
|
670
|
+
await fs.rm(path.dirname(dbPath), { recursive: true, force: true });
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
// ============================================================================
|
|
674
|
+
// SQL Injection Prevention Tests (Parameterized Queries)
|
|
675
|
+
// ============================================================================
|
|
676
|
+
test('insertChunk is safe from SQL injection in id field', async () => {
|
|
677
|
+
const { db, cleanup } = await createTempDb();
|
|
678
|
+
try {
|
|
679
|
+
const maliciousId = "'; DROP TABLE code_chunks; --";
|
|
680
|
+
const chunk = createTestChunk({ id: maliciousId });
|
|
681
|
+
db.insertChunk(chunk);
|
|
682
|
+
// Table should still exist and chunk should be inserted with malicious ID as literal
|
|
683
|
+
const chunks = db.getChunks('openai', 5);
|
|
684
|
+
assert.equal(chunks.length, 1);
|
|
685
|
+
assert.equal(chunks[0].id, maliciousId);
|
|
686
|
+
}
|
|
687
|
+
finally {
|
|
688
|
+
await cleanup();
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
test('insertChunk is safe from SQL injection in file_path field', async () => {
|
|
692
|
+
const { db, cleanup } = await createTempDb();
|
|
693
|
+
try {
|
|
694
|
+
const maliciousPath = "/src/'; DELETE FROM code_chunks WHERE '1'='1";
|
|
695
|
+
const chunk = createTestChunk({ file_path: maliciousPath });
|
|
696
|
+
db.insertChunk(chunk);
|
|
697
|
+
const chunks = db.getChunks('openai', 5);
|
|
698
|
+
assert.equal(chunks.length, 1);
|
|
699
|
+
assert.equal(chunks[0].file_path, maliciousPath);
|
|
700
|
+
}
|
|
701
|
+
finally {
|
|
702
|
+
await cleanup();
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
test('deleteChunks is safe from SQL injection', async () => {
|
|
706
|
+
const { db, cleanup } = await createTempDb();
|
|
707
|
+
try {
|
|
708
|
+
db.insertChunk(createTestChunk({ id: 'safe-chunk' }));
|
|
709
|
+
const maliciousIds = ["'; DROP TABLE code_chunks; --", "1' OR '1'='1"];
|
|
710
|
+
db.deleteChunks(maliciousIds);
|
|
711
|
+
// Table should still exist
|
|
712
|
+
const chunks = db.getChunks('openai', 5);
|
|
713
|
+
assert.equal(chunks.length, 1);
|
|
714
|
+
assert.equal(chunks[0].id, 'safe-chunk');
|
|
715
|
+
}
|
|
716
|
+
finally {
|
|
717
|
+
await cleanup();
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
test('getChunks is safe from SQL injection in provider name', async () => {
|
|
721
|
+
const { db, cleanup } = await createTempDb();
|
|
722
|
+
try {
|
|
723
|
+
db.insertChunk(createTestChunk({ embedding_provider: 'safe-provider' }));
|
|
724
|
+
const maliciousProvider = "'; DROP TABLE code_chunks; --";
|
|
725
|
+
const result = db.getChunks(maliciousProvider, 5);
|
|
726
|
+
// Should return empty (no match), table still exists
|
|
727
|
+
assert.equal(result.length, 0);
|
|
728
|
+
const safeResult = db.getChunks('safe-provider', 5);
|
|
729
|
+
assert.equal(safeResult.length, 1);
|
|
730
|
+
}
|
|
731
|
+
finally {
|
|
732
|
+
await cleanup();
|
|
733
|
+
}
|
|
734
|
+
});
|
|
735
|
+
test('recordIntention is safe from SQL injection', async () => {
|
|
736
|
+
const { db, cleanup } = await createTempDb();
|
|
737
|
+
try {
|
|
738
|
+
const maliciousQuery = "'; DELETE FROM intention_cache; --";
|
|
739
|
+
db.recordIntention(maliciousQuery, 'original', 'sha-123', 0.9);
|
|
740
|
+
// Should not throw and intention should be recorded
|
|
741
|
+
const result = db.searchByIntention(maliciousQuery);
|
|
742
|
+
assert.ok(result);
|
|
743
|
+
}
|
|
744
|
+
finally {
|
|
745
|
+
await cleanup();
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
test('searchByIntention is safe from SQL injection', async () => {
|
|
749
|
+
const { db, cleanup } = await createTempDb();
|
|
750
|
+
try {
|
|
751
|
+
db.recordIntention('safe-query', 'original', 'sha-123', 0.9);
|
|
752
|
+
const maliciousQuery = "' OR '1'='1";
|
|
753
|
+
const result = db.searchByIntention(maliciousQuery);
|
|
754
|
+
// Should return undefined (no match), not all records
|
|
755
|
+
assert.equal(result, undefined);
|
|
756
|
+
}
|
|
757
|
+
finally {
|
|
758
|
+
await cleanup();
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
test('recordQueryPattern is safe from SQL injection', async () => {
|
|
762
|
+
const { db, cleanup } = await createTempDb();
|
|
763
|
+
try {
|
|
764
|
+
const maliciousPattern = "'; DROP TABLE query_patterns; --";
|
|
765
|
+
db.recordQueryPattern(maliciousPattern);
|
|
766
|
+
// Should not throw, table should still exist
|
|
767
|
+
db.recordQueryPattern('safe-pattern');
|
|
768
|
+
assert.ok(true);
|
|
769
|
+
}
|
|
770
|
+
finally {
|
|
771
|
+
await cleanup();
|
|
772
|
+
}
|
|
773
|
+
});
|
|
774
|
+
test('getOverviewChunks is safe from SQL injection in limit', async () => {
|
|
775
|
+
const { db, cleanup } = await createTempDb();
|
|
776
|
+
try {
|
|
777
|
+
db.insertChunk(createTestChunk());
|
|
778
|
+
// Limit is a number, so SQL injection is not directly possible here
|
|
779
|
+
// But we verify the function works correctly with valid numeric input
|
|
780
|
+
const result = db.getOverviewChunks(10);
|
|
781
|
+
assert.ok(Array.isArray(result));
|
|
782
|
+
}
|
|
783
|
+
finally {
|
|
784
|
+
await cleanup();
|
|
785
|
+
}
|
|
786
|
+
});
|
|
787
|
+
test('deleteChunksByFilePath is safe from SQL injection', async () => {
|
|
788
|
+
const { db, cleanup } = await createTempDb();
|
|
789
|
+
try {
|
|
790
|
+
db.insertChunk(createTestChunk({ id: 'chunk-1', file_path: '/safe/path.ts' }));
|
|
791
|
+
const maliciousPath = "'; DELETE FROM code_chunks WHERE '1'='1";
|
|
792
|
+
db.deleteChunksByFilePath(maliciousPath);
|
|
793
|
+
// Original chunk should still exist
|
|
794
|
+
const chunks = db.getChunks('openai', 5);
|
|
795
|
+
assert.equal(chunks.length, 1);
|
|
796
|
+
}
|
|
797
|
+
finally {
|
|
798
|
+
await cleanup();
|
|
799
|
+
}
|
|
800
|
+
});
|
|
801
|
+
// ============================================================================
|
|
802
|
+
// Edge Cases and Error Handling Tests
|
|
803
|
+
// ============================================================================
|
|
804
|
+
test('handles very large embedding arrays', async () => {
|
|
805
|
+
const { db, cleanup } = await createTempDb();
|
|
806
|
+
try {
|
|
807
|
+
const largeEmbedding = new Float32Array(3072); // Large embedding dimension
|
|
808
|
+
for (let i = 0; i < largeEmbedding.length; i++) {
|
|
809
|
+
largeEmbedding[i] = Math.random();
|
|
810
|
+
}
|
|
811
|
+
const chunk = createTestChunk({
|
|
812
|
+
embedding: largeEmbedding,
|
|
813
|
+
embedding_dimensions: 3072
|
|
814
|
+
});
|
|
815
|
+
db.insertChunk(chunk);
|
|
816
|
+
const chunks = db.getChunks('openai', 3072);
|
|
817
|
+
assert.equal(chunks.length, 1);
|
|
818
|
+
const decoded = decodeEmbedding(chunks[0].embedding, 3072);
|
|
819
|
+
assert.equal(decoded.length, 3072);
|
|
820
|
+
// Verify round-trip accuracy
|
|
821
|
+
for (let i = 0; i < 10; i++) {
|
|
822
|
+
assert.ok(Math.abs(decoded[i] - largeEmbedding[i]) < 0.0001);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
finally {
|
|
826
|
+
await cleanup();
|
|
827
|
+
}
|
|
828
|
+
});
|
|
829
|
+
test('handles unicode characters in chunk fields', async () => {
|
|
830
|
+
const { db, cleanup } = await createTempDb();
|
|
831
|
+
try {
|
|
832
|
+
const chunk = createTestChunk({
|
|
833
|
+
id: 'unicode-chunk-123',
|
|
834
|
+
symbol: 'testFunction',
|
|
835
|
+
file_path: '/src/example.ts',
|
|
836
|
+
codevault_description: 'Description with unicode and special chars',
|
|
837
|
+
doc_comments: '/** Japanese docs and more unicode chars */'
|
|
838
|
+
});
|
|
839
|
+
db.insertChunk(chunk);
|
|
840
|
+
const chunks = db.getChunks('openai', 5);
|
|
841
|
+
assert.equal(chunks.length, 1);
|
|
842
|
+
assert.ok(chunks[0].codevault_description?.includes('unicode'));
|
|
843
|
+
}
|
|
844
|
+
finally {
|
|
845
|
+
await cleanup();
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
test('handles empty strings in chunk fields', async () => {
|
|
849
|
+
const { db, cleanup } = await createTempDb();
|
|
850
|
+
try {
|
|
851
|
+
const chunk = createTestChunk({
|
|
852
|
+
symbol: '',
|
|
853
|
+
codevault_intent: '',
|
|
854
|
+
codevault_description: '',
|
|
855
|
+
doc_comments: ''
|
|
856
|
+
});
|
|
857
|
+
db.insertChunk(chunk);
|
|
858
|
+
const chunks = db.getChunks('openai', 5);
|
|
859
|
+
assert.equal(chunks.length, 1);
|
|
860
|
+
assert.equal(chunks[0].symbol, '');
|
|
861
|
+
}
|
|
862
|
+
finally {
|
|
863
|
+
await cleanup();
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
test('handles null values in optional chunk fields', async () => {
|
|
867
|
+
const { db, cleanup } = await createTempDb();
|
|
868
|
+
try {
|
|
869
|
+
const chunk = createTestChunk({
|
|
870
|
+
codevault_intent: null,
|
|
871
|
+
codevault_description: null,
|
|
872
|
+
doc_comments: null
|
|
873
|
+
});
|
|
874
|
+
db.insertChunk(chunk);
|
|
875
|
+
const chunks = db.getChunks('openai', 5);
|
|
876
|
+
assert.equal(chunks.length, 1);
|
|
877
|
+
assert.equal(chunks[0].codevault_intent, null);
|
|
878
|
+
}
|
|
879
|
+
finally {
|
|
880
|
+
await cleanup();
|
|
881
|
+
}
|
|
882
|
+
});
|
|
883
|
+
test('handles concurrent insertions without data corruption', async () => {
|
|
884
|
+
const { db, cleanup } = await createTempDb();
|
|
885
|
+
try {
|
|
886
|
+
// Insert many chunks rapidly
|
|
887
|
+
const promises = [];
|
|
888
|
+
for (let i = 0; i < 100; i++) {
|
|
889
|
+
promises.push(new Promise((resolve) => {
|
|
890
|
+
db.insertChunk(createTestChunk({ id: `concurrent-${i}` }));
|
|
891
|
+
resolve();
|
|
892
|
+
}));
|
|
893
|
+
}
|
|
894
|
+
await Promise.all(promises);
|
|
895
|
+
const chunks = db.getChunks('openai', 5);
|
|
896
|
+
assert.equal(chunks.length, 100);
|
|
897
|
+
}
|
|
898
|
+
finally {
|
|
899
|
+
await cleanup();
|
|
900
|
+
}
|
|
901
|
+
});
|
|
902
|
+
test('batch insert handles large batches efficiently', async () => {
|
|
903
|
+
const { db, cleanup } = await createTempDb();
|
|
904
|
+
try {
|
|
905
|
+
const chunks = [];
|
|
906
|
+
for (let i = 0; i < 500; i++) {
|
|
907
|
+
chunks.push(createTestChunk({ id: `batch-${i}`, symbol: `func${i}` }));
|
|
908
|
+
}
|
|
909
|
+
const startTime = Date.now();
|
|
910
|
+
db.insertChunks(chunks);
|
|
911
|
+
const endTime = Date.now();
|
|
912
|
+
// Should complete in reasonable time (< 5 seconds for 500 items)
|
|
913
|
+
assert.ok(endTime - startTime < 5000);
|
|
914
|
+
const result = db.getChunks('openai', 5);
|
|
915
|
+
assert.equal(result.length, 500);
|
|
916
|
+
}
|
|
917
|
+
finally {
|
|
918
|
+
await cleanup();
|
|
919
|
+
}
|
|
920
|
+
});
|
|
921
|
+
// ============================================================================
|
|
922
|
+
// In-Memory Database Tests
|
|
923
|
+
// ============================================================================
|
|
924
|
+
test('works correctly with in-memory database', async () => {
|
|
925
|
+
const db = new CodeVaultDatabase(':memory:');
|
|
926
|
+
db.initialize(1536);
|
|
927
|
+
try {
|
|
928
|
+
const stats = db.getStats();
|
|
929
|
+
assert.equal(stats.memory, true);
|
|
930
|
+
assert.equal(stats.isOpen, true);
|
|
931
|
+
db.insertChunk(createTestChunk({ id: 'memory-chunk' }));
|
|
932
|
+
const chunks = db.getChunks('openai', 5);
|
|
933
|
+
assert.equal(chunks.length, 1);
|
|
934
|
+
assert.equal(chunks[0].id, 'memory-chunk');
|
|
935
|
+
}
|
|
936
|
+
finally {
|
|
937
|
+
db.close();
|
|
938
|
+
}
|
|
939
|
+
});
|
|
940
|
+
test('in-memory database supports all operations', async () => {
|
|
941
|
+
const db = new CodeVaultDatabase(':memory:');
|
|
942
|
+
db.initialize(1536);
|
|
943
|
+
try {
|
|
944
|
+
// Test all major operations
|
|
945
|
+
db.insertChunk(createTestChunk({ id: 'chunk-1', file_path: '/a.ts' }));
|
|
946
|
+
db.insertChunks([
|
|
947
|
+
createTestChunk({ id: 'chunk-2', file_path: '/b.ts' }),
|
|
948
|
+
createTestChunk({ id: 'chunk-3', file_path: '/b.ts' })
|
|
949
|
+
]);
|
|
950
|
+
const paths = db.getAllFilePaths();
|
|
951
|
+
assert.equal(paths.length, 2);
|
|
952
|
+
db.deleteChunksByFilePath('/b.ts');
|
|
953
|
+
assert.equal(db.getAllFilePaths().length, 1);
|
|
954
|
+
db.recordIntention('test', 'test query', 'sha-123', 0.9);
|
|
955
|
+
db.recordQueryPattern('test pattern');
|
|
956
|
+
const overview = db.getOverviewChunks(10);
|
|
957
|
+
assert.equal(overview.length, 1);
|
|
958
|
+
const dims = db.getExistingDimensions();
|
|
959
|
+
assert.ok(dims.length >= 1);
|
|
960
|
+
}
|
|
961
|
+
finally {
|
|
962
|
+
db.close();
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
//# sourceMappingURL=database.test.js.map
|