From da541b675c7b608c83dec12a4abf3c688bbf9dd1 Mon Sep 17 00:00:00 2001 From: Stephen Kalpin Date: Thu, 15 Aug 2019 16:27:32 -0500 Subject: [PATCH] Generate Sqlite create table comments - This only works with create table. Alter table commands do not preserve comments. - If comments are included, each column will be spaced. - Table comments - Column comments Fixes #16820 --- .../SqliteMigrationsSqlGenerator.cs | 83 ++++++++- .../SqliteMigrationSqlGeneratorTest.cs | 175 ++++++++++++++++++ 2 files changed, 257 insertions(+), 1 deletion(-) diff --git a/src/EFCore.Sqlite.Core/Migrations/SqliteMigrationsSqlGenerator.cs b/src/EFCore.Sqlite.Core/Migrations/SqliteMigrationsSqlGenerator.cs index 9c91131ebb3..fc5179eb7f1 100644 --- a/src/EFCore.Sqlite.Core/Migrations/SqliteMigrationsSqlGenerator.cs +++ b/src/EFCore.Sqlite.Core/Migrations/SqliteMigrationsSqlGenerator.cs @@ -345,7 +345,88 @@ protected override void Generate( } } - base.Generate(operation, model, builder, terminate); + if (string.IsNullOrEmpty(operation.Comment)) + { + base.Generate(operation, model, builder, terminate); + } + else + { + builder + .Append("CREATE TABLE ") + .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name, operation.Schema)) + .AppendLine(" ("); + + using (builder.Indent()) + { + CreateComment(builder, operation.Comment); + builder.AppendLine(); + CreateTableColumns(operation, model, builder); + CreateTableConstraints(operation, model, builder); + builder.AppendLine(); + } + + builder.Append(")"); + + if (terminate) + { + builder.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator); + EndStatement(builder); + } + } + } + + protected override void CreateTableColumns( + CreateTableOperation operation, + IModel model, + MigrationCommandListBuilder builder) + { + Check.NotNull(operation, nameof(operation)); + Check.NotNull(builder, nameof(builder)); + + if (!operation.Columns.Any(c => !string.IsNullOrEmpty(c.Comment))) + { + base.CreateTableColumns(operation, model, builder); + } + else + { + CreateTableColumnsWithComments(operation, model, builder); + } + } + + private void CreateTableColumnsWithComments( + CreateTableOperation operation, + IModel model, + MigrationCommandListBuilder builder) + { + for (var i = 0; i < operation.Columns.Count; i++) + { + var column = operation.Columns[i]; + + if (i > 0) + { + builder.AppendLine(); + } + + if (!string.IsNullOrEmpty(column.Comment)) + { + CreateComment(builder, column.Comment); + } + + ColumnDefinition(column, model, builder); + + if (i != operation.Columns.Count - 1) + { + builder.AppendLine(","); + } + } + } + + private void CreateComment(MigrationCommandListBuilder builder, string comment) + { + foreach (var line in comment.Split(Environment.NewLine).Select(l => $"-- {l}")) + { + builder.AppendLine(line); + } } /// diff --git a/test/EFCore.Sqlite.FunctionalTests/SqliteMigrationSqlGeneratorTest.cs b/test/EFCore.Sqlite.FunctionalTests/SqliteMigrationSqlGeneratorTest.cs index 48bfaff3f08..8ec6f1c79c9 100644 --- a/test/EFCore.Sqlite.FunctionalTests/SqliteMigrationSqlGeneratorTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/SqliteMigrationSqlGeneratorTest.cs @@ -506,6 +506,181 @@ public virtual void CreateTableOperation_old_autoincrement_annotation() "); } + [ConditionalFact] + public virtual void CreateTableOperation_has_comment() + { + Generate( + new CreateTableOperation + { + Name = "People", + Columns = + { + new AddColumnOperation + { + Name = "Id", + Table = "People", + ClrType = typeof(int), + IsNullable = false, + Comment = "The ID" + }, + new AddColumnOperation + { + Name = "UncommentedColumn1", + Table = "People", + ClrType = typeof(string), + IsNullable = false + }, + new AddColumnOperation + { + Name = "UncommentedColumn2", + Table = "People", + ClrType = typeof(string), + IsNullable = false + }, + new AddColumnOperation + { + Name = "Name", + Table = "People", + ClrType = typeof(string), + IsNullable = false, + Comment = "The Name" + } + } + }); + + AssertSql( + @"CREATE TABLE ""People"" ( + -- The ID + ""Id"" INTEGER NOT NULL, + + ""UncommentedColumn1"" TEXT NOT NULL, + + ""UncommentedColumn2"" TEXT NOT NULL, + + -- The Name + ""Name"" TEXT NOT NULL +); +"); + } + + [ConditionalFact] + public virtual void CreateTableOperation_no_comments() + { + Generate( + new CreateTableOperation + { + Name = "People", + Columns = + { + new AddColumnOperation + { + Name = "Id", + Table = "People", + ClrType = typeof(int), + IsNullable = false, + }, + new AddColumnOperation + { + Name = "UncommentedColumn1", + Table = "People", + ClrType = typeof(string), + IsNullable = false + }, + new AddColumnOperation + { + Name = "UncommentedColumn2", + Table = "People", + ClrType = typeof(string), + IsNullable = false + }, + new AddColumnOperation + { + Name = "UncommentedName", + Table = "People", + ClrType = typeof(string), + IsNullable = false, + } + } + }); + + AssertSql( + @"CREATE TABLE ""People"" ( + ""Id"" INTEGER NOT NULL, + ""UncommentedColumn1"" TEXT NOT NULL, + ""UncommentedColumn2"" TEXT NOT NULL, + ""UncommentedName"" TEXT NOT NULL +); +"); + } + + [ConditionalFact] + public virtual void CreateTableOperation_has_multi_line_comment() + { + Generate( + new CreateTableOperation + { + Name = "People", + Columns = + { + new AddColumnOperation + { + Name = "Id", + Table = "People", + ClrType = typeof(int), + IsNullable = false, + Comment = @"This is a multi-line +comment. +More information can +be found in the docs." + + }, + } + }); + + AssertSql( + @"CREATE TABLE ""People"" ( + -- This is a multi-line + -- comment. + -- More information can + -- be found in the docs. + ""Id"" INTEGER NOT NULL +); +"); + } + + [ConditionalFact] + public virtual void CreateTableOperation_has_multi_line_table_comment() + { + Generate( + new CreateTableOperation + { + Name = "People", + Comment = @"Table level comment +that continues onto another line", + Columns = + { + new AddColumnOperation + { + Name = "Id", + Table = "People", + ClrType = typeof(int), + IsNullable = false, + Comment = "My Comment" + }, + } + }); + + AssertSql( + @"CREATE TABLE ""People"" ( + -- Table level comment + -- that continues onto another line + + -- My Comment + ""Id"" INTEGER NOT NULL +); +"); + } + public SqliteMigrationSqlGeneratorTest() : base(SqliteTestHelpers.Instance) {