49df40cb11
TRQL (pronounced Treacle like the delicious British dark sweet syrup) is the TRiggerQueryLanguage. It allows users to safely write queries on their data. The queries are safely turned into ClickHouse queries which are tenant-safe and not SQL injectable. https://github.com/user-attachments/assets/bbfca473-b3fc-4150-8fe6-79e8840a2d29 This started out as a translation of HogQL by PostHog from Python to TypeScript. Features - Tenant safe queries. - Many underlying ClickHouse features including functions and aggregations. - Virtual columns, which are exposed to users as real columns but are actually expressions. - Transformations of data types and where clauses. - Simple JSON path querying. - Limits on execution time. - Reporting of query statistics. ## Query page There’s a new Query page (currently behind a feature flag) where you can write TRQL queries and execute them against your environment, project or organization. Features - Executing TRQL queries - Syntax highlighting and errors - Autocomplete - AI generation/editing of queries - Help and examples - Table with auto-inferred data types from the table schema - Table cell renderers for our special types like Run ids, environments, machines, tasks, queues, etc. - Copy/export as CSV/JSON - Line and bar graphs with grouping and stacking - History of queries
80 lines
2.8 KiB
TypeScript
80 lines
2.8 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { isValidTSQLQuery, getTSQLError } from "./tsqlLinter";
|
|
|
|
describe("tsqlLinter", () => {
|
|
describe("isValidTSQLQuery", () => {
|
|
it("should return true for empty queries", () => {
|
|
expect(isValidTSQLQuery("")).toBe(true);
|
|
expect(isValidTSQLQuery(" ")).toBe(true);
|
|
});
|
|
|
|
it("should return true for valid SELECT queries", () => {
|
|
expect(isValidTSQLQuery("SELECT * FROM users")).toBe(true);
|
|
expect(isValidTSQLQuery("SELECT id, name FROM users WHERE status = 'active'")).toBe(true);
|
|
expect(isValidTSQLQuery("SELECT count(*) FROM users GROUP BY status")).toBe(true);
|
|
});
|
|
|
|
it("should return true for queries with ORDER BY", () => {
|
|
expect(isValidTSQLQuery("SELECT * FROM users ORDER BY created_at DESC")).toBe(true);
|
|
});
|
|
|
|
it("should return true for queries with LIMIT", () => {
|
|
expect(isValidTSQLQuery("SELECT * FROM users LIMIT 10")).toBe(true);
|
|
expect(isValidTSQLQuery("SELECT * FROM users LIMIT 10 OFFSET 20")).toBe(true);
|
|
});
|
|
|
|
it("should return true for queries with JOINs", () => {
|
|
expect(isValidTSQLQuery("SELECT * FROM users JOIN orders ON users.id = orders.user_id")).toBe(
|
|
true
|
|
);
|
|
expect(
|
|
isValidTSQLQuery(
|
|
"SELECT * FROM users LEFT JOIN orders ON users.id = orders.user_id"
|
|
)
|
|
).toBe(true);
|
|
});
|
|
|
|
it("should return false for invalid syntax", () => {
|
|
expect(isValidTSQLQuery("SELEC * FROM users")).toBe(false);
|
|
expect(isValidTSQLQuery("SELECT * FORM users")).toBe(false);
|
|
expect(isValidTSQLQuery("SELECT FROM users")).toBe(false);
|
|
});
|
|
|
|
it("should return false for incomplete queries", () => {
|
|
expect(isValidTSQLQuery("SELECT * FROM")).toBe(false);
|
|
expect(isValidTSQLQuery("SELECT")).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("getTSQLError", () => {
|
|
it("should return null for empty queries", () => {
|
|
expect(getTSQLError("")).toBeNull();
|
|
expect(getTSQLError(" ")).toBeNull();
|
|
});
|
|
|
|
it("should return null for valid queries", () => {
|
|
expect(getTSQLError("SELECT * FROM users")).toBeNull();
|
|
expect(getTSQLError("SELECT id, name FROM users WHERE id = 1")).toBeNull();
|
|
});
|
|
|
|
it("should return error message for invalid queries", () => {
|
|
const error = getTSQLError("SELEC * FROM users");
|
|
expect(error).not.toBeNull();
|
|
expect(typeof error).toBe("string");
|
|
});
|
|
|
|
it("should include position information in error", () => {
|
|
const error = getTSQLError("SELECT * FORM users");
|
|
expect(error).not.toBeNull();
|
|
// Error message should contain line/column info
|
|
expect(error).toContain("line");
|
|
});
|
|
|
|
it("should handle missing FROM clause", () => {
|
|
const error = getTSQLError("SELECT * WHERE id = 1");
|
|
expect(error).not.toBeNull();
|
|
});
|
|
});
|
|
});
|
|
|