diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs index 22a2f36f..fbfa8477 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs @@ -9005,6 +9005,22 @@ namespace Microsoft.SqlTools.ServiceLayer } } + public static string AddNewEdgeConstraintLabel + { + get + { + return Keys.GetString(Keys.AddNewEdgeConstraintLabel); + } + } + + public static string AddNewClauseLabel + { + get + { + return Keys.GetString(Keys.AddNewClauseLabel); + } + } + public static string ConnectionServiceListDbErrorNotConnected(string uri) { return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri); @@ -12867,6 +12883,12 @@ namespace Microsoft.SqlTools.ServiceLayer public const string TableColumnDefaultConstraintNamePropertyTitle = "TableColumnDefaultConstraintNamePropertyTitle"; + public const string AddNewEdgeConstraintLabel = "AddNewEdgeConstraintLabel"; + + + public const string AddNewClauseLabel = "AddNewClauseLabel"; + + private Keys() { } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx index 59badd85..233a660f 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx @@ -4914,4 +4914,12 @@ The Query Processor estimates that implementing the following index could improv Default Constraint Name + + New Edge Constraint + + + + New Clause + + diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings index 0011de7e..11b0c30c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings @@ -2300,4 +2300,6 @@ TableDesignerAutoCreateHistoryTableTitle = Auto Create History Table TableDesignerNewHistoryTableDescription = Specifies the name of the new history table. TableDesignerNewHistoryTableTitle = New History Table Name TableColumnDefaultConstraintNamePropertyDescription = Specifies the default constraint name. -TableColumnDefaultConstraintNamePropertyTitle = Default Constraint Name \ No newline at end of file +TableColumnDefaultConstraintNamePropertyTitle = Default Constraint Name +AddNewEdgeConstraintLabel = New Edge Constraint +AddNewClauseLabel = New Clause \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf index 3ed95019..12830ce1 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf @@ -5983,6 +5983,16 @@ The Query Processor estimates that implementing the following index could improv Default Constraint Name + + New Edge Constraint + New Edge Constraint + + + + New Clause + New Clause + + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Components/InputBoxProperties.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Components/InputBoxProperties.cs index 97bcf930..c1b3383c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Components/InputBoxProperties.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Components/InputBoxProperties.cs @@ -3,13 +3,27 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts { + [JsonConverter(typeof(StringEnumConverter))] + public enum InputType + { + [EnumMember(Value = "text")] + Text, + [EnumMember(Value = "number")] + Number + } /// /// Inputbox properties /// public class InputBoxProperties : ComponentPropertiesBase { public string Value { get; set; } + + public InputType InputType { get; set; } = InputType.Text; } } \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Components/TableProperties.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Components/TableProperties.cs index c9a90685..88b2984a 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Components/TableProperties.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Components/TableProperties.cs @@ -50,5 +50,10 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts /// The confirmation message to be displayed when a row is about to be removed. /// public string RemoveRowConfirmationMessage { get; set; } + + /// + /// The label for the add new button for this table. + /// + public string LabelForAddNewButton { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Requests/ProcessTableDesignerEditRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Requests/ProcessTableDesignerEditRequest.cs index 855c7d98..c978e52d 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Requests/ProcessTableDesignerEditRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Requests/ProcessTableDesignerEditRequest.cs @@ -23,7 +23,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts public bool IsValid { get; set; } - public TableDesignerValidationError[] Errors { get; set; } + public TableDesignerIssue[] Issues { get; set; } } /// diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/TableDesignerIssue.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/TableDesignerIssue.cs new file mode 100644 index 00000000..ebefa65e --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/TableDesignerIssue.cs @@ -0,0 +1,43 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum IssueSeverity + { + [EnumMember(Value = "error")] + Error, + [EnumMember(Value = "warning")] + Warning, + [EnumMember(Value = "informational")] + Informational, + } + + /// + /// Table Designer Issue + /// + public class TableDesignerIssue + { + /// + /// The description. + /// + public string Description { get; set; } + + /// + /// The property path associated with the message + /// + public object[] PropertyPath { get; set; } + + /// + /// The severity of the message. Default value is Error. + /// + public IssueSeverity Severity { get; set; } = IssueSeverity.Error; + } +} \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/TableDesignerValidationError.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/TableDesignerValidationError.cs deleted file mode 100644 index 9cf37f51..00000000 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/TableDesignerValidationError.cs +++ /dev/null @@ -1,23 +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 -{ - /// - /// Validation error - /// - public class TableDesignerValidationError - { - /// - /// The error message - /// - public string Message { get; set; } - - /// - /// The property path associated with the message - /// - public object[] PropertyPath { get; set; } - } -} \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs index fa86fbb9..a1d4f819 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs @@ -113,12 +113,12 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner break; } var designer = this.GetTableDesigner(requestParams.TableInfo); - var errors = TableDesignerValidator.Validate(designer.TableViewModel); + var issues = TableDesignerValidator.Validate(designer.TableViewModel); await requestContext.SendResult(new ProcessTableDesignerEditResponse() { ViewModel = this.GetTableViewModel(requestParams.TableInfo), - IsValid = errors.Count == 0, - Errors = errors.ToArray(), + IsValid = issues.Where(i => i.Severity == IssueSeverity.Error).Count() == 0, + Issues = issues.ToArray(), View = refreshViewRequired ? this.GetDesignerViewInfo(requestParams.TableInfo) : null }); }); @@ -897,7 +897,8 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner ComponentType = DesignerComponentType.Input, ComponentProperties = new InputBoxProperties() { - Title = SR.TableColumnIdentitySeedPropertyTitle + Title = SR.TableColumnIdentitySeedPropertyTitle, + InputType = InputType.Number } }, new DesignerDataPropertyInfo() @@ -908,7 +909,8 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner ComponentType = DesignerComponentType.Input, ComponentProperties = new InputBoxProperties() { - Title = SR.TableColumnIdentityIncrementPropertyTitle + Title = SR.TableColumnIdentityIncrementPropertyTitle, + InputType = InputType.Number } }, new DesignerDataPropertyInfo() @@ -1069,7 +1071,8 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner var constraintsTableProperties = new TableComponentProperties() { Title = SR.TableDesignerEdgeConstraintsTabTitle, - ObjectTypeDisplayName = SR.TableDesignerEdgeConstraintObjectType + ObjectTypeDisplayName = SR.TableDesignerEdgeConstraintObjectType, + LabelForAddNewButton = SR.AddNewEdgeConstraintLabel }; constraintsTableProperties.Columns.AddRange(new string[] { EdgeConstraintPropertyNames.Name, EdgeConstraintPropertyNames.ClausesDisplayValue }); constraintsTableProperties.ItemProperties.AddRange(new DesignerDataPropertyInfo[] { @@ -1125,6 +1128,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner Title = SR.TableDesignerEdgeConstraintClausesPropertyTitle, ObjectTypeDisplayName = SR.TableDesignerEdgeConstraintClauseObjectType, Columns = new List () { EdgeConstraintClausePropertyNames.FromTable, EdgeConstraintClausePropertyNames.ToTable}, + LabelForAddNewButton = SR.AddNewClauseLabel, ItemProperties = new List() { new DesignerDataPropertyInfo() diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerValidator.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerValidator.cs index cb1f09a6..2abc42fc 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerValidator.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerValidator.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using Microsoft.Data.Tools.Sql.DesignServices.TableDesigner; -using ValidationError = Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts.TableDesignerValidationError; +using TableDesignerIssue = Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts.TableDesignerIssue; using System.Linq; namespace Microsoft.SqlTools.ServiceLayer.TableDesigner { @@ -28,15 +28,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner new OnlyDurableMemoryOptimizedTableCanBeSystemVersionedRule(), new TemporalTableMustHavePrimaryKeyRule(), new TableMustHaveAtLeastOneColumnRule(), - new MemoryOptimizedTableIdentityColumnRule() + new MemoryOptimizedTableIdentityColumnRule(), + new TableShouldAvoidHavingMultipleEdgeConstraintsRule() }; /// /// Validate the table and return the validation errors. /// - public static List Validate(TableViewModel table) + public static List Validate(TableViewModel table) { - var errors = new List(); + var errors = new List(); foreach (var rule in Rules) { errors.AddRange(rule.Run(table)); @@ -47,22 +48,22 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public interface ITableDesignerValidationRule { - List Run(TableViewModel table); + List Run(TableViewModel table); } public class IndexMustHaveColumnsRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); for (int i = 0; i < table.Indexes.Items.Count; i++) { var index = table.Indexes.Items[i]; if (index.Columns.Count == 0) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = string.Format("Index '{0}' does not have any columns associated with it.", index.Name), + Description = string.Format("Index '{0}' does not have any columns associated with it.", index.Name), PropertyPath = new object[] { TablePropertyNames.Indexes, i } }); } @@ -73,17 +74,17 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class ForeignKeyMustHaveColumnsRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); for (int i = 0; i < table.ForeignKeys.Items.Count; i++) { var foreignKey = table.ForeignKeys.Items[i]; if (foreignKey.Columns.Count == 0) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = string.Format("Foreign key '{0}' does not have any columns specified.", foreignKey.Name), + Description = string.Format("Foreign key '{0}' does not have any columns specified.", foreignKey.Name), PropertyPath = new object[] { TablePropertyNames.ForeignKeys, i } }); } @@ -94,9 +95,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class ColumnCanOnlyAppearOnceInIndexRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); for (int i = 0; i < table.Indexes.Items.Count; i++) { var index = table.Indexes.Items[i]; @@ -106,9 +107,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner var columnSpec = index.Columns[j]; if (existingColumns.Contains(columnSpec.Column)) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = string.Format("Column with name '{0}' has already been added to the index '{1}'. Row number: {2}.", columnSpec.Column, index.Name, j + 1), + Description = string.Format("Column with name '{0}' has already been added to the index '{1}'. Row number: {2}.", columnSpec.Column, index.Name, j + 1), PropertyPath = new object[] { TablePropertyNames.Indexes, i, IndexPropertyNames.Columns, j } }); } @@ -124,9 +125,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class ColumnCanOnlyAppearOnceInForeignKeyRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); for (int i = 0; i < table.ForeignKeys.Items.Count; i++) { var foreignKey = table.ForeignKeys.Items[i]; @@ -136,9 +137,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner var column = foreignKey.Columns[j]; if (existingColumns.Contains(column)) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = string.Format("Column with name '{0}' has already been added to the foreign key '{1}'. Row number: {2}.", column, foreignKey.Name, j + 1), + Description = string.Format("Column with name '{0}' has already been added to the foreign key '{1}'. Row number: {2}.", column, foreignKey.Name, j + 1), PropertyPath = new object[] { TablePropertyNames.ForeignKeys, i, ForeignKeyPropertyNames.ColumnMapping, j, ForeignKeyColumnMappingPropertyNames.Column } }); } @@ -154,9 +155,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner var foreignColumn = foreignKey.ForeignColumns[j]; if (existingForeignColumns.Contains(foreignColumn)) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = string.Format("Foreign column with name '{0}' has already been added to the foreign key '{1}'. Row number: {2}.", foreignColumn, foreignKey.Name, j + 1), + Description = string.Format("Foreign column with name '{0}' has already been added to the foreign key '{1}'. Row number: {2}.", foreignColumn, foreignKey.Name, j + 1), PropertyPath = new object[] { TablePropertyNames.ForeignKeys, i, ForeignKeyPropertyNames.ColumnMapping, j, ForeignKeyColumnMappingPropertyNames.ForeignColumn } }); } @@ -172,18 +173,18 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class NoDuplicateConstraintNameRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); var existingNames = new HashSet(); for (int i = 0; i < table.ForeignKeys.Items.Count; i++) { var foreignKey = table.ForeignKeys.Items[i]; if (existingNames.Contains(foreignKey.Name)) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = string.Format("The name '{0}' is already used by another constraint. Row number: {1}.", foreignKey.Name, i + 1), + Description = string.Format("The name '{0}' is already used by another constraint. Row number: {1}.", foreignKey.Name, i + 1), PropertyPath = new object[] { TablePropertyNames.ForeignKeys, i, ForeignKeyPropertyNames.Name } }); } @@ -198,9 +199,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner var checkConstraint = table.CheckConstraints.Items[i]; if (existingNames.Contains(checkConstraint.Name)) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = string.Format("The name '{0}' is already used by another constraint. Row number: {1}.", checkConstraint.Name, i + 1), + Description = string.Format("The name '{0}' is already used by another constraint. Row number: {1}.", checkConstraint.Name, i + 1), PropertyPath = new object[] { TablePropertyNames.CheckConstraints, i, CheckConstraintPropertyNames.Name } }); } @@ -215,9 +216,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner var edgeConstraint = table.EdgeConstraints.Items[i]; if (existingNames.Contains(edgeConstraint.Name)) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = string.Format("The name '{0}' is already used by another constraint. Row number: {1}.", edgeConstraint.Name, i + 1), + Description = string.Format("The name '{0}' is already used by another constraint. Row number: {1}.", edgeConstraint.Name, i + 1), PropertyPath = new object[] { TablePropertyNames.EdgeConstraints, i, EdgeConstraintPropertyNames.Name } }); } @@ -232,18 +233,18 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class NoDuplicateColumnNameRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); var existingNames = new HashSet(); for (int i = 0; i < table.Columns.Items.Count; i++) { var column = table.Columns.Items[i]; if (existingNames.Contains(column.Name)) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = string.Format("The name '{0}' is already used by another column. Row number: {1}.", column.Name, i + 1), + Description = string.Format("The name '{0}' is already used by another column. Row number: {1}.", column.Name, i + 1), PropertyPath = new object[] { TablePropertyNames.Columns, i, TableColumnPropertyNames.Name } }); } @@ -258,18 +259,18 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class NoDuplicateIndexNameRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); var existingNames = new HashSet(); for (int i = 0; i < table.Indexes.Items.Count; i++) { var index = table.Indexes.Items[i]; if (existingNames.Contains(index.Name)) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = string.Format("The name '{0}' is already used by another index. Row number: {1}.", index.Name, i + 1), + Description = string.Format("The name '{0}' is already used by another index. Row number: {1}.", index.Name, i + 1), PropertyPath = new object[] { TablePropertyNames.Indexes, i, IndexPropertyNames.Name } }); } @@ -284,17 +285,17 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class EdgeConstraintMustHaveClausesRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); for (int i = 0; i < table.EdgeConstraints.Items.Count; i++) { var edgeConstraint = table.EdgeConstraints.Items[i]; if (edgeConstraint.Clauses.Count == 0) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = string.Format("Edge constraint '{0}' does not have any clauses specified.", edgeConstraint.Name), + Description = string.Format("Edge constraint '{0}' does not have any clauses specified.", edgeConstraint.Name), PropertyPath = new object[] { TablePropertyNames.EdgeConstraints, i } }); } @@ -305,9 +306,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class EdgeConstraintNoRepeatingClausesRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); for (int i = 0; i < table.EdgeConstraints.Items.Count; i++) { var edgeConstraint = table.EdgeConstraints.Items[i]; @@ -318,9 +319,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner var pair = string.Format("{0} - {1}", clause.FromTable, clause.ToTable); if (existingPairs.Contains(pair)) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = string.Format("The pair '{0}' is already defined by another clause in the edge constraint. Row number: {1}.", pair, j + 1), + Description = string.Format("The pair '{0}' is already defined by another clause in the edge constraint. Row number: {1}.", pair, j + 1), PropertyPath = new object[] { TablePropertyNames.EdgeConstraints, i, EdgeConstraintPropertyNames.Clauses, j, EdgeConstraintClausePropertyNames.FromTable } }); } @@ -336,14 +337,14 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class MemoryOptimizedTableMustHaveNonClusteredPrimaryKeyRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); if (table.IsMemoryOptimized && (table.PrimaryKey == null || table.PrimaryKey.IsClustered)) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = "Memory-optimized table must have non-clustered primary key.", + Description = "Memory-optimized table must have non-clustered primary key.", PropertyPath = new object[] { TablePropertyNames.PrimaryKeyIsClustered } }); } @@ -353,14 +354,14 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class TemporalTableMustHavePrimaryKeyRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); if (table.SystemVersioningHistoryTable != null && table.PrimaryKey == null) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = "System versioned table must have primary key." + Description = "System versioned table must have primary key." }); } return errors; @@ -369,14 +370,14 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class TemporalTableMustHavePeriodColumns : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); if (table.SystemVersioningHistoryTable != null && !table.PeriodColumnsDefined) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = "System versioned table must have the period columns defined." + Description = "System versioned table must have the period columns defined." }); } return errors; @@ -385,23 +386,23 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class PeriodColumnsRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); var rowStart = table.Columns.Items.Where(c => c.GeneratedAlwaysAs == ColumnGeneratedAlwaysAsType.GeneratedAlwaysAsRowStart); var rowEnd = table.Columns.Items.Where(c => c.GeneratedAlwaysAs == ColumnGeneratedAlwaysAsType.GeneratedAlwaysAsRowEnd); if (rowStart.Count() > 1 || rowEnd.Count() > 1) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = "Period columns (Generated Always As Row Start/End) can only be defined once." + Description = "Period columns (Generated Always As Row Start/End) can only be defined once." }); } else if (rowEnd.Count() != rowStart.Count()) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = "Period columns (Generated Always As Row Start/End) must be defined as pair. If one is defined, the other must also be defined" + Description = "Period columns (Generated Always As Row Start/End) must be defined as pair. If one is defined, the other must also be defined" }); } return errors; @@ -410,17 +411,17 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class ColumnsInPrimaryKeyCannotBeNullableRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); for (int i = 0; i < table.Columns.Items.Count; i++) { var column = table.Columns.Items[i]; if (column.IsPrimaryKey && column.IsNullable) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = "Columns in primary key cannot be nullable.", + Description = "Columns in primary key cannot be nullable.", PropertyPath = new object[] { TablePropertyNames.Columns, i } }); } @@ -431,14 +432,14 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class OnlyDurableMemoryOptimizedTableCanBeSystemVersionedRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); if (table.Durability == TableDurability.SchemaOnly && table.IsMemoryOptimized && table.IsSystemVersioningEnabled) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = "Only durable (DURABILITY = SCHEMA_AND_DATA) memory-optimized tables can be system-versioned." + Description = "Only durable (DURABILITY = SCHEMA_AND_DATA) memory-optimized tables can be system-versioned." }); } return errors; @@ -447,14 +448,14 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class TableMustHaveAtLeastOneColumnRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); if (!table.IsEdge && table.Columns.Items.Count == 0) { - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = "A table must have at least one column defined." + Description = "A table must have at least one column defined." }); } return errors; @@ -463,9 +464,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public class MemoryOptimizedTableIdentityColumnRule : ITableDesignerValidationRule { - public List Run(TableViewModel table) + public List Run(TableViewModel table) { - var errors = new List(); + var errors = new List(); if (table.IsMemoryOptimized) { for (int i = 0; i < table.Columns.Items.Count; i++) @@ -474,9 +475,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner if (column.IsIdentity && (column.IdentitySeed != 1 || column.IdentityIncrement != 1)) { var propertyName = column.IdentitySeed != 1 ? TableColumnPropertyNames.IdentitySeed : TableColumnPropertyNames.IdentityIncrement; - errors.Add(new ValidationError() + errors.Add(new TableDesignerIssue() { - Message = "The use of seed and increment values other than 1 is not supported with memory optimized tables.", + Description = "The use of seed and increment values other than 1 is not supported with memory optimized tables.", PropertyPath = new object[] { TablePropertyNames.Columns, i, propertyName } }); } @@ -485,4 +486,21 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner return errors; } } + + public class TableShouldAvoidHavingMultipleEdgeConstraintsRule : ITableDesignerValidationRule + { + public List Run(TableViewModel table) + { + var errors = new List(); + if (table.EdgeConstraints.Items.Count > 1) + { + errors.Add(new TableDesignerIssue() + { + Description = "The table has more than one edge constraint on it. This is only useful as a temporary state when modifying existing edge constraints, and should not be used in other cases. Please refer to https://docs.microsoft.com/sql/relational-databases/tables/graph-edge-constraints for more details.", + Severity = Contracts.IssueSeverity.Warning + }); + } + return errors; + } + } } \ No newline at end of file