diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c06fd60..a56226b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,14 +12,17 @@ concurrency: group: ci-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: build-typecheck-test: name: Build, typecheck & test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 cache: npm diff --git a/tests/benchmarks/native_worker_ddl_batch.ts b/tests/benchmarks/native_worker_ddl_batch.ts index 0f4a436..1883155 100644 --- a/tests/benchmarks/native_worker_ddl_batch.ts +++ b/tests/benchmarks/native_worker_ddl_batch.ts @@ -1,52 +1,68 @@ import '../unit/vscode_mock_setup'; import { createNativeDatabaseConnection } from '../../src/nativeWorker'; +import type { ModificationEntry } from '../../src/core/types'; import * as vscode from 'vscode'; import * as path from 'path'; +import * as fs from 'fs/promises'; async function runBenchmark() { const bundle = await createNativeDatabaseConnection(vscode.Uri.file(process.cwd())); - const loadResult = await (bundle as any).loadDatabase({ buffer: new Uint8Array() }); - const db = loadResult.databaseOps; - - // create table - await db.createTable('test_table', [ - { name: 'id', type: 'INTEGER', primaryKey: true }, - ...Array.from({ length: 50 }, (_, i) => ({ name: `col_${i}`, type: 'TEXT' })) - ]); - - // insert row - await db.insertRow('test_table', { - id: 1, - ...Object.fromEntries(Array.from({ length: 50 }, (_, i) => [`col_${i}`, `val_${i}`])) - }); - - const mod = { - modificationType: 'column_drop' as const, - targetTable: 'test_table', - deletedColumns: Array.from({ length: 50 }, (_, i) => ({ - name: `col_${i}`, - type: 'TEXT', - data: [{ rowId: 1, value: `val_${i}` }] - })) - }; - - console.log('Warming up...'); - - // warmup - await db.undoModification(mod); - await db.redoModification(mod); - - console.log('Running benchmark...'); - - const start = performance.now(); - for (let i = 0; i < 5; i++) { + // The native API opens a file URI, so the benchmark uses a unique local database and removes it after disposal. + const databasePath = path.join(process.cwd(), `native_worker_ddl_batch_${process.pid}_${Date.now()}.sqlite`); + + try { + const { databaseOps: db } = await bundle.establishConnection( + vscode.Uri.file(databasePath), + path.basename(databasePath) + ); + + // create table + await db.createTable('test_table', [ + { name: 'id', type: 'INTEGER', primaryKey: true, notNull: false }, + ...Array.from({ length: 50 }, (_, i) => ({ + name: `col_${i}`, + type: 'TEXT', + primaryKey: false, + notNull: false + })) + ]); + + // insert row + await db.insertRow('test_table', { + id: 1, + ...Object.fromEntries(Array.from({ length: 50 }, (_, i) => [`col_${i}`, `val_${i}`])) + }); + + const mod = { + description: 'Drop benchmark columns', + modificationType: 'column_drop' as const, + targetTable: 'test_table', + deletedColumns: Array.from({ length: 50 }, (_, i) => ({ + name: `col_${i}`, + type: 'TEXT', + data: [{ rowId: 1, value: `val_${i}` }] + })) + } satisfies ModificationEntry; + + console.log('Warming up...'); + + // warmup await db.undoModification(mod); await db.redoModification(mod); - } - const end = performance.now(); - console.log(`Time taken: ${(end - start).toFixed(2)}ms`); - bundle.workerMethods[Symbol.dispose](); + console.log('Running benchmark...'); + + const start = performance.now(); + for (let i = 0; i < 5; i++) { + await db.undoModification(mod); + await db.redoModification(mod); + } + const end = performance.now(); + console.log(`Time taken: ${(end - start).toFixed(2)}ms`); + } finally { + bundle.workerMethods[Symbol.dispose](); + await fs.rm(databasePath, { force: true }); + } } runBenchmark().catch(console.error); diff --git a/tests/unit/workerFactory.test.ts b/tests/unit/workerFactory.test.ts index 137e0e5..3642f34 100644 --- a/tests/unit/workerFactory.test.ts +++ b/tests/unit/workerFactory.test.ts @@ -84,11 +84,19 @@ describe('workerFactory error path tests', () => { workerTerminated = false; // Reset VSCode mock behaviors - mockVscode.workspace.fs = { - readFile: async () => new Uint8Array(), - stat: async () => ({ size: 0 }) - } as any; - (mockVscode.Uri as any).joinPath = () => ({ scheme: 'file', fsPath: '/test/path/assets/sqlite3.wasm' }); + Object.defineProperty(mockVscode.workspace, 'fs', { + value: { + readFile: async () => new Uint8Array(), + stat: async () => ({ size: 0 }) + }, + writable: true, + configurable: true + }); + Object.defineProperty(mockVscode.Uri, 'joinPath', { + value: () => ({ scheme: 'file', fsPath: '/test/path/assets/sqlite3.wasm' }), + writable: true, + configurable: true + }); }); afterEach(() => { diff --git a/website/app/globals.css b/website/app/globals.css index 69cdb57..af8a3f5 100644 --- a/website/app/globals.css +++ b/website/app/globals.css @@ -18,8 +18,8 @@ --color-accent: var(--ui-accent); --color-accent-foreground: var(--ui-accent-fg); - --font-sans: var(--font-sans), system-ui, sans-serif; - --font-mono: var(--font-mono), monospace; + --font-sans: var(--font-sans-stack); + --font-mono: var(--font-mono-stack); --animate-fade-in: fadeIn 0.5s ease-out; --animate-slide-up: slideUp 0.5s ease-out; @@ -44,6 +44,36 @@ } } +:root { + /* Light theme (default) */ + --ui-bg: #ffffff; + --ui-fg: #171717; + --ui-subtle: #f5f5f5; + --ui-subtle-fg: #737373; + --ui-edge: #e5e5e5; + --ui-accent: #0070f3; + --ui-accent-fg: #ffffff; + + /* Typography */ + --font-sans-stack: + var(--font-inter), -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + 'Helvetica Neue', Arial, sans-serif; + --font-mono-stack: 'SF Mono', 'Fira Code', 'Fira Mono', 'Roboto Mono', monospace; + --font-sans: var(--font-sans-stack); + --font-mono: var(--font-mono-stack); +} + +.dark { + /* Dark theme */ + --ui-bg: #0a0a0a; + --ui-fg: #ededed; + --ui-subtle: #1a1a1a; + --ui-subtle-fg: #a3a3a3; + --ui-edge: #262626; + --ui-accent: #0070f3; + --ui-accent-fg: #ffffff; +} + /* The default border color has changed to `currentcolor` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still @@ -60,46 +90,6 @@ ::file-selector-button { border-color: var(--color-gray-200, currentcolor); } -} - -@utility text-balance { - text-wrap: balance; -} -@utility text-gradient { - background: linear-gradient(to right, var(--ui-fg), var(--ui-subtle-fg)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -@layer utilities { - :root { - /* Light theme (default) */ - --ui-bg: #ffffff; - --ui-fg: #171717; - --ui-subtle: #f5f5f5; - --ui-subtle-fg: #737373; - --ui-edge: #e5e5e5; - --ui-accent: #0070f3; - --ui-accent-fg: #ffffff; - - /* Typography */ - --font-sans: - var(--font-inter), -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, - 'Helvetica Neue', Arial, sans-serif; - --font-mono: 'SF Mono', 'Fira Code', 'Fira Mono', 'Roboto Mono', monospace; - } - - .dark { - /* Dark theme */ - --ui-bg: #0a0a0a; - --ui-fg: #ededed; - --ui-subtle: #1a1a1a; - --ui-subtle-fg: #a3a3a3; - --ui-edge: #262626; - --ui-accent: #0070f3; - --ui-accent-fg: #ffffff; - } /* Base styles */ * { @@ -121,8 +111,16 @@ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } +} - /* Utility classes */ +@utility text-balance { + text-wrap: balance; +} +@utility text-gradient { + background: linear-gradient(to right, var(--ui-fg), var(--ui-subtle-fg)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; } /* Selection styling */