diff --git a/src/Microsoft.SqlTools.ServiceLayer/EditData/Contracts/EditRow.cs b/src/Microsoft.SqlTools.ServiceLayer/EditData/Contracts/EditRow.cs index 2042bea0..4ced0f17 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/EditData/Contracts/EditRow.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/EditData/Contracts/EditRow.cs @@ -25,7 +25,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.Contracts /// The cells in the row. If the row has pending changes, they will be represented in /// this list /// - public DbCellValue[] Cells { get; set; } + public EditCell[] Cells { get; set; } /// /// Internal ID of the row. This should be used whenever referencing a row in row edit operations. diff --git a/src/Microsoft.SqlTools.ServiceLayer/EditData/EditSession.cs b/src/Microsoft.SqlTools.ServiceLayer/EditData/EditSession.cs index d402c6b5..5886c253 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/EditData/EditSession.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/EditData/EditSession.cs @@ -283,7 +283,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData EditRow er = new EditRow { Id = rowId, - Cells = cachedRows.Rows[i], + Cells = cachedRows.Rows[i].Select(cell => new EditCell(cell, false)).ToArray(), State = EditRow.EditRowState.Clean }; editRows.Add(er); diff --git a/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/RowCreate.cs b/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/RowCreate.cs index 05874937..70ae9f76 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/RowCreate.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/RowCreate.cs @@ -130,9 +130,13 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement public override EditRow GetEditRow(DbCellValue[] cachedRow) { // Iterate over the new cells. If they are null, generate a blank value - DbCellValue[] editCells = newCells.Select(cell => cell == null - ? new DbCellValue {DisplayValue = string.Empty, IsNull = false, RawObject = null} - : cell.AsDbCellValue) + EditCell[] editCells = newCells.Select(cell => + { + DbCellValue dbCell = cell == null + ? new DbCellValue {DisplayValue = string.Empty, IsNull = false, RawObject = null} + : cell.AsDbCellValue; + return new EditCell(dbCell, true); + }) .ToArray(); return new EditRow { diff --git a/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/RowDelete.cs b/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/RowDelete.cs index 16e6ff59..3bbed902 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/RowDelete.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/RowDelete.cs @@ -6,6 +6,7 @@ using System; using System.Data.Common; using System.Globalization; +using System.Linq; using System.Threading.Tasks; using Microsoft.SqlTools.ServiceLayer.EditData.Contracts; using Microsoft.SqlTools.ServiceLayer.QueryExecution; @@ -86,7 +87,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement return new EditRow { Id = RowId, - Cells = cachedRow, + Cells = cachedRow.Select(cell => new EditCell(cell, true)).ToArray(), State = EditRow.EditRowState.DirtyDelete }; } diff --git a/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/RowUpdate.cs b/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/RowUpdate.cs index ebf19729..db377e2c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/RowUpdate.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/EditData/UpdateManagement/RowUpdate.cs @@ -122,16 +122,19 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement { Validate.IsNotNull(nameof(cachedRow), cachedRow); - // For each cell that is pending update, replace the db cell value with a new one + // Treat all the cells as clean initially + EditCell[] editCells = cachedRow.Select(cell => new EditCell(cell, false)).ToArray(); + + // For each cell that is pending update, replace the db cell value with a dirty one foreach (var cellUpdate in cellUpdates) { - cachedRow[cellUpdate.Key] = cellUpdate.Value.AsDbCellValue; + editCells[cellUpdate.Key] = cellUpdate.Value.AsEditCell; } return new EditRow { Id = RowId, - Cells = cachedRow, + Cells = editCells, State = EditRow.EditRowState.DirtyUpdate }; } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/CellUpdateTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/CellUpdateTests.cs index a61b4ed7..23c45aaf 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/CellUpdateTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/CellUpdateTests.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Data.Common; +using Microsoft.SqlTools.ServiceLayer.EditData.Contracts; using Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement; using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts; using Xunit; @@ -243,6 +244,36 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData Assert.Equal(isNull ? (object)DBNull.Value : value, dbc.RawObject); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void AsEditCellValue(bool isNull) + { + // Setup: Create a cell update + var value = isNull ? "NULL" : "foo"; + var col = GetWrapper("NTEXT"); + CellUpdate cu = new CellUpdate(col, value); + + // If: I convert the cell update to an EditCell + EditCell ec = cu.AsEditCell; + + // Then: + // ... It should not be null + Assert.NotNull(ec); + + // ... The display value should be the same as the value we supplied + Assert.Equal(value, ec.DisplayValue); + + // ... The null-ness of the value should be the same as what we supplied + Assert.Equal(isNull, ec.IsNull); + + // ... We don't care *too* much about the raw value, but we'll check it anyhow + Assert.Equal(isNull ? (object)DBNull.Value : value, ec.RawObject); + + // ... The edit cell should be dirty + Assert.True(ec.IsDirty); + } + private static DbColumnWrapper GetWrapper(string dataTypeName, bool allowNull = true) { return new DbColumnWrapper(new CellUpdateTestDbColumn(typeof(T), dataTypeName, allowNull)); diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowCreateTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowCreateTests.cs index 322c44b3..a4f3cecc 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowCreateTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowCreateTests.cs @@ -12,7 +12,6 @@ using Microsoft.SqlTools.ServiceLayer.EditData; using Microsoft.SqlTools.ServiceLayer.EditData.Contracts; using Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement; using Microsoft.SqlTools.ServiceLayer.QueryExecution; -using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts; using Microsoft.SqlTools.ServiceLayer.Test.Common; using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility; using Xunit; @@ -199,12 +198,13 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData Assert.True(er.IsDirty); Assert.Equal(EditRow.EditRowState.DirtyInsert, er.State); - // ... The row should have a bunch of empty cells (equal to number of columns) + // ... The row should have a bunch of empty cells (equal to number of columns) and all are dirty Assert.Equal(rc.newCells.Length, er.Cells.Length); - Assert.All(er.Cells, dbc => + Assert.All(er.Cells, ec => { - Assert.Equal(string.Empty, dbc.DisplayValue); - Assert.False(dbc.IsNull); + Assert.Equal(string.Empty, ec.DisplayValue); + Assert.False(ec.IsNull); + Assert.True(ec.IsDirty); }); } @@ -227,16 +227,18 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData Assert.True(er.IsDirty); Assert.Equal(EditRow.EditRowState.DirtyInsert, er.State); - // ... The row should have a single non-empty cell at the beginning + // ... The row should have a single non-empty cell at the beginning that is dirty Assert.Equal("foo", er.Cells[0].DisplayValue); Assert.False(er.Cells[0].IsNull); + Assert.True(er.Cells[0].IsDirty); - // ... The rest of the cells should be blank + // ... The rest of the cells should be blank, but dirty for (int i = 1; i < er.Cells.Length; i++) { - DbCellValue dbc = er.Cells[i]; - Assert.Equal(string.Empty, dbc.DisplayValue); - Assert.False(dbc.IsNull); + EditCell ec = er.Cells[i]; + Assert.Equal(string.Empty, ec.DisplayValue); + Assert.False(ec.IsNull); + Assert.True(ec.IsDirty); } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowDeleteTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowDeleteTests.cs index 8ed1dd2b..13f07446 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowDeleteTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowDeleteTests.cs @@ -159,15 +159,16 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // ... The ID should be the same as the one provided Assert.Equal(0, er.Id); - // ... The row should match the cells that were given + // ... The row should match the cells that were given and should be dirty Assert.Equal(cells.Length, er.Cells.Length); for (int i = 0; i < cells.Length; i++) { DbCellValue originalCell = cells[i]; - DbCellValue outputCell = er.Cells[i]; + EditCell outputCell = er.Cells[i]; Assert.Equal(originalCell.DisplayValue, outputCell.DisplayValue); Assert.Equal(originalCell.IsNull, outputCell.IsNull); + Assert.True(outputCell.IsDirty); // Note: No real need to check the RawObject property } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowUpdateTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowUpdateTests.cs index 373934a0..65ea7f9d 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowUpdateTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/RowUpdateTests.cs @@ -331,10 +331,11 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData // Note: No real need to check the RawObject property } - // ... The updated cell should match what it was set to - DbCellValue newCell = er.Cells[0]; - Assert.Equal(newCell.DisplayValue, "foo"); - Assert.Equal(newCell.IsNull, false); + // ... The updated cell should match what it was set to and be dirty + EditCell newCell = er.Cells[0]; + Assert.Equal("foo", newCell.DisplayValue); + Assert.False(newCell.IsNull); + Assert.True(newCell.IsDirty); } [Fact] diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/SessionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/SessionTests.cs index 3b1609d4..b7b49313 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/SessionTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/SessionTests.cs @@ -780,6 +780,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData { Assert.Equal(cachedRow[j].DisplayValue, er.Cells[j].DisplayValue); Assert.Equal(cachedRow[j].IsNull, er.Cells[j].IsNull); + Assert.False(er.Cells[j].IsDirty); } // ... Be clean, since we didn't apply any updates