Skip to content

Commit 641b6b8

Browse files
Add Schema Compare Service endpoint to include/exclude all comparison diffs (#2466)
* Add schema compare include/exclude all diffs * Add service test for include/exclude all * Code review changes * Add test for include/exclude all schema differences * Reorder using statements. * Add count assert * Verify expected number of included/excluded diffs * Move include/exclude all count assert * Verify include all works after excluding all * Improve test example * Make target script match dev setup for include/exclude all
1 parent 1ef86e9 commit 641b6b8

File tree

4 files changed

+397
-2
lines changed

4 files changed

+397
-2
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
#nullable disable
7+
8+
using System.Collections.Generic;
9+
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
10+
using Microsoft.SqlTools.ServiceLayer.TaskServices;
11+
using Microsoft.SqlTools.ServiceLayer.Utility;
12+
13+
namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts
14+
{
15+
/// <summary>
16+
/// Parameters for a schema compare include specific node request
17+
/// </summary>
18+
public class SchemaCompareIncludeExcludeAllNodesParams
19+
{
20+
/// <summary>
21+
/// Operation id of the schema compare operation
22+
/// </summary>
23+
public string OperationId { get; set; }
24+
25+
/// <summary>
26+
/// Indicator for include or exclude request
27+
/// </summary>
28+
public bool IncludeRequest { get; set; }
29+
30+
/// <summary>
31+
/// Execution mode for the operation. Default is execution
32+
/// </summary>
33+
public TaskExecutionMode TaskExecutionMode { get; set; }
34+
}
35+
36+
public class SchemaCompareIncludeExcludeAllNodesRequest
37+
{
38+
public static readonly RequestType<SchemaCompareIncludeExcludeAllNodesParams, ResultStatus> Type =
39+
RequestType<SchemaCompareIncludeExcludeAllNodesParams, ResultStatus>.Create("schemaCompare/includeExcludeAllNodes");
40+
}
41+
42+
/// <summary>
43+
/// Parameters returned from a schema compare include/exclude all node request.
44+
/// </summary>
45+
public class SchemaCompareIncludeExcludeAllNodesResult : ResultStatus
46+
{
47+
/// <summary>
48+
/// Differences that were all included or excluded
49+
/// </summary>
50+
public List<DiffEntry> AllIncludedOrExcludedDifferences { get; set; }
51+
52+
}
53+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
#nullable disable
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Threading;
10+
using Microsoft.SqlServer.Dac.Compare;
11+
using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts;
12+
using Microsoft.SqlTools.ServiceLayer.TaskServices;
13+
using Microsoft.SqlTools.Utility;
14+
15+
namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
16+
{
17+
/// <summary>
18+
/// Class to represent an in-progress schema compare include/exclude all Node operation
19+
/// </summary>
20+
class SchemaCompareIncludeExcludeAllNodesOperation : ITaskOperation
21+
{
22+
private CancellationTokenSource cancellation = new CancellationTokenSource();
23+
private bool disposed = false;
24+
25+
/// <summary>
26+
/// Gets the unique id associated with this instance.
27+
/// </summary>
28+
public string OperationId { get; private set; }
29+
30+
public SchemaCompareIncludeExcludeAllNodesParams Parameters { get; }
31+
32+
protected CancellationToken CancellationToken { get { return this.cancellation.Token; } }
33+
34+
public string ErrorMessage { get; set; }
35+
36+
public SqlTask SqlTask { get; set; }
37+
38+
public SchemaComparisonResult ComparisonResult { get; set; }
39+
40+
public bool Success { get; set; }
41+
42+
public List<DiffEntry> AllIncludedOrExcludedDifferences;
43+
44+
45+
public SchemaCompareIncludeExcludeAllNodesOperation(SchemaCompareIncludeExcludeAllNodesParams parameters, SchemaComparisonResult comparisonResult)
46+
{
47+
Validate.IsNotNull("parameters", parameters);
48+
this.Parameters = parameters;
49+
Validate.IsNotNull("comparisonResult", comparisonResult);
50+
this.ComparisonResult = comparisonResult;
51+
}
52+
53+
/// <summary>
54+
/// Execute will include/exclude all differences in the schema compare result.
55+
/// </summary>
56+
/// <param name="mode"></param>
57+
public void Execute(TaskExecutionMode mode)
58+
{
59+
this.CancellationToken.ThrowIfCancellationRequested();
60+
61+
try
62+
{
63+
var schemaDifferences = new List<SchemaDifference>(this.ComparisonResult.Differences);
64+
this.IncludeExcludeAllDifferences(schemaDifferences);
65+
}
66+
catch (Exception e)
67+
{
68+
ErrorMessage = e.Message;
69+
Logger.Error(string.Format("Schema compare include/exclude all operation {0} failed with exception {1}", this.OperationId, e.Message));
70+
throw;
71+
}
72+
73+
this.AllIncludedOrExcludedDifferences = new List<DiffEntry>();
74+
if (this.ComparisonResult.Differences != null)
75+
{
76+
foreach (SchemaDifference difference in this.ComparisonResult.Differences)
77+
{
78+
DiffEntry diffEntry = SchemaCompareUtils.CreateDiffEntry(difference, null, this.ComparisonResult);
79+
this.AllIncludedOrExcludedDifferences.Add(diffEntry);
80+
}
81+
}
82+
}
83+
84+
private void IncludeExcludeAllDifferences(List<SchemaDifference> schemaDifferences)
85+
{
86+
var problematicDifferences = new List<SchemaDifference>();
87+
foreach (SchemaDifference difference in schemaDifferences)
88+
{
89+
this.Success = this.Parameters.IncludeRequest ? this.ComparisonResult.Include(difference) : this.ComparisonResult.Exclude(difference);
90+
91+
if (!this.Success)
92+
{
93+
problematicDifferences.Add(difference);
94+
}
95+
}
96+
97+
if (problematicDifferences.Count != 0)
98+
{
99+
IncludeExcludeAllDifferences(problematicDifferences);
100+
}
101+
}
102+
103+
/// <summary>
104+
/// The schema compare public api doesn't currently take a cancellation token so the operation can't be cancelled
105+
/// </summary>
106+
public void Cancel()
107+
{
108+
}
109+
110+
/// <summary>
111+
/// Disposes the operation.
112+
/// </summary>
113+
public void Dispose()
114+
{
115+
if (!disposed)
116+
{
117+
this.Cancel();
118+
disposed = true;
119+
}
120+
}
121+
}
122+
}

src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareService.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public void InitializeService(ServiceHost serviceHost)
5555
serviceHost.SetRequestHandler(SchemaComparePublishDatabaseChangesRequest.Type, this.HandleSchemaComparePublishDatabaseChangesRequest, true);
5656
serviceHost.SetRequestHandler(SchemaComparePublishProjectChangesRequest.Type, this.HandleSchemaComparePublishProjectChangesRequest, true);
5757
serviceHost.SetRequestHandler(SchemaCompareIncludeExcludeNodeRequest.Type, this.HandleSchemaCompareIncludeExcludeNodeRequest, true);
58+
serviceHost.SetRequestHandler(SchemaCompareIncludeExcludeAllNodesRequest.Type, this.HandleSchemaCompareIncludeExcludeAllNodesRequest, true);
5859
serviceHost.SetRequestHandler(SchemaCompareGetDefaultOptionsRequest.Type, this.HandleSchemaCompareGetDefaultOptionsRequest, true);
5960
serviceHost.SetRequestHandler(SchemaCompareOpenScmpRequest.Type, this.HandleSchemaCompareOpenScmpRequest, true);
6061
serviceHost.SetRequestHandler(SchemaCompareSaveScmpRequest.Type, this.HandleSchemaCompareSaveScmpRequest, true);
@@ -305,6 +306,44 @@ await requestContext.SendResult(new ResultStatus()
305306
}
306307
}
307308

309+
// <summary>
310+
/// Handles request for exclude incude all nodes in Schema compare result
311+
/// </summary>
312+
/// <returns></returns>
313+
public async Task HandleSchemaCompareIncludeExcludeAllNodesRequest(SchemaCompareIncludeExcludeAllNodesParams parameters, RequestContext<ResultStatus> requestContext)
314+
{
315+
SchemaCompareIncludeExcludeAllNodesOperation operation = null;
316+
try
317+
{
318+
SchemaComparisonResult compareResult = schemaCompareResults.Value[parameters.OperationId];
319+
operation = new SchemaCompareIncludeExcludeAllNodesOperation(parameters, compareResult);
320+
321+
operation.Execute(parameters.TaskExecutionMode);
322+
323+
// update the comparison result if the include/exclude was successful
324+
if (operation.Success)
325+
{
326+
schemaCompareResults.Value[parameters.OperationId] = operation.ComparisonResult;
327+
}
328+
329+
await requestContext.SendResult(new SchemaCompareIncludeExcludeAllNodesResult()
330+
{
331+
Success = operation.Success,
332+
ErrorMessage = operation.ErrorMessage,
333+
AllIncludedOrExcludedDifferences = operation.AllIncludedOrExcludedDifferences
334+
});
335+
}
336+
catch (Exception e)
337+
{
338+
Logger.Error("Failed to select compare schema result node. Error: " + e);
339+
await requestContext.SendResult(new SchemaCompareIncludeExcludeAllNodesResult()
340+
{
341+
Success = false,
342+
ErrorMessage = operation == null ? e.Message : operation.ErrorMessage,
343+
});
344+
}
345+
}
346+
308347
/// <summary>
309348
/// Handles request to create default deployment options as per DacFx
310349
/// </summary>

0 commit comments

Comments
 (0)