@skillsmith/core 0.4.8 → 0.4.10
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 +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/analysis/adapters/java-parsers.d.ts.map +1 -1
- package/dist/src/analysis/adapters/java-parsers.js +9 -2
- package/dist/src/analysis/adapters/java-parsers.js.map +1 -1
- package/dist/src/analytics/AnalyticsRepository.d.ts +1 -1
- package/dist/src/analytics/AnalyticsRepository.d.ts.map +1 -1
- package/dist/src/analytics/ExperimentService.d.ts +1 -1
- package/dist/src/analytics/ExperimentService.d.ts.map +1 -1
- package/dist/src/analytics/ROIDashboardService.d.ts +1 -1
- package/dist/src/analytics/ROIDashboardService.d.ts.map +1 -1
- package/dist/src/analytics/UsageAnalyticsService.d.ts +1 -1
- package/dist/src/analytics/UsageAnalyticsService.d.ts.map +1 -1
- package/dist/src/analytics/metrics-aggregator.d.ts +1 -1
- package/dist/src/analytics/metrics-aggregator.d.ts.map +1 -1
- package/dist/src/analytics/schema.d.ts +1 -1
- package/dist/src/analytics/schema.d.ts.map +1 -1
- package/dist/src/analytics/storage.d.ts.map +1 -1
- package/dist/src/analytics/storage.js +2 -2
- package/dist/src/analytics/storage.js.map +1 -1
- package/dist/src/api/client.d.ts +1 -0
- package/dist/src/api/client.d.ts.map +1 -1
- package/dist/src/api/client.js +14 -7
- package/dist/src/api/client.js.map +1 -1
- package/dist/src/api/schemas.d.ts +17 -10
- package/dist/src/api/schemas.d.ts.map +1 -1
- package/dist/src/api/schemas.js +9 -2
- package/dist/src/api/schemas.js.map +1 -1
- package/dist/src/billing/BillingService.d.ts.map +1 -1
- package/dist/src/billing/BillingService.js.map +1 -1
- package/dist/src/billing/BillingService.types.d.ts +2 -2
- package/dist/src/billing/BillingService.types.d.ts.map +1 -1
- package/dist/src/billing/GDPRComplianceService.d.ts.map +1 -1
- package/dist/src/billing/GDPRComplianceService.js.map +1 -1
- package/dist/src/billing/StripeReconciliationJob.d.ts.map +1 -1
- package/dist/src/billing/StripeReconciliationJob.js.map +1 -1
- package/dist/src/billing/StripeWebhookHandler.d.ts.map +1 -1
- package/dist/src/billing/StripeWebhookHandler.js.map +1 -1
- package/dist/src/billing/gdpr-types.d.ts +2 -2
- package/dist/src/billing/gdpr-types.d.ts.map +1 -1
- package/dist/src/billing/reconciliation-types.d.ts +2 -2
- package/dist/src/billing/reconciliation-types.d.ts.map +1 -1
- package/dist/src/billing/webhook-handlers.d.ts +4 -4
- package/dist/src/billing/webhook-handlers.d.ts.map +1 -1
- package/dist/src/billing/webhook-handlers.js.map +1 -1
- package/dist/src/billing/webhook-types.d.ts +2 -2
- package/dist/src/billing/webhook-types.d.ts.map +1 -1
- package/dist/src/cache/TieredCache.d.ts.map +1 -1
- package/dist/src/cache/TieredCache.js +2 -2
- package/dist/src/cache/TieredCache.js.map +1 -1
- package/dist/src/cache/sqlite.d.ts.map +1 -1
- package/dist/src/cache/sqlite.js +5 -4
- package/dist/src/cache/sqlite.js.map +1 -1
- package/dist/src/db/createDatabase.d.ts +86 -0
- package/dist/src/db/createDatabase.d.ts.map +1 -0
- package/dist/src/db/createDatabase.js +139 -0
- package/dist/src/db/createDatabase.js.map +1 -0
- package/dist/src/db/database-interface.d.ts +141 -0
- package/dist/src/db/database-interface.d.ts.map +1 -0
- package/dist/src/db/database-interface.js +14 -0
- package/dist/src/db/database-interface.js.map +1 -0
- package/dist/src/db/drivers/betterSqlite3Driver.d.ts +48 -0
- package/dist/src/db/drivers/betterSqlite3Driver.d.ts.map +1 -0
- package/dist/src/db/drivers/betterSqlite3Driver.js +138 -0
- package/dist/src/db/drivers/betterSqlite3Driver.js.map +1 -0
- package/dist/src/db/drivers/index.d.ts +8 -0
- package/dist/src/db/drivers/index.d.ts.map +1 -0
- package/dist/src/db/drivers/index.js +8 -0
- package/dist/src/db/drivers/index.js.map +1 -0
- package/dist/src/db/drivers/sqljsDriver.d.ts +91 -0
- package/dist/src/db/drivers/sqljsDriver.d.ts.map +1 -0
- package/dist/src/db/drivers/sqljsDriver.js +335 -0
- package/dist/src/db/drivers/sqljsDriver.js.map +1 -0
- package/dist/src/db/migration.d.ts +1 -1
- package/dist/src/db/migration.d.ts.map +1 -1
- package/dist/src/db/quarantine-schema.d.ts +1 -1
- package/dist/src/db/quarantine-schema.d.ts.map +1 -1
- package/dist/src/db/schema.d.ts +22 -2
- package/dist/src/db/schema.d.ts.map +1 -1
- package/dist/src/db/schema.js +55 -3
- package/dist/src/db/schema.js.map +1 -1
- package/dist/src/embeddings/hnsw-store.js +2 -2
- package/dist/src/embeddings/hnsw-store.js.map +1 -1
- package/dist/src/embeddings/index.d.ts.map +1 -1
- package/dist/src/embeddings/index.js +2 -2
- package/dist/src/embeddings/index.js.map +1 -1
- package/dist/src/exports/repositories.d.ts +4 -1
- package/dist/src/exports/repositories.d.ts.map +1 -1
- package/dist/src/exports/repositories.js +9 -3
- package/dist/src/exports/repositories.js.map +1 -1
- package/dist/src/exports/services.d.ts +1 -0
- package/dist/src/exports/services.d.ts.map +1 -1
- package/dist/src/exports/services.js +4 -0
- package/dist/src/exports/services.js.map +1 -1
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/indexer/SkillParser.d.ts +20 -0
- package/dist/src/indexer/SkillParser.d.ts.map +1 -1
- package/dist/src/indexer/SkillParser.js +58 -0
- package/dist/src/indexer/SkillParser.js.map +1 -1
- package/dist/src/learning/PatternStore.d.ts.map +1 -1
- package/dist/src/learning/PatternStore.js +2 -7
- package/dist/src/learning/PatternStore.js.map +1 -1
- package/dist/src/learning/PatternStore.queries.d.ts +17 -17
- package/dist/src/learning/PatternStore.queries.d.ts.map +1 -1
- package/dist/src/learning/PatternStore.queries.js.map +1 -1
- package/dist/src/repositories/CacheRepository.d.ts +1 -1
- package/dist/src/repositories/CacheRepository.d.ts.map +1 -1
- package/dist/src/repositories/IndexerRepository.d.ts +1 -1
- package/dist/src/repositories/IndexerRepository.d.ts.map +1 -1
- package/dist/src/repositories/SkillRepository.d.ts +1 -1
- package/dist/src/repositories/SkillRepository.d.ts.map +1 -1
- package/dist/src/repositories/SyncConfigRepository.d.ts +1 -1
- package/dist/src/repositories/SyncConfigRepository.d.ts.map +1 -1
- package/dist/src/repositories/SyncHistoryRepository.d.ts +1 -1
- package/dist/src/repositories/SyncHistoryRepository.d.ts.map +1 -1
- package/dist/src/repositories/quarantine/QuarantineRepository.d.ts +1 -1
- package/dist/src/repositories/quarantine/QuarantineRepository.d.ts.map +1 -1
- package/dist/src/repositories/quarantine/QuarantineRepository.js +4 -1
- package/dist/src/repositories/quarantine/QuarantineRepository.js.map +1 -1
- package/dist/src/scripts/merge-skills.d.ts.map +1 -1
- package/dist/src/scripts/merge-skills.js +2 -2
- package/dist/src/scripts/merge-skills.js.map +1 -1
- package/dist/src/scripts/review-lenny-skills.js +2 -2
- package/dist/src/scripts/review-lenny-skills.js.map +1 -1
- package/dist/src/scripts/validation/types.d.ts +2 -2
- package/dist/src/search/hybrid.d.ts.map +1 -1
- package/dist/src/search/hybrid.js +2 -2
- package/dist/src/search/hybrid.js.map +1 -1
- package/dist/src/security/AuditLogger.d.ts +1 -1
- package/dist/src/security/AuditLogger.d.ts.map +1 -1
- package/dist/src/security/audit-types.d.ts +2 -2
- package/dist/src/security/audit-types.d.ts.map +1 -1
- package/dist/src/security/audit-types.js.map +1 -1
- package/dist/src/security/sanitization.d.ts.map +1 -1
- package/dist/src/security/sanitization.js +25 -17
- package/dist/src/security/sanitization.js.map +1 -1
- package/dist/src/services/SearchService.d.ts +1 -1
- package/dist/src/services/SearchService.d.ts.map +1 -1
- package/dist/src/services/TransformationService.d.ts +1 -1
- package/dist/src/services/TransformationService.d.ts.map +1 -1
- package/dist/src/services/index.d.ts +9 -0
- package/dist/src/services/index.d.ts.map +1 -0
- package/dist/src/services/index.js +10 -0
- package/dist/src/services/index.js.map +1 -0
- package/dist/src/services/quarantine/QuarantineService.d.ts +149 -0
- package/dist/src/services/quarantine/QuarantineService.d.ts.map +1 -0
- package/dist/src/services/quarantine/QuarantineService.js +406 -0
- package/dist/src/services/quarantine/QuarantineService.js.map +1 -0
- package/dist/src/services/quarantine/index.d.ts +10 -0
- package/dist/src/services/quarantine/index.d.ts.map +1 -0
- package/dist/src/services/quarantine/index.js +14 -0
- package/dist/src/services/quarantine/index.js.map +1 -0
- package/dist/src/services/quarantine/types.d.ts +127 -0
- package/dist/src/services/quarantine/types.d.ts.map +1 -0
- package/dist/src/services/quarantine/types.js +59 -0
- package/dist/src/services/quarantine/types.js.map +1 -0
- package/dist/src/types/skill.d.ts +6 -1
- package/dist/src/types/skill.d.ts.map +1 -1
- package/dist/src/types/skill.js.map +1 -1
- package/dist/src/types.d.ts +1 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/github-url.d.ts +57 -0
- package/dist/src/utils/github-url.d.ts.map +1 -0
- package/dist/src/utils/github-url.js +88 -0
- package/dist/src/utils/github-url.js.map +1 -0
- package/dist/src/utils/index.d.ts +2 -0
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +4 -0
- package/dist/src/utils/index.js.map +1 -1
- package/dist/src/utils/safe-fs.d.ts +63 -0
- package/dist/src/utils/safe-fs.d.ts.map +1 -0
- package/dist/src/utils/safe-fs.js +119 -0
- package/dist/src/utils/safe-fs.js.map +1 -0
- package/dist/src/validation/input-validators.d.ts.map +1 -1
- package/dist/src/validation/input-validators.js +11 -4
- package/dist/src/validation/input-validators.js.map +1 -1
- package/dist/tests/Analytics.integration.test.js +2 -2
- package/dist/tests/Analytics.integration.test.js.map +1 -1
- package/dist/tests/AnalyticsRepository.test.js +2 -2
- package/dist/tests/AnalyticsRepository.test.js.map +1 -1
- package/dist/tests/AuditLogger.test.js.map +1 -1
- package/dist/tests/ExperimentService.test.js +2 -2
- package/dist/tests/ExperimentService.test.js.map +1 -1
- package/dist/tests/QuarantineRepository.test.js +39 -2
- package/dist/tests/QuarantineRepository.test.js.map +1 -1
- package/dist/tests/ROIDashboardService.test.js +2 -2
- package/dist/tests/ROIDashboardService.test.js.map +1 -1
- package/dist/tests/UsageAnalyticsService.test.js +2 -2
- package/dist/tests/UsageAnalyticsService.test.js.map +1 -1
- package/dist/tests/analytics/metrics-aggregator.test.js +2 -2
- package/dist/tests/analytics/metrics-aggregator.test.js.map +1 -1
- package/dist/tests/analytics/metrics-exporter.test.js +2 -2
- package/dist/tests/analytics/metrics-exporter.test.js.map +1 -1
- package/dist/tests/api/client.structural-typing.test.d.ts +11 -0
- package/dist/tests/api/client.structural-typing.test.d.ts.map +1 -0
- package/dist/tests/api/client.structural-typing.test.js +209 -0
- package/dist/tests/api/client.structural-typing.test.js.map +1 -0
- package/dist/tests/billing/BillingService.test.js +2 -2
- package/dist/tests/billing/BillingService.test.js.map +1 -1
- package/dist/tests/billing/GDPRCompliance.test.js +2 -2
- package/dist/tests/billing/GDPRCompliance.test.js.map +1 -1
- package/dist/tests/billing/StripeReconciliation.test.js +2 -2
- package/dist/tests/billing/StripeReconciliation.test.js.map +1 -1
- package/dist/tests/db/database-abstraction.test.d.ts +8 -0
- package/dist/tests/db/database-abstraction.test.d.ts.map +1 -0
- package/dist/tests/db/database-abstraction.test.js +208 -0
- package/dist/tests/db/database-abstraction.test.js.map +1 -0
- package/dist/tests/db/fts5-support.test.d.ts +14 -0
- package/dist/tests/db/fts5-support.test.d.ts.map +1 -0
- package/dist/tests/db/fts5-support.test.js +128 -0
- package/dist/tests/db/fts5-support.test.js.map +1 -0
- package/dist/tests/db/schema-async.test.d.ts +9 -0
- package/dist/tests/db/schema-async.test.d.ts.map +1 -0
- package/dist/tests/db/schema-async.test.js +302 -0
- package/dist/tests/db/schema-async.test.js.map +1 -0
- package/dist/tests/db/sqljs-driver.test.d.ts +8 -0
- package/dist/tests/db/sqljs-driver.test.d.ts.map +1 -0
- package/dist/tests/db/sqljs-driver.test.js +323 -0
- package/dist/tests/db/sqljs-driver.test.js.map +1 -0
- package/dist/tests/edge-cases/EdgeCases.test.js +5 -2
- package/dist/tests/edge-cases/EdgeCases.test.js.map +1 -1
- package/dist/tests/integration/QuarantineService.test.d.ts +11 -0
- package/dist/tests/integration/QuarantineService.test.d.ts.map +1 -0
- package/dist/tests/integration/QuarantineService.test.js +378 -0
- package/dist/tests/integration/QuarantineService.test.js.map +1 -0
- package/dist/tests/schema.test.js.map +1 -1
- package/dist/tests/scripts/import-to-database.test.js +7 -7
- package/dist/tests/scripts/import-to-database.test.js.map +1 -1
- package/dist/tests/unit/check-references.test.d.ts +2 -0
- package/dist/tests/unit/check-references.test.d.ts.map +1 -0
- package/dist/tests/unit/check-references.test.js +118 -0
- package/dist/tests/unit/check-references.test.js.map +1 -0
- package/dist/tests/utils/safe-fs.test.d.ts +12 -0
- package/dist/tests/utils/safe-fs.test.d.ts.map +1 -0
- package/dist/tests/utils/safe-fs.test.js +116 -0
- package/dist/tests/utils/safe-fs.test.js.map +1 -0
- package/package.json +16 -10
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-2206: Async Schema Functions Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for async database initialization with WASM fallback support.
|
|
5
|
+
* These tests verify that createDatabaseAsync and openDatabaseAsync work
|
|
6
|
+
* correctly with automatic driver selection.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
9
|
+
import { existsSync, unlinkSync, mkdirSync, rmSync } from 'node:fs';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { tmpdir } from 'node:os';
|
|
12
|
+
import { createDatabaseAsync, openDatabaseAsync, closeDatabase, getSchemaVersion, SCHEMA_VERSION, } from '../../src/db/schema.js';
|
|
13
|
+
import { isBetterSqlite3Available } from '../../src/db/drivers/betterSqlite3Driver.js';
|
|
14
|
+
// Track databases to clean up
|
|
15
|
+
const testDatabases = [];
|
|
16
|
+
const testPaths = [];
|
|
17
|
+
// Unique test directory to avoid collisions
|
|
18
|
+
const TEST_DIR = join(tmpdir(), `skillsmith-schema-async-test-${Date.now()}`);
|
|
19
|
+
describe('Async Schema Functions (SMI-2206)', () => {
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
// Close all test databases
|
|
22
|
+
for (const db of testDatabases) {
|
|
23
|
+
if (db.open) {
|
|
24
|
+
closeDatabase(db);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
testDatabases.length = 0;
|
|
28
|
+
// Clean up test files
|
|
29
|
+
for (const testPath of testPaths) {
|
|
30
|
+
try {
|
|
31
|
+
if (existsSync(testPath)) {
|
|
32
|
+
unlinkSync(testPath);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Ignore cleanup errors
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
testPaths.length = 0;
|
|
40
|
+
// Clean up test directory
|
|
41
|
+
try {
|
|
42
|
+
if (existsSync(TEST_DIR)) {
|
|
43
|
+
rmSync(TEST_DIR, { recursive: true, force: true });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Ignore cleanup errors
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
describe('createDatabaseAsync', () => {
|
|
51
|
+
it('creates in-memory database', async () => {
|
|
52
|
+
// Skip if no driver available
|
|
53
|
+
if (!isBetterSqlite3Available()) {
|
|
54
|
+
console.log('Skipping test: no SQLite driver available');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const db = await createDatabaseAsync(':memory:');
|
|
58
|
+
testDatabases.push(db);
|
|
59
|
+
expect(db.open).toBe(true);
|
|
60
|
+
expect(db.memory).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
it('creates file-based database', async () => {
|
|
63
|
+
if (!isBetterSqlite3Available()) {
|
|
64
|
+
console.log('Skipping test: no SQLite driver available');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Ensure test directory exists
|
|
68
|
+
mkdirSync(TEST_DIR, { recursive: true });
|
|
69
|
+
const testPath = join(TEST_DIR, `test-async-create-${Date.now()}.db`);
|
|
70
|
+
testPaths.push(testPath);
|
|
71
|
+
const db = await createDatabaseAsync(testPath);
|
|
72
|
+
testDatabases.push(db);
|
|
73
|
+
expect(db.open).toBe(true);
|
|
74
|
+
expect(existsSync(testPath)).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
it('initializes schema with FTS5 table', async () => {
|
|
77
|
+
if (!isBetterSqlite3Available()) {
|
|
78
|
+
console.log('Skipping test: no SQLite driver available');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const db = await createDatabaseAsync(':memory:');
|
|
82
|
+
testDatabases.push(db);
|
|
83
|
+
const result = db
|
|
84
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='skills_fts'")
|
|
85
|
+
.get();
|
|
86
|
+
expect(result).toBeDefined();
|
|
87
|
+
expect(result?.name).toBe('skills_fts');
|
|
88
|
+
});
|
|
89
|
+
it('creates all required tables', async () => {
|
|
90
|
+
if (!isBetterSqlite3Available()) {
|
|
91
|
+
console.log('Skipping test: no SQLite driver available');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const db = await createDatabaseAsync(':memory:');
|
|
95
|
+
testDatabases.push(db);
|
|
96
|
+
const tables = db
|
|
97
|
+
.prepare(`
|
|
98
|
+
SELECT name FROM sqlite_master
|
|
99
|
+
WHERE type='table' AND name NOT LIKE 'sqlite_%'
|
|
100
|
+
ORDER BY name
|
|
101
|
+
`)
|
|
102
|
+
.all();
|
|
103
|
+
const tableNames = tables.map((t) => t.name);
|
|
104
|
+
expect(tableNames).toContain('skills');
|
|
105
|
+
expect(tableNames).toContain('skills_fts');
|
|
106
|
+
expect(tableNames).toContain('sources');
|
|
107
|
+
expect(tableNames).toContain('categories');
|
|
108
|
+
expect(tableNames).toContain('cache');
|
|
109
|
+
expect(tableNames).toContain('schema_version');
|
|
110
|
+
});
|
|
111
|
+
it('sets foreign_keys pragma', async () => {
|
|
112
|
+
if (!isBetterSqlite3Available()) {
|
|
113
|
+
console.log('Skipping test: no SQLite driver available');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const db = await createDatabaseAsync(':memory:');
|
|
117
|
+
testDatabases.push(db);
|
|
118
|
+
const result = db.pragma('foreign_keys');
|
|
119
|
+
expect(result[0].foreign_keys).toBe(1);
|
|
120
|
+
});
|
|
121
|
+
it('initializes schema version', async () => {
|
|
122
|
+
if (!isBetterSqlite3Available()) {
|
|
123
|
+
console.log('Skipping test: no SQLite driver available');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const db = await createDatabaseAsync(':memory:');
|
|
127
|
+
testDatabases.push(db);
|
|
128
|
+
const version = getSchemaVersion(db);
|
|
129
|
+
expect(version).toBe(SCHEMA_VERSION);
|
|
130
|
+
});
|
|
131
|
+
it('creates required indexes', async () => {
|
|
132
|
+
if (!isBetterSqlite3Available()) {
|
|
133
|
+
console.log('Skipping test: no SQLite driver available');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const db = await createDatabaseAsync(':memory:');
|
|
137
|
+
testDatabases.push(db);
|
|
138
|
+
const indexes = db
|
|
139
|
+
.prepare(`
|
|
140
|
+
SELECT name FROM sqlite_master
|
|
141
|
+
WHERE type='index' AND name LIKE 'idx_%'
|
|
142
|
+
`)
|
|
143
|
+
.all();
|
|
144
|
+
const indexNames = indexes.map((i) => i.name);
|
|
145
|
+
expect(indexNames).toContain('idx_skills_author');
|
|
146
|
+
expect(indexNames).toContain('idx_skills_trust_tier');
|
|
147
|
+
expect(indexNames).toContain('idx_skills_quality_score');
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
describe('openDatabaseAsync', () => {
|
|
151
|
+
it('opens existing database', async () => {
|
|
152
|
+
if (!isBetterSqlite3Available()) {
|
|
153
|
+
console.log('Skipping test: no SQLite driver available');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
// Ensure test directory exists
|
|
157
|
+
mkdirSync(TEST_DIR, { recursive: true });
|
|
158
|
+
const testPath = join(TEST_DIR, `test-open-existing-${Date.now()}.db`);
|
|
159
|
+
testPaths.push(testPath);
|
|
160
|
+
// Create first
|
|
161
|
+
const db1 = await createDatabaseAsync(testPath);
|
|
162
|
+
testDatabases.push(db1);
|
|
163
|
+
closeDatabase(db1);
|
|
164
|
+
testDatabases.pop(); // Remove from tracking since we closed it
|
|
165
|
+
// Open existing
|
|
166
|
+
const db2 = await openDatabaseAsync(testPath);
|
|
167
|
+
testDatabases.push(db2);
|
|
168
|
+
expect(db2.open).toBe(true);
|
|
169
|
+
});
|
|
170
|
+
it('preserves data when reopening database', async () => {
|
|
171
|
+
if (!isBetterSqlite3Available()) {
|
|
172
|
+
console.log('Skipping test: no SQLite driver available');
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
mkdirSync(TEST_DIR, { recursive: true });
|
|
176
|
+
const testPath = join(TEST_DIR, `test-preserve-data-${Date.now()}.db`);
|
|
177
|
+
testPaths.push(testPath);
|
|
178
|
+
// Create and insert data
|
|
179
|
+
const db1 = await createDatabaseAsync(testPath);
|
|
180
|
+
db1
|
|
181
|
+
.prepare(`
|
|
182
|
+
INSERT INTO skills (id, name, description, author)
|
|
183
|
+
VALUES (?, ?, ?, ?)
|
|
184
|
+
`)
|
|
185
|
+
.run('test-skill-1', 'Test Skill', 'A test skill', 'test-author');
|
|
186
|
+
closeDatabase(db1);
|
|
187
|
+
// Reopen and verify data persists
|
|
188
|
+
const db2 = await openDatabaseAsync(testPath);
|
|
189
|
+
testDatabases.push(db2);
|
|
190
|
+
const skill = db2.prepare('SELECT * FROM skills WHERE id = ?').get('test-skill-1');
|
|
191
|
+
expect(skill).toBeDefined();
|
|
192
|
+
expect(skill.name).toBe('Test Skill');
|
|
193
|
+
expect(skill.author).toBe('test-author');
|
|
194
|
+
});
|
|
195
|
+
it('throws for non-existent file', async () => {
|
|
196
|
+
if (!isBetterSqlite3Available()) {
|
|
197
|
+
console.log('Skipping test: no SQLite driver available');
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const nonExistentPath = join(TEST_DIR, 'nonexistent', `db-${Date.now()}.sqlite`);
|
|
201
|
+
await expect(openDatabaseAsync(nonExistentPath)).rejects.toThrow(/SQLITE_CANTOPEN|unable to open|directory does not exist/);
|
|
202
|
+
});
|
|
203
|
+
it('enables foreign keys after opening', async () => {
|
|
204
|
+
if (!isBetterSqlite3Available()) {
|
|
205
|
+
console.log('Skipping test: no SQLite driver available');
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
mkdirSync(TEST_DIR, { recursive: true });
|
|
209
|
+
const testPath = join(TEST_DIR, `test-fk-open-${Date.now()}.db`);
|
|
210
|
+
testPaths.push(testPath);
|
|
211
|
+
// Create first
|
|
212
|
+
const db1 = await createDatabaseAsync(testPath);
|
|
213
|
+
closeDatabase(db1);
|
|
214
|
+
// Open and check foreign keys
|
|
215
|
+
const db2 = await openDatabaseAsync(testPath);
|
|
216
|
+
testDatabases.push(db2);
|
|
217
|
+
const result = db2.pragma('foreign_keys');
|
|
218
|
+
expect(result[0].foreign_keys).toBe(1);
|
|
219
|
+
});
|
|
220
|
+
it('runs pending migrations on open', async () => {
|
|
221
|
+
if (!isBetterSqlite3Available()) {
|
|
222
|
+
console.log('Skipping test: no SQLite driver available');
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
mkdirSync(TEST_DIR, { recursive: true });
|
|
226
|
+
const testPath = join(TEST_DIR, `test-migrations-${Date.now()}.db`);
|
|
227
|
+
testPaths.push(testPath);
|
|
228
|
+
// Create database
|
|
229
|
+
const db1 = await createDatabaseAsync(testPath);
|
|
230
|
+
closeDatabase(db1);
|
|
231
|
+
// Open and verify schema version is current
|
|
232
|
+
const db2 = await openDatabaseAsync(testPath);
|
|
233
|
+
testDatabases.push(db2);
|
|
234
|
+
const version = getSchemaVersion(db2);
|
|
235
|
+
expect(version).toBe(SCHEMA_VERSION);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
describe('FTS5 functionality with async creation', () => {
|
|
239
|
+
it('should sync FTS on insert', async () => {
|
|
240
|
+
if (!isBetterSqlite3Available()) {
|
|
241
|
+
console.log('Skipping test: no SQLite driver available');
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const db = await createDatabaseAsync(':memory:');
|
|
245
|
+
testDatabases.push(db);
|
|
246
|
+
db.prepare(`
|
|
247
|
+
INSERT INTO skills (id, name, description) VALUES (?, ?, ?)
|
|
248
|
+
`).run('fts-async-test', 'Async Searchable Skill', 'This is async searchable content');
|
|
249
|
+
const results = db
|
|
250
|
+
.prepare(`
|
|
251
|
+
SELECT * FROM skills_fts WHERE skills_fts MATCH 'async'
|
|
252
|
+
`)
|
|
253
|
+
.all();
|
|
254
|
+
expect(results.length).toBe(1);
|
|
255
|
+
});
|
|
256
|
+
it('should sync FTS on update', async () => {
|
|
257
|
+
if (!isBetterSqlite3Available()) {
|
|
258
|
+
console.log('Skipping test: no SQLite driver available');
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const db = await createDatabaseAsync(':memory:');
|
|
262
|
+
testDatabases.push(db);
|
|
263
|
+
db.prepare(`
|
|
264
|
+
INSERT INTO skills (id, name) VALUES (?, ?)
|
|
265
|
+
`).run('fts-async-update', 'Original Async Name');
|
|
266
|
+
db.prepare(`
|
|
267
|
+
UPDATE skills SET name = ? WHERE id = ?
|
|
268
|
+
`).run('Updated Async Name', 'fts-async-update');
|
|
269
|
+
const original = db
|
|
270
|
+
.prepare(`
|
|
271
|
+
SELECT * FROM skills_fts WHERE skills_fts MATCH 'original'
|
|
272
|
+
`)
|
|
273
|
+
.all();
|
|
274
|
+
const updated = db
|
|
275
|
+
.prepare(`
|
|
276
|
+
SELECT * FROM skills_fts WHERE skills_fts MATCH 'updated'
|
|
277
|
+
`)
|
|
278
|
+
.all();
|
|
279
|
+
expect(original.length).toBe(0);
|
|
280
|
+
expect(updated.length).toBe(1);
|
|
281
|
+
});
|
|
282
|
+
it('should sync FTS on delete', async () => {
|
|
283
|
+
if (!isBetterSqlite3Available()) {
|
|
284
|
+
console.log('Skipping test: no SQLite driver available');
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const db = await createDatabaseAsync(':memory:');
|
|
288
|
+
testDatabases.push(db);
|
|
289
|
+
db.prepare(`
|
|
290
|
+
INSERT INTO skills (id, name) VALUES (?, ?)
|
|
291
|
+
`).run('fts-async-delete', 'Deletable Async Skill');
|
|
292
|
+
db.prepare('DELETE FROM skills WHERE id = ?').run('fts-async-delete');
|
|
293
|
+
const results = db
|
|
294
|
+
.prepare(`
|
|
295
|
+
SELECT * FROM skills_fts WHERE skills_fts MATCH 'deletable'
|
|
296
|
+
`)
|
|
297
|
+
.all();
|
|
298
|
+
expect(results.length).toBe(0);
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
//# sourceMappingURL=schema-async.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-async.test.js","sourceRoot":"","sources":["../../../tests/db/schema-async.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AACnE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,cAAc,GACf,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAA;AAEtF,8BAA8B;AAC9B,MAAM,aAAa,GAAe,EAAE,CAAA;AACpC,MAAM,SAAS,GAAa,EAAE,CAAA;AAE9B,4CAA4C;AAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,gCAAgC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;AAE7E,QAAQ,CAAC,mCAAmC,EAAE,GAAG,EAAE;IACjD,SAAS,CAAC,GAAG,EAAE;QACb,2BAA2B;QAC3B,KAAK,MAAM,EAAE,IAAI,aAAa,EAAE,CAAC;YAC/B,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;gBACZ,aAAa,CAAC,EAAE,CAAC,CAAA;YACnB,CAAC;QACH,CAAC;QACD,aAAa,CAAC,MAAM,GAAG,CAAC,CAAA;QAExB,sBAAsB;QACtB,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACzB,UAAU,CAAC,QAAQ,CAAC,CAAA;gBACtB,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;QACH,CAAC;QACD,SAAS,CAAC,MAAM,GAAG,CAAC,CAAA;QAEpB,0BAA0B;QAC1B,IAAI,CAAC;YACH,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACzB,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;YACpD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACnC,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,8BAA8B;YAC9B,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAA;YAChD,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAEtB,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC1B,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC9B,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;YAC3C,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,+BAA+B;YAC/B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YAExC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,qBAAqB,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YACrE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAExB,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAAC,QAAQ,CAAC,CAAA;YAC9C,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAEtB,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC1B,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACzC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAA;YAChD,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAEtB,MAAM,MAAM,GAAG,EAAE;iBACd,OAAO,CAAC,yEAAyE,CAAC;iBAClF,GAAG,EAAkC,CAAA;YAExC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAA;YAC5B,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QACzC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;YAC3C,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAA;YAChD,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAEtB,MAAM,MAAM,GAAG,EAAE;iBACd,OAAO,CACN;;;;SAID,CACA;iBACA,GAAG,EAAwB,CAAA;YAE9B,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YAE5C,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;YACtC,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAA;YAC1C,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;YACvC,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAA;YAC1C,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;YACrC,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAA;QAChD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;YACxC,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAA;YAChD,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAEtB,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,cAAc,CAA+B,CAAA;YACtE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACxC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAA;YAChD,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAEtB,MAAM,OAAO,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAA;YACpC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QACtC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;YACxC,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAA;YAChD,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAEtB,MAAM,OAAO,GAAG,EAAE;iBACf,OAAO,CACN;;;SAGD,CACA;iBACA,GAAG,EAAwB,CAAA;YAE9B,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YAE7C,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAA;YACjD,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAA;YACrD,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAA;QAC1D,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;YACvC,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,+BAA+B;YAC/B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YAExC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,sBAAsB,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YACtE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAExB,eAAe;YACf,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC,QAAQ,CAAC,CAAA;YAC/C,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACvB,aAAa,CAAC,GAAG,CAAC,CAAA;YAClB,aAAa,CAAC,GAAG,EAAE,CAAA,CAAC,0CAA0C;YAE9D,gBAAgB;YAChB,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAA;YAC7C,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAEvB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC7B,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YAExC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,sBAAsB,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YACtE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAExB,yBAAyB;YACzB,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC,QAAQ,CAAC,CAAA;YAC/C,GAAG;iBACA,OAAO,CACN;;;OAGH,CACE;iBACA,GAAG,CAAC,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,CAAC,CAAA;YACnE,aAAa,CAAC,GAAG,CAAC,CAAA;YAElB,kCAAkC;YAClC,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAA;YAC7C,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAEvB,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC,GAAG,CAAC,cAAc,CAGhF,CAAA;YAED,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAA;YAC3B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;YACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QAC1C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;YAC5C,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,MAAM,eAAe,GAAG,IAAI,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;YAEhF,MAAM,MAAM,CAAC,iBAAiB,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC9D,yDAAyD,CAC1D,CAAA;QACH,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YAExC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,gBAAgB,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YAChE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAExB,eAAe;YACf,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC,QAAQ,CAAC,CAAA;YAC/C,aAAa,CAAC,GAAG,CAAC,CAAA;YAElB,8BAA8B;YAC9B,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAA;YAC7C,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAEvB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,cAAc,CAA+B,CAAA;YACvE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACxC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC/C,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YAExC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,mBAAmB,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YACnE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAExB,kBAAkB;YAClB,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC,QAAQ,CAAC,CAAA;YAC/C,aAAa,CAAC,GAAG,CAAC,CAAA;YAElB,4CAA4C;YAC5C,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAA;YAC7C,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAEvB,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAA;YACrC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QACtC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;QACtD,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;YACzC,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAA;YAChD,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAEtB,EAAE,CAAC,OAAO,CACR;;OAED,CACA,CAAC,GAAG,CAAC,gBAAgB,EAAE,wBAAwB,EAAE,kCAAkC,CAAC,CAAA;YAErF,MAAM,OAAO,GAAG,EAAE;iBACf,OAAO,CACN;;OAEH,CACE;iBACA,GAAG,EAAE,CAAA;YAER,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAChC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;YACzC,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAA;YAChD,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAEtB,EAAE,CAAC,OAAO,CACR;;OAED,CACA,CAAC,GAAG,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,CAAA;YAEhD,EAAE,CAAC,OAAO,CACR;;OAED,CACA,CAAC,GAAG,CAAC,oBAAoB,EAAE,kBAAkB,CAAC,CAAA;YAE/C,MAAM,QAAQ,GAAG,EAAE;iBAChB,OAAO,CACN;;OAEH,CACE;iBACA,GAAG,EAAE,CAAA;YAER,MAAM,OAAO,GAAG,EAAE;iBACf,OAAO,CACN;;OAEH,CACE;iBACA,GAAG,EAAE,CAAA;YAER,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YAC/B,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAChC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;YACzC,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBACxD,OAAM;YACR,CAAC;YAED,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAA;YAChD,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAEtB,EAAE,CAAC,OAAO,CACR;;OAED,CACA,CAAC,GAAG,CAAC,kBAAkB,EAAE,uBAAuB,CAAC,CAAA;YAElD,EAAE,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;YAErE,MAAM,OAAO,GAAG,EAAE;iBACf,OAAO,CACN;;OAEH,CACE;iBACA,GAAG,EAAE,CAAA;YAER,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAChC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqljs-driver.test.d.ts","sourceRoot":"","sources":["../../../tests/db/sqljs-driver.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-2182: sql.js Driver Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for the sql.js WASM driver implementation.
|
|
5
|
+
* Includes both unit tests and parity tests comparing sql.js vs better-sqlite3.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
8
|
+
import { existsSync, unlinkSync } from 'node:fs';
|
|
9
|
+
import { tmpdir } from 'node:os';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { createSqlJsDatabase, isSqlJsAvailable, } from '../../src/db/drivers/sqljsDriver.js';
|
|
12
|
+
import { createBetterSqlite3Database, isBetterSqlite3Available, } from '../../src/db/drivers/betterSqlite3Driver.js';
|
|
13
|
+
// Helper to generate unique temp file paths
|
|
14
|
+
function tempDbPath() {
|
|
15
|
+
return join(tmpdir(), `sqljs-test-${Date.now()}-${Math.random().toString(36).slice(2)}.db`);
|
|
16
|
+
}
|
|
17
|
+
// Cleanup helper
|
|
18
|
+
function cleanupFile(path) {
|
|
19
|
+
if (existsSync(path)) {
|
|
20
|
+
unlinkSync(path);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
describe('sql.js Driver', () => {
|
|
24
|
+
describe('isSqlJsAvailable', () => {
|
|
25
|
+
it('should detect sql.js is installed', () => {
|
|
26
|
+
expect(isSqlJsAvailable()).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe('createSqlJsDatabase', () => {
|
|
30
|
+
let db;
|
|
31
|
+
afterEach(() => {
|
|
32
|
+
if (db?.open) {
|
|
33
|
+
db.close();
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
it('should create an in-memory database', async () => {
|
|
37
|
+
db = await createSqlJsDatabase(':memory:');
|
|
38
|
+
expect(db).toBeDefined();
|
|
39
|
+
expect(db.open).toBe(true);
|
|
40
|
+
expect(db.memory).toBe(true);
|
|
41
|
+
expect(db.name).toBe(':memory:');
|
|
42
|
+
});
|
|
43
|
+
it('should create a file-based database', async () => {
|
|
44
|
+
const path = tempDbPath();
|
|
45
|
+
try {
|
|
46
|
+
db = await createSqlJsDatabase(path);
|
|
47
|
+
expect(db).toBeDefined();
|
|
48
|
+
expect(db.open).toBe(true);
|
|
49
|
+
expect(db.memory).toBe(false);
|
|
50
|
+
expect(db.name).toBe(path);
|
|
51
|
+
db.close();
|
|
52
|
+
expect(existsSync(path)).toBe(true);
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
cleanupFile(path);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
it('should throw when file must exist but does not', async () => {
|
|
59
|
+
const path = tempDbPath();
|
|
60
|
+
await expect(createSqlJsDatabase(path, { fileMustExist: true })).rejects.toThrow(/SQLITE_CANTOPEN/);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
describe('Database operations', () => {
|
|
64
|
+
let db;
|
|
65
|
+
beforeEach(async () => {
|
|
66
|
+
db = await createSqlJsDatabase(':memory:');
|
|
67
|
+
});
|
|
68
|
+
afterEach(() => {
|
|
69
|
+
if (db?.open) {
|
|
70
|
+
db.close();
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
it('should execute raw SQL with exec()', () => {
|
|
74
|
+
db.exec(`
|
|
75
|
+
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);
|
|
76
|
+
INSERT INTO users (name) VALUES ('Alice');
|
|
77
|
+
`);
|
|
78
|
+
const stmt = db.prepare('SELECT * FROM users');
|
|
79
|
+
const rows = stmt.all();
|
|
80
|
+
stmt.finalize();
|
|
81
|
+
expect(rows).toHaveLength(1);
|
|
82
|
+
expect(rows[0]).toEqual({ id: 1, name: 'Alice' });
|
|
83
|
+
});
|
|
84
|
+
it('should prepare and execute statements', () => {
|
|
85
|
+
db.exec('CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, price REAL)');
|
|
86
|
+
const insert = db.prepare('INSERT INTO products (name, price) VALUES (?, ?)');
|
|
87
|
+
const result1 = insert.run('Widget', 9.99);
|
|
88
|
+
const result2 = insert.run('Gadget', 19.99);
|
|
89
|
+
insert.finalize();
|
|
90
|
+
expect(result1.changes).toBe(1);
|
|
91
|
+
expect(result1.lastInsertRowid).toBe(1);
|
|
92
|
+
expect(result2.lastInsertRowid).toBe(2);
|
|
93
|
+
const select = db.prepare('SELECT name, price FROM products');
|
|
94
|
+
const products = select.all();
|
|
95
|
+
select.finalize();
|
|
96
|
+
expect(products).toHaveLength(2);
|
|
97
|
+
expect(products[0]).toEqual({ name: 'Widget', price: 9.99 });
|
|
98
|
+
expect(products[1]).toEqual({ name: 'Gadget', price: 19.99 });
|
|
99
|
+
});
|
|
100
|
+
it('should get single row', () => {
|
|
101
|
+
db.exec(`
|
|
102
|
+
CREATE TABLE items (id INTEGER PRIMARY KEY, value TEXT);
|
|
103
|
+
INSERT INTO items (value) VALUES ('first'), ('second');
|
|
104
|
+
`);
|
|
105
|
+
const stmt = db.prepare('SELECT * FROM items WHERE id = ?');
|
|
106
|
+
const row = stmt.get(1);
|
|
107
|
+
const noRow = stmt.get(999);
|
|
108
|
+
stmt.finalize();
|
|
109
|
+
expect(row).toEqual({ id: 1, value: 'first' });
|
|
110
|
+
expect(noRow).toBeUndefined();
|
|
111
|
+
});
|
|
112
|
+
it('should iterate over rows', () => {
|
|
113
|
+
db.exec(`
|
|
114
|
+
CREATE TABLE numbers (n INTEGER);
|
|
115
|
+
INSERT INTO numbers (n) VALUES (1), (2), (3), (4), (5);
|
|
116
|
+
`);
|
|
117
|
+
const stmt = db.prepare('SELECT n FROM numbers');
|
|
118
|
+
const values = [];
|
|
119
|
+
for (const row of stmt.iterate()) {
|
|
120
|
+
values.push(row.n);
|
|
121
|
+
}
|
|
122
|
+
stmt.finalize();
|
|
123
|
+
expect(values).toEqual([1, 2, 3, 4, 5]);
|
|
124
|
+
});
|
|
125
|
+
it('should handle transactions', () => {
|
|
126
|
+
db.exec('CREATE TABLE accounts (id INTEGER PRIMARY KEY, balance INTEGER)');
|
|
127
|
+
db.exec('INSERT INTO accounts (balance) VALUES (100), (200)');
|
|
128
|
+
const transfer = (from, to, amount) => {
|
|
129
|
+
// transaction() returns a callable function
|
|
130
|
+
const txn = db.transaction(() => {
|
|
131
|
+
db.prepare('UPDATE accounts SET balance = balance - ? WHERE id = ?').run(amount, from);
|
|
132
|
+
db.prepare('UPDATE accounts SET balance = balance + ? WHERE id = ?').run(amount, to);
|
|
133
|
+
});
|
|
134
|
+
txn(); // Execute the transaction
|
|
135
|
+
};
|
|
136
|
+
transfer(1, 2, 50);
|
|
137
|
+
const stmt = db.prepare('SELECT * FROM accounts ORDER BY id');
|
|
138
|
+
const accounts = stmt.all();
|
|
139
|
+
stmt.finalize();
|
|
140
|
+
expect(accounts[0].balance).toBe(50);
|
|
141
|
+
expect(accounts[1].balance).toBe(250);
|
|
142
|
+
});
|
|
143
|
+
it('should rollback transaction on error', () => {
|
|
144
|
+
db.exec('CREATE TABLE test (value INTEGER)');
|
|
145
|
+
db.exec('INSERT INTO test (value) VALUES (1)');
|
|
146
|
+
// transaction() returns a callable function
|
|
147
|
+
const txn = db.transaction(() => {
|
|
148
|
+
db.exec('UPDATE test SET value = 2');
|
|
149
|
+
throw new Error('Intentional failure');
|
|
150
|
+
});
|
|
151
|
+
expect(() => {
|
|
152
|
+
txn(); // Execute the transaction - should throw
|
|
153
|
+
}).toThrow('Intentional failure');
|
|
154
|
+
const stmt = db.prepare('SELECT value FROM test');
|
|
155
|
+
const row = stmt.get();
|
|
156
|
+
stmt.finalize();
|
|
157
|
+
expect(row?.value).toBe(1); // Rolled back
|
|
158
|
+
});
|
|
159
|
+
it('should handle pragmas', () => {
|
|
160
|
+
// Set a pragma
|
|
161
|
+
db.pragma('cache_size = 10000');
|
|
162
|
+
// Get a pragma value
|
|
163
|
+
const foreignKeys = db.pragma('foreign_keys');
|
|
164
|
+
expect(foreignKeys).toBe(1); // Default ON in our driver
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
describe('File persistence', () => {
|
|
168
|
+
it('should persist data across open/close cycles', async () => {
|
|
169
|
+
const path = tempDbPath();
|
|
170
|
+
try {
|
|
171
|
+
// Create and populate database
|
|
172
|
+
const db1 = await createSqlJsDatabase(path);
|
|
173
|
+
db1.exec('CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)');
|
|
174
|
+
db1.exec("INSERT INTO test (value) VALUES ('persisted')");
|
|
175
|
+
db1.close();
|
|
176
|
+
// Reopen and verify data
|
|
177
|
+
const db2 = await createSqlJsDatabase(path);
|
|
178
|
+
const stmt = db2.prepare('SELECT value FROM test');
|
|
179
|
+
const row = stmt.get();
|
|
180
|
+
stmt.finalize();
|
|
181
|
+
db2.close();
|
|
182
|
+
expect(row?.value).toBe('persisted');
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
cleanupFile(path);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
it('should export database as Uint8Array', async () => {
|
|
189
|
+
const db = await createSqlJsDatabase(':memory:');
|
|
190
|
+
db.exec('CREATE TABLE test (id INTEGER)');
|
|
191
|
+
db.exec('INSERT INTO test (id) VALUES (1), (2), (3)');
|
|
192
|
+
const data = db.export();
|
|
193
|
+
db.close();
|
|
194
|
+
expect(data).toBeInstanceOf(Uint8Array);
|
|
195
|
+
expect(data.length).toBeGreaterThan(0);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
// Parity tests - comparing sql.js with better-sqlite3
|
|
200
|
+
describe('Driver Parity Tests', () => {
|
|
201
|
+
// Skip if better-sqlite3 is not available (e.g., on macOS without Docker)
|
|
202
|
+
const hasBetterSqlite3 = isBetterSqlite3Available();
|
|
203
|
+
describe.skipIf(!hasBetterSqlite3)('sql.js vs better-sqlite3', () => {
|
|
204
|
+
let sqlJsDb;
|
|
205
|
+
let betterSqliteDb;
|
|
206
|
+
beforeEach(async () => {
|
|
207
|
+
sqlJsDb = await createSqlJsDatabase(':memory:');
|
|
208
|
+
betterSqliteDb = createBetterSqlite3Database(':memory:');
|
|
209
|
+
// Create identical schema
|
|
210
|
+
const schema = `
|
|
211
|
+
CREATE TABLE skills (
|
|
212
|
+
id INTEGER PRIMARY KEY,
|
|
213
|
+
name TEXT NOT NULL,
|
|
214
|
+
author TEXT NOT NULL,
|
|
215
|
+
description TEXT,
|
|
216
|
+
score REAL DEFAULT 0
|
|
217
|
+
);
|
|
218
|
+
CREATE INDEX idx_skills_author ON skills(author);
|
|
219
|
+
`;
|
|
220
|
+
sqlJsDb.exec(schema);
|
|
221
|
+
betterSqliteDb.exec(schema);
|
|
222
|
+
});
|
|
223
|
+
afterEach(() => {
|
|
224
|
+
sqlJsDb?.close();
|
|
225
|
+
betterSqliteDb?.close();
|
|
226
|
+
});
|
|
227
|
+
it('should return identical results for INSERT', () => {
|
|
228
|
+
const sql = 'INSERT INTO skills (name, author, description, score) VALUES (?, ?, ?, ?)';
|
|
229
|
+
const sqlJsStmt = sqlJsDb.prepare(sql);
|
|
230
|
+
const betterStmt = betterSqliteDb.prepare(sql);
|
|
231
|
+
const sqlJsResult = sqlJsStmt.run('test-skill', 'test-author', 'A test skill', 85.5);
|
|
232
|
+
const betterResult = betterStmt.run('test-skill', 'test-author', 'A test skill', 85.5);
|
|
233
|
+
sqlJsStmt.finalize();
|
|
234
|
+
betterStmt.finalize();
|
|
235
|
+
expect(sqlJsResult.changes).toBe(betterResult.changes);
|
|
236
|
+
expect(Number(sqlJsResult.lastInsertRowid)).toBe(Number(betterResult.lastInsertRowid));
|
|
237
|
+
});
|
|
238
|
+
it('should return identical results for SELECT', () => {
|
|
239
|
+
// Insert test data - use exec for simple inserts without needing statement cleanup
|
|
240
|
+
sqlJsDb.exec("INSERT INTO skills (name, author, score) VALUES ('skill-a', 'author-1', 90)");
|
|
241
|
+
sqlJsDb.exec("INSERT INTO skills (name, author, score) VALUES ('skill-b', 'author-2', 80)");
|
|
242
|
+
betterSqliteDb.exec("INSERT INTO skills (name, author, score) VALUES ('skill-a', 'author-1', 90)");
|
|
243
|
+
betterSqliteDb.exec("INSERT INTO skills (name, author, score) VALUES ('skill-b', 'author-2', 80)");
|
|
244
|
+
// Query and compare
|
|
245
|
+
const query = 'SELECT * FROM skills ORDER BY name';
|
|
246
|
+
const sqlJsStmt = sqlJsDb.prepare(query);
|
|
247
|
+
const betterStmt = betterSqliteDb.prepare(query);
|
|
248
|
+
const sqlJsRows = sqlJsStmt.all();
|
|
249
|
+
const betterRows = betterStmt.all();
|
|
250
|
+
sqlJsStmt.finalize();
|
|
251
|
+
betterStmt.finalize();
|
|
252
|
+
expect(sqlJsRows).toEqual(betterRows);
|
|
253
|
+
});
|
|
254
|
+
it('should return identical results for UPDATE', () => {
|
|
255
|
+
// Insert test data
|
|
256
|
+
sqlJsDb.exec("INSERT INTO skills (name, author) VALUES ('skill', 'author')");
|
|
257
|
+
betterSqliteDb.exec("INSERT INTO skills (name, author) VALUES ('skill', 'author')");
|
|
258
|
+
const update = 'UPDATE skills SET score = ? WHERE name = ?';
|
|
259
|
+
const sqlJsStmt = sqlJsDb.prepare(update);
|
|
260
|
+
const betterStmt = betterSqliteDb.prepare(update);
|
|
261
|
+
const sqlJsResult = sqlJsStmt.run(100, 'skill');
|
|
262
|
+
const betterResult = betterStmt.run(100, 'skill');
|
|
263
|
+
sqlJsStmt.finalize();
|
|
264
|
+
betterStmt.finalize();
|
|
265
|
+
expect(sqlJsResult.changes).toBe(betterResult.changes);
|
|
266
|
+
});
|
|
267
|
+
it('should return identical results for DELETE', () => {
|
|
268
|
+
// Insert test data
|
|
269
|
+
sqlJsDb.exec("INSERT INTO skills (name, author) VALUES ('to-delete', 'author')");
|
|
270
|
+
betterSqliteDb.exec("INSERT INTO skills (name, author) VALUES ('to-delete', 'author')");
|
|
271
|
+
const del = 'DELETE FROM skills WHERE name = ?';
|
|
272
|
+
const sqlJsStmt = sqlJsDb.prepare(del);
|
|
273
|
+
const betterStmt = betterSqliteDb.prepare(del);
|
|
274
|
+
const sqlJsResult = sqlJsStmt.run('to-delete');
|
|
275
|
+
const betterResult = betterStmt.run('to-delete');
|
|
276
|
+
sqlJsStmt.finalize();
|
|
277
|
+
betterStmt.finalize();
|
|
278
|
+
expect(sqlJsResult.changes).toBe(betterResult.changes);
|
|
279
|
+
});
|
|
280
|
+
it('should handle transactions identically', () => {
|
|
281
|
+
// Insert initial data
|
|
282
|
+
sqlJsDb.exec("INSERT INTO skills (name, author, score) VALUES ('skill', 'author', 50)");
|
|
283
|
+
betterSqliteDb.exec("INSERT INTO skills (name, author, score) VALUES ('skill', 'author', 50)");
|
|
284
|
+
// Transaction that modifies and reads - transaction() returns a callable
|
|
285
|
+
const executeTransaction = (db) => {
|
|
286
|
+
const txn = db.transaction(() => {
|
|
287
|
+
db.prepare('UPDATE skills SET score = score + 10').run();
|
|
288
|
+
return db.prepare('SELECT score FROM skills').get();
|
|
289
|
+
});
|
|
290
|
+
return txn(); // Call the transaction function
|
|
291
|
+
};
|
|
292
|
+
const sqlJsResult = executeTransaction(sqlJsDb);
|
|
293
|
+
const betterResult = executeTransaction(betterSqliteDb);
|
|
294
|
+
expect(sqlJsResult).toEqual(betterResult);
|
|
295
|
+
expect(sqlJsResult?.score).toBe(60);
|
|
296
|
+
});
|
|
297
|
+
it('should handle NULL values identically', () => {
|
|
298
|
+
// Insert with NULL description
|
|
299
|
+
sqlJsDb.exec("INSERT INTO skills (name, author) VALUES ('nullable', 'author')");
|
|
300
|
+
betterSqliteDb.exec("INSERT INTO skills (name, author) VALUES ('nullable', 'author')");
|
|
301
|
+
const query = 'SELECT * FROM skills WHERE name = ?';
|
|
302
|
+
const sqlJsStmt = sqlJsDb.prepare(query);
|
|
303
|
+
const betterStmt = betterSqliteDb.prepare(query);
|
|
304
|
+
const sqlJsRow = sqlJsStmt.get('nullable');
|
|
305
|
+
const betterRow = betterStmt.get('nullable');
|
|
306
|
+
sqlJsStmt.finalize();
|
|
307
|
+
betterStmt.finalize();
|
|
308
|
+
expect(sqlJsRow).toEqual(betterRow);
|
|
309
|
+
});
|
|
310
|
+
it('should return undefined for non-existent rows', () => {
|
|
311
|
+
const query = 'SELECT * FROM skills WHERE id = ?';
|
|
312
|
+
const sqlJsStmt = sqlJsDb.prepare(query);
|
|
313
|
+
const betterStmt = betterSqliteDb.prepare(query);
|
|
314
|
+
const sqlJsRow = sqlJsStmt.get(99999);
|
|
315
|
+
const betterRow = betterStmt.get(99999);
|
|
316
|
+
sqlJsStmt.finalize();
|
|
317
|
+
betterStmt.finalize();
|
|
318
|
+
expect(sqlJsRow).toBeUndefined();
|
|
319
|
+
expect(betterRow).toBeUndefined();
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
//# sourceMappingURL=sqljs-driver.test.js.map
|