Skip to content

Commit b64bea0

Browse files
committed
feat: enhance compatibility handling for legacy UserDefinedType formatting during comparison
1 parent de82866 commit b64bea0

5 files changed

Lines changed: 51 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
1717
- Treat equivalent `TableData` scripts as compatible during comparison when the normalized `INSERT` statements differ only by row ordering within the same contiguous data block.
1818
- Treat equivalent `Table` scripts as compatible during comparison when post-create statement packages differ only by ordering after the base `CREATE TABLE` block.
1919
- Treat equivalent legacy `Table` statement formatting as compatible during comparison when normalized table definitions, post-create table statements, and persisted option values are otherwise identical.
20+
- Treat equivalent legacy `UserDefinedType` `CREATE TYPE` formatting as compatible during comparison when the normalized type definition is otherwise identical.
2021
- Treat omitted `TEXTIMAGE_ON` on `Table` scripts as compatible during comparison only when DB metadata shows the table LOB data space matches the current default data space.
2122
- Treat equivalent extended-property blocks as compatible during comparison when the normalized `sp_addextendedproperty` statements differ only by ordering, argument spacing, or named-vs-positional argument forms within the same contiguous block.
2223
- Treat leading SSMS-generated banner comments on programmable objects as compatible during comparison.

specs/01-cli.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ Behavior:
207207
- Equivalent `TableData` `INSERT` statement ordering within the same contiguous data block compares as compatible when the inserted row set is otherwise identical.
208208
- Equivalent `Table` post-create statement package ordering compares as compatible when the normalized package set after the base `CREATE TABLE` block is otherwise identical.
209209
- Equivalent legacy `Table` statement formatting for `CREATE TABLE`, `ALTER TABLE`, and `CREATE ... INDEX` statements compares as compatible when normalized identifiers, type tokens, default expressions, semicolons, and persisted option values are otherwise identical.
210+
- Equivalent legacy `UserDefinedType` `CREATE TYPE` statement formatting compares as compatible when normalized identifiers, type tokens, default expressions, semicolons, and inline table-valued type bodies are otherwise identical.
210211
- For `Table`, omitted `TEXTIMAGE_ON [name]` compares as compatible with an explicit clause only when DB metadata shows that the table LOB data space equals the current default data space represented by `[name]`.
211212
- Equivalent extended-property statement ordering within the same contiguous extended-property block compares as compatible when the normalized property statement set is otherwise identical. Equivalent named-vs-positional `sp_addextendedproperty` argument forms, including omitted trailing `NULL` levels, compare as compatible.
212213
- Equivalent `Queue` option spacing, line wrapping, explicit default `ON [PRIMARY]`, and disabled default activation compare as compatible.
@@ -239,6 +240,7 @@ Behavior:
239240
- Equivalent `TableData` `INSERT` statement ordering within the same contiguous data block compares as compatible when the inserted row set is otherwise identical.
240241
- Equivalent `Table` post-create statement package ordering compares as compatible when the normalized package set after the base `CREATE TABLE` block is otherwise identical.
241242
- Equivalent legacy `Table` statement formatting for `CREATE TABLE`, `ALTER TABLE`, and `CREATE ... INDEX` statements compares as compatible when normalized identifiers, type tokens, default expressions, semicolons, and persisted option values are otherwise identical.
243+
- Equivalent legacy `UserDefinedType` `CREATE TYPE` statement formatting compares as compatible when normalized identifiers, type tokens, default expressions, semicolons, and inline table-valued type bodies are otherwise identical.
242244
- For `Table`, omitted `TEXTIMAGE_ON [name]` compares as compatible with an explicit clause only when DB metadata shows that the table LOB data space equals the current default data space represented by `[name]`.
243245
- Equivalent extended-property statement ordering within the same contiguous extended-property block compares as compatible when the normalized property statement set is otherwise identical. Equivalent named-vs-positional `sp_addextendedproperty` argument forms, including omitted trailing `NULL` levels, compare as compatible.
244246
- Equivalent `Queue` option spacing, line wrapping, explicit default `ON [PRIMARY]`, and disabled default activation compare as compatible.

