///|
/// The type inside `T?` or `Option[T]`, or `None` when `ty` is not optional.
fn inner_option(ty : String) -> String? {
let ty = ty.trim(chars=" ")
if ty.has_suffix("?") {
Some(ty.exact_view(end=ty.length() - 1).trim(chars=" ").to_owned())
} else if ty.has_prefix("Option[") && ty.has_suffix("]") {
Some(
ty
.exact_view(start="Option[".length(), end=ty.length() - 1)
.trim(chars=" ")
.to_owned(),
)
} else {
None
}
}
///|
/// The column type a field of type `ty` takes when `kind=` is not given, as the
/// `ColumnType` constructor. The types are the ones behind each `Value` case.
fn column_of(ty : String) -> String? {
match ty {
"Int" | "Int32" => Some("IntType")
"Int64" => Some("BigIntType")
"Double" => Some("RealType")
"String" => Some("TextType")
"Bytes" => Some("BlobType")
"Bool" => Some("BoolType")
_ => None
}
}
///|
/// The `ColumnType` constructor a `kind=` names: the SQL spelling, lower case.
fn column_named(name : String) -> String? {
let name = name.trim(chars=" ").to_lower()
match name {
"int" | "integer" => Some("IntType")
"bigint" => Some("BigIntType")
"text" => Some("TextType")
"real" => Some("RealType")
"blob" => Some("BlobType")
"bool" | "boolean" => Some("BoolType")
"numeric" => Some("NumericType")
"datetime" => Some("DateTimeType")
"date" => Some("DateType")
"time" => Some("TimeType")
"uuid" => Some("UuidType")
"json" => Some("JsonType")
_ => {
guard name.has_prefix("varchar(") && name.has_suffix(")") else {
return None
}
let n = name.exact_view(start="varchar(".length(), end=name.length() - 1)
let n = @string.parse_int(n) catch { _ => return None }
if n > 0 {
Some("VarcharType(\{n})")
} else {
None
}
}
}
}
///|
/// `HeroTeam` as `hero_team`, `HTTPLog` as `http_log`.
fn snake(name : String) -> String {
let out = StringBuilder()
let chars = name.to_array()
for i, c in chars {
if c.is_ascii_uppercase() {
let prev = if i > 0 { Some(chars[i - 1]) } else { None }
let next = chars.get(i + 1)
let boundary = match prev {
Some(p) =>
p.is_ascii_lowercase() ||
p.is_ascii_digit() ||
(p.is_ascii_uppercase() && next is Some(n) && n.is_ascii_lowercase())
None => false
}
if boundary {
out.write_char('_')
}
out.write_char(c.to_ascii_lowercase())
} else {
out.write_char(c)
}
}
out.to_string()
}