teo_sql_connector/exts/
index.rs1use std::borrow::Cow;
2use teo_runtime::model::index::Type;
3use teo_runtime::model::index::Item;
4use crate::exts::sort::SortExt;
5use crate::schema::dialect::SQLDialect;
6
7pub trait IndexExt {
8
9 fn psql_primary_to_unique(&self, table_name: &str) -> Self;
10
11 fn sql_name(&self, table_name: &str, dialect: SQLDialect) -> Cow<str>;
12
13 fn joined_names(&self) -> String;
14
15 fn psql_suffix(&self) -> &str;
16
17 fn normalize_name_psql(&self, table_name: &str) -> String;
18
19 fn normalize_name_normal(&self, table_name: &str) -> String;
20
21 fn normalize_name(&self, table_name: &str, dialect: SQLDialect) -> String;
22
23 fn to_sql_drop(&self, dialect: SQLDialect, table_name: &str) -> String;
24
25 fn to_sql_create(&self, dialect: SQLDialect, table_name: &str) -> String;
26
27 fn sql_format_item(dialect: SQLDialect, item: &Item, table_create_mode: bool) -> String;
28}
29
30impl IndexExt for teo_runtime::model::Index {
31
32 fn psql_primary_to_unique(&self, table_name: &str) -> Self {
33 Self::new(Type::Unique, format!("{table_name}_{}_pkey", self.joined_names()), self.items().clone())
34 }
35
36 fn sql_name(&self, table_name: &str, dialect: SQLDialect) -> Cow<str> {
37 if self.r#type().is_primary() {
38 Cow::Owned(self.normalize_name(table_name, dialect))
39 } else {
40 if dialect.is_sqlite() || (dialect.is_postgres() && !self.name().ends_with("pkey")) {
41 Cow::Owned(format!("{}_{}", table_name, self.name()))
42 } else {
43 Cow::Borrowed(self.name())
44 }
45 }
46 }
47
48 fn joined_names(&self) -> String {
49 self.keys().join("_")
50 }
51
52 fn psql_suffix(&self) -> &str {
53 if self.r#type().is_primary() {
54 "pkey"
55 } else {
56 "idx"
57 }
58 }
59
60 fn normalize_name_psql(&self, table_name: &str) -> String {
61 if self.r#type().is_primary() {
62 format!("{table_name}_{}", self.psql_suffix())
63 } else {
64 format!("{table_name}_{}_{}", self.joined_names(), self.psql_suffix())
65 }
66 }
67
68 fn normalize_name_normal(&self, table_name: &str) -> String {
69 format!("{table_name}_{}", self.joined_names())
70 }
71
72 fn normalize_name(&self, table_name: &str, dialect: SQLDialect) -> String {
73 match self.r#type() {
74 Type::Primary => match dialect {
75 SQLDialect::MySQL => "PRIMARY".to_owned(),
76 SQLDialect::SQLite => format!("teo_primary_sqlite_index_{}", table_name),
77 SQLDialect::PostgreSQL => self.normalize_name_psql(table_name),
79 _ => unreachable!()
80 },
81 _ => match dialect {
82 SQLDialect::PostgreSQL => self.normalize_name_psql(table_name),
83 _ => self.normalize_name_normal(table_name),
84 }
85 }
86 }
87
88 fn to_sql_drop(&self, dialect: SQLDialect, table_name: &str) -> String {
89 let escape = dialect.escape();
90 let index_name_cow = self.sql_name(table_name, dialect);
91 let index_name = index_name_cow.as_ref();
92 if dialect == SQLDialect::PostgreSQL {
93 format!("DROP INDEX {escape}{index_name}{escape}")
94 } else if dialect == SQLDialect::SQLite {
95 format!("DROP INDEX IF EXISTS {escape}{index_name}{escape}")
96 } else {
97 format!("DROP INDEX {escape}{index_name}{escape} ON {escape}{table_name}{escape}")
98 }
99 }
100
101 fn to_sql_create(&self, dialect: SQLDialect, table_name: &str) -> String {
102 let escape = dialect.escape();
103 let index_name_cow = self.sql_name(table_name, dialect);
104 let index_name = index_name_cow.as_ref();
105 let unique = if self.r#type().is_unique() { "UNIQUE " } else { "" };
106 let fields: Vec<String> = self.items().iter().map(|item| {
107 Self::sql_format_item(dialect, item, false)
108 }).collect();
109 format!("CREATE {unique}INDEX {escape}{index_name}{escape} ON {escape}{table_name}{escape}({})", fields.join(","))
110 }
111
112 fn sql_format_item(dialect: SQLDialect, item: &Item, table_create_mode: bool) -> String {
113 let escape = dialect.escape();
114 let name = &item.field;
115 let sort = item.sort.to_str();
116 let len = if let Some(len) = item.len {
117 if dialect == SQLDialect::MySQL {
118 Cow::Owned(format!("({})", len))
119 } else {
120 Cow::Borrowed("")
121 }
122 } else {
123 Cow::Borrowed("")
124 };
125 if table_create_mode && dialect == SQLDialect::PostgreSQL {
126 format!("{escape}{name}{escape}")
127 } else {
128 format!("{escape}{name}{escape}{len} {sort}")
129 }
130 }
131}