table name

This commit is contained in:
Filipriec
2026-08-25 13:01:32 +02:00
parent ed01d1ec5b
commit aea54f8d33
12 changed files with 135 additions and 45 deletions

View File

@@ -853,6 +853,8 @@ error-identifier-underscore = { $label } nesmí začínat podtržítkem.
error-identifier-number = { $label } nesmí začínat číslicí.
error-identifier-too-long = { $label } nesmí být delší než { $limit } znaků.
error-identifier-charset = { $label } může obsahovat jen malá písmena, číslice a podtržítko.
error-table-name-charset = { $label } může obsahovat jen ASCII písmena, číslice, podtržítka a pomlčky.
error-table-name-boundary = { $label } musí začínat a končit písmenem nebo číslicí.
error-alias-charset = { $label } musí obsahovat písmeno, číslo, interpunkci nebo symbol mimo emoji a nesmí obsahovat řídicí znaky.
error-alias-too-long = { $label } nesmí být delší než { $limit } bajtů UTF-8.
error-identifier-reserved = { $label } používá vyhrazený název.

View File

@@ -838,6 +838,8 @@ error-identifier-underscore = { $label } cannot start with an underscore.
error-identifier-number = { $label } cannot start with a number.
error-identifier-too-long = { $label } cannot be longer than { $limit } characters.
error-identifier-charset = { $label } may only use lowercase letters, digits and underscores.
error-table-name-charset = { $label } may only use ASCII letters, digits, underscores and hyphens.
error-table-name-boundary = { $label } must start and end with a letter or number.
error-alias-charset = { $label } must contain a letter, number, punctuation mark or non-emoji symbol, and cannot contain control characters.
error-alias-too-long = { $label } cannot be longer than { $limit } UTF-8 bytes.
error-identifier-reserved = { $label } uses a reserved name.

View File

@@ -851,6 +851,8 @@ error-identifier-underscore = { $label } nesmie začínať podčiarkovníkom.
error-identifier-number = { $label } nesmie začínať číslom.
error-identifier-too-long = { $label } nesmie byť dlhšie ako { $limit } znakov.
error-identifier-charset = { $label } môže obsahovať len malé písmená, číslice a podčiarkovník.
error-table-name-charset = { $label } môže obsahovať len ASCII písmená, číslice, podčiarkovníky a pomlčky.
error-table-name-boundary = { $label } musí začínať a končiť písmenom alebo číslicou.
error-alias-charset = { $label } musí obsahovať písmeno, číslo, interpunkciu alebo symbol mimo emoji a nesmie obsahovať riadiace znaky.
error-alias-too-long = { $label } nesmie byť dlhšie ako { $limit } bajtov UTF-8.
error-identifier-reserved = { $label } používa vyhradený názov.

View File

@@ -224,7 +224,10 @@ impl TableDraft {
) {
self.relation_table_options = options
.into_iter()
.filter(|option| option.name != self.table_name)
.filter(|option| {
common::alias::canonical_table_name(&option.name)
!= common::alias::canonical_table_name(&self.table_name)
})
.collect();
self.relation_tables = self
.relation_table_options
@@ -399,7 +402,10 @@ impl TableDraft {
&& self
.existing_profile_tables
.iter()
.any(|name| name == &self.table_name)
.any(|name| {
common::alias::canonical_table_name(name)
== common::alias::canonical_table_name(&self.table_name)
})
}
/// Position of `column` among the display columns, counting from 1.

View File

@@ -71,7 +71,7 @@ pub(crate) async fn load_page(
// for, so it is told what that table is on every render rather than left to
// read a copy that a `refresh` could have moved on from.
draft.columns.global = draft.global;
draft.columns.table_name = draft.table_name.trim().to_ascii_lowercase();
draft.columns.table_name = draft.table_name.trim().to_string();
let tree = definitions
.get_profile_tree(

View File

@@ -140,7 +140,7 @@ impl BuilderForm {
// takes no column that posts to one profile's books, and no link
// may point at the table being created.
global: self.global,
table_name: self.table_name.trim().to_ascii_lowercase(),
table_name: self.table_name.trim().to_string(),
};
// Drop display columns whose column is gone, so a stale post cannot

View File

@@ -579,7 +579,7 @@ impl ColumnDraft {
return Ok(None);
}
if self.catalog.is_link(&column_type) {
let target = self.link_table_input.trim().to_ascii_lowercase();
let target = self.link_table_input.trim();
return Ok((!target.is_empty()).then(|| format!("{column_type}({target})")));
}
let Some(group) = self.pending_group() else {
@@ -1209,8 +1209,28 @@ pub(crate) fn validate_table_name(
locale: crate::i18n::Locale,
value: &str,
) -> Option<String> {
if let Some(error) = validate_identifier(locale, value, "label-table-name", true) {
return Some(error);
let label = crate::tr!(locale, "label-table-name");
if value.is_empty() {
return Some(crate::tr!(locale, "error-identifier-empty", "label" => label));
}
if value != value.trim() {
return Some(crate::tr!(locale, "error-identifier-whitespace", "label" => label));
}
if !value.chars().all(|character| {
character.is_ascii_alphanumeric() || matches!(character, '_' | '-')
}) {
return Some(crate::tr!(locale, "error-table-name-charset", "label" => label));
}
if !value
.chars()
.next()
.is_some_and(|character| character.is_ascii_alphanumeric())
|| !value
.chars()
.last()
.is_some_and(|character| character.is_ascii_alphanumeric())
{
return Some(crate::tr!(locale, "error-table-name-boundary", "label" => label));
}
if value.len() > MAX_TABLE_NAME_LENGTH {
// The limit is arithmetic, not a literal: it moves when a system column
@@ -1221,7 +1241,10 @@ pub(crate) fn validate_table_name(
"limit" => MAX_TABLE_NAME_LENGTH as i64,
));
}
if RESERVED_TABLE_NAMES.contains(&value) {
let canonical = common::alias::canonical_table_name(value);
if RESERVED_TABLE_NAMES.contains(&canonical.as_str())
|| crate::system_column::is_system_column(&canonical)
{
return Some(crate::tr!(
locale,
"schema-err-table-name-reserved",
@@ -2305,6 +2328,12 @@ pub(crate) mod tests {
.unwrap_or_else(|| panic!("`{name}` should be reserved"));
assert!(error.contains(name), "{error}");
}
assert_eq!(validate_table_name(crate::i18n::Locale::default(), "Custom_Exchange_Rates"),
validate_table_name(crate::i18n::Locale::default(), "custom_exchange_rates"));
assert_eq!(validate_table_name(crate::i18n::Locale::default(), "2026-Sales_Q4"), None);
for name in ["_sales", "sales_", "-sales", "sales-"] {
assert!(validate_table_name(crate::i18n::Locale::default(), name).is_some());
}
assert_eq!(validate_table_name(crate::i18n::Locale::default(), "invoice"), None);
}
}