feat(datasync): extend DbBulkMergeDestination with excludeFromUpdate and updateCondition
This commit is contained in:
@@ -115,4 +115,189 @@ public class DbBulkMergeDestinationTests
|
||||
// Assert
|
||||
Assert.NotNull(dest);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithExcludeFromUpdate_Succeeds()
|
||||
{
|
||||
// Arrange & Act
|
||||
var factory = Substitute.For<IDbConnectionFactory>();
|
||||
var dest = new DbBulkMergeDestination(
|
||||
factory,
|
||||
"WorkOrder",
|
||||
new[] { "OrderNumber" },
|
||||
excludeFromUpdate: new[] { "CreatedDate", "CreatedBy" });
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(dest);
|
||||
Assert.Equal("BulkMerge:WorkOrder", dest.DestinationName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithUpdateCondition_Succeeds()
|
||||
{
|
||||
// Arrange & Act
|
||||
var factory = Substitute.For<IDbConnectionFactory>();
|
||||
var dest = new DbBulkMergeDestination(
|
||||
factory,
|
||||
"WorkOrder",
|
||||
new[] { "OrderNumber" },
|
||||
updateCondition: "source.LastUpdate > target.LastUpdate");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(dest);
|
||||
Assert.Equal("BulkMerge:WorkOrder", dest.DestinationName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithAllNewParameters_Succeeds()
|
||||
{
|
||||
// Arrange & Act
|
||||
var factory = Substitute.For<IDbConnectionFactory>();
|
||||
var dest = new DbBulkMergeDestination(
|
||||
factory,
|
||||
"WorkOrder",
|
||||
new[] { "OrderNumber" },
|
||||
updateColumns: new[] { "Status", "Description" },
|
||||
excludeFromUpdate: new[] { "CreatedDate" },
|
||||
updateCondition: "source.LastUpdate > target.LastUpdate",
|
||||
batchSize: 5000,
|
||||
commandTimeoutSeconds: 300);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(dest);
|
||||
Assert.Equal("BulkMerge:WorkOrder", dest.DestinationName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithNullExcludeFromUpdate_Succeeds()
|
||||
{
|
||||
// Arrange & Act
|
||||
var factory = Substitute.For<IDbConnectionFactory>();
|
||||
var dest = new DbBulkMergeDestination(
|
||||
factory,
|
||||
"WorkOrder",
|
||||
new[] { "OrderNumber" },
|
||||
updateColumns: null,
|
||||
excludeFromUpdate: null,
|
||||
updateCondition: null);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(dest);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithEmptyExcludeFromUpdate_Succeeds()
|
||||
{
|
||||
// Arrange & Act
|
||||
var factory = Substitute.For<IDbConnectionFactory>();
|
||||
var dest = new DbBulkMergeDestination(
|
||||
factory,
|
||||
"WorkOrder",
|
||||
new[] { "OrderNumber" },
|
||||
excludeFromUpdate: Array.Empty<string>());
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(dest);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithEmptyUpdateCondition_Succeeds()
|
||||
{
|
||||
// Arrange & Act
|
||||
var factory = Substitute.For<IDbConnectionFactory>();
|
||||
var dest = new DbBulkMergeDestination(
|
||||
factory,
|
||||
"WorkOrder",
|
||||
new[] { "OrderNumber" },
|
||||
updateCondition: "");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(dest);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithWhitespaceUpdateCondition_Succeeds()
|
||||
{
|
||||
// Arrange & Act
|
||||
var factory = Substitute.For<IDbConnectionFactory>();
|
||||
var dest = new DbBulkMergeDestination(
|
||||
factory,
|
||||
"WorkOrder",
|
||||
new[] { "OrderNumber" },
|
||||
updateCondition: " ");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(dest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Documents that excludeFromUpdate takes precedence over updateColumns.
|
||||
/// If a column is in both updateColumns and excludeFromUpdate, it should be excluded.
|
||||
/// This is verified during actual MERGE SQL generation (integration test concept).
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Constructor_WithConflictingUpdateAndExclude_Succeeds()
|
||||
{
|
||||
// Arrange & Act - excludeFromUpdate takes precedence over updateColumns
|
||||
var factory = Substitute.For<IDbConnectionFactory>();
|
||||
var dest = new DbBulkMergeDestination(
|
||||
factory,
|
||||
"WorkOrder",
|
||||
new[] { "OrderNumber" },
|
||||
updateColumns: new[] { "Status", "CreatedDate" },
|
||||
excludeFromUpdate: new[] { "CreatedDate" });
|
||||
|
||||
// Assert - construction succeeds; actual exclusion behavior is in MERGE SQL generation
|
||||
Assert.NotNull(dest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Documents that updateCondition is applied to the WHEN MATCHED clause.
|
||||
/// This adds conditional update logic like "source.LastUpdate > target.LastUpdate"
|
||||
/// to prevent stale data from overwriting newer data.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void UpdateCondition_DocumentsUsage_IntegrationTestConcept()
|
||||
{
|
||||
// The updateCondition parameter adds a condition to the MERGE statement's WHEN MATCHED clause.
|
||||
// Example: WHEN MATCHED AND source.LastUpdate > target.LastUpdate THEN UPDATE SET ...
|
||||
//
|
||||
// This is useful for:
|
||||
// - Preventing stale data from overwriting newer data
|
||||
// - Only updating rows that have actually changed
|
||||
// - Implementing optimistic concurrency patterns
|
||||
//
|
||||
// Full verification requires an integration test with a real database.
|
||||
var factory = Substitute.For<IDbConnectionFactory>();
|
||||
var dest = new DbBulkMergeDestination(
|
||||
factory,
|
||||
"WorkOrder",
|
||||
new[] { "OrderNumber" },
|
||||
updateCondition: "source.LastUpdate > target.LastUpdate");
|
||||
Assert.NotNull(dest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Documents that excludeFromUpdate removes columns from the UPDATE SET clause.
|
||||
/// This is useful for columns that should only be set on INSERT (e.g., CreatedDate).
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExcludeFromUpdate_DocumentsUsage_IntegrationTestConcept()
|
||||
{
|
||||
// The excludeFromUpdate parameter removes specified columns from the UPDATE SET clause.
|
||||
// These columns are still included in the INSERT clause for new rows.
|
||||
//
|
||||
// Common use cases:
|
||||
// - CreatedDate, CreatedBy - set only on insert, never updated
|
||||
// - Audit columns that should preserve original values
|
||||
//
|
||||
// Full verification requires an integration test with a real database.
|
||||
var factory = Substitute.For<IDbConnectionFactory>();
|
||||
var dest = new DbBulkMergeDestination(
|
||||
factory,
|
||||
"WorkOrder",
|
||||
new[] { "OrderNumber" },
|
||||
excludeFromUpdate: new[] { "CreatedDate", "CreatedBy" });
|
||||
Assert.NotNull(dest);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user