handle add column request (#1272)

* handle add column request

* comments

* rename data to ViewModel
This commit is contained in:
Alan Ren
2021-10-19 09:54:57 -07:00
committed by GitHub
parent 791c3594a9
commit 192f7fccd4
18 changed files with 310 additions and 83 deletions

View File

@@ -126,8 +126,14 @@ namespace Microsoft.SqlTools.Hosting.Protocol
TParams typedParams = default(TParams);
if (requestMessage.Contents != null)
{
// TODO: Catch parse errors!
typedParams = requestMessage.Contents.ToObject<TParams>();
try
{
typedParams = requestMessage.Contents.ToObject<TParams>();
}
catch (Exception ex)
{
return requestContext.SendError(ex.Message);
}
}
return requestHandler(typedParams, requestContext);
@@ -256,7 +262,7 @@ namespace Microsoft.SqlTools.Hosting.Protocol
}
protected async Task DispatchMessage(
Message messageToDispatch,
Message messageToDispatch,
MessageWriter messageWriter)
{
Task handlerToAwait = null;

View File

@@ -0,0 +1,31 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Threading.Tasks;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.TableDesigner
{
public static class TablePropertyNames
{
public const string Name = "name";
public const string Schema = "schema";
public const string Description = "description";
public const string Columns = "columns";
}
public static class TableColumnPropertyNames
{
public const string Name = "name";
public const string Type = "type";
public const string DefaultValue = "defaultValue";
public const string Length = "length";
public const string AllowNulls = "allowNulls";
public const string IsPrimaryKey = "isPrimaryKey";
}
}

View File

@@ -12,17 +12,12 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
/// </summary>
public abstract class ComponentPropertiesBase
{
public ComponentPropertiesBase()
{
this.Enabled = true;
}
public string Title { get; set; }
public string AriaLabel { get; set; }
public Nullable<int> Width { get; set; }
public bool Enabled { get; set; }
public bool Enabled { get; set; } = true;
}
}

View File

@@ -3,6 +3,8 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
{
/// <summary>
@@ -12,6 +14,6 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
{
public string Value { get; set; }
public string[] Values { get; set; }
public List<string> Values { get; set; }
}
}

View File

@@ -3,12 +3,16 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
{
/// <summary>
/// Table component properties
/// </summary>
public class TableProperties<T> : ComponentPropertiesBase
public abstract class TableComponentProperties<T> : ComponentPropertiesBase where T : ObjectViewModelBase
{
/// <summary>
/// The column names to be displayed
@@ -23,11 +27,38 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
/// <summary>
/// All properties of the object.
/// </summary>
public DesignerDataPropertyInfo[] ItemProperties { get; set; }
public List<DesignerDataPropertyInfo> ItemProperties { get; set; } = new List<DesignerDataPropertyInfo>();
/// <summary>
/// The object list.
/// </summary>
public T[] Data { get; set; }
public List<T> Data { get; set; } = new List<T>();
/// <summary>
/// Add a new object into the Data property
/// </summary>
public void AddNew()
{
this.Data.Add(this.CreateNew(this.GetDefaultNewObjectName()));
}
protected abstract string NewObjectNamePrefix { get; }
protected abstract T CreateNew(string name);
/// <summary>
/// Get the next available name for a new item
/// </summary>
protected string GetDefaultNewObjectName()
{
int i = 1;
string newName;
do
{
newName = string.Format("{0}{1}", this.NewObjectNamePrefix, i);
i++;
} while (this.Data?.AsEnumerable().FirstOrDefault(obj => string.Equals(obj.Name?.Value, newName, StringComparison.InvariantCultureIgnoreCase)) != null);
return newName;
}
}
}

View File

