From 399353986fd417dc12f1ab18cea72904cce301d1 Mon Sep 17 00:00:00 2001 From: Andrey Avtomonov Date: Mon, 11 May 2026 10:20:45 +0200 Subject: [PATCH] feat: use managed runtime for sl query compute --- packages/cli/src/sl.test.ts | 67 +++++++++++++++++++++++++++++++++++++ packages/cli/src/sl.ts | 21 ++++++++++-- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/sl.test.ts b/packages/cli/src/sl.test.ts index d623e35b..bd746b0b 100644 --- a/packages/cli/src/sl.test.ts +++ b/packages/cli/src/sl.test.ts @@ -129,6 +129,8 @@ joins: [] query: { measures: ['orders.order_count'], dimensions: [] }, format: 'sql', execute: false, + cliVersion: '0.2.0', + runtimeInstallPolicy: 'auto', }, { stdout, stderr }, { loadProject, createSemanticLayerCompute }, @@ -139,6 +141,67 @@ joins: [] expect(stderr.write).not.toHaveBeenCalled(); }); + it('creates default sl query compute through the managed runtime helper', async () => { + const projectDir = join(tempDir, 'project'); + const project = await initKtxProject({ projectDir, projectName: 'warehouse' }); + project.config.connections.warehouse = { driver: 'postgres', readonly: true }; + await project.fileStore.writeFile( + 'semantic-layer/warehouse/orders.yaml', + `name: orders +table: public.orders +grain: [id] +columns: + - name: id + type: number +measures: + - name: order_count + expr: count(*) +joins: [] +`, + 'ktx', + 'ktx@example.com', + 'Add orders source', + ); + + const stdout = { write: vi.fn() }; + const stderr = { write: vi.fn() }; + const compute = { + query: vi.fn(async () => ({ + sql: 'select count(*) as order_count from public.orders', + dialect: 'postgres', + columns: [{ name: 'orders.order_count' }], + plan: {}, + })), + validateSources: vi.fn(), + generateSources: vi.fn(), + }; + const createManagedSemanticLayerCompute = vi.fn(async () => compute); + + await expect( + runKtxSl( + { + command: 'query', + projectDir, + connectionId: 'warehouse', + query: { measures: ['orders.order_count'], dimensions: [] }, + format: 'sql', + execute: false, + cliVersion: '0.2.0', + runtimeInstallPolicy: 'auto', + }, + { stdout, stderr }, + { createManagedSemanticLayerCompute }, + ), + ).resolves.toBe(0); + + expect(createManagedSemanticLayerCompute).toHaveBeenCalledWith({ + cliVersion: '0.2.0', + installPolicy: 'auto', + io: { stdout, stderr }, + }); + expect(stdout.write).toHaveBeenCalledWith('select count(*) as order_count from public.orders\n'); + }); + it('executes sl query through the injected query executor', async () => { const projectDir = join(tempDir, 'project'); const project = await initKtxProject({ projectDir, projectName: 'warehouse' }); @@ -194,6 +257,8 @@ joins: [] format: 'json', execute: true, maxRows: 20, + cliVersion: '0.2.0', + runtimeInstallPolicy: 'auto', }, { stdout, stderr }, { @@ -292,6 +357,8 @@ joins: [] format: 'json', execute: true, maxRows: 20, + cliVersion: '0.2.0', + runtimeInstallPolicy: 'auto', }, { stdout, stderr }, { createSemanticLayerCompute }, diff --git a/packages/cli/src/sl.ts b/packages/cli/src/sl.ts index 17087328..a82f84d8 100644 --- a/packages/cli/src/sl.ts +++ b/packages/cli/src/sl.ts @@ -1,5 +1,5 @@ import { createDefaultLocalQueryExecutor, type KtxSqlQueryExecutorPort } from '@ktx/context/connections'; -import { createPythonSemanticLayerComputePort, type KtxSemanticLayerComputePort } from '@ktx/context/daemon'; +import type { KtxSemanticLayerComputePort } from '@ktx/context/daemon'; import { loadKtxProject, type KtxLocalProject } from '@ktx/context/project'; import { compileLocalSlQuery, @@ -9,6 +9,10 @@ import { writeLocalSlSource, type SemanticLayerQueryInput, } from '@ktx/context/sl'; +import { + createManagedPythonSemanticLayerComputePort, + type KtxManagedPythonInstallPolicy, +} from './managed-python-command.js'; import { profileMark } from './startup-profile.js'; profileMark('module:sl'); @@ -28,6 +32,8 @@ export type KtxSlArgs = format: SlQueryFormat; execute: boolean; maxRows?: number; + cliVersion: string; + runtimeInstallPolicy: KtxManagedPythonInstallPolicy; }; interface KtxSlIo { @@ -38,6 +44,11 @@ interface KtxSlIo { interface KtxSlDeps { loadProject?: typeof loadKtxProject; createSemanticLayerCompute?: () => KtxSemanticLayerComputePort; + createManagedSemanticLayerCompute?: (options: { + cliVersion: string; + installPolicy: KtxManagedPythonInstallPolicy; + io: KtxSlIo; + }) => Promise; createQueryExecutor?: () => KtxSqlQueryExecutorPort; } @@ -97,7 +108,13 @@ export async function runKtxSl(args: KtxSlArgs, io: KtxSlIo = process, deps: Ktx return 0; } if (args.command === 'query') { - const compute = (deps.createSemanticLayerCompute ?? createPythonSemanticLayerComputePort)(); + const compute = deps.createSemanticLayerCompute + ? deps.createSemanticLayerCompute() + : await (deps.createManagedSemanticLayerCompute ?? createManagedPythonSemanticLayerComputePort)({ + cliVersion: args.cliVersion, + installPolicy: args.runtimeInstallPolicy, + io, + }); const queryExecutor = args.execute ? (deps.createQueryExecutor ?? createDefaultLocalQueryExecutor)() : undefined; const result = await compileLocalSlQuery(project as KtxLocalProject, { connectionId: args.connectionId,