phonograph/svelte/src/expression.svelte.ts
2025-10-24 18:27:26 +00:00

175 lines
4.9 KiB
TypeScript

import { z } from "zod";
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<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: 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<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: '<i class="ti ti-cube-3d-sphere-off"></i>', label: "Is Null" };
} else if (expr.c.t === "IsNotNull") {
return { html: '<i class="ti ti-cube"></i>', 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: '<i class="ti ti-variable"></i>', label: "Dynamic Value" };
} else if (expr.t === "Literal") {
return { html: '<i class="ti ti-hash"></i>', label: "Static Value" };
} else if (expr.t === "ToJson") {
return { html: '<i class="ti ti-code"></i>', 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");
}