@@ -14,12 +14,12 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
public TableDesignerChangeInfo TableChangeInfo { get; set; }
public TableDataModel Data { get; set; }
public TableViewModel ViewModel { get; set; }
}
public class ProcessTableDesignerEditResponse
{
public TableDataModel Data { get; set; }
public TableViewModel ViewModel { get; set; }
public bool IsValid { get; set; }

View File

@@ -12,7 +12,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
{
public TableInfo TableInfo { get; set; }
public TableDataModel Data { get; set; }
public TableViewModel ViewModel { get; set; }
}
public class SaveTableChangesResponse

View File

@@ -3,6 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
@@ -27,8 +28,41 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
{
public DesignerEditType Type { get; set; }
[JsonConverter(typeof(TableDesignerPropertyConverter))]
public object Property { get; set; }
public object Value { get; set; }
}
/// <summary>
/// The property "Property" of <c>TableDesignerChangeInfo</c> could be string or <c>TableDesignerPropertyIdentifier</c>, use this custom converter to set the property value.
/// </summary>
public class TableDesignerPropertyConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object property;
if (reader.TokenType == JsonToken.StartObject)
{
TableDesignerPropertyIdentifier obj = serializer.Deserialize(reader, typeof(TableDesignerPropertyIdentifier)) as TableDesignerPropertyIdentifier;
property = obj;
}
else
{
property = reader.Value;
}
return property;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// We don't need to serialize this class.
throw new NotImplementedException();
}
}
}

View File

@@ -1,25 +0,0 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
{
/// <summary>
/// The data model of a table column object
/// </summary>
public class TableColumn
{
public InputBoxProperties Name { get; set; }
public DropdownProperties Type { get; set; }
public InputBoxProperties Length { get; set; }
public CheckBoxProperties AllowNulls { get; set; }
public InputBoxProperties DefaultValue { get; set; }
public CheckBoxProperties IsPrimaryKey { get; set; }
}
}

View File

@@ -1,27 +0,0 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
{
/// <summary>
/// The data model for a table object
/// </summary>
public class TableDataModel
{
public InputBoxProperties Name { get; set; }
public DropdownProperties Schema { get; set; }
public InputBoxProperties Description { get; set; }
public TableColumnCollection Columns { get; set; }
public InputBoxProperties Script { get; set; }
}
public class TableColumnCollection : TableProperties<TableColumn>
{
}
}

View File

@@ -2,6 +2,7 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
{
@@ -12,10 +13,10 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
{
public TableDesignerView View { get; set; }
public TableDataModel Data { get; set; }
public TableViewModel ViewModel { get; set; }
public string[] ColumnTypes { get; set; }
public List<string> ColumnTypes { get; set; }
public string[] Schemas { get; set; }
public List<string> Schemas { get; set; }
}
}

View File

