Actual query function
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
"dependencies": {
|
||||
"@clickhouse/client": "^1.12.1",
|
||||
"@internal/tracing": "workspace:*",
|
||||
"@internal/tsql": "workspace:*",
|
||||
"@trigger.dev/core": "workspace:*",
|
||||
"zod": "3.25.76",
|
||||
"zod-error": "1.5.0"
|
||||
|
||||
@@ -7,9 +7,13 @@
|
||||
|
||||
import type { ClickHouseSettings } from "@clickhouse/client";
|
||||
import { z } from "zod";
|
||||
import { compileTSQL, type TableSchema, type QuerySettings } from "@internal/tsql";
|
||||
import type { ClickhouseReader } from "./types.js";
|
||||
import { QueryError } from "./errors.js";
|
||||
|
||||
// Re-export TableSchema for convenience
|
||||
export type { TableSchema, QuerySettings };
|
||||
|
||||
/**
|
||||
* Options for executing a TSQL query
|
||||
*/
|
||||
@@ -27,49 +31,11 @@ export interface ExecuteTSQLOptions<TOut extends z.ZodSchema> {
|
||||
/** The environment ID for tenant isolation */
|
||||
environmentId: string;
|
||||
/** Schema registry defining allowed tables and columns */
|
||||
tableSchema: TSQLTableSchema[];
|
||||
tableSchema: TableSchema[];
|
||||
/** Optional ClickHouse query settings */
|
||||
settings?: ClickHouseSettings;
|
||||
/** Maximum number of rows to return (default: 10000) */
|
||||
maxRows?: number;
|
||||
/** Timezone for date/time operations (default: UTC) */
|
||||
timezone?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schema definition for a table accessible via TSQL
|
||||
*/
|
||||
export interface TSQLTableSchema {
|
||||
/** The name of the table as used in TSQL queries */
|
||||
name: string;
|
||||
/** The fully qualified ClickHouse table name */
|
||||
clickhouseName: string;
|
||||
/** Column definitions */
|
||||
columns: Record<string, TSQLColumnSchema>;
|
||||
/** Tenant isolation column configuration */
|
||||
tenantColumns: {
|
||||
organizationId: string;
|
||||
projectId: string;
|
||||
environmentId: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Schema definition for a column
|
||||
*/
|
||||
export interface TSQLColumnSchema {
|
||||
/** The column name */
|
||||
name: string;
|
||||
/** The ClickHouse column name (if different from name) */
|
||||
clickhouseName?: string;
|
||||
/** Whether the column can be selected */
|
||||
selectable?: boolean;
|
||||
/** Whether the column can be used in WHERE */
|
||||
filterable?: boolean;
|
||||
/** Whether the column can be used in ORDER BY */
|
||||
sortable?: boolean;
|
||||
/** Whether the column can be used in GROUP BY */
|
||||
groupable?: boolean;
|
||||
clickhouseSettings?: ClickHouseSettings;
|
||||
/** Optional TSQL query settings (maxRows, timezone, etc.) */
|
||||
querySettings?: Partial<QuerySettings>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,11 +47,8 @@ export type TSQLQueryResult<T> = [QueryError, null] | [null, T[]];
|
||||
* Execute a TSQL query against ClickHouse
|
||||
*
|
||||
* This function:
|
||||
* 1. Parses the TSQL query into an AST
|
||||
* 2. Validates tables and columns against the schema
|
||||
* 3. Injects tenant isolation WHERE clauses
|
||||
* 4. Generates parameterized ClickHouse SQL
|
||||
* 5. Executes the query and returns validated results
|
||||
* 1. Compiles the TSQL query to ClickHouse SQL (parse, validate, inject tenant guards)
|
||||
* 2. Executes the query and returns validated results
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
@@ -104,43 +67,23 @@ export async function executeTSQL<TOut extends z.ZodSchema>(
|
||||
reader: ClickhouseReader,
|
||||
options: ExecuteTSQLOptions<TOut>
|
||||
): Promise<TSQLQueryResult<z.output<TOut>>> {
|
||||
// Lazy import to avoid circular dependencies and keep the TSQL package optional
|
||||
const {
|
||||
parseTSQLSelect,
|
||||
createPrinterContext,
|
||||
createSchemaRegistry,
|
||||
printToClickHouse,
|
||||
} = await import("@internal/tsql");
|
||||
|
||||
try {
|
||||
// 1. Parse the TSQL query
|
||||
const ast = parseTSQLSelect(options.query);
|
||||
|
||||
// 2. Create schema registry from table schemas
|
||||
const schemaRegistry = createSchemaRegistry(options.tableSchema);
|
||||
|
||||
// 3. Create printer context with tenant IDs
|
||||
const context = createPrinterContext({
|
||||
// 1. Compile the TSQL query to ClickHouse SQL
|
||||
const { sql, params } = compileTSQL(options.query, {
|
||||
organizationId: options.organizationId,
|
||||
projectId: options.projectId,
|
||||
environmentId: options.environmentId,
|
||||
schema: schemaRegistry,
|
||||
settings: {
|
||||
maxRows: options.maxRows ?? 10000,
|
||||
timezone: options.timezone ?? "UTC",
|
||||
},
|
||||
tableSchema: options.tableSchema,
|
||||
settings: options.querySettings,
|
||||
});
|
||||
|
||||
// 4. Print the AST to ClickHouse SQL
|
||||
const { sql, params } = printToClickHouse(ast, context);
|
||||
|
||||
// 5. Execute the query
|
||||
// 2. Execute the query
|
||||
const queryFn = reader.query({
|
||||
name: options.name,
|
||||
query: sql,
|
||||
params: z.record(z.any()),
|
||||
schema: options.schema,
|
||||
settings: options.settings,
|
||||
settings: options.clickhouseSettings,
|
||||
});
|
||||
|
||||
return await queryFn(params);
|
||||
@@ -169,7 +112,7 @@ export async function executeTSQL<TOut extends z.ZodSchema>(
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export function createTSQLExecutor(reader: ClickhouseReader, tableSchema: TSQLTableSchema[]) {
|
||||
export function createTSQLExecutor(reader: ClickhouseReader, tableSchema: TableSchema[]) {
|
||||
return {
|
||||
execute: <TOut extends z.ZodSchema>(
|
||||
options: Omit<ExecuteTSQLOptions<TOut>, "tableSchema">
|
||||
@@ -178,4 +121,3 @@ export function createTSQLExecutor(reader: ClickhouseReader, tableSchema: TSQLTa
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
"types": "./src/index.ts",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@internal/clickhouse": "workspace:*",
|
||||
"@trigger.dev/core": "workspace:*",
|
||||
"antlr4ts": "0.5.0-alpha.4",
|
||||
"zod": "3.25.76"
|
||||
|
||||
@@ -9,6 +9,9 @@ import { TSQLParser } from "./grammar/TSQLParser.js";
|
||||
import { TSQLParseTreeConverter } from "./query/parser.js";
|
||||
import type { SelectQuery, SelectSetQuery, Expression } from "./query/ast.js";
|
||||
import { SyntaxError } from "./query/errors.js";
|
||||
import { createSchemaRegistry, type TableSchema } from "./query/schema.js";
|
||||
import { createPrinterContext, type QuerySettings } from "./query/printer_context.js";
|
||||
import { printToClickHouse, type PrintResult } from "./query/printer.js";
|
||||
|
||||
/**
|
||||
* Simple error listener that captures syntax errors
|
||||
@@ -164,3 +167,67 @@ export function parseTSQLExpr(expr: string): Expression {
|
||||
const converter = new TSQLParseTreeConverter();
|
||||
return converter.visit(parseTree) as Expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for compiling a TSQL query to ClickHouse SQL
|
||||
*/
|
||||
export interface CompileTSQLOptions {
|
||||
/** The organization ID for tenant isolation */
|
||||
organizationId: string;
|
||||
/** The project ID for tenant isolation */
|
||||
projectId: string;
|
||||
/** The environment ID for tenant isolation */
|
||||
environmentId: string;
|
||||
/** Schema definitions for allowed tables and columns */
|
||||
tableSchema: TableSchema[];
|
||||
/** Optional query settings */
|
||||
settings?: Partial<QuerySettings>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a TSQL query string to ClickHouse SQL with parameters
|
||||
*
|
||||
* This function:
|
||||
* 1. Parses the TSQL query into an AST
|
||||
* 2. Validates tables and columns against the schema
|
||||
* 3. Injects tenant isolation WHERE clauses
|
||||
* 4. Generates parameterized ClickHouse SQL
|
||||
*
|
||||
* @param query - The TSQL query string to compile
|
||||
* @param options - Compilation options including tenant IDs and schema
|
||||
* @returns The compiled SQL and parameters
|
||||
* @throws SyntaxError if the query is invalid
|
||||
* @throws QueryError if tables/columns are not allowed
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const { sql, params } = compileTSQL(
|
||||
* "SELECT * FROM task_runs WHERE status = 'completed' LIMIT 100",
|
||||
* {
|
||||
* organizationId: "org_123",
|
||||
* projectId: "proj_456",
|
||||
* environmentId: "env_789",
|
||||
* tableSchema: [taskRunsSchema],
|
||||
* }
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
export function compileTSQL(query: string, options: CompileTSQLOptions): PrintResult {
|
||||
// 1. Parse the TSQL query
|
||||
const ast = parseTSQLSelect(query);
|
||||
|
||||
// 2. Create schema registry from table schemas
|
||||
const schemaRegistry = createSchemaRegistry(options.tableSchema);
|
||||
|
||||
// 3. Create printer context with tenant IDs
|
||||
const context = createPrinterContext({
|
||||
organizationId: options.organizationId,
|
||||
projectId: options.projectId,
|
||||
environmentId: options.environmentId,
|
||||
schema: schemaRegistry,
|
||||
settings: options.settings,
|
||||
});
|
||||
|
||||
// 4. Print the AST to ClickHouse SQL
|
||||
return printToClickHouse(ast, context);
|
||||
}
|
||||
|
||||
Generated
+3
-3
@@ -999,6 +999,9 @@ importers:
|
||||
'@internal/tracing':
|
||||
specifier: workspace:*
|
||||
version: link:../tracing
|
||||
'@internal/tsql':
|
||||
specifier: workspace:*
|
||||
version: link:../tsql
|
||||
'@trigger.dev/core':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/core
|
||||
@@ -1265,9 +1268,6 @@ importers:
|
||||
|
||||
internal-packages/tsql:
|
||||
dependencies:
|
||||
'@internal/clickhouse':
|
||||
specifier: workspace:*
|
||||
version: link:../clickhouse
|
||||
'@trigger.dev/core':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/core
|
||||
|
||||
Reference in New Issue
Block a user