import { z } from "zod"; import code_bracket_square_icon from "../assets/heroicons/20/solid/code-bracket-square.svg?raw"; import cube_icon from "../assets/heroicons/20/solid/cube.svg?raw"; import cube_transparent_icon from "../assets/heroicons/20/solid/cube-transparent.svg?raw"; import hashtag_icon from "../assets/heroicons/20/solid/hashtag.svg?raw"; import variable_icon from "../assets/heroicons/20/solid/variable.svg?raw"; import { datum_schema } from "./datum.svelte.ts"; export const all_expression_types = [ "Comparison", "Identifier", "Literal", "ToJson", ] as const; // Type checking to ensure that all valid enum tags are included. type Assert<_T extends true> = void; type _ = Assert; export const expression_type_schema = z.enum(all_expression_types); export const all_infix_comparison_operators = [ "Eq", "Neq", "Gt", "Lt", "And", "Or", ] as const; const pg_comparison_operator_schema = z.enum(all_infix_comparison_operators); const pg_infix_expression_schema = z.object({ operator: z.union([pg_comparison_operator_schema]), get lhs() { return pg_expression_any_schema.optional(); }, get rhs() { return pg_expression_any_schema.optional(); }, }); const pg_comparison_expression_infix_schema = z.object({ t: z.literal("Infix"), c: pg_infix_expression_schema, }); const pg_is_null_expression_schema = z.object({ get lhs() { return pg_expression_any_schema.optional(); }, }); const pg_comparison_expression_is_null_schema = z.object({ t: z.literal("IsNull"), c: pg_is_null_expression_schema, }); const pg_is_not_null_expression_schema = z.object({ get lhs() { return pg_expression_any_schema.optional(); }, }); const pg_comparison_expression_is_not_null_schema = z.object({ t: z.literal("IsNotNull"), c: pg_is_not_null_expression_schema, }); const pg_comparison_expression_schema = z.union([ pg_comparison_expression_infix_schema, pg_comparison_expression_is_null_schema, pg_comparison_expression_is_not_null_schema, ]); const pg_expression_any_comparison_schema = z.object({ t: z.literal("Comparison"), c: pg_comparison_expression_schema, }); const pg_identifier_expression_schema = z.object({ parts_raw: z.array(z.string()), }); const pg_expression_any_identifier_schema = z.object({ t: z.literal("Identifier"), c: pg_identifier_expression_schema, }); const pg_expression_any_literal_schema = z.object({ t: z.literal("Literal"), c: datum_schema, }); const pg_to_json_expression_schema = z.object({ get entries() { return z.array(z.tuple([z.string(), pg_expression_any_schema.optional()])); }, }); const pg_expression_any_to_json_expression_schema = z.object({ t: z.literal("ToJson"), c: pg_to_json_expression_schema, }); export const pg_expression_any_schema = z.union([ pg_expression_any_comparison_schema, pg_expression_any_identifier_schema, pg_expression_any_literal_schema, pg_expression_any_to_json_expression_schema, ]); export type PgExpressionAny = z.infer; export type PgExpressionType = z.infer; export function expression_human_name(expr_type: PgExpressionType): string { if (expr_type === "Comparison") { return "Condition"; } if (expr_type === "Identifier") { return "Identifier"; } if (expr_type === "Literal") { return "Literal"; } if (expr_type === "ToJson") { return "JSON"; } // Type guard to check for exhaustive matching. type _ = Assert; throw new Error("this should be unreachable"); } export function expression_icon(expr: PgExpressionAny): { html: string; label: string; } { if (expr.t === "Comparison") { if (expr.c.t === "Infix") { const op = expr.c.c.operator; if (op === "And") { return { html: "&&", label: "And" }; } if (op === "Eq") { return { html: "=", label: "Is Equal To" }; } if (op === "Gt") { return { html: ">", label: "Is Greater Than" }; } if (op === "Lt") { return { html: "<", label: "Is Less Than" }; } if (op === "Or") { return { html: "||", label: "Or" }; } if (op === "Neq") { return { html: "\u2260", label: "Is Not Equal To" }; } // Type guard to check for exhaustive matching. type _ = Assert; throw new Error("this should be unreachable"); } else if (expr.c.t === "IsNull") { return { html: cube_transparent_icon, label: "Is Null" }; } else if (expr.c.t === "IsNotNull") { return { html: cube_icon, label: "Is Not Null" }; } // Type guard to check for exhaustive matching. type _ = Assert; throw new Error("this should be unreachable"); } else if (expr.t === "Identifier") { return { html: variable_icon, label: "Dynamic Value" }; } else if (expr.t === "Literal") { return { html: hashtag_icon, label: "Static Value" }; } else if (expr.t === "ToJson") { return { html: code_bracket_square_icon, label: "JSON String" }; } // Type guard to check for exhaustive matching. type _ = Assert; throw new Error("this should be unreachable"); }