scythe_codegen/backends/
typescript_common.rs1use std::fmt::Write;
2
3use scythe_core::errors::{ErrorCode, ScytheError};
4
5use crate::backend_trait::ResolvedColumn;
6
7#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
9pub enum TsRowType {
10 #[default]
11 Interface,
12 Zod,
13}
14
15impl TsRowType {
16 pub fn from_option(value: &str) -> Result<Self, ScytheError> {
18 match value {
19 "interface" => Ok(Self::Interface),
20 "zod" => Ok(Self::Zod),
21 _ => Err(ScytheError::new(
22 ErrorCode::InternalError,
23 format!(
24 "invalid row_type '{}': expected 'interface' or 'zod'",
25 value
26 ),
27 )),
28 }
29 }
30}
31
32pub fn neutral_to_zod(neutral_type: &str, nullable: bool) -> String {
34 let base = match neutral_type {
35 "int16" | "int32" | "int64" => "z.number()",
36 "float32" | "float64" => "z.number()",
37 "string" | "text" | "inet" | "interval" | "time" | "time_tz" => "z.string()",
38 "bool" => "z.boolean()",
39 "datetime" | "datetime_tz" => "z.date()",
40 "date" => "z.string()",
41 "uuid" => "z.string().uuid()",
42 "json" => "z.unknown()",
43 "decimal" => "z.string()",
44 "bytes" => "z.instanceof(Buffer)",
45 t if t.starts_with("enum::") => "z.string()",
46 _ => "z.unknown()",
47 };
48 if nullable {
49 format!("{base}.nullable()")
50 } else {
51 base.to_string()
52 }
53}
54
55pub fn generate_zod_row_struct(
57 struct_name: &str,
58 query_name: &str,
59 columns: &[ResolvedColumn],
60) -> String {
61 let schema_name = format!("{struct_name}Schema");
62 let mut out = String::new();
63 let _ = writeln!(out, "/** Row type for {} queries. */", query_name);
64 let _ = writeln!(out, "export const {} = z.object({{", schema_name);
65 for col in columns {
66 let zod_type = neutral_to_zod(&col.neutral_type, col.nullable);
67 let _ = writeln!(out, "\t{}: {},", col.field_name, zod_type);
68 }
69 let _ = writeln!(out, "}});");
70 let _ = writeln!(out);
71 let _ = write!(
72 out,
73 "export type {} = z.infer<typeof {}>;",
74 struct_name, schema_name
75 );
76 out
77}
78
79pub fn generate_zod_enum(type_name: &str, values: &[String]) -> String {
81 let schema_name = format!("{type_name}Schema");
82 let mut out = String::new();
83 let variants: Vec<String> = values.iter().map(|v| format!("\"{}\"", v)).collect();
84 let _ = writeln!(
85 out,
86 "export const {} = z.enum([{}]);",
87 schema_name,
88 variants.join(", ")
89 );
90 let _ = writeln!(out);
91 let _ = write!(
92 out,
93 "export type {} = z.infer<typeof {}>;",
94 type_name, schema_name
95 );
96 out
97}