feat(manticore): add Manticore Search support
Add Manticore Search table data editing, structure editing, metadata handling, and SQL completion support.
This commit is contained in:
1 parent
93d2e7dc18
commit
f385386284
34 files changed
+1250
-130
No files matched your search
@@ -4,8 +4,8 @@ use super::comments::build_sqlserver_column_comment_sql;
|
||||
use super::dialect::{capabilities_for, database_label, StructureDialect};
|
||||
use super::types::{EditableStructureColumn, SingleColumnAlterSqlOptions, TableStructureSqlResult};
|
||||
use super::util::{
|
||||
clean, format_default_for_sql, normalize_default, original_comment, original_default, qualified_table, quote_ident,
|
||||
quote_string,
|
||||
clean, format_default_for_sql, is_protected_manticore_id_column, normalize_default, original_comment,
|
||||
original_default, qualified_table, quote_ident, quote_string,
|
||||
};
|
||||
use crate::table_structure_sql::ColumnExtra;
|
||||
|
||||
@@ -30,6 +30,10 @@ pub fn build_single_column_alter_sql(options: SingleColumnAlterSqlOptions) -> Ta
|
||||
warnings.push(format!("Primary key column \"{}\" cannot be dropped from this editor.", original.name));
|
||||
return TableStructureSqlResult { statements, warnings };
|
||||
}
|
||||
if is_protected_manticore_id_column(dialect, &original.name) {
|
||||
warnings.push("Manticore Search id column cannot be dropped from this editor.".to_string());
|
||||
return TableStructureSqlResult { statements, warnings };
|
||||
}
|
||||
statements.push(build_drop_column_sql(dialect, &table, &original.name));
|
||||
return TableStructureSqlResult { statements, warnings };
|
||||
}
|
||||
@@ -95,6 +99,22 @@ fn is_column_extra_empty(extra: &ColumnExtra) -> bool {
|
||||
!extra.auto_increment.unwrap_or(false)
|
||||
&& !extra.on_update_current_timestamp.unwrap_or(false)
|
||||
&& extra.identity.is_none()
|
||||
&& !extra.manticore_indexed.unwrap_or(false)
|
||||
&& !extra.manticore_stored.unwrap_or(false)
|
||||
&& !extra.manticore_attribute.unwrap_or(false)
|
||||
&& !extra.manticore_secondary_index.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn original_manticore_extra_flags(extra: &str) -> (bool, bool, bool, bool) {
|
||||
let lower = extra.to_lowercase();
|
||||
(
|
||||
lower.split_whitespace().any(|token| token == "indexed"),
|
||||
lower.split_whitespace().any(|token| token == "stored"),
|
||||
lower.split_whitespace().any(|token| token == "attribute"),
|
||||
lower.contains("secondary_index='1'")
|
||||
|| lower.contains("secondary_index=\"1\"")
|
||||
|| lower.contains("secondary_index=1"),
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn has_column_extra_change(column: &EditableStructureColumn) -> bool {
|
||||
@@ -103,8 +123,18 @@ pub(super) fn has_column_extra_change(column: &EditableStructureColumn) -> bool
|
||||
match (current_extra, original.extra.as_deref()) {
|
||||
// Neither has extra → no change
|
||||
(None, None | Some("")) => false,
|
||||
// Current extra is empty (all None) → no effective extra
|
||||
(Some(curr), _) if is_column_extra_empty(curr) => false,
|
||||
// Current extra is empty (all None) → changed only if the original had effective extra
|
||||
(Some(curr), None | Some("")) if is_column_extra_empty(curr) => false,
|
||||
(Some(curr), Some(orig)) if is_column_extra_empty(curr) => {
|
||||
let (indexed, stored, attribute, secondary_index) = original_manticore_extra_flags(orig);
|
||||
let orig_lower = orig.to_lowercase();
|
||||
orig_lower.contains("auto_increment")
|
||||
|| orig_lower.contains("on update")
|
||||
|| indexed
|
||||
|| stored
|
||||
|| attribute
|
||||
|| secondary_index
|
||||
}
|
||||
// Extra added or removed
|
||||
(Some(_), None | Some("")) => true,
|
||||
(None, Some(_)) => true,
|
||||
@@ -116,8 +146,18 @@ pub(super) fn has_column_extra_change(column: &EditableStructureColumn) -> bool
|
||||
let curr_has_on_update = curr.on_update_current_timestamp.unwrap_or(false);
|
||||
let orig_has_on_update = orig_lower.contains("on update");
|
||||
let curr_has_identity = curr.identity.is_some();
|
||||
let curr_manticore = (
|
||||
curr.manticore_indexed.unwrap_or(false),
|
||||
curr.manticore_stored.unwrap_or(false),
|
||||
curr.manticore_attribute.unwrap_or(false),
|
||||
curr.manticore_secondary_index.unwrap_or(false),
|
||||
);
|
||||
let orig_manticore = original_manticore_extra_flags(orig);
|
||||
// identity is harder to detect in free-form original.extra, so treat it as changed if present
|
||||
curr_has_ai != orig_has_ai || curr_has_on_update != orig_has_on_update || curr_has_identity
|
||||
curr_has_ai != orig_has_ai
|
||||
|| curr_has_on_update != orig_has_on_update
|
||||
|| curr_has_identity
|
||||
|| curr_manticore != orig_manticore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,9 +71,44 @@ pub(super) fn column_data_type(dialect: StructureDialect, column: &EditableStruc
|
||||
if dialect == StructureDialect::ClickHouse {
|
||||
return clickhouse_column_type(column);
|
||||
}
|
||||
if dialect == StructureDialect::ManticoreSearch {
|
||||
return manticore_column_type(column);
|
||||
}
|
||||
normalize_column_data_type(dialect, &column.data_type)
|
||||
}
|
||||
|
||||
fn manticore_column_type(column: &EditableStructureColumn) -> String {
|
||||
let data_type = normalize_column_data_type(StructureDialect::ManticoreSearch, &column.data_type);
|
||||
let normalized = data_type.trim().to_ascii_lowercase();
|
||||
if normalized == "json" {
|
||||
let Some(extra) = column.extra.as_ref() else {
|
||||
return data_type;
|
||||
};
|
||||
if extra.manticore_secondary_index.unwrap_or(false) {
|
||||
return format!("{data_type} secondary_index='1'");
|
||||
}
|
||||
return data_type;
|
||||
}
|
||||
if !matches!(normalized.as_str(), "text" | "string") {
|
||||
return data_type;
|
||||
}
|
||||
|
||||
let Some(extra) = column.extra.as_ref() else {
|
||||
return data_type;
|
||||
};
|
||||
let mut parts = vec![data_type];
|
||||
if extra.manticore_stored.unwrap_or(false) {
|
||||
parts.push("stored".to_string());
|
||||
}
|
||||
if extra.manticore_attribute.unwrap_or(false) {
|
||||
parts.push("attribute".to_string());
|
||||
}
|
||||
if extra.manticore_indexed.unwrap_or(false) {
|
||||
parts.push("indexed".to_string());
|
||||
}
|
||||
parts.join(" ")
|
||||
}
|
||||
|
||||
pub(super) fn normalize_column_data_type(dialect: StructureDialect, data_type: &str) -> String {
|
||||
let trimmed = data_type.trim();
|
||||
let Some(open_index) = trimmed.find('(') else {
|
||||
|
||||
@@ -9,7 +9,8 @@ use super::comments::build_sqlserver_column_comment_sql;
|
||||
use super::dialect::{capabilities_for, database_label, StructureDialect};
|
||||
use super::types::{EditableStructureColumn, TableStructureSqlOptions};
|
||||
use super::util::{
|
||||
clean, normalize_default, original_comment, original_default, qualified_table, quote_ident, quote_string,
|
||||
clean, is_protected_manticore_id_column, normalize_default, original_comment, original_default, qualified_table,
|
||||
quote_ident, quote_string,
|
||||
};
|
||||
|
||||
pub(super) fn build_column_sql(options: &TableStructureSqlOptions, warnings: &mut Vec<String>) -> Vec<String> {
|
||||
@@ -34,6 +35,10 @@ pub(super) fn build_column_sql(options: &TableStructureSqlOptions, warnings: &mu
|
||||
warnings.push(format!("Primary key column \"{}\" cannot be dropped from this editor.", original.name));
|
||||
continue;
|
||||
}
|
||||
if is_protected_manticore_id_column(dialect, &original.name) {
|
||||
warnings.push("Manticore Search id column cannot be dropped from this editor.".to_string());
|
||||
continue;
|
||||
}
|
||||
statements.push(build_drop_column_sql(dialect, &table, &original.name));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -31,14 +31,17 @@ pub fn build_create_table_sql(options: TableStructureSqlOptions) -> TableStructu
|
||||
for column in &active_columns {
|
||||
let data_type = column_data_type(dialect, column);
|
||||
let mut parts = vec![quote_ident(dialect, &column.name), data_type];
|
||||
if !column.is_nullable && !column.is_primary_key && dialect != StructureDialect::ClickHouse {
|
||||
if !column.is_nullable
|
||||
&& !column.is_primary_key
|
||||
&& !matches!(dialect, StructureDialect::ClickHouse | StructureDialect::ManticoreSearch)
|
||||
{
|
||||
parts.push("NOT NULL".to_string());
|
||||
}
|
||||
if let Some(extra_clause) = column_extra_clause(dialect, column) {
|
||||
parts.push(extra_clause);
|
||||
}
|
||||
let default_value = normalize_default(Some(&column.default_value));
|
||||
if !default_value.is_empty() {
|
||||
if !default_value.is_empty() && dialect != StructureDialect::ManticoreSearch {
|
||||
parts.push(format!("DEFAULT {}", format_default_for_sql(dialect, &column.data_type, &default_value)));
|
||||
}
|
||||
if let Some(on_update) = column.extra.as_ref().and_then(|e| e.on_update_current_timestamp).filter(|v| *v) {
|
||||
@@ -52,7 +55,10 @@ pub fn build_create_table_sql(options: TableStructureSqlOptions) -> TableStructu
|
||||
column_definitions.push(parts.join(" "));
|
||||
}
|
||||
|
||||
let pk_columns: Vec<_> = active_columns.iter().filter(|column| column.is_primary_key).collect();
|
||||
let pk_columns: Vec<_> = active_columns
|
||||
.iter()
|
||||
.filter(|column| column.is_primary_key && dialect != StructureDialect::ManticoreSearch)
|
||||
.collect();
|
||||
if !pk_columns.is_empty() {
|
||||
let pk_list = pk_columns.iter().map(|column| quote_ident(dialect, &column.name)).collect::<Vec<_>>().join(", ");
|
||||
column_definitions.push(format!("PRIMARY KEY ({pk_list})"));
|
||||
|
||||
@@ -11,6 +11,7 @@ pub(super) enum StructureDialect {
|
||||
Oracle,
|
||||
H2,
|
||||
ClickHouse,
|
||||
ManticoreSearch,
|
||||
Informix,
|
||||
Unsupported,
|
||||
}
|
||||
@@ -204,6 +205,12 @@ pub(super) fn capabilities_for(database_type: Option<DatabaseType>) -> TableStru
|
||||
comment: true,
|
||||
..base
|
||||
},
|
||||
Some(DatabaseType::ManticoreSearch) => TableStructureCapabilities {
|
||||
dialect: StructureDialect::ManticoreSearch,
|
||||
add_column: true,
|
||||
drop_column: true,
|
||||
..base
|
||||
},
|
||||
Some(DatabaseType::Informix) => TableStructureCapabilities {
|
||||
dialect: StructureDialect::Informix,
|
||||
add_column: true,
|
||||
@@ -245,6 +252,7 @@ pub(super) fn dialect_label(dialect: StructureDialect) -> String {
|
||||
StructureDialect::Oracle => "oracle",
|
||||
StructureDialect::H2 => "h2",
|
||||
StructureDialect::ClickHouse => "clickhouse",
|
||||
StructureDialect::ManticoreSearch => "manticoresearch",
|
||||
StructureDialect::Informix => "informix",
|
||||
StructureDialect::Unsupported => "this database",
|
||||
}
|
||||
@@ -262,6 +270,7 @@ pub(super) fn database_type_for_dialect(dialect: StructureDialect) -> Option<Dat
|
||||
StructureDialect::Oracle => Some(DatabaseType::Oracle),
|
||||
StructureDialect::H2 => Some(DatabaseType::H2),
|
||||
StructureDialect::ClickHouse => Some(DatabaseType::ClickHouse),
|
||||
StructureDialect::ManticoreSearch => Some(DatabaseType::ManticoreSearch),
|
||||
StructureDialect::Informix => Some(DatabaseType::Informix),
|
||||
StructureDialect::Unsupported => None,
|
||||
}
|
||||
|
||||
@@ -215,6 +215,76 @@ fn mysql_create_index_with_comment() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manticoresearch_builds_create_table_sql_only() {
|
||||
let mut title = column("title");
|
||||
title.data_type = "text".to_string();
|
||||
title.is_nullable = false;
|
||||
let mut views = column("views");
|
||||
views.data_type = "int".to_string();
|
||||
|
||||
let result = build_create_table_sql(TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::ManticoreSearch),
|
||||
schema: None,
|
||||
table_name: "materials".to_string(),
|
||||
columns: vec![title, views],
|
||||
indexes: Vec::new(),
|
||||
foreign_keys: Vec::new(),
|
||||
triggers: Vec::new(),
|
||||
table_comment: None,
|
||||
original_table_comment: None,
|
||||
});
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(result.statements, vec!["CREATE TABLE `materials` (\n `title` text,\n `views` int\n);"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manticoresearch_builds_add_and_drop_column_sql() {
|
||||
let mut old_code = column("code");
|
||||
old_code.data_type = "string".to_string();
|
||||
old_code.marked_for_drop = true;
|
||||
old_code.original = Some(ColumnInfo {
|
||||
name: "code".to_string(),
|
||||
data_type: "string".to_string(),
|
||||
is_nullable: true,
|
||||
column_default: None,
|
||||
is_primary_key: false,
|
||||
extra: None,
|
||||
comment: None,
|
||||
});
|
||||
|
||||
let mut name = column("name");
|
||||
name.data_type = "string".to_string();
|
||||
name.extra =
|
||||
Some(ColumnExtra { manticore_attribute: Some(true), manticore_indexed: Some(true), ..Default::default() });
|
||||
let mut resource = column("resource");
|
||||
resource.data_type = "json".to_string();
|
||||
resource.extra = Some(ColumnExtra { manticore_secondary_index: Some(true), ..Default::default() });
|
||||
|
||||
let result = build_table_structure_change_sql(TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::ManticoreSearch),
|
||||
schema: None,
|
||||
table_name: "materials".to_string(),
|
||||
columns: vec![old_code, name, resource],
|
||||
indexes: Vec::new(),
|
||||
foreign_keys: Vec::new(),
|
||||
triggers: Vec::new(),
|
||||
table_comment: None,
|
||||
original_table_comment: None,
|
||||
});
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(
|
||||
result.statements,
|
||||
vec![
|
||||
"ALTER TABLE `materials` DROP COLUMN `code`;",
|
||||
"ALTER TABLE `materials` ADD COLUMN `name` string attribute indexed;",
|
||||
"ALTER TABLE `materials` ADD COLUMN `resource` json secondary_index='1';",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gbase8a_uses_limited_mysql_ddl() {
|
||||
let mut renamed = column("display_email");
|
||||
@@ -278,6 +348,193 @@ fn gbase8a_uses_limited_mysql_ddl() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manticoresearch_does_not_drop_id_column() {
|
||||
let mut id = column("id");
|
||||
id.data_type = "bigint".to_string();
|
||||
id.marked_for_drop = true;
|
||||
id.original = Some(ColumnInfo {
|
||||
name: "id".to_string(),
|
||||
data_type: "bigint".to_string(),
|
||||
is_nullable: false,
|
||||
column_default: None,
|
||||
is_primary_key: false,
|
||||
extra: None,
|
||||
comment: None,
|
||||
});
|
||||
|
||||
let result = build_table_structure_change_sql(TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::ManticoreSearch),
|
||||
schema: None,
|
||||
table_name: "materials".to_string(),
|
||||
columns: vec![id],
|
||||
indexes: Vec::new(),
|
||||
foreign_keys: Vec::new(),
|
||||
triggers: Vec::new(),
|
||||
table_comment: None,
|
||||
original_table_comment: None,
|
||||
});
|
||||
|
||||
assert_eq!(result.statements, Vec::<String>::new());
|
||||
assert_eq!(result.warnings, vec!["Manticore Search id column cannot be dropped from this editor."]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manticoresearch_warns_when_existing_column_properties_change() {
|
||||
let mut name = column("name");
|
||||
name.data_type = "string".to_string();
|
||||
name.extra = Some(ColumnExtra {
|
||||
manticore_indexed: Some(true),
|
||||
manticore_stored: Some(true),
|
||||
manticore_attribute: Some(true),
|
||||
..Default::default()
|
||||
});
|
||||
name.original = Some(ColumnInfo {
|
||||
name: "name".to_string(),
|
||||
data_type: "string".to_string(),
|
||||
is_nullable: true,
|
||||
column_default: None,
|
||||
is_primary_key: false,
|
||||
extra: None,
|
||||
comment: None,
|
||||
});
|
||||
|
||||
let mut resource = column("resource");
|
||||
resource.data_type = "json".to_string();
|
||||
resource.extra = Some(ColumnExtra { manticore_secondary_index: Some(true), ..Default::default() });
|
||||
resource.original = Some(ColumnInfo {
|
||||
name: "resource".to_string(),
|
||||
data_type: "json".to_string(),
|
||||
is_nullable: true,
|
||||
column_default: None,
|
||||
is_primary_key: false,
|
||||
extra: None,
|
||||
comment: None,
|
||||
});
|
||||
|
||||
let mut old_resource = column("old_resource");
|
||||
old_resource.data_type = "json".to_string();
|
||||
old_resource.extra = Some(ColumnExtra::default());
|
||||
old_resource.original = Some(ColumnInfo {
|
||||
name: "old_resource".to_string(),
|
||||
data_type: "json".to_string(),
|
||||
is_nullable: true,
|
||||
column_default: None,
|
||||
is_primary_key: false,
|
||||
extra: Some("secondary_index='1'".to_string()),
|
||||
comment: None,
|
||||
});
|
||||
|
||||
let result = build_table_structure_change_sql(TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::ManticoreSearch),
|
||||
schema: None,
|
||||
table_name: "materials".to_string(),
|
||||
columns: vec![name, resource, old_resource],
|
||||
indexes: Vec::new(),
|
||||
foreign_keys: Vec::new(),
|
||||
triggers: Vec::new(),
|
||||
table_comment: None,
|
||||
original_table_comment: None,
|
||||
});
|
||||
|
||||
assert_eq!(result.statements, Vec::<String>::new());
|
||||
assert_eq!(
|
||||
result.warnings,
|
||||
vec![
|
||||
"Editing existing columns is not supported for manticoresearch yet.",
|
||||
"Editing existing columns is not supported for manticoresearch yet.",
|
||||
"Editing existing columns is not supported for manticoresearch yet.",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manticoresearch_ignores_mysql_column_options() {
|
||||
let mut title = column("title");
|
||||
title.data_type = "text".to_string();
|
||||
title.is_nullable = false;
|
||||
title.is_primary_key = true;
|
||||
title.default_value = "'untitled'".to_string();
|
||||
title.comment = "Title text".to_string();
|
||||
|
||||
let result = build_create_table_sql(TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::ManticoreSearch),
|
||||
schema: None,
|
||||
table_name: "materials".to_string(),
|
||||
columns: vec![title],
|
||||
indexes: Vec::new(),
|
||||
foreign_keys: Vec::new(),
|
||||
triggers: Vec::new(),
|
||||
table_comment: None,
|
||||
original_table_comment: None,
|
||||
});
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(result.statements, vec!["CREATE TABLE `materials` (\n `title` text\n);"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manticoresearch_builds_text_column_properties() {
|
||||
let mut title = column("title");
|
||||
title.data_type = "text".to_string();
|
||||
title.extra =
|
||||
Some(ColumnExtra { manticore_indexed: Some(true), manticore_stored: Some(true), ..Default::default() });
|
||||
let mut sku = column("sku");
|
||||
sku.data_type = "string".to_string();
|
||||
sku.extra =
|
||||
Some(ColumnExtra { manticore_indexed: Some(true), manticore_attribute: Some(true), ..Default::default() });
|
||||
let mut name = column("name");
|
||||
name.data_type = "string".to_string();
|
||||
name.extra = Some(ColumnExtra {
|
||||
manticore_indexed: Some(true),
|
||||
manticore_stored: Some(true),
|
||||
manticore_attribute: Some(true),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let result = build_create_table_sql(TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::ManticoreSearch),
|
||||
schema: None,
|
||||
table_name: "materials".to_string(),
|
||||
columns: vec![title, sku, name],
|
||||
indexes: Vec::new(),
|
||||
foreign_keys: Vec::new(),
|
||||
triggers: Vec::new(),
|
||||
table_comment: None,
|
||||
original_table_comment: None,
|
||||
});
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(
|
||||
result.statements,
|
||||
vec![
|
||||
"CREATE TABLE `materials` (\n `title` text stored indexed,\n `sku` string attribute indexed,\n `name` string stored attribute indexed\n);"
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manticoresearch_builds_json_secondary_index_property() {
|
||||
let mut metadata = column("metadata");
|
||||
metadata.data_type = "json".to_string();
|
||||
metadata.extra = Some(ColumnExtra { manticore_secondary_index: Some(true), ..Default::default() });
|
||||
|
||||
let result = build_create_table_sql(TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::ManticoreSearch),
|
||||
schema: None,
|
||||
table_name: "materials".to_string(),
|
||||
columns: vec![metadata],
|
||||
indexes: Vec::new(),
|
||||
foreign_keys: Vec::new(),
|
||||
triggers: Vec::new(),
|
||||
table_comment: None,
|
||||
original_table_comment: None,
|
||||
});
|
||||
|
||||
assert_eq!(result.warnings, Vec::<String>::new());
|
||||
assert_eq!(result.statements, vec!["CREATE TABLE `materials` (\n `metadata` json secondary_index='1'\n);"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mysql_create_unique_index_with_comment_and_btree() {
|
||||
let mut idx = index("uniq_users_email", &["email"]);
|
||||
@@ -854,7 +1111,7 @@ fn mysql_create_table_with_auto_increment() {
|
||||
col.data_type = "int".to_string();
|
||||
col.is_nullable = false;
|
||||
col.is_primary_key = true;
|
||||
col.extra = Some(ColumnExtra { auto_increment: Some(true), on_update_current_timestamp: None, identity: None });
|
||||
col.extra = Some(ColumnExtra { auto_increment: Some(true), ..Default::default() });
|
||||
|
||||
let result = build_create_table_sql(TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
@@ -879,7 +1136,7 @@ fn mysql_create_table_with_on_update_current_timestamp() {
|
||||
col.data_type = "timestamp".to_string();
|
||||
col.is_nullable = false;
|
||||
col.default_value = "CURRENT_TIMESTAMP".to_string();
|
||||
col.extra = Some(ColumnExtra { auto_increment: None, on_update_current_timestamp: Some(true), identity: None });
|
||||
col.extra = Some(ColumnExtra { on_update_current_timestamp: Some(true), ..Default::default() });
|
||||
|
||||
let result = build_create_table_sql(TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::Mysql),
|
||||
@@ -903,9 +1160,8 @@ fn postgres_create_table_with_identity() {
|
||||
col.data_type = "integer".to_string();
|
||||
col.is_nullable = false;
|
||||
col.extra = Some(ColumnExtra {
|
||||
auto_increment: None,
|
||||
on_update_current_timestamp: None,
|
||||
identity: Some(ColumnIdentity { generation: Some("BY DEFAULT".to_string()), seed: None, increment: None }),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let result = build_create_table_sql(TableStructureSqlOptions {
|
||||
@@ -931,8 +1187,8 @@ fn sqlserver_create_table_with_identity() {
|
||||
col.is_nullable = false;
|
||||
col.extra = Some(ColumnExtra {
|
||||
auto_increment: Some(true),
|
||||
on_update_current_timestamp: None,
|
||||
identity: Some(ColumnIdentity { generation: None, seed: Some(100), increment: Some(5) }),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let result = build_create_table_sql(TableStructureSqlOptions {
|
||||
|
||||
@@ -25,7 +25,7 @@ pub struct EditableStructureColumn {
|
||||
pub marked_for_drop: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ColumnExtra {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
@@ -34,6 +34,14 @@ pub struct ColumnExtra {
|
||||
pub on_update_current_timestamp: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub identity: Option<ColumnIdentity>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub manticore_indexed: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub manticore_stored: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub manticore_attribute: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub manticore_secondary_index: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
|
||||
@@ -18,7 +18,7 @@ pub(super) fn qualified_table(dialect: StructureDialect, schema: Option<&str>, t
|
||||
|
||||
pub(super) fn quote_ident(dialect: StructureDialect, name: &str) -> String {
|
||||
match dialect {
|
||||
StructureDialect::Mysql => format!("`{}`", name.replace('`', "``")),
|
||||
StructureDialect::Mysql | StructureDialect::ManticoreSearch => format!("`{}`", name.replace('`', "``")),
|
||||
StructureDialect::SqlServer => format!("[{}]", name.replace(']', "]]")),
|
||||
StructureDialect::Informix if is_simple_informix_identifier(name) => name.to_string(),
|
||||
_ => format!("\"{}\"", name.replace('"', "\"\"")),
|
||||
@@ -42,6 +42,10 @@ pub(super) fn clean(value: &str) -> String {
|
||||
value.trim().to_string()
|
||||
}
|
||||
|
||||
pub(super) fn is_protected_manticore_id_column(dialect: StructureDialect, column_name: &str) -> bool {
|
||||
dialect == StructureDialect::ManticoreSearch && column_name.trim().eq_ignore_ascii_case("id")
|
||||
}
|
||||
|
||||
pub(super) fn is_temporal_type_for_default(dialect: StructureDialect, base_type: &str) -> bool {
|
||||
let normalized = base_type.split_whitespace().collect::<Vec<_>>().join(" ").to_ascii_lowercase();
|
||||
match dialect {
|
||||
|
||||
Reference in new issue
Block a user