MdpSchemaAlignerTests.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. using Admin.NET.Plugin.AiDOP.DataPlatform.Schema;
  2. using Xunit;
  3. namespace Admin.NET.Plugin.AiDOP.Tests.DataPlatform;
  4. public class MdpSchemaAlignerTests
  5. {
  6. private const string Create = """
  7. CREATE TABLE IF NOT EXISTS mdp_std_demo (
  8. id BIGINT AUTO_INCREMENT PRIMARY KEY,
  9. tenant_id BIGINT NOT NULL,
  10. approved_flag TINYINT NOT NULL DEFAULT 1,
  11. UNIQUE KEY uk_demo (tenant_id),
  12. KEY idx_demo (approved_flag)
  13. ) ENGINE=InnoDB
  14. """;
  15. [Fact]
  16. public void MissingTable_PlansCreateOnly()
  17. {
  18. var planned = MdpSchemaAligner.Plan(Create, SchemaSnapshot.Missing);
  19. Assert.Single(planned);
  20. Assert.StartsWith("CREATE TABLE", planned[0], StringComparison.OrdinalIgnoreCase);
  21. Assert.DoesNotContain("DROP", planned[0], StringComparison.OrdinalIgnoreCase);
  22. }
  23. [Fact]
  24. public void MissingColumnAndIndex_PlansAdditiveAlterOnly()
  25. {
  26. var snapshot = new SchemaSnapshot(true, ["id", "tenant_id"], ["PRIMARY"]);
  27. var planned = MdpSchemaAligner.Plan(Create, snapshot);
  28. Assert.Equal(3, planned.Count);
  29. Assert.Contains(planned, x => x.Contains("ADD COLUMN approved_flag", StringComparison.OrdinalIgnoreCase));
  30. Assert.Contains(planned, x => x.Contains("ADD UNIQUE KEY `uk_demo`", StringComparison.OrdinalIgnoreCase));
  31. Assert.Contains(planned, x => x.Contains("ADD KEY `idx_demo`", StringComparison.OrdinalIgnoreCase));
  32. Assert.DoesNotContain(planned, x => x.Contains("DROP", StringComparison.OrdinalIgnoreCase));
  33. }
  34. [Fact]
  35. public void ReadyTable_PlansNothing()
  36. {
  37. var snapshot = new SchemaSnapshot(
  38. true,
  39. ["id", "tenant_id", "approved_flag"],
  40. ["PRIMARY", "uk_demo", "idx_demo"]);
  41. Assert.Empty(MdpSchemaAligner.Plan(Create, snapshot));
  42. }
  43. [Fact]
  44. public void LikeTable_SkippedWhenPresent()
  45. {
  46. const string like = "CREATE TABLE IF NOT EXISTS mdp_stg_s4_shipment LIKE mdp_stg_s4_iqc";
  47. Assert.Empty(MdpSchemaAligner.Plan(like, new SchemaSnapshot(true, [], [])));
  48. var created = MdpSchemaAligner.Plan(like, SchemaSnapshot.Missing);
  49. Assert.Single(created);
  50. Assert.Contains("LIKE", created[0], StringComparison.OrdinalIgnoreCase);
  51. }
  52. /// <summary>
  53. /// dwd_requirement_examine_detail 的 need_count 前面有一段说明注释。
  54. /// Plan 过去不剥行注释,ColumnName 取到的是「--」而不是 need_count,于是这一列
  55. /// 每次都被当成缺列再 ADD 一次;MySQL 执行 ALTER 时自己吃掉注释,抛
  56. /// 「Duplicate column name 'need_count'」,S1 重算因此每次都在对齐阶段失败。
  57. /// </summary>
  58. [Fact]
  59. public void CommentedColumns_AreNotReAdded()
  60. {
  61. const string create = """
  62. CREATE TABLE IF NOT EXISTS mdp_std_demo (
  63. id BIGINT AUTO_INCREMENT PRIMARY KEY,
  64. tenant_id BIGINT NOT NULL,
  65. -- 说明:这一列前面有注释,注释里还有逗号、括号 (a,b) 和 don't 这种单引号
  66. -- 第二行注释
  67. need_count DECIMAL(18,4) NULL COMMENT '标准列·需求量',
  68. approved_flag TINYINT NOT NULL DEFAULT 1
  69. ) ENGINE=InnoDB
  70. """;
  71. var ready = new SchemaSnapshot(
  72. true, ["id", "tenant_id", "need_count", "approved_flag"], ["PRIMARY"]);
  73. Assert.Empty(MdpSchemaAligner.Plan(create, ready));
  74. var missingOne = new SchemaSnapshot(true, ["id", "tenant_id", "approved_flag"], ["PRIMARY"]);
  75. var planned = MdpSchemaAligner.Plan(create, missingOne);
  76. Assert.Single(planned);
  77. Assert.Contains("ADD COLUMN need_count", planned[0], StringComparison.OrdinalIgnoreCase);
  78. Assert.DoesNotContain("--", planned[0], StringComparison.Ordinal);
  79. }
  80. /// <summary>COMMENT 字符串里的 -- 不是注释,不能被剥掉。</summary>
  81. [Fact]
  82. public void StripLineComments_KeepsDashesInsideQuotedText()
  83. {
  84. var stripped = MdpSchemaAligner.StripLineComments(
  85. "a VARCHAR(10) COMMENT 'x -- y', -- 真注释\nb INT");
  86. Assert.Contains("'x -- y'", stripped, StringComparison.Ordinal);
  87. Assert.DoesNotContain("真注释", stripped, StringComparison.Ordinal);
  88. Assert.Contains("b INT", stripped, StringComparison.Ordinal);
  89. }
  90. [Fact]
  91. public void NonNeutralTable_IsLeftUntouched()
  92. {
  93. const string sql = "CREATE TABLE IF NOT EXISTS qms_demo (id BIGINT)";
  94. var planned = MdpSchemaAligner.Plan(sql, SchemaSnapshot.Missing);
  95. Assert.Equal([sql], planned);
  96. }
  97. }