specs/04-scripting.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,7 @@ When compatibility reference files are available, `sqlct` MAY apply reconciliati
820820
- For `TableData`, comparison normalization MAY treat reordered `INSERT ... VALUES (...)` statements within the same contiguous data block as compatible when the normalized inserted-row set is otherwise identical.
821821
- For `Table`, comparison normalization MAY treat reordered post-create statement packages as compatible when the normalized package set after the base table `CREATE` block is otherwise identical. Table-scoped trigger packages MUST include the trigger body together with any immediately preceding programmable-object `SET` blocks.
822822
- For `Table`, comparison normalization MAY treat equivalent legacy formatting for `CREATE TABLE`, `ALTER TABLE`, and `CREATE ... INDEX` statement blocks as compatible when normalized identifiers, type tokens, default expressions, semicolons, and persisted option values are otherwise identical.
823+
- For `UserDefinedType`, comparison normalization MAY treat equivalent legacy `CREATE TYPE` statement formatting as compatible when normalized identifiers, type tokens, default expressions, semicolons, and inline table-valued type bodies are otherwise identical.
823824
- For `Table`, comparison normalization MAY treat omitted `TEXTIMAGE_ON [name]` as compatible with an explicit clause only when DB metadata shows that the table `lob_data_space_id` resolves to the current default data space named `[name]`; otherwise omission remains a semantic difference.
824825
- For extended-property blocks, comparison normalization MAY treat reordered `EXEC sp_addextendedproperty ...` statements as compatible within the same contiguous extended-property block when the normalized property statement set is otherwise identical, MAY ignore equivalent spacing around commas and arguments in those statements, and MAY treat equivalent named-vs-positional argument forms with omitted trailing `NULL` levels as compatible.
825826
- For programmable `StoredProcedure`, `View`, `Function`, and `Trigger` scripts, comparison normalization MAY ignore leading SSMS-generated `/*** Object: ... Script Date: ... ***/` banner comments.

src/SqlChangeTracker/Sync/SyncCommandService.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2110,6 +2110,10 @@ internal static string NormalizeForComparison(
21102110
compatibleOmittedTextImageOnDataSpaceName);
21112111
joined = NormalizeTableScriptForComparison(joined);
21122112
}
2113+
else if (string.Equals(objectType, "UserDefinedType", StringComparison.OrdinalIgnoreCase))
2114+
{
2115+
joined = NormalizeUserDefinedTypeScriptForComparison(joined);
2116+
}
21132117

21142118
if (!joined.Contains("INSERT ", StringComparison.OrdinalIgnoreCase))
21152119
{
@@ -2693,6 +2697,24 @@ private static string NormalizeTablePostCreatePackageForComparison(string packag
26932697
return NormalizeTableBlockForComparison(blocks[0]);
26942698
}
26952699

2700+
private static string NormalizeUserDefinedTypeScriptForComparison(string script)
2701+
{
2702+
var blocks = SplitGoDelimitedBlocks(script);
2703+
for (var i = 0; i < blocks.Count; i++)
2704+
{
2705+
var firstLine = GetFirstMeaningfulLine(blocks[i]);
2706+
if (firstLine is null ||
2707+
!firstLine.StartsWith("CREATE TYPE", StringComparison.OrdinalIgnoreCase))
2708+
{
2709+
continue;
2710+
}
2711+
2712+
blocks[i] = [NormalizeLegacyTableStatementBlockForComparison(blocks[i])];
2713+
}
2714+
2715+
return string.Join("\n", blocks.SelectMany(block => block));
2716+
}
2717+
26962718
private static string NormalizeLegacyTableStatementBlockForComparison(IEnumerable<string> block)
26972719
{
26982720
var statement = string.Join(

tests/SqlChangeTracker.Tests/Sync/SyncCommandServiceTests.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,6 +1615,31 @@ public void BuildUnifiedDiff_Table_SuppressesEquivalentLegacyTableFormattingDiff
16151615
Assert.Empty(diff);
16161616
}
16171617

1618+
[Fact]
1619+
public void BuildUnifiedDiff_UserDefinedType_SuppressesEquivalentLegacyTableValuedTypeFormattingDifferences()
1620+
{
1621+
var source =
1622+
"CREATE TYPE [Accounting].[RateWindow] AS TABLE\n" +
1623+
"(\n" +
1624+
"[EffectiveDate] [date] NOT NULL,\n" +
1625+
"[RateValue] [decimal] (15, 8) NOT NULL,\n" +
1626+
"[YearFraction] [decimal] (15, 12) NOT NULL\n" +
1627+
")\n" +
1628+
"GO";
1629+
var target =
1630+
"CREATE TYPE Accounting.RateWindow AS TABLE\n" +
1631+
"(\n" +
1632+
" [EffectiveDate] DATE NOT NULL,\n" +
1633+
" RateValue DECIMAL(15,8) NOT NULL,\n" +
1634+
" YearFraction Decimal(15,12) NOT NULL\n" +
1635+
");\n" +
1636+
"GO";
1637+
1638+
var diff = SyncCommandService.BuildUnifiedDiff("UserDefinedType", "db", "folder", source, target);
1639+
1640+
Assert.Empty(diff);
1641+
}
1642+
16181643
[Fact]
16191644
public void BuildUnifiedDiff_Table_PreservesPostCreatePackageContentDifferencesWhenOrderAlsoDiffers()
16201645
{

0 commit comments

Comments
 (0)