@@ -3,10 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
{
/// <summary>

View File

@@ -0,0 +1,15 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
{
/// <summary>
/// The base class for view model object.
/// </summary>
public abstract class ObjectViewModelBase
{
public InputBoxProperties Name { get; set; } = new InputBoxProperties();
}
}

View File

@@ -0,0 +1,25 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Newtonsoft.Json;
namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
{
/// <summary>
/// The view model of a table column object
/// </summary>
public class TableColumnViewModel : ObjectViewModelBase
{
public DropdownProperties Type { get; set; } = new DropdownProperties();
public InputBoxProperties Length { get; set; } = new InputBoxProperties();
public CheckBoxProperties AllowNulls { get; set; } = new CheckBoxProperties();
public InputBoxProperties DefaultValue { get; set; } = new InputBoxProperties();
public CheckBoxProperties IsPrimaryKey { get; set; } = new CheckBoxProperties();
}
}

View File

@@ -0,0 +1,37 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Newtonsoft.Json;
namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts
{
/// <summary>
/// The view model for a table object
/// </summary>
public class TableViewModel : ObjectViewModelBase
{
public DropdownProperties Schema { get; set; } = new DropdownProperties();
public InputBoxProperties Description { get; set; } = new InputBoxProperties();
public TableColumnCollection Columns { get; set; } = new TableColumnCollection();
public InputBoxProperties Script { get; set; } = new InputBoxProperties();
}
public class TableColumnCollection : TableComponentProperties<TableColumnViewModel>
{
[JsonIgnore]
protected override string NewObjectNamePrefix { get { return "column"; } }
protected override TableColumnViewModel CreateNew(string name)
{
//TODO: Add the default values
var column = new TableColumnViewModel();
column.Name.Value = this.GetDefaultNewObjectName();
return column;
}
}
}

View File

@@ -4,6 +4,7 @@
//
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Hosting;
@@ -57,15 +58,15 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner
{
try
{
// TODO
TableDataModel tableModel = new TableDataModel();
// TODO: populate the data and view information
TableViewModel tableModel = new TableViewModel();
TableDesignerView view = new TableDesignerView();
await requestContext.SendResult(new TableDesignerInfo()
{
Data = tableModel,
ViewModel = tableModel,
View = view,
ColumnTypes = new string[] { },
Schemas = new string[] { }
ColumnTypes = this.GetSupportedColumnTypes(tableInfo),
Schemas = this.GetSchemas(tableInfo)
});
}
catch (Exception e)
@@ -81,10 +82,21 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner
{
try
{
// TODO
switch (requestParams.TableChangeInfo.Type)
{
case DesignerEditType.Add:
this.HandleAddItemRequest(requestParams);
break;
case DesignerEditType.Remove:
// TODO: Handle 'Remove' request
break;
default:
// TODO: Handle 'Update' request
break;
}
await requestContext.SendResult(new ProcessTableDesignerEditResponse()
{
Data = requestParams.Data,
ViewModel = requestParams.ViewModel,
IsValid = true
});
}
@@ -101,7 +113,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner
{
try
{
// TODO
// TODO: Handle the save changes request.
await requestContext.SendResult(new SaveTableChangesResponse());
}
catch (Exception e)
@@ -111,6 +123,40 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner
});
}
private void HandleAddItemRequest(ProcessTableDesignerEditRequestParams requestParams)
{
var property = requestParams.TableChangeInfo.Property;
// Handle the add item request on top level table properties, e.g. Columns, Indexes.
if (property.GetType() == typeof(string))
{
string propertyName = property as string;
switch (propertyName)
{
case TablePropertyNames.Columns:
requestParams.ViewModel.Columns.AddNew();
break;
default:
break;
}
} else {
// TODO: Handle the add item request on second level properties, e.g. Adding a column to an index
}
}
private List<string> GetSupportedColumnTypes(TableInfo tableInfo)
{
//TODO: get the supported column types.
var columnTypes = new List<string>();
return columnTypes;
}
private List<string> GetSchemas(TableInfo tableInfo)
{
//TODO: get the schemas.
var schemas = new List<string>();
return schemas;
}
/// <summary>
/// Disposes the table designer Service
/// </summary>

View File

@@ -0,0 +1,30 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts;
using NUnit.Framework;
using Newtonsoft.Json;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.TableDesigner
{
public class TableColumnCollectionTest
{
[Test]
public void AutoNameForNewItemTest()
{
var collection = new TableColumnCollection();
collection.AddNew();
Assert.AreEqual(1, collection.Data.Count, "The item count should be 1");
Assert.AreEqual("column1", collection.Data[0].Name.Value);
collection.Data.Add(new TableColumnViewModel() { Name = new InputBoxProperties() { Value = "column3" } });
Assert.AreEqual(2, collection.Data.Count, "The item count should be 2");
collection.AddNew();
Assert.AreEqual(3, collection.Data.Count, "The item count should be 3");
// the name that is not yet used should be picked
Assert.AreEqual("column2", collection.Data[2].Name.Value);
}
}
}

View File

@@ -0,0 +1,30 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts;
using NUnit.Framework;
using Newtonsoft.Json;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.TableDesigner
{
public class TableDesignerChangeInfoTest
{
[Test]
public void DeserializeTableChangeProperty()
{
string testJsonStringType = "{\"type\": 1, \"property\": \"columns\"}";
TableDesignerChangeInfo changeInfo = JsonConvert.DeserializeObject<TableDesignerChangeInfo>(testJsonStringType);
Assert.IsNotNull(changeInfo, "string property: the changeInfo shouldn't be null.");
Assert.IsNotNull(changeInfo.Property, "string property: the property shouldn't be null.");
Assert.IsTrue(changeInfo.Property.GetType() == typeof(string));
string testJsonObjectType = "{\"type\": 1, \"property\": {\"parentProperty\": \"columns\",\"index\": 0,\"property\": \"length\"}}";
changeInfo = JsonConvert.DeserializeObject<TableDesignerChangeInfo>(testJsonObjectType);
Assert.IsNotNull(changeInfo, "object property: the changeInfo shouldn't be null.");
Assert.IsNotNull(changeInfo.Property, "object property: the property shouldn't be null.");
Assert.IsTrue(changeInfo.Property.GetType() == typeof(TableDesignerPropertyIdentifier));
}
}
}