Repository: SeaQL/sea-query (Rust)

Issue:
Wrong spacing before UNIQUE keyword
I think there should be a space in `"idx-comment"UNIQUE`.
```
fn create_comment_table() -> TableCreateStatement {
    Table::create()
        .table(Comment::Table)
        .if_not_exists()
        .col(
            ColumnDef::new(Comment::Id)
                .integer()
                .not_null()
                .auto_increment()
                .primary_key(),
        )
        .col(
            ColumnDef::new(Comment::Content)
                .text()
                .not_null(),
        )
        .col(
            ColumnDef::new(Comment::DateCreated)
                .date_time()
                .not_null(),
        )
        .col(
            ColumnDef::new(Comment::LastUpdated)
                .date_time()
                .not_null(),
        )
        .col(
            ColumnDef::new(Comment::UserId)
                .integer()
                .not_null(),
        )
        .col(
            ColumnDef::new(Comment::MediaId)
                .integer()
                .not_null(),
        )
        .foreign_key(
            ForeignKey::create()
                .name("fk_Comment_User")
                .from(Comment::Table, Comment::UserId)
                .to(User::Table, User::Id)
                .on_delete(ForeignKeyAction::Cascade)
                .on_update(ForeignKeyAction::Cascade),
        )
        .foreign_key(
            ForeignKey::create()
                .name("fk_Comment_Media")
                .from(Comment::Table, Comment::MediaId)
                .to(Media::Table, Media::Id)
                .on_delete(ForeignKeyAction::Cascade)
                .on_update(ForeignKeyAction::Cascade),
        )
        .index(
            Index::create()
                .name("idx-comment")
                .table(Comment::Table)
                .col(Comment::UserId)
                .col(Comment::MediaId)
                .unique(),
        )
        .to_owned()
}

#[test]
    fn test_create_comment_table() {
        assert_eq!(
            create_comment_table().to_string(SqliteQueryBuilder),
            vec![
            r#"CREATE TABLE IF NOT EXISTS "comment" ("#,
                r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
                r#""content" text NOT NULL,"#,
                r#""date_created" text NOT NULL,"#,
                r#""last_updated" text NOT NULL,"#,
                r#""user_id" integer NOT NULL,"#,
                r#""media_id" integer NOT NULL,"#,
                r#"CONSTRAINT "idx-comment"UNIQUE ("user_id", "media_id"),"#,
                r#"FOREIGN KEY ("user_id") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,"#,
                r#"FOREIGN KEY ("media_id") REFERENCES "media" ("id") ON DELETE CASCADE ON UPDATE CASCADE"#,
            r#")"#,
            ].join(" ")
        );
    }

```


Discussion:
@JediMaster25 yes, you are right! Thank you. Would you like to create PR?)
If @JediMaster25 has no time I could also help (depends on @JediMaster25's decision) :)
@nahuakang please, do this)



Patch:
diff --git a/src/backend/index_builder.rs b/src/backend/index_builder.rs
index ff1b73f2b..bd2034fbe 100644
--- a/src/backend/index_builder.rs
+++ b/src/backend/index_builder.rs
@@ -2,34 +2,22 @@ use crate::*;
 
 pub trait IndexBuilder: QuotedBuilder + TableRefBuilder {
     /// Translate [`IndexCreateStatement`] into SQL expression.
+    /// This is the default implementation for `PostgresQueryBuilder` and `SqliteQueryBuilder`.
+    /// `MysqlQueryBuilder` overrides this default implementation.
     fn prepare_table_index_expression(&self, create: &IndexCreateStatement, sql: &mut SqlWriter) {
-        self.prepare_index_prefix(create, sql);
-        write!(sql, "KEY ").unwrap();
-
-        self.prepare_index_name(&create.index.name, sql);
+        if create.index.name.is_some() {
+            write!(sql, "CONSTRAINT ").unwrap();
+            self.prepare_index_name(&create.index.name, sql);
+            write!(sql, " ").unwrap();
+        }
 
-        self.prepare_index_type(&create.index_type, sql);
+        self.prepare_index_prefix(create, sql);
 
         self.prepare_index_columns(&create.index.columns, sql);
     }
 
     /// Translate [`IndexCreateStatement`] into SQL statement.
-    fn prepare_index_create_statement(&self, create: &IndexCreateStatement, sql: &mut SqlWriter) {
-        write!(sql, "CREATE ").unwrap();
-        self.prepare_index_prefix(create, sql);
-        write!(sql, "INDEX ").unwrap();
-
-        self.prepare_index_name(&create.index.name, sql);
-
-        write!(sql, " ON ").unwrap();
-        if let Some(table) = &create.table {
-            self.prepare_table_ref_index_stmt(table, sql);
-        }
-
-        self.prepare_index_type(&create.index_type, sql);
-
-        self.prepare_index_columns(&create.index.columns, sql);
-    }
+    fn prepare_index_create_statement(&self, create: &IndexCreateStatement, sql: &mut SqlWriter);
 
     /// Translate [`TableRef`] into SQL statement.
     fn prepare_table_ref_index_stmt(&self, table_ref: &TableRef, sql: &mut SqlWriter);
diff --git a/src/backend/postgres/index.rs b/src/backend/postgres/index.rs
index 943844fea..4b3d98f4e 100644
--- a/src/backend/postgres/index.rs
+++ b/src/backend/postgres/index.rs
@@ -1,18 +1,6 @@
 use super::*;
 
 impl IndexBuilder for PostgresQueryBuilder {
-    fn prepare_table_index_expression(&self, create: &IndexCreateStatement, sql: &mut SqlWriter) {
-        if create.index.name.is_some() {
-            write!(sql, "CONSTRAINT ").unwrap();
-            self.prepare_index_name(&create.index.name, sql);
-            write!(sql, " ").unwrap();
-        }
-
-        self.prepare_index_prefix(create, sql);
-
-        self.prepare_index_columns(&create.index.columns, sql);
-    }
-
     fn prepare_index_create_statement(&self, create: &IndexCreateStatement, sql: &mut SqlWriter) {
         write!(sql, "CREATE ").unwrap();
         self.prepare_index_prefix(create, sql);
diff --git a/src/backend/sqlite/index.rs b/src/backend/sqlite/index.rs
index 238f9fb07..54069cff5 100644
--- a/src/backend/sqlite/index.rs
+++ b/src/backend/sqlite/index.rs
@@ -1,17 +1,6 @@
 use super::*;
 
 impl IndexBuilder for SqliteQueryBuilder {
-    fn prepare_table_index_expression(&self, create: &IndexCreateStatement, sql: &mut SqlWriter) {
-        if create.index.name.is_some() {
-            write!(sql, "CONSTRAINT ").unwrap();
-        }
-        self.prepare_index_name(&create.index.name, sql);
-
-        self.prepare_index_prefix(create, sql);
-
-        self.prepare_index_columns(&create.index.columns, sql);
-    }
-
     fn prepare_index_create_statement(&self, create: &IndexCreateStatement, sql: &mut SqlWriter) {
         write!(sql, "CREATE ").unwrap();
         self.prepare_index_prefix(create, sql);


Test patch:
diff --git a/tests/sqlite/table.rs b/tests/sqlite/table.rs
index c5e4e8a5b..1f0f5a6a7 100644
--- a/tests/sqlite/table.rs
+++ b/tests/sqlite/table.rs
@@ -239,6 +239,59 @@ fn create_with_primary_unique_index() {
     );
 }
 
+#[test]
+fn create_with_unique_index_constraint() {
+    assert_eq!(
+        Table::create()
+            .table(Char::Table)
+            .if_not_exists()
+            .col(
+                ColumnDef::new(Char::Id)
+                    .integer()
+                    .not_null()
+                    .auto_increment()
+                    .primary_key(),
+            )
+            .col(ColumnDef::new(Char::FontSize).integer().not_null())
+            .col(ColumnDef::new(Char::Character).string().not_null())
+            .col(ColumnDef::new(Char::SizeW).integer().not_null())
+            .col(ColumnDef::new(Char::SizeH).integer().not_null())
+            .col(
+                ColumnDef::new(Char::FontId)
+                    .integer()
+                    .default(Value::Int(None)),
+            )
+            .foreign_key(
+                ForeignKey::create()
+                    .from(Char::Table, Char::FontId)
+                    .to(Font::Table, Font::Id)
+                    .on_delete(ForeignKeyAction::Cascade)
+                    .on_update(ForeignKeyAction::Cascade),
+            )
+            .index(
+                Index::create()
+                    .name("idx-sizehw")
+                    .table(Char::Table)
+                    .col(Char::SizeH)
+                    .col(Char::SizeW)
+                    .unique(),
+            )
+            .to_string(SqliteQueryBuilder),
+        vec![
+            r#"CREATE TABLE IF NOT EXISTS "character" ("#,
+            r#""id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"#,
+            r#""font_size" integer NOT NULL,"#,
+            r#""character" text NOT NULL,"#,
+            r#""size_w" integer NOT NULL,"#,
+            r#""size_h" integer NOT NULL,"#,
+            r#""font_id" integer DEFAULT NULL,"#,
+            r#"CONSTRAINT "idx-sizehw" UNIQUE ("size_h", "size_w"),"#,
+            r#"FOREIGN KEY ("font_id") REFERENCES "font" ("id") ON DELETE CASCADE ON UPDATE CASCADE"#,
+            r#")"#,
+        ].join(" ")
+    );
+}
+
 #[test]
 fn drop_1() {
     assert_eq!(