edit/createRow Default Values (#266)

Returns strings for the default value of a column when a new row is created. The values that could come back:
* `null` when there isn't a default for the column
* a string when there is a default for the column
* a placeholder (currently <TBD>) when the column cannot be updated

* Renaming EditTableMetadata to reflect its SMO source

* Implementation of returning default values

* Unit test for default values

* Reworking column defaults using default constraints

* Adding unit test for new sql script unwrapper

* Disabling flaky test

* Fixing oddities in tests, removing personal tests

* Fixing broken unit test
This commit is contained in:
Benjamin Russell
2017-03-08 13:51:38 -08:00
committed by GitHub
parent 29d27c2341
commit 056a08cd1b
21 changed files with 286 additions and 90 deletions

View File

@@ -19,6 +19,12 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.Contracts
/// </summary>
public class EditCreateRowResult
{
/// <summary>
/// Each element corresponds to the default value for the column. If null, no default is
/// defined. Calculated columns will have placeholders provided here.
/// </summary>
public string[] DefaultValues { get; set; }
/// <summary>
/// The internal ID of the newly created row
/// </summary>

View File

@@ -18,11 +18,23 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
/// </summary>
public DbColumnWrapper DbColumn { get; set; }
/// <summary>
/// If set, this is a string representation of the default value. If set to null, then the
/// column does not have a default value.
/// </summary>
public string DefaultValue { get; set; }
/// <summary>
/// Escaped identifier for the name of the column
/// </summary>
public string EscapedName { get; set; }
/// <summary>
/// Whether or not the column is calculated on the server side. This could be a computed
/// column or a identity column.
/// </summary>
public bool IsCalculated { get; set; }
/// <summary>
/// Whether or not the column is used in a key to uniquely identify a row
/// </summary>

View File

@@ -115,15 +115,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
internal Task HandleCreateRowRequest(EditCreateRowParams createParams,
RequestContext<EditCreateRowResult> requestContext)
{
return HandleSessionRequest(createParams, requestContext, session =>
{
// Create the row and get the ID of the new row
long newRowId = session.CreateRow();
return new EditCreateRowResult
{
NewRowId = newRowId
};
});
return HandleSessionRequest(createParams, requestContext, s => s.CreateRow());
}
internal Task HandleDeleteRowRequest(EditDeleteRowParams deleteParams,

View File

@@ -5,6 +5,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data.Common;
using System.IO;
using System.Linq;
@@ -96,7 +97,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
/// </summary>
/// <exception cref="InvalidOperationException">If inserting into cache fails</exception>
/// <returns>The internal ID of the newly created row</returns>
public long CreateRow()
public EditCreateRowResult CreateRow()
{
// Create a new row ID (atomically, since this could be accesses concurrently)
long newRowId = NextRowId++;
@@ -110,7 +111,33 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
throw new InvalidOperationException(SR.EditDataFailedAddRow);
}
return newRowId;
// Set the default values of the row if we know them
string[] defaultValues = new string[objectMetadata.Columns.Count];
for(int i = 0; i < objectMetadata.Columns.Count; i++)
{
EditColumnWrapper col = objectMetadata.Columns[i];
// If the column is calculated, return the calculated placeholder as the display value
if (col.IsCalculated)
{
defaultValues[i] = SR.EditDataComputedColumnPlaceholder;
}
else
{
if (col.DefaultValue != null)
{
newRow.SetCell(i, col.DefaultValue);
}
defaultValues[i] = col.DefaultValue;
}
}
EditCreateRowResult output = new EditCreateRowResult
{
NewRowId = newRowId,
DefaultValues = defaultValues
};
return output;
}
/// <summary>

View File

@@ -16,7 +16,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
/// <summary>
/// All columns in the table that's being edited
/// </summary>
IEnumerable<EditColumnWrapper> Columns { get; }
IReadOnlyList<EditColumnWrapper> Columns { get; }
/// <summary>
/// The escaped name of the table that's being edited
@@ -31,6 +31,6 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
/// <summary>
/// Columns that can be used to uniquely identify the a row
/// </summary>
IEnumerable<EditColumnWrapper> KeyColumns { get; }
IReadOnlyList<EditColumnWrapper> KeyColumns { get; }
}
}

View File

@@ -62,7 +62,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
throw new ArgumentOutOfRangeException(nameof(objectName), SR.EditDataObjectMetadataNotFound);
}
return new EditTableMetadata(columns, result);
return new SmoEditTableMetadata(columns, result);
}
}
}

View File

@@ -16,7 +16,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
/// <summary>
/// Provides metadata about the table or view being edited
/// </summary>
public class EditTableMetadata : IEditTableMetadata
public class SmoEditTableMetadata : IEditTableMetadata
{
private readonly List<EditColumnWrapper> columns;
private readonly List<EditColumnWrapper> keyColumns;
@@ -26,7 +26,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
/// </summary>
/// <param name="dbColumns">DB columns from the ResultSet</param>
/// <param name="smoObject">SMO metadata object for the table/view being edited</param>
public EditTableMetadata(IList<DbColumnWrapper> dbColumns, TableViewTableTypeBase smoObject)
public SmoEditTableMetadata(IList<DbColumnWrapper> dbColumns, TableViewTableTypeBase smoObject)
{
Validate.IsNotNull(nameof(dbColumns), dbColumns);
Validate.IsNotNull(nameof(smoObject), smoObject);
@@ -46,15 +46,24 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
// identify a row in the table
bool isTrustworthyForUniqueness = dbColumn.IsUpdatable || smoColumn.Identity;
// The default value may be escaped
string defaultValue = smoColumn.DefaultConstraint == null
? null
: SqlScriptFormatter.UnwrapLiteral(smoColumn.DefaultConstraint.Text);
EditColumnWrapper column = new EditColumnWrapper
{
DbColumn = dbColumn,
Ordinal = i,
DefaultValue = defaultValue,
EscapedName = SqlScriptFormatter.FormatIdentifier(dbColumn.ColumnName),
IsTrustworthyForUniqueness = isTrustworthyForUniqueness,
// A key column is determined by whether it is in the primary key and trustworthy
IsKey = smoColumn.InPrimaryKey && isTrustworthyForUniqueness
IsKey = smoColumn.InPrimaryKey && isTrustworthyForUniqueness,
// A column is calculated if it is identity, computed, or otherwise not updatable
IsCalculated = smoColumn.Identity || smoColumn.Computed || !dbColumn.IsUpdatable
};
columns.Add(column);
}
@@ -80,7 +89,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
/// <summary>
/// Read-only list of columns in the object being edited
/// </summary>
public IEnumerable<EditColumnWrapper> Columns => columns.AsReadOnly();
public IReadOnlyList<EditColumnWrapper> Columns => columns.AsReadOnly();
/// <summary>
/// Full escaped multipart identifier for the object being edited
@@ -95,6 +104,6 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
/// <summary>
/// Read-only list of columns that are used to uniquely identify a row
/// </summary>
public IEnumerable<EditColumnWrapper> KeyColumns => keyColumns.AsReadOnly();
public IReadOnlyList<EditColumnWrapper> KeyColumns => keyColumns.AsReadOnly();
}
}

View File

@@ -501,6 +501,14 @@ namespace Microsoft.SqlTools.ServiceLayer
}
}
public static string EditDataComputedColumnPlaceholder
{
get
{
return Keys.GetString(Keys.EditDataComputedColumnPlaceholder);
}
}
public static string EditDataInitializeInProgress
{
get
@@ -1054,6 +1062,9 @@ namespace Microsoft.SqlTools.ServiceLayer
public const string EditDataCommitInProgress = "EditDataCommitInProgress";
public const string EditDataComputedColumnPlaceholder = "EditDataComputedColumnPlaceholder";
public const string EditDataInitializeInProgress = "EditDataInitializeInProgress";

View File

@@ -423,6 +423,10 @@
<value>A commit task is in progress. Please wait for completion.</value>
<comment></comment>
</data>
<data name="EditDataComputedColumnPlaceholder" xml:space="preserve">
<value>&lt;TBD&gt;</value>
<comment></comment>
</data>
<data name="EditDataInitializeInProgress" xml:space="preserve">
<value>Another edit data initialize is in progress for this owner URI. Please wait for completion.</value>
<comment></comment>

View File

@@ -200,6 +200,8 @@ EditDataScriptFilePathNull = An output filename must be provided
EditDataCommitInProgress = A commit task is in progress. Please wait for completion.
EditDataComputedColumnPlaceholder = <TBD>
EditDataInitializeInProgress = Another edit data initialize is in progress for this owner URI. Please wait for completion.
############################################################################

View File

@@ -531,9 +531,9 @@
<target state="new">Decimal column is missing numeric precision or numeric scale</target>
<note></note>
</trans-unit>
<trans-unit id="QueryServiceResultSetAddNoRows">
<source>Cannot add row to result buffer, data reader does not contain rows</source>
<target state="new">Cannot add row to result buffer, data reader does not contain rows</target>
<trans-unit id="EditDataComputedColumnPlaceholder">
<source>&lt;TBD&gt;</source>
<target state="new">&lt;TBD&gt;</target>
<note></note>
</trans-unit>
<trans-unit id="EditDataInitializeInProgress">
@@ -541,6 +541,11 @@
<target state="new">Another edit data initialize is in progress for this owner URI. Please wait for completion.</target>
<note></note>
</trans-unit>
<trans-unit id="QueryServiceResultSetAddNoRows">
<source>Cannot add row to result buffer, data reader does not contain rows</source>
<target state="new">Cannot add row to result buffer, data reader does not contain rows</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -9,6 +9,7 @@ using System.Data.Common;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
using Microsoft.SqlTools.Utility;
@@ -64,6 +65,19 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
// sysname - it doesn't appear possible to insert a sysname column
};
private static readonly Type[] NumericTypes =
{
typeof(byte),
typeof(short),
typeof(int),
typeof(long),
typeof(decimal),
typeof(float),
typeof(double)
};
private static Regex StringRegex = new Regex("^N?'(.*)'$", RegexOptions.Compiled);
#endregion
/// <summary>
@@ -141,6 +155,27 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
return string.Join(".", escapedParts);
}
/// <summary>
/// Converts a value from a script into a plain version by unwrapping literal wrappers
/// and unescaping characters.
/// </summary>
/// <param name="literal">The value to unwrap</param>
/// <returns>The unwrapped/unescaped literal</returns>
public static string UnwrapLiteral(string literal)
{
// Always remove parens
literal = literal.Trim('(', ')');
// Attempt to unwrap inverted commas around a string
Match match = StringRegex.Match(literal);
if (match.Success)
{
// Like: N'stuff' or 'stuff'
return UnEscapeString(match.Groups[1].Value, '\'');
}
return literal;
}
#region Private Helpers
private static string SimpleFormatter(object value)
@@ -258,6 +293,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
return sb.ToString();
}
private static string UnEscapeString(string value, char escapeCharacter)
{
Validate.IsNotNull(nameof(value), value);
// Replace 2x of the escape character with 1x of the escape character
return value.Replace(new string(escapeCharacter, 2), escapeCharacter.ToString());
}
#endregion
}
}

View File

@@ -319,7 +319,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
await TestService.Disconnect(queryTempFile.FilePath);
}
}
*/
[Theory]
[InlineData("-- no-op")]
@@ -332,7 +332,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
{
Assert.True(await testService.Connect(TestServerType.OnPrem, queryTempFile.FilePath));
// If: the query is executed...
// If: the no-op query is executed...
var queryResult = await testService.RunQueryAsync(queryTempFile.FilePath, query);
var message = await testService.WaitForMessage();
@@ -350,5 +350,6 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
await testService.Disconnect(queryTempFile.FilePath);
}
}
*/
}
}

View File

@@ -22,7 +22,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
{
public const string OwnerUri = "testFile";
public static IEditTableMetadata GetMetadata(DbColumn[] columns, bool allKeys = true, bool isMemoryOptimized = false)
public static IEditTableMetadata GetStandardMetadata(DbColumn[] columns, bool allKeys = true, bool isMemoryOptimized = false)
{
// Create a Column Metadata Provider
var columnMetas = columns.Select((c, i) =>
@@ -33,24 +33,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
Ordinal = i,
IsKey = c.IsIdentity.HasTrue()
}).ToArray();
// Create a table metadata provider
var tableMetaMock = new Mock<IEditTableMetadata>();
if (allKeys)
{
// All columns should be returned as "keys"
tableMetaMock.Setup(m => m.KeyColumns).Returns(columnMetas);
}
else
{
// All identity columns should be returned as keys
tableMetaMock.Setup(m => m.KeyColumns).Returns(columnMetas.Where(c => c.DbColumn.IsIdentity.HasTrue()));
}
tableMetaMock.Setup(m => m.Columns).Returns(columnMetas);
tableMetaMock.Setup(m => m.IsMemoryOptimized).Returns(isMemoryOptimized);
tableMetaMock.Setup(m => m.EscapedMultipartName).Returns("tbl");
return tableMetaMock.Object;
return GetMetadataProvider(columnMetas, allKeys, isMemoryOptimized);
}
public static DbColumn[] GetColumns(bool includeIdentity)
@@ -99,5 +82,26 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
rc.SetCell(i, "123");
}
}
public static IEditTableMetadata GetMetadataProvider(EditColumnWrapper[] columnMetas, bool allKeys = false, bool isMemoryOptimized = false)
{
// Create a table metadata provider
var tableMetaMock = new Mock<IEditTableMetadata>();
if (allKeys)
{
// All columns should be returned as "keys"
tableMetaMock.Setup(m => m.KeyColumns).Returns(columnMetas);
}
else
{
// All identity columns should be returned as keys
tableMetaMock.Setup(m => m.KeyColumns).Returns(columnMetas.Where(c => c.DbColumn.IsIdentity.HasTrue()).ToList());
}
tableMetaMock.Setup(m => m.Columns).Returns(columnMetas);
tableMetaMock.Setup(m => m.IsMemoryOptimized).Returns(isMemoryOptimized);
tableMetaMock.Setup(m => m.EscapedMultipartName).Returns("tbl");
return tableMetaMock.Object;
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create the values to store
const long rowId = 100;
ResultSet rs = QueryExecution.Common.GetBasicExecutedBatch().ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
// If: I create a RowCreate instance
RowCreate rc = new RowCreate(rowId, rs, etm);
@@ -43,7 +43,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
const long rowId = 100;
DbColumn[] columns = Common.GetColumns(includeIdentity);
ResultSet rs = Common.GetResultSet(columns, includeIdentity);
IEditTableMetadata etm = Common.GetMetadata(columns);
IEditTableMetadata etm = Common.GetStandardMetadata(columns);
// If: I ask for a script to be generated without an identity column
RowCreate rc = new RowCreate(rowId, rs, etm);
@@ -75,7 +75,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
const long rowId = 100;
DbColumn[] columns = Common.GetColumns(false);
ResultSet rs = Common.GetResultSet(columns, false);
IEditTableMetadata etm = Common.GetMetadata(columns);
IEditTableMetadata etm = Common.GetStandardMetadata(columns);
// If: I ask for a script to be generated without setting any values
// Then: An exception should be thrown for missing cells
@@ -93,7 +93,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
const long rowId = 100;
DbColumn[] columns = Common.GetColumns(includeIdentity);
ResultSet rs = Common.GetResultSet(columns, includeIdentity);
IEditTableMetadata etm = Common.GetMetadata(columns);
IEditTableMetadata etm = Common.GetStandardMetadata(columns);
// ... Setup a db reader for the result of an insert
var newRowReader = Common.GetNewRowDataReader(columns, includeIdentity);
@@ -116,7 +116,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
const long rowId = 100;
var columns = Common.GetColumns(includeIdentity);
var rs = Common.GetResultSet(columns, includeIdentity);
var etm = Common.GetMetadata(columns);
var etm = Common.GetStandardMetadata(columns);
RowCreate rc = new RowCreate(rowId, rs, etm);
Common.AddCells(rc, includeIdentity);
@@ -164,7 +164,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
const long rowId = 100;
var columns = Common.GetColumns(false);
var rs = Common.GetResultSet(columns, false);
var etm = Common.GetMetadata(columns);
var etm = Common.GetStandardMetadata(columns);
RowCreate rc = new RowCreate(rowId, rs, etm);
// If: I attempt to create a command with a null connection
@@ -179,7 +179,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
const long rowId = 100;
var columns = Common.GetColumns(false);
var rs = Common.GetResultSet(columns, false);
var etm = Common.GetMetadata(columns);
var etm = Common.GetStandardMetadata(columns);
var mockConn = new TestSqlConnection(null);
// If: I ask for a script to be generated without setting any values

View File

@@ -23,7 +23,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create the values to store
const long rowId = 100;
ResultSet rs = QueryExecution.Common.GetBasicExecutedBatch().ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
// If: I create a RowCreate instance
RowCreate rc = new RowCreate(rowId, rs, etm);
@@ -41,7 +41,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
{
DbColumn[] columns = Common.GetColumns(true);
ResultSet rs = Common.GetResultSet(columns, true);
IEditTableMetadata etm = Common.GetMetadata(columns, false, isMemoryOptimized);
IEditTableMetadata etm = Common.GetStandardMetadata(columns, false, isMemoryOptimized);
// If: I ask for a script to be generated for delete
RowDelete rd = new RowDelete(0, rs, etm);
@@ -68,7 +68,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
const long rowId = 0;
var columns = Common.GetColumns(false);
var rs = Common.GetResultSet(columns, false);
var etm = Common.GetMetadata(columns);
var etm = Common.GetStandardMetadata(columns);
// If: I ask for the change to be applied
RowDelete rd = new RowDelete(rowId, rs, etm);
@@ -90,7 +90,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
const long rowId = 0;
var columns = Common.GetColumns(includeIdentity);
var rs = Common.GetResultSet(columns, includeIdentity);
var etm = Common.GetMetadata(columns, !includeIdentity, isMemoryOptimized);
var etm = Common.GetStandardMetadata(columns, !includeIdentity, isMemoryOptimized);
RowDelete rd = new RowDelete(rowId, rs, etm);
// ... Mock db connection for building the command
@@ -133,7 +133,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a row delete
var columns = Common.GetColumns(false);
var rs = Common.GetResultSet(columns, false);
var etm = Common.GetMetadata(columns);
var etm = Common.GetStandardMetadata(columns);
RowDelete rd = new RowDelete(0, rs, etm);
// If: I attempt to create a command with a null connection
@@ -146,7 +146,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
{
DbColumn[] columns = Common.GetColumns(true);
ResultSet rs = Common.GetResultSet(columns, true);
IEditTableMetadata etm = Common.GetMetadata(columns, false);
IEditTableMetadata etm = Common.GetStandardMetadata(columns, false);
// If: I set a cell on a delete row edit
// Then: It should throw as invalid operation

View File

@@ -59,7 +59,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a result set and metadata provider with a single column
var cols = new[] {col};
ResultSet rs = GetResultSet(cols, new[] {val});
IEditTableMetadata etm = Common.GetMetadata(cols);
IEditTableMetadata etm = Common.GetStandardMetadata(cols);
RowEditTester rt = new RowEditTester(rs, etm);
rt.ValidateWhereClauseSingleKey(nullClause);
@@ -82,7 +82,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a result set and metadata provider with multiple key columns
DbColumn[] cols = {new TestDbColumn("col1"), new TestDbColumn("col2")};
ResultSet rs = GetResultSet(cols, new object[] {"abc", "def"});
IEditTableMetadata etm = Common.GetMetadata(cols);
IEditTableMetadata etm = Common.GetStandardMetadata(cols);
RowEditTester rt = new RowEditTester(rs, etm);
rt.ValidateWhereClauseMultipleKeys();
@@ -94,7 +94,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a result set and metadata provider with no key columns
DbColumn[] cols = {new TestDbColumn("col1"), new TestDbColumn("col2")};
ResultSet rs = GetResultSet(cols, new object[] {"abc", "def"});
IEditTableMetadata etm = Common.GetMetadata(new DbColumn[] {});
IEditTableMetadata etm = Common.GetStandardMetadata(new DbColumn[] {});
RowEditTester rt = new RowEditTester(rs, etm);
rt.ValidateWhereClauseNoKeys();
@@ -106,7 +106,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a result set and metadata we can reuse
var cols = Common.GetColumns(false);
var rs = Common.GetResultSet(cols, false);
var etm = Common.GetMetadata(cols);
var etm = Common.GetStandardMetadata(cols);
// If: I request to sort a list of the three different edit operations
List<RowEditBase> rowEdits = new List<RowEditBase>
@@ -128,7 +128,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a result set and metadata we can reuse
var cols = Common.GetColumns(false);
var rs = Common.GetResultSet(cols, false, 4);
var etm = Common.GetMetadata(cols);
var etm = Common.GetStandardMetadata(cols);
// If: I sort 3 edit operations of the same type
List<RowEditBase> rowEdits = new List<RowEditBase>
@@ -151,7 +151,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a result set and metadata we can reuse
var cols = Common.GetColumns(false);
var rs = Common.GetResultSet(cols, false);
var etm = Common.GetMetadata(cols);
var etm = Common.GetStandardMetadata(cols);
// If: I sort 3 edit operations of the same type
List<RowEditBase> rowEdits = new List<RowEditBase>
@@ -174,7 +174,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a result set and metadata we can reuse
var cols = Common.GetColumns(false);
var rs = Common.GetResultSet(cols, false);
var etm = Common.GetMetadata(cols);
var etm = Common.GetStandardMetadata(cols);
// If: I sort 3 delete operations of the same type
List<RowEditBase> rowEdits = new List<RowEditBase>

View File

@@ -23,7 +23,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create the values to store
const long rowId = 0;
ResultSet rs = QueryExecution.Common.GetBasicExecutedBatch().ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
// If: I create a RowUpdate instance
RowUpdate rc = new RowUpdate(rowId, rs, etm);
@@ -40,7 +40,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a fake table to update
DbColumn[] columns = Common.GetColumns(true);
ResultSet rs = Common.GetResultSet(columns, true);
IEditTableMetadata etm = Common.GetMetadata(columns);
IEditTableMetadata etm = Common.GetStandardMetadata(columns);
// If:
// ... I add updates to all the cells in the row
@@ -77,7 +77,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a fake table to update
DbColumn[] columns = Common.GetColumns(true);
ResultSet rs = Common.GetResultSet(columns, true);
IEditTableMetadata etm = Common.GetMetadata(columns, false, isMemoryOptimized);
IEditTableMetadata etm = Common.GetStandardMetadata(columns, false, isMemoryOptimized);
// If: I ask for a script to be generated for update
RowUpdate ru = new RowUpdate(0, rs, etm);
@@ -116,7 +116,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// ... Create a row update with cell updates
var columns = Common.GetColumns(includeIdentity);
var rs = Common.GetResultSet(columns, includeIdentity);
var etm = Common.GetMetadata(columns, !includeIdentity, isMemoryOptimized);
var etm = Common.GetStandardMetadata(columns, !includeIdentity, isMemoryOptimized);
RowUpdate ru = new RowUpdate(0, rs, etm);
Common.AddCells(ru, includeIdentity);
@@ -169,7 +169,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a row create
var columns = Common.GetColumns(false);
var rs = Common.GetResultSet(columns, false);
var etm = Common.GetMetadata(columns);
var etm = Common.GetStandardMetadata(columns);
RowUpdate rc = new RowUpdate(0, rs, etm);
// If: I attempt to create a command with a null connection
@@ -186,7 +186,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// ... Create a row update (no cell updates needed)
var columns = Common.GetColumns(includeIdentity);
var rs = Common.GetResultSet(columns, includeIdentity);
var etm = Common.GetMetadata(columns, !includeIdentity);
var etm = Common.GetStandardMetadata(columns, !includeIdentity);
RowUpdate ru = new RowUpdate(0, rs, etm);
long oldBytesWritten = rs.totalBytesWritten;
@@ -209,7 +209,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// ... Create a row update (no cell updates needed)
var columns = Common.GetColumns(true);
var rs = Common.GetResultSet(columns, true);
var etm = Common.GetMetadata(columns, false);
var etm = Common.GetStandardMetadata(columns, false);
RowUpdate ru = new RowUpdate(0, rs, etm);
// If: I ask for the changes to be applied with a null db reader

View File

@@ -6,11 +6,14 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
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.Test.Common;
using Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.Execution;
using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility;
using Moq;
using Xunit;
@@ -356,7 +359,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// ... Create a session with a proper query and metadata
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
EditSession s = new EditSession(rs, etm);
return s;
}

View File

@@ -10,8 +10,10 @@ using System.IO;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection;
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.SqlContext;
using Microsoft.SqlTools.ServiceLayer.Test.Common;
using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility;
@@ -29,7 +31,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
{
// If: I create a session object without a null query
// Then: It should throw an exception
Assert.Throws<ArgumentNullException>(() => new EditSession(null, Common.GetMetadata(new DbColumn[] {})));
Assert.Throws<ArgumentNullException>(() => new EditSession(null, Common.GetStandardMetadata(new DbColumn[] {})));
}
[Fact]
@@ -48,7 +50,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// If: I create a session object with a proper query and metadata
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
EditSession s = new EditSession(rs, etm);
// Then:
@@ -122,7 +124,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// ... Create a session with a proper query and metadata
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
EditSession s = new EditSession(rs, etm);
// ... Add a mock edit to the edit cache to cause the .TryAdd to fail
@@ -147,22 +149,83 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a session with a proper query and metadata
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
EditSession s = new EditSession(rs, etm);
// If: I add a row to the session
long newId = s.CreateRow();
EditCreateRowResult result = s.CreateRow();
// Then:
// ... The new ID should be equal to the row count
Assert.Equal(rs.RowCount, newId);
Assert.Equal(rs.RowCount, result.NewRowId);
// ... The next row ID should have been incremented
Assert.Equal(rs.RowCount + 1, s.NextRowId);
// ... There should be a new row create object in the cache
Assert.Contains(newId, s.EditCache.Keys);
Assert.IsType<RowCreate>(s.EditCache[newId]);
Assert.Contains(result.NewRowId, s.EditCache.Keys);
Assert.IsType<RowCreate>(s.EditCache[result.NewRowId]);
// ... The default values should be returned (we will test this in depth below)
Assert.NotEmpty(result.DefaultValues);
}
[Fact]
public void CreateRowDefaultTest()
{
// Setup:
// ... We will have 3 columns
DbColumn[] cols =
{
new TestDbColumn("col1", false), // No default
new TestDbColumn("col2", false), // Has default (defined below)
new TestDbColumn("filler", false) // Filler column so we can use the common code
};
// ... Metadata provider will return 3 columns
EditColumnWrapper[] metas =
{
new EditColumnWrapper // No default
{
DbColumn = new DbColumnWrapper(cols[0]),
DefaultValue = null,
EscapedName = cols[0].ColumnName,
Ordinal = 0,
IsKey = false
},
new EditColumnWrapper // Has default
{
DbColumn = new DbColumnWrapper(cols[1]),
DefaultValue = "default",
EscapedName = cols[0].ColumnName,
Ordinal = 0,
IsKey = false
},
new EditColumnWrapper()
};
var etm = Common.GetMetadataProvider(metas, true);
// ... Create a result set
var rs = Common.GetResultSet(cols, false, 1);
// ... Create a session from all this
var session = new EditSession(rs, etm);
// If: I add a row to the session, on a table that has defaults
var result = session.CreateRow();
// Then:
// ... Result should not be null, new row ID should be > 0
Assert.NotNull(result);
Assert.True(result.NewRowId > 0);
// ... There should be 3 default values (3 columns)
Assert.NotEmpty(result.DefaultValues);
Assert.Equal(3, result.DefaultValues.Length);
// ... There should be specific values for each kind of default
Assert.Null(result.DefaultValues[0]);
Assert.Equal("default", result.DefaultValues[1]);
}
#endregion
@@ -174,7 +237,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a session with a proper query and metadata
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
EditSession s = new EditSession(rs, etm);
// If: I delete a row that is out of range for the result set
@@ -207,7 +270,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// ... Create a session with a proper query and metadata
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
EditSession s = new EditSession(rs, etm);
// ... Add a mock edit to the edit cache to cause the .TryAdd to fail
@@ -229,7 +292,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a session with a proper query and metadata
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
EditSession s = new EditSession(rs, etm);
// If: I add a row to the session
@@ -250,7 +313,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a session with a proper query and metadata
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
EditSession s = new EditSession(rs, etm);
// If: I revert a row that doesn't have any pending changes
@@ -265,7 +328,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// ... Create a session with a proper query and metadata
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
EditSession s = new EditSession(rs, etm);
// ... Add a mock edit to the edit cache to cause the .TryAdd to fail
@@ -291,7 +354,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// ... Create a session with a proper query and metadata
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
EditSession s = new EditSession(rs, etm);
// ... Add a mock edit to the edit cache to cause the .TryAdd to fail
@@ -315,7 +378,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// ... Create a session with a proper query and metadata
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
EditSession s = new EditSession(rs, etm);
// If: I update a cell on a row that does not have a pending edit
@@ -340,7 +403,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// Setup: Create a session with a proper query and metadata
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
EditSession s = new EditSession(rs, etm);
// If: I try to script the edit cache with a null or whitespace output path
@@ -355,7 +418,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
// ... Create a session with a proper query and metadata
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
EditSession s = new EditSession(rs, etm);
// ... Add two mock edits that will generate a script
@@ -534,7 +597,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
{
Query q = QueryExecution.Common.GetBasicExecutedQuery();
ResultSet rs = q.Batches[0].ResultSets[0];
IEditTableMetadata etm = Common.GetMetadata(rs.Columns);
IEditTableMetadata etm = Common.GetStandardMetadata(rs.Columns);
return new EditSession(rs, etm);
}
}

View File

@@ -11,7 +11,7 @@ using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.Test.Utility
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
{
public class SqlScriptFormatterTests
{
@@ -308,6 +308,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Utility
#endregion
[Theory]
[InlineData("(0)", "0")]
[InlineData("((0))", "0")]
[InlineData("('')", "")]
[InlineData("('stuff')", "stuff")]
[InlineData("(N'')", "")]
[InlineData("(N'stuff')", "stuff")]
[InlineData("('''stuff')", "'stuff")]
[InlineData("(N'stu''''ff')", "stu''ff")]
public void UnescapeTest(string input, string output)
{
Assert.Equal(output, SqlScriptFormatter.UnwrapLiteral(input));
}
private class FormatterTestDbColumn : DbColumn
{
public FormatterTestDbColumn(string dataType, int? precision = null, int? scale = null)