181 lines
5.3 KiB
TypeScript
181 lines
5.3 KiB
TypeScript
|
|
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 { encodable_schema } from "./field.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<PgExpressionAny["t"] extends PgExpressionType ? true : false>;
|
||
|
|
|
||
|
|
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: encodable_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<typeof pg_expression_any_schema>;
|
||
|
|
export type PgExpressionType = z.infer<typeof expression_type_schema>;
|
||
|
|
|
||
|
|
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<typeof expr_type extends never ? true : false>;
|
||
|
|
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<typeof op extends never ? true : false>;
|
||
|
|
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<typeof expr.c extends never ? true : false>;
|
||
|
|
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<typeof expr extends never ? true : false>;
|
||
|
|
throw new Error("this should be unreachable");
|
||
|
|
}
|