From 7a326b2487c208254a95541b84256ab331d0c6a5 Mon Sep 17 00:00:00 2001 From: Alan Ren Date: Tue, 8 Mar 2022 18:52:51 -0800 Subject: [PATCH] new table designer features (#1420) * support graph table types * more fixes * refresh view upon edit * support temporal tables * temporal and memory table * primary key and default constraint * bug fixes * dispose table designer * vbump dacfx * update string --- Packages.props | 2 +- .../Localization/sr.cs | 490 +++++++++++++++- .../Localization/sr.resx | 180 +++++- .../Localization/sr.strings | 46 +- .../Localization/sr.xlf | 232 +++++++- .../TableDesigner/Constants.cs | 30 + .../Contracts/Components/TableProperties.cs | 22 +- .../ProcessTableDesignerEditRequest.cs | 2 + .../Requests/PublishTableChangesRequest.cs | 1 + .../Contracts/TableDesignerView.cs | 12 +- .../ViewModel/EdgeConstraintViewModel.cs | 28 + .../ViewModel/TableColumnViewModel.cs | 8 + .../Contracts/ViewModel/TableViewModel.cs | 22 + .../TableDesigner/EnumUtils.cs | 93 +++ .../TableDesigner/SqlForeignKeyActionUtil.cs | 56 -- .../TableDesigner/TableDesignerService.cs | 551 +++++++++++++++++- .../TableDesigner/TableDesignerValidator.cs | 210 ++++++- 17 files changed, 1896 insertions(+), 89 deletions(-) create mode 100644 src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/ViewModel/EdgeConstraintViewModel.cs create mode 100644 src/Microsoft.SqlTools.ServiceLayer/TableDesigner/EnumUtils.cs delete mode 100644 src/Microsoft.SqlTools.ServiceLayer/TableDesigner/SqlForeignKeyActionUtil.cs diff --git a/Packages.props b/Packages.props index b8b0b904..4c4d50c1 100644 --- a/Packages.props +++ b/Packages.props @@ -21,7 +21,7 @@ - + diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs index e847cfbf..22a2f36f 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs @@ -8653,6 +8653,358 @@ namespace Microsoft.SqlTools.ServiceLayer } } + public static string TableDesignerGraphTableGroupTitle + { + get + { + return Keys.GetString(Keys.TableDesignerGraphTableGroupTitle); + } + } + + public static string TableDesignerGraphTableTypeTitle + { + get + { + return Keys.GetString(Keys.TableDesignerGraphTableTypeTitle); + } + } + + public static string TableDesignerGraphTableTypeDescription + { + get + { + return Keys.GetString(Keys.TableDesignerGraphTableTypeDescription); + } + } + + public static string TableDesignerGraphTableTypeEdge + { + get + { + return Keys.GetString(Keys.TableDesignerGraphTableTypeEdge); + } + } + + public static string TableDesignerGraphTableTypeNode + { + get + { + return Keys.GetString(Keys.TableDesignerGraphTableTypeNode); + } + } + + public static string TableDesignerGraphTableTypeNone + { + get + { + return Keys.GetString(Keys.TableDesignerGraphTableTypeNone); + } + } + + public static string TableDesignerEdgeConstraintsTabTitle + { + get + { + return Keys.GetString(Keys.TableDesignerEdgeConstraintsTabTitle); + } + } + + public static string TableDesignerEdgeConstraintObjectType + { + get + { + return Keys.GetString(Keys.TableDesignerEdgeConstraintObjectType); + } + } + + public static string TableDesignerEdgeConstraintNamePropertyDescription + { + get + { + return Keys.GetString(Keys.TableDesignerEdgeConstraintNamePropertyDescription); + } + } + + public static string TableDesignerEdgeConstraintNamePropertyTitle + { + get + { + return Keys.GetString(Keys.TableDesignerEdgeConstraintNamePropertyTitle); + } + } + + public static string TableDesignerEdgeConstraintIsEnabledPropertyDescription + { + get + { + return Keys.GetString(Keys.TableDesignerEdgeConstraintIsEnabledPropertyDescription); + } + } + + public static string TableDesignerEdgeConstraintIsEnabledPropertyTitle + { + get + { + return Keys.GetString(Keys.TableDesignerEdgeConstraintIsEnabledPropertyTitle); + } + } + + public static string TableDesignerEdgeConstraintOnDeleteActionPropertyDescription + { + get + { + return Keys.GetString(Keys.TableDesignerEdgeConstraintOnDeleteActionPropertyDescription); + } + } + + public static string TableDesignerEdgeConstraintOnDeleteActionPropertyTitle + { + get + { + return Keys.GetString(Keys.TableDesignerEdgeConstraintOnDeleteActionPropertyTitle); + } + } + + public static string TableDesignerEdgeConstraintClausesPropertyDescription + { + get + { + return Keys.GetString(Keys.TableDesignerEdgeConstraintClausesPropertyDescription); + } + } + + public static string TableDesignerEdgeConstraintClausesPropertyTitle + { + get + { + return Keys.GetString(Keys.TableDesignerEdgeConstraintClausesPropertyTitle); + } + } + + public static string TableDesignerEdgeConstraintClauseObjectType + { + get + { + return Keys.GetString(Keys.TableDesignerEdgeConstraintClauseObjectType); + } + } + + public static string TableDesignerEdgeConstraintClauseFromTablePropertyName + { + get + { + return Keys.GetString(Keys.TableDesignerEdgeConstraintClauseFromTablePropertyName); + } + } + + public static string TableDesignerEdgeConstraintClauseToTablePropertyName + { + get + { + return Keys.GetString(Keys.TableDesignerEdgeConstraintClauseToTablePropertyName); + } + } + + public static string SqlTableDurability_SchemaAndData + { + get + { + return Keys.GetString(Keys.SqlTableDurability_SchemaAndData); + } + } + + public static string SqlTableDurability_SchemaOnly + { + get + { + return Keys.GetString(Keys.SqlTableDurability_SchemaOnly); + } + } + + public static string GeneratedAlwaysColumnType_None + { + get + { + return Keys.GetString(Keys.GeneratedAlwaysColumnType_None); + } + } + + public static string GeneratedAlwaysColumnType_RowStart + { + get + { + return Keys.GetString(Keys.GeneratedAlwaysColumnType_RowStart); + } + } + + public static string GeneratedAlwaysColumnType_RowEnd + { + get + { + return Keys.GetString(Keys.GeneratedAlwaysColumnType_RowEnd); + } + } + + public static string TableDesignerIsSystemVersioningEnabledTitle + { + get + { + return Keys.GetString(Keys.TableDesignerIsSystemVersioningEnabledTitle); + } + } + + public static string TableDesignerIsSystemVersioningEnabledDescription + { + get + { + return Keys.GetString(Keys.TableDesignerIsSystemVersioningEnabledDescription); + } + } + + public static string TableDesignerSystemVersioningGroupTitle + { + get + { + return Keys.GetString(Keys.TableDesignerSystemVersioningGroupTitle); + } + } + + public static string TableDesignerHistoryTableDescription + { + get + { + return Keys.GetString(Keys.TableDesignerHistoryTableDescription); + } + } + + public static string TableDesignerHistoryTableTitle + { + get + { + return Keys.GetString(Keys.TableDesignerHistoryTableTitle); + } + } + + public static string TableDesignerIsMemoryOptimizedDescription + { + get + { + return Keys.GetString(Keys.TableDesignerIsMemoryOptimizedDescription); + } + } + + public static string TableDesignerMemoryOptimizedGroupTitle + { + get + { + return Keys.GetString(Keys.TableDesignerMemoryOptimizedGroupTitle); + } + } + + public static string TableDesignerIsMemoryOptimizedTitle + { + get + { + return Keys.GetString(Keys.TableDesignerIsMemoryOptimizedTitle); + } + } + + public static string TableDesignerDurabilityDescription + { + get + { + return Keys.GetString(Keys.TableDesignerDurabilityDescription); + } + } + + public static string TableDesignerDurabilityTitle + { + get + { + return Keys.GetString(Keys.TableDesignerDurabilityTitle); + } + } + + public static string TableDesignerColumnGeneratedAlwaysAsDescription + { + get + { + return Keys.GetString(Keys.TableDesignerColumnGeneratedAlwaysAsDescription); + } + } + + public static string TableDesignerColumnGeneratedAlwaysAsTitle + { + get + { + return Keys.GetString(Keys.TableDesignerColumnGeneratedAlwaysAsTitle); + } + } + + public static string TableDesignerColumnIsHiddenTitle + { + get + { + return Keys.GetString(Keys.TableDesignerColumnIsHiddenTitle); + } + } + + public static string TableDesignerColumnIsHiddenDescription + { + get + { + return Keys.GetString(Keys.TableDesignerColumnIsHiddenDescription); + } + } + + public static string TableDesignerAutoCreateHistoryTableDescription + { + get + { + return Keys.GetString(Keys.TableDesignerAutoCreateHistoryTableDescription); + } + } + + public static string TableDesignerAutoCreateHistoryTableTitle + { + get + { + return Keys.GetString(Keys.TableDesignerAutoCreateHistoryTableTitle); + } + } + + public static string TableDesignerNewHistoryTableDescription + { + get + { + return Keys.GetString(Keys.TableDesignerNewHistoryTableDescription); + } + } + + public static string TableDesignerNewHistoryTableTitle + { + get + { + return Keys.GetString(Keys.TableDesignerNewHistoryTableTitle); + } + } + + public static string TableColumnDefaultConstraintNamePropertyDescription + { + get + { + return Keys.GetString(Keys.TableColumnDefaultConstraintNamePropertyDescription); + } + } + + public static string TableColumnDefaultConstraintNamePropertyTitle + { + get + { + return Keys.GetString(Keys.TableColumnDefaultConstraintNamePropertyTitle); + } + } + public static string ConnectionServiceListDbErrorNotConnected(string uri) { return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri); @@ -8953,9 +9305,9 @@ namespace Microsoft.SqlTools.ServiceLayer return Keys.GetString(Keys.InvalidTableEditPathException, path, editType); } - public static string UnKnownSqlForeignKeyAction(string name) + public static string UnknownEnumString(string name) { - return Keys.GetString(Keys.UnKnownSqlForeignKeyAction, name); + return Keys.GetString(Keys.UnknownEnumString, name); } [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] @@ -12350,7 +12702,7 @@ namespace Microsoft.SqlTools.ServiceLayer public const string SqlForeignKeyAction_SetDefault = "SqlForeignKeyAction_SetDefault"; - public const string UnKnownSqlForeignKeyAction = "UnKnownSqlForeignKeyAction"; + public const string UnknownEnumString = "UnknownEnumString"; public const string CheckConstraintIsEnabledDescription = "CheckConstraintIsEnabledDescription"; @@ -12383,6 +12735,138 @@ namespace Microsoft.SqlTools.ServiceLayer public const string TableDesignerDeleteColumnConfirmationMessage = "TableDesignerDeleteColumnConfirmationMessage"; + public const string TableDesignerGraphTableGroupTitle = "TableDesignerGraphTableGroupTitle"; + + + public const string TableDesignerGraphTableTypeTitle = "TableDesignerGraphTableTypeTitle"; + + + public const string TableDesignerGraphTableTypeDescription = "TableDesignerGraphTableTypeDescription"; + + + public const string TableDesignerGraphTableTypeEdge = "TableDesignerGraphTableTypeEdge"; + + + public const string TableDesignerGraphTableTypeNode = "TableDesignerGraphTableTypeNode"; + + + public const string TableDesignerGraphTableTypeNone = "TableDesignerGraphTableTypeNone"; + + + public const string TableDesignerEdgeConstraintsTabTitle = "TableDesignerEdgeConstraintsTabTitle"; + + + public const string TableDesignerEdgeConstraintObjectType = "TableDesignerEdgeConstraintObjectType"; + + + public const string TableDesignerEdgeConstraintNamePropertyDescription = "TableDesignerEdgeConstraintNamePropertyDescription"; + + + public const string TableDesignerEdgeConstraintNamePropertyTitle = "TableDesignerEdgeConstraintNamePropertyTitle"; + + + public const string TableDesignerEdgeConstraintIsEnabledPropertyDescription = "TableDesignerEdgeConstraintIsEnabledPropertyDescription"; + + + public const string TableDesignerEdgeConstraintIsEnabledPropertyTitle = "TableDesignerEdgeConstraintIsEnabledPropertyTitle"; + + + public const string TableDesignerEdgeConstraintOnDeleteActionPropertyDescription = "TableDesignerEdgeConstraintOnDeleteActionPropertyDescription"; + + + public const string TableDesignerEdgeConstraintOnDeleteActionPropertyTitle = "TableDesignerEdgeConstraintOnDeleteActionPropertyTitle"; + + + public const string TableDesignerEdgeConstraintClausesPropertyDescription = "TableDesignerEdgeConstraintClausesPropertyDescription"; + + + public const string TableDesignerEdgeConstraintClausesPropertyTitle = "TableDesignerEdgeConstraintClausesPropertyTitle"; + + + public const string TableDesignerEdgeConstraintClauseObjectType = "TableDesignerEdgeConstraintClauseObjectType"; + + + public const string TableDesignerEdgeConstraintClauseFromTablePropertyName = "TableDesignerEdgeConstraintClauseFromTablePropertyName"; + + + public const string TableDesignerEdgeConstraintClauseToTablePropertyName = "TableDesignerEdgeConstraintClauseToTablePropertyName"; + + + public const string SqlTableDurability_SchemaAndData = "SqlTableDurability_SchemaAndData"; + + + public const string SqlTableDurability_SchemaOnly = "SqlTableDurability_SchemaOnly"; + + + public const string GeneratedAlwaysColumnType_None = "GeneratedAlwaysColumnType_None"; + + + public const string GeneratedAlwaysColumnType_RowStart = "GeneratedAlwaysColumnType_RowStart"; + + + public const string GeneratedAlwaysColumnType_RowEnd = "GeneratedAlwaysColumnType_RowEnd"; + + + public const string TableDesignerIsSystemVersioningEnabledTitle = "TableDesignerIsSystemVersioningEnabledTitle"; + + + public const string TableDesignerIsSystemVersioningEnabledDescription = "TableDesignerIsSystemVersioningEnabledDescription"; + + + public const string TableDesignerSystemVersioningGroupTitle = "TableDesignerSystemVersioningGroupTitle"; + + + public const string TableDesignerHistoryTableDescription = "TableDesignerHistoryTableDescription"; + + + public const string TableDesignerHistoryTableTitle = "TableDesignerHistoryTableTitle"; + + + public const string TableDesignerIsMemoryOptimizedDescription = "TableDesignerIsMemoryOptimizedDescription"; + + + public const string TableDesignerMemoryOptimizedGroupTitle = "TableDesignerMemoryOptimizedGroupTitle"; + + + public const string TableDesignerIsMemoryOptimizedTitle = "TableDesignerIsMemoryOptimizedTitle"; + + + public const string TableDesignerDurabilityDescription = "TableDesignerDurabilityDescription"; + + + public const string TableDesignerDurabilityTitle = "TableDesignerDurabilityTitle"; + + + public const string TableDesignerColumnGeneratedAlwaysAsDescription = "TableDesignerColumnGeneratedAlwaysAsDescription"; + + + public const string TableDesignerColumnGeneratedAlwaysAsTitle = "TableDesignerColumnGeneratedAlwaysAsTitle"; + + + public const string TableDesignerColumnIsHiddenTitle = "TableDesignerColumnIsHiddenTitle"; + + + public const string TableDesignerColumnIsHiddenDescription = "TableDesignerColumnIsHiddenDescription"; + + + public const string TableDesignerAutoCreateHistoryTableDescription = "TableDesignerAutoCreateHistoryTableDescription"; + + + public const string TableDesignerAutoCreateHistoryTableTitle = "TableDesignerAutoCreateHistoryTableTitle"; + + + public const string TableDesignerNewHistoryTableDescription = "TableDesignerNewHistoryTableDescription"; + + + public const string TableDesignerNewHistoryTableTitle = "TableDesignerNewHistoryTableTitle"; + + + public const string TableColumnDefaultConstraintNamePropertyDescription = "TableColumnDefaultConstraintNamePropertyDescription"; + + + public const string TableColumnDefaultConstraintNamePropertyTitle = "TableColumnDefaultConstraintNamePropertyTitle"; + + private Keys() { } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx index d8e3afff..59badd85 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx @@ -4693,8 +4693,8 @@ The Query Processor estimates that implementing the following index could improv Set Default - - '{0}' is not a supported SqlForeignKeyAction. + + Unknown enum value: {0}. . Parameters: 0 - name (string) @@ -4738,4 +4738,180 @@ The Query Processor estimates that implementing the following index could improv Removing a column will also remove it from the indexes and foreign keys. Are you sure you want to continue? + + Graph Table + + + + Type + + + + Specifies the table type. + + + + Edge + + + + Node + + + + None + + + + Edge Constraints + + + + Edge Constraint + + + + Name of the constraint. + + + + Name + + + + Specifies whether the constraint is enabled. + + + + Is Enabled + + + + The behavior when a user tries to delete a row with data that is involved in an edge constraint. + + + + On Delete Action + + + + Edge constraint clauses. + + + + Clauses + + + + Clause + + + + From Table + + + + To Table + + + + Schema and Data + + + + Schema Only + + + + None + + + + Row start + + + + Row End + + + + System Versioning Enabled + + + + Specifies whether the table is system versioning enabled. + + + + System Versioning + + + + History table of the current table. + + + + History Table + + + + Specifies whether the table is memory optimized. + + + + Memory Optimized + + + + Memory Optimized + + + + Specifies the durability setting of the table. + + + + Durability + + + + Specifies the start or end of the system versioning table's period setting. + + + + Generated Always As + + + + Is Hidden + + + + Specifies whether the column will be returned by select statement. + + + + Specifies whether the engine should automatically create the history table. + + + + Auto Create History Table + + + + Specifies the name of the new history table. + + + + New History Table Name + + + + Specifies the default constraint name. + + + + Default Constraint Name + + diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings index f4e2154b..0011de7e 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings @@ -2246,7 +2246,7 @@ SqlForeignKeyAction_NoAction = No Action SqlForeignKeyAction_Cascade = Cascade SqlForeignKeyAction_SetNull = Set Null SqlForeignKeyAction_SetDefault = Set Default -UnKnownSqlForeignKeyAction(string name) = '{0}' is not a supported SqlForeignKeyAction. +UnknownEnumString(string name) = Unknown enum value: {0}. CheckConstraintIsEnabledDescription = Specifies whether the check constraint is Enabled IndexIsEnabledPropertyDescription = Specifies whether the index is enabled IndexIsClusteredPropertyDescription = Whether the index is clustered, only one clustered index is allowed in a table. @@ -2257,3 +2257,47 @@ IndexColumnIsAscendingPropertyDescription = Specifies the sort order of the colu IndexColumnIsAscendingPropertyTitle = Is Ascending TableDesignerColumnsDisplayValueTitle = Columns TableDesignerDeleteColumnConfirmationMessage = Removing a column will also remove it from the indexes and foreign keys. Are you sure you want to continue? +TableDesignerGraphTableGroupTitle = Graph Table +TableDesignerGraphTableTypeTitle = Type +TableDesignerGraphTableTypeDescription = Specifies the table type. +TableDesignerGraphTableTypeEdge = Edge +TableDesignerGraphTableTypeNode = Node +TableDesignerGraphTableTypeNone = None +TableDesignerEdgeConstraintsTabTitle = Edge Constraints +TableDesignerEdgeConstraintObjectType = Edge Constraint +TableDesignerEdgeConstraintNamePropertyDescription = Name of the constraint. +TableDesignerEdgeConstraintNamePropertyTitle = Name +TableDesignerEdgeConstraintIsEnabledPropertyDescription = Specifies whether the constraint is enabled. +TableDesignerEdgeConstraintIsEnabledPropertyTitle = Is Enabled +TableDesignerEdgeConstraintOnDeleteActionPropertyDescription = The behavior when a user tries to delete a row with data that is involved in an edge constraint. +TableDesignerEdgeConstraintOnDeleteActionPropertyTitle = On Delete Action +TableDesignerEdgeConstraintClausesPropertyDescription = Edge constraint clauses. +TableDesignerEdgeConstraintClausesPropertyTitle = Clauses +TableDesignerEdgeConstraintClauseObjectType = Clause +TableDesignerEdgeConstraintClauseFromTablePropertyName = From Table +TableDesignerEdgeConstraintClauseToTablePropertyName = To Table +SqlTableDurability_SchemaAndData = Schema and Data +SqlTableDurability_SchemaOnly = Schema Only +GeneratedAlwaysColumnType_None = None +GeneratedAlwaysColumnType_RowStart = Row start +GeneratedAlwaysColumnType_RowEnd = Row End +TableDesignerIsSystemVersioningEnabledTitle = System Versioning Enabled +TableDesignerIsSystemVersioningEnabledDescription = Specifies whether the table is system versioning enabled. +TableDesignerSystemVersioningGroupTitle = System Versioning +TableDesignerHistoryTableDescription = History table of the current table. +TableDesignerHistoryTableTitle = History Table +TableDesignerIsMemoryOptimizedDescription = Specifies whether the table is memory optimized. +TableDesignerMemoryOptimizedGroupTitle = Memory Optimized +TableDesignerIsMemoryOptimizedTitle = Memory Optimized +TableDesignerDurabilityDescription = Specifies the durability setting of the table. +TableDesignerDurabilityTitle = Durability +TableDesignerColumnGeneratedAlwaysAsDescription = Specifies the start or end of the system versioning table's period setting. +TableDesignerColumnGeneratedAlwaysAsTitle = Generated Always As +TableDesignerColumnIsHiddenTitle = Is Hidden +TableDesignerColumnIsHiddenDescription = Specifies whether the column will be returned by select statement. +TableDesignerAutoCreateHistoryTableDescription = Specifies whether the engine should automatically create the history table. +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 diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf index 235299fd..3ed95019 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf @@ -5685,12 +5685,6 @@ Set Default - - '{0}' is not a supported SqlForeignKeyAction. - '{0}' is not a supported SqlForeignKeyAction. - . - Parameters: 0 - name (string) - Specifies whether the check constraint is Enabled Specifies whether the check constraint is Enabled @@ -5763,6 +5757,232 @@ The Query Processor estimates that implementing the following index could improv */ title of missing index details + + Type + Type + + + + Edge + Edge + + + + Node + Node + + + + Graph Table + Graph Table + + + + Edge Constraints + Edge Constraints + + + + Edge Constraint + Edge Constraint + + + + Name of the constraint. + Name of the constraint. + + + + Name + Name + + + + Specifies whether the constraint is enabled. + Specifies whether the constraint is enabled. + + + + Is Enabled + Is Enabled + + + + The behavior when a user tries to delete a row with data that is involved in an edge constraint. + The behavior when a user tries to delete a row with data that is involved in an edge constraint. + + + + On Delete Action + On Delete Action + + + + Edge constraint clauses. + Edge constraint clauses. + + + + Clauses + Clauses + + + + Clause + Clause + + + + From Table + From Table + + + + To Table + To Table + + + + None + None + + + + Specifies the table type. + Specifies the table type. + + + + Unknown enum value: {0}. + Unknown enum value: {0}. + . + Parameters: 0 - name (string) + + + Schema and Data + Schema and Data + + + + Schema Only + Schema Only + + + + None + None + + + + Row start + Row start + + + + Row End + Row End + + + + System Versioning Enabled + System Versioning Enabled + + + + Specifies whether the table is system versioning enabled. + Specifies whether the table is system versioning enabled. + + + + System Versioning + System Versioning + + + + History table of the current table. + History table of the current table. + + + + History Table + History Table + + + + Specifies whether the table is memory optimized. + Specifies whether the table is memory optimized. + + + + Memory Optimized + Memory Optimized + + + + Memory Optimized + Memory Optimized + + + + Specifies the durability setting of the table. + Specifies the durability setting of the table. + + + + Durability + Durability + + + + Specifies the start or end of the system versioning table's period setting. + Specifies the start or end of the system versioning table's period setting. + + + + Generated Always As + Generated Always As + + + + Is Hidden + Is Hidden + + + + Specifies whether the column will be returned by select statement. + Specifies whether the column will be returned by select statement. + + + + Specifies whether the engine should automatically create the history table. + Specifies whether the engine should automatically create the history table. + + + + Auto Create History Table + Auto Create History Table + + + + Specifies the name of the new history table. + Specifies the name of the new history table. + + + + New History Table Name + New History Table Name + + + + Specifies the default constraint name. + Specifies the default constraint name. + + + + Default Constraint Name + Default Constraint Name + + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Constants.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Constants.cs index 5772435e..13895295 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Constants.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Constants.cs @@ -14,6 +14,17 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public const string ForeignKeys = "foreignKeys"; public const string CheckConstraints = "checkConstraints"; public const string Indexes = "indexes"; + public const string EdgeConstraints = "edgeConstraints"; + public const string GraphTableType = "graphTableType"; + public const string IsSystemVersioningEnabled = "isSystemVersioningEnabled"; + public const string AutoCreateHistoryTable = "autoCreateHistoryTable"; + public const string NewHistoryTableTable = "newHistoryTableName"; + public const string ExistingHistoryTableName = "existingHistoryTable"; + public const string IsMemoryOptimized = "isMemoryOptimized"; + public const string Durability = "durability"; + public const string PrimaryKeyName = "primaryKeyName"; + public const string PrimaryKeyIsClustered = "primaryKeyIsClustered"; + public const string PrimaryKeyColumns = "primaryKeyColumns"; } public static class TableColumnPropertyNames @@ -29,6 +40,10 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public const string IsIdentity = "isIdentity"; public const string IdentityIncrement = "identityIncrement"; public const string IdentitySeed = "identitySeed"; + public const string CanBeDeleted = "canBeDeleted"; + public const string GeneratedAlwaysAs = "generatedAlwaysAs"; + public const string IsHidden = "isHidden"; + public const string DefaultConstraintName = "defaultConstraintName"; } public static class ForeignKeyPropertyNames @@ -70,4 +85,19 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner public const string Column = "column"; public const string Ascending = "ascending"; } + + public static class EdgeConstraintPropertyNames + { + public const string Name = "name"; + public const string Enabled = "enabled"; + public const string Clauses = "clauses"; + public const string OnDeleteAction = "onDeleteAction"; + public const string ClausesDisplayValue = "clausesDisplayValue"; + } + + public static class EdgeConstraintClausePropertyNames + { + public const string FromTable = "fromTable"; + public const string ToTable = "toTable"; + } } \ 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 5c608570..c9a90685 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Components/TableProperties.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Components/TableProperties.cs @@ -14,7 +14,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts /// /// The column names to be displayed /// - public string[] Columns { get; set; } + public List Columns { get; set; } = new List(); /// /// The object type display name of the objects in this table @@ -30,5 +30,25 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts /// The object list. /// public List Data { get; set; } = new List(); + + /// + /// Whether new rows can be added. + /// + public bool CanAddRows { get; set; } = true; + + /// + /// Whether rows can be deleted. + /// + public bool CanRemoveRows { get; set; } = true; + + /// + /// Whether a confirmation should be shown when a row is about to be removed. + /// + public bool ShowRemoveRowConfirmation { get; set; } = false; + + /// + /// The confirmation message to be displayed when a row is about to be removed. + /// + public string RemoveRowConfirmationMessage { 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 4d539d14..855c7d98 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Requests/ProcessTableDesignerEditRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Requests/ProcessTableDesignerEditRequest.cs @@ -19,6 +19,8 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts { public TableViewModel ViewModel { get; set; } + public TableDesignerView View { get; set; } + public bool IsValid { get; set; } public TableDesignerValidationError[] Errors { get; set; } diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Requests/PublishTableChangesRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Requests/PublishTableChangesRequest.cs index afd81f8d..4489d758 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Requests/PublishTableChangesRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/Requests/PublishTableChangesRequest.cs @@ -11,6 +11,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts { public TableInfo NewTableInfo; public TableViewModel ViewModel; + public TableDesignerView View; } /// diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/TableDesignerView.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/TableDesignerView.cs index 3feb600e..e6d017e8 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/TableDesignerView.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/TableDesignerView.cs @@ -16,9 +16,13 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts public List AdditionalTableProperties { get; set; } = new List(); public BuiltinTableOptions ColumnTableOptions { get; set; } = new BuiltinTableOptions(); public BuiltinTableOptions ForeignKeyTableOptions { get; set; } = new BuiltinTableOptions(); + public BuiltinTableOptions ForeignKeyColumnMappingTableOptions { get; set; } = new BuiltinTableOptions(); public BuiltinTableOptions CheckConstraintTableOptions { get; set; } = new BuiltinTableOptions(); public BuiltinTableOptions IndexTableOptions { get; set; } = new BuiltinTableOptions(); public BuiltinTableOptions IndexColumnSpecificationTableOptions { get; set; } = new BuiltinTableOptions(); + public List AdditionalPrimaryKeyProperties { get; set; } = new List(); + public BuiltinTableOptions PrimaryKeyColumnSpecificationTableOptions = new BuiltinTableOptions(); + public List AdditionalTabs { get; } = new List(); } public class BuiltinTableOptions @@ -29,6 +33,12 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts public bool CanRemoveRows { get; set; } = true; public List AdditionalProperties { get; set; } = new List(); public string RemoveRowConfirmationMessage { get; set; } - public bool ShowRemoveRowConfirmation { get; set;} = false; + public bool ShowRemoveRowConfirmation { get; set; } = false; + } + + public class DesignerTabView + { + public string Title { get; set; } + public List Components { get; } = new List(); } } \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/ViewModel/EdgeConstraintViewModel.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/ViewModel/EdgeConstraintViewModel.cs new file mode 100644 index 00000000..db6d28e1 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/ViewModel/EdgeConstraintViewModel.cs @@ -0,0 +1,28 @@ +// +// 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 +{ + /// + /// The view model of edge constraint. + /// + public class EdgeConstraintViewModel : ObjectViewModelBase + { + public CheckBoxProperties Enabled { get; set; } = new CheckBoxProperties(); + + public DropdownProperties OnDeleteAction { get; set; } = new DropdownProperties(); + + public TableComponentProperties Clauses { get; set; } = new TableComponentProperties(); + + public InputBoxProperties ClausesDisplayValue { get; set; } = new InputBoxProperties(); + } + + public class EdgeConstraintClause + { + public DropdownProperties FromTable { get; set; } = new DropdownProperties(); + + public DropdownProperties ToTable { get; set; } = new DropdownProperties(); + } +} \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/ViewModel/TableColumnViewModel.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/ViewModel/TableColumnViewModel.cs index 8abe7c72..abff3983 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/ViewModel/TableColumnViewModel.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/ViewModel/TableColumnViewModel.cs @@ -29,5 +29,13 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts public InputBoxProperties IdentitySeed { get; set; } = new InputBoxProperties(); public InputBoxProperties IdentityIncrement { get; set; } = new InputBoxProperties(); + + public DropdownProperties GeneratedAlwaysAs { get; set; } = new DropdownProperties(); + + public CheckBoxProperties IsHidden { get; set; } = new CheckBoxProperties(); + + public InputBoxProperties DefaultConstraintName { get; set; } = new InputBoxProperties(); + + public bool CanBeDeleted { get; set; } = true; } } \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/ViewModel/TableViewModel.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/ViewModel/TableViewModel.cs index 5ecada6a..8ae54036 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/ViewModel/TableViewModel.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/Contracts/ViewModel/TableViewModel.cs @@ -14,12 +14,34 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts public InputBoxProperties Description { get; set; } = new InputBoxProperties(); + public DropdownProperties GraphTableType { get; set; } = new DropdownProperties(); + + public CheckBoxProperties IsMemoryOptimized { get; set; } = new CheckBoxProperties(); + + public DropdownProperties Durability { get; set; } = new DropdownProperties(); + + public CheckBoxProperties IsSystemVersioningEnabled { get; set; } = new CheckBoxProperties(); + + public DropdownProperties ExistingHistoryTable { get; set; } = new DropdownProperties(); + + public CheckBoxProperties AutoCreateHistoryTable { get; set; } = new CheckBoxProperties(); + + public InputBoxProperties NewHistoryTableName { get; set; } = new InputBoxProperties(); + + public InputBoxProperties PrimaryKeyName { get; set; } = new InputBoxProperties(); + + public CheckBoxProperties PrimaryKeyIsClustered { get; set; } = new CheckBoxProperties(); + + public TableComponentProperties PrimaryKeyColumns { get; set; } = new TableComponentProperties(); + public TableComponentProperties Columns { get; set; } = new TableComponentProperties(); public TableComponentProperties ForeignKeys { get; set; } = new TableComponentProperties(); public TableComponentProperties CheckConstraints { get; set; } = new TableComponentProperties(); + public TableComponentProperties EdgeConstraints { get; set; } = new TableComponentProperties(); + public TableComponentProperties Indexes { get; set; } = new TableComponentProperties(); public InputBoxProperties Script { get; set; } = new InputBoxProperties(); diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/EnumUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/EnumUtils.cs new file mode 100644 index 00000000..af7c8977 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/EnumUtils.cs @@ -0,0 +1,93 @@ +// +// 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.Linq; +using System.Collections.Generic; +using Microsoft.Data.Tools.Sql.DesignServices.TableDesigner; + +namespace Microsoft.SqlTools.ServiceLayer.TableDesigner +{ + public abstract class EnumUtil where T : struct, IConvertible + { + protected Dictionary Mapping = new Dictionary(); + + public List DisplayNames + { + get + { + return this.Mapping.Keys.ToList(); + } + } + + public string GetName(T enumValue) + { + foreach (var key in this.Mapping.Keys) + { + if (this.Mapping[key].Equals(enumValue)) + { + return key; + } + } + throw new KeyNotFoundException(SR.UnknownEnumString(enumValue.ToString())); + } + + public T GetValue(string displayName) + { + if (this.Mapping.ContainsKey(displayName)) + { + return this.Mapping[displayName]; + } + else + { + throw new KeyNotFoundException(SR.UnknownEnumString(displayName)); + } + } + } + + public class SqlForeignKeyActionUtil : EnumUtil + { + public static SqlForeignKeyActionUtil Instance { get; } = new SqlForeignKeyActionUtil(); + + public SqlForeignKeyActionUtil() + { + this.Mapping.Add(SR.SqlForeignKeyAction_NoAction, SqlForeignKeyAction.NoAction); + this.Mapping.Add(SR.SqlForeignKeyAction_Cascade, SqlForeignKeyAction.Cascade); + this.Mapping.Add(SR.SqlForeignKeyAction_SetNull, SqlForeignKeyAction.SetNull); + this.Mapping.Add(SR.SqlForeignKeyAction_SetDefault, SqlForeignKeyAction.SetDefault); + } + + public List EdgeConstraintOnDeleteActionNames + { + get + { + return new List { SR.SqlForeignKeyAction_NoAction, SR.SqlForeignKeyAction_Cascade }; + } + } + } + + public class SqlTableDurabilityUtil : EnumUtil + { + public static SqlTableDurabilityUtil Instance { get; } = new SqlTableDurabilityUtil(); + + public SqlTableDurabilityUtil() + { + this.Mapping.Add(SR.SqlTableDurability_SchemaAndData, TableDurability.SchemaAndData); + this.Mapping.Add(SR.SqlTableDurability_SchemaOnly, TableDurability.SchemaOnly); + } + } + + public class ColumnGeneratedAlwaysAsTypeUtil : EnumUtil + { + public static ColumnGeneratedAlwaysAsTypeUtil Instance { get; } = new ColumnGeneratedAlwaysAsTypeUtil(); + + public ColumnGeneratedAlwaysAsTypeUtil() + { + this.Mapping.Add(SR.GeneratedAlwaysColumnType_None, ColumnGeneratedAlwaysAsType.None); + this.Mapping.Add(SR.GeneratedAlwaysColumnType_RowStart, ColumnGeneratedAlwaysAsType.GeneratedAlwaysAsRowStart); + this.Mapping.Add(SR.GeneratedAlwaysColumnType_RowEnd, ColumnGeneratedAlwaysAsType.GeneratedAlwaysAsRowEnd); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/SqlForeignKeyActionUtil.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/SqlForeignKeyActionUtil.cs deleted file mode 100644 index 4fe01301..00000000 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/SqlForeignKeyActionUtil.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// 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.Linq; -using System.Collections.Generic; -using Microsoft.Data.Tools.Sql.DesignServices.TableDesigner; - -namespace Microsoft.SqlTools.ServiceLayer.TableDesigner -{ - public static class SqlForeignKeyActionUtil - { - private static Dictionary mapping = new Dictionary(); - - static SqlForeignKeyActionUtil() - { - mapping.Add(SR.SqlForeignKeyAction_NoAction, SqlForeignKeyAction.NoAction); - mapping.Add(SR.SqlForeignKeyAction_Cascade, SqlForeignKeyAction.Cascade); - mapping.Add(SR.SqlForeignKeyAction_SetNull, SqlForeignKeyAction.SetNull); - mapping.Add(SR.SqlForeignKeyAction_SetDefault, SqlForeignKeyAction.SetDefault); - } - public static List ActionNames - { - get - { - return mapping.Keys.ToList(); - } - } - - public static string GetName(SqlForeignKeyAction action) - { - foreach (var key in mapping.Keys) - { - if (mapping[key] == action) - { - return key; - } - } - throw new NotSupportedException(SR.UnKnownSqlForeignKeyAction(action.ToString())); - } - - public static SqlForeignKeyAction GetValue(string displayName) - { - if (mapping.ContainsKey(displayName)) - { - return mapping[displayName]; - } - else - { - throw new KeyNotFoundException(SR.UnKnownSqlForeignKeyAction(displayName)); - } - } - } -} \ 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 c5a6991e..fa86fbb9 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs @@ -87,9 +87,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner await requestContext.SendResult(new TableDesignerInfo() { ViewModel = viewModel, - View = view, - ColumnTypes = tableDesigner.DataTypes.ToList(), - Schemas = tableDesigner.Schemas.ToList() + View = view }); }); } @@ -98,6 +96,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner { return this.HandleRequest(requestContext, async () => { + var refreshViewRequired = false; DesignerPathUtils.Validate(requestParams.TableChangeInfo.Path, requestParams.TableChangeInfo.Type); switch (requestParams.TableChangeInfo.Type) { @@ -108,7 +107,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner this.HandleRemoveItemRequest(requestParams); break; case DesignerEditType.Update: - this.HandleUpdateItemRequest(requestParams); + refreshViewRequired = this.HandleUpdateItemRequest(requestParams); break; default: break; @@ -119,7 +118,8 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner { ViewModel = this.GetTableViewModel(requestParams.TableInfo), IsValid = errors.Count == 0, - Errors = errors.ToArray() + Errors = errors.ToArray(), + View = refreshViewRequired ? this.GetDesignerViewInfo(requestParams.TableInfo) : null }); }); } @@ -146,7 +146,8 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner await requestContext.SendResult(new PublishTableChangesResponse() { NewTableInfo = tableInfo, - ViewModel = this.GetTableViewModel(tableInfo) + ViewModel = this.GetTableViewModel(tableInfo), + View = GetDesignerViewInfo(tableInfo) }); }); } @@ -179,6 +180,8 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner { return this.HandleRequest(requestContext, async () => { + var td = this.GetTableDesigner(tableInfo); + td.Dispose(); this.idTableMap.Remove(tableInfo.Id); await requestContext.SendResult(new DisposeTableDesignerResponse()); }); @@ -206,6 +209,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner case TablePropertyNames.Indexes: table.Indexes.AddNew(); break; + case TablePropertyNames.EdgeConstraints: + table.EdgeConstraints.AddNew(); + break; + case TablePropertyNames.PrimaryKeyColumns: + if (table.PrimaryKey == null) + { + table.CreatePrimaryKey(); + } + table.PrimaryKey.AddNewColumnSpecification(); + break; default: break; } @@ -237,6 +250,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner break; } break; + case TablePropertyNames.EdgeConstraints: + switch (propertyNameL2) + { + case EdgeConstraintPropertyNames.Clauses: + table.EdgeConstraints.Items[indexL1].AddNewClause(); + break; + default: + break; + } + break; default: break; } @@ -266,6 +289,12 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner case TablePropertyNames.Indexes: table.Indexes.RemoveAt(objIndex); break; + case TablePropertyNames.EdgeConstraints: + table.EdgeConstraints.RemoveAt(objIndex); + break; + case TablePropertyNames.PrimaryKeyColumns: + table.PrimaryKey.RemoveColumnSpecification(objIndex); + break; default: break; } @@ -298,15 +327,27 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner break; } break; + case TablePropertyNames.EdgeConstraints: + switch (propertyNameL2) + { + case EdgeConstraintPropertyNames.Clauses: + table.EdgeConstraints.Items[indexL1].RemoveClause(indexL2); + break; + default: + break; + } + break; default: break; } } } - private void HandleUpdateItemRequest(ProcessTableDesignerEditRequestParams requestParams) + private bool HandleUpdateItemRequest(ProcessTableDesignerEditRequestParams requestParams) { - var table = this.GetTableDesigner(requestParams.TableInfo).TableViewModel; + var refreshView = false; + var tableDesigner = this.GetTableDesigner(requestParams.TableInfo); + var table = tableDesigner.TableViewModel; var path = requestParams.TableChangeInfo.Path; var newValue = requestParams.TableChangeInfo.Value; if (path.Length == 1) @@ -323,6 +364,55 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner case TablePropertyNames.Schema: table.Schema = GetStringValue(newValue); break; + case TablePropertyNames.GraphTableType: + var wasEdgeTable = table.IsEdge; + table.IsEdge = false; + table.IsNode = false; + + var newType = GetStringValue(newValue); + if (newType == SR.TableDesignerGraphTableTypeNode) + { + table.IsNode = true; + } + else if (newType == SR.TableDesignerGraphTableTypeEdge) + { + table.IsEdge = true; + } + refreshView = (wasEdgeTable || table.IsEdge) && tableDesigner.IsEdgeConstraintSupported; + break; + case TablePropertyNames.IsSystemVersioningEnabled: + table.IsSystemVersioningEnabled = GetBooleanValue(newValue); + refreshView = true; + break; + case TablePropertyNames.AutoCreateHistoryTable: + table.AutoCreateHistoryTable = GetBooleanValue(newValue); + refreshView = true; + break; + case TablePropertyNames.NewHistoryTableTable: + table.NewHistoryTableName = GetStringValue(newValue); + break; + case TablePropertyNames.ExistingHistoryTableName: + table.ExistingHistoryTable = GetStringValue(newValue); + break; + case TablePropertyNames.IsMemoryOptimized: + table.IsMemoryOptimized = GetBooleanValue(newValue); + refreshView = true; + break; + case TablePropertyNames.Durability: + table.Durability = SqlTableDurabilityUtil.Instance.GetValue(GetStringValue(newValue)); + break; + case TablePropertyNames.PrimaryKeyName: + if (table.PrimaryKey != null) + { + table.PrimaryKey.Name = GetStringValue(newValue); + } + break; + case TablePropertyNames.PrimaryKeyIsClustered: + if (table.PrimaryKey != null) + { + table.PrimaryKey.IsClustered = GetBooleanValue(newValue); + } + break; default: break; } @@ -371,6 +461,15 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner case TableColumnPropertyNames.Type: column.DataType = GetStringValue(newValue); break; + case TableColumnPropertyNames.GeneratedAlwaysAs: + column.GeneratedAlwaysAs = ColumnGeneratedAlwaysAsTypeUtil.Instance.GetValue(GetStringValue(newValue)); + break; + case TableColumnPropertyNames.IsHidden: + column.IsHidden = GetBooleanValue(newValue); + break; + case TableColumnPropertyNames.DefaultConstraintName: + column.DefaultConstraintName = GetStringValue(newValue); + break; default: break; } @@ -406,10 +505,10 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner foreignKey.Name = GetStringValue(newValue); break; case ForeignKeyPropertyNames.OnDeleteAction: - foreignKey.OnDeleteAction = SqlForeignKeyActionUtil.GetValue(GetStringValue(newValue)); + foreignKey.OnDeleteAction = SqlForeignKeyActionUtil.Instance.GetValue(GetStringValue(newValue)); break; case ForeignKeyPropertyNames.OnUpdateAction: - foreignKey.OnUpdateAction = SqlForeignKeyActionUtil.GetValue(GetStringValue(newValue)); + foreignKey.OnUpdateAction = SqlForeignKeyActionUtil.Instance.GetValue(GetStringValue(newValue)); break; case ForeignKeyPropertyNames.ForeignTable: foreignKey.ForeignTable = GetStringValue(newValue); @@ -438,6 +537,36 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner break; } break; + case TablePropertyNames.EdgeConstraints: + var constraint = table.EdgeConstraints.Items[indexL1]; + switch (propertyNameL2) + { + case EdgeConstraintPropertyNames.Enabled: + constraint.Enabled = GetBooleanValue(newValue); + break; + case EdgeConstraintPropertyNames.Name: + constraint.Name = GetStringValue(newValue); + break; + case EdgeConstraintPropertyNames.OnDeleteAction: + constraint.OnDeleteAction = SqlForeignKeyActionUtil.Instance.GetValue(GetStringValue(newValue)); + break; + default: + break; + } + break; + case TablePropertyNames.PrimaryKeyColumns: + switch (propertyNameL2) + { + case IndexColumnSpecificationPropertyNames.Column: + table.PrimaryKey.UpdateColumnName(indexL1, GetStringValue(newValue)); + break; + case IndexColumnSpecificationPropertyNames.Ascending: + table.PrimaryKey.UpdateIsAscending(indexL1, GetBooleanValue(newValue)); + break; + default: + break; + } + break; default: break; } @@ -493,10 +622,32 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner break; } break; + case TablePropertyNames.EdgeConstraints: + var constraint = table.EdgeConstraints.Items[indexL1]; + switch (propertyNameL2) + { + case EdgeConstraintPropertyNames.Clauses: + switch (propertyNameL3) + { + case EdgeConstraintClausePropertyNames.FromTable: + constraint.UpdateFromTable(indexL2, GetStringValue(newValue)); + break; + case EdgeConstraintClausePropertyNames.ToTable: + constraint.UpdateToTable(indexL2, GetStringValue(newValue)); + break; + default: + break; + } + break; + default: + break; + } + break; default: break; } } + return refreshView; } private int GetInt32Value(object value) @@ -521,8 +672,48 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner var tableViewModel = new TableViewModel(); tableViewModel.Name.Value = table.Name; tableViewModel.Schema.Value = table.Schema; + tableViewModel.Schema.Values = tableDesigner.Schemas.ToList(); tableViewModel.Description.Value = table.Description; - tableViewModel.Description.Enabled = false; // TODO: https://github.com/microsoft/azuredatastudio/issues/18247 + var primaryKey = table.PrimaryKey; + tableViewModel.PrimaryKeyName.Enabled = primaryKey != null; + tableViewModel.PrimaryKeyIsClustered.Enabled = primaryKey != null; + if (primaryKey != null) + { + tableViewModel.PrimaryKeyName.Value = primaryKey.Name; + tableViewModel.PrimaryKeyIsClustered.Checked = primaryKey.IsClustered; + foreach (var cs in primaryKey.Columns) + { + var columnSpecVM = new IndexedColumnSpecification(); + columnSpecVM.Ascending.Checked = cs.IsAscending; + columnSpecVM.Column.Value = cs.Column; + columnSpecVM.Column.Values = tableDesigner.GetColumnsForTable(table.FullName).ToList(); + tableViewModel.PrimaryKeyColumns.Data.Add(columnSpecVM); + } + } + + // Graph table related properties + tableViewModel.GraphTableType.Enabled = table.CanEditGraphTableType; + tableViewModel.GraphTableType.Values = new List() { SR.TableDesignerGraphTableTypeNone, SR.TableDesignerGraphTableTypeEdge, SR.TableDesignerGraphTableTypeNode }; + tableViewModel.GraphTableType.Value = (table.IsEdge || table.IsNode) ? (table.IsEdge ? SR.TableDesignerGraphTableTypeEdge : SR.TableDesignerGraphTableTypeNode) : SR.TableDesignerGraphTableTypeNone; + + // Memory-optimized related properties + tableViewModel.IsMemoryOptimized.Checked = table.IsMemoryOptimized; + tableViewModel.IsMemoryOptimized.Enabled = table.CanEditIsMemoryOptimized; + tableViewModel.Durability.Enabled = table.CanEditDurability; + tableViewModel.Durability.Value = SqlTableDurabilityUtil.Instance.GetName(table.Durability); + tableViewModel.Durability.Values = SqlTableDurabilityUtil.Instance.DisplayNames; + + // Temporal related properties + var isTemporalTable = table.SystemVersioningHistoryTable != null; + tableViewModel.IsSystemVersioningEnabled.Enabled = table.CanEditIsSystemVersioningEnabled; + tableViewModel.IsSystemVersioningEnabled.Checked = isTemporalTable; + tableViewModel.AutoCreateHistoryTable.Enabled = table.CanEditAutoCreateHistoryTable; + tableViewModel.AutoCreateHistoryTable.Checked = table.AutoCreateHistoryTable; + tableViewModel.NewHistoryTableName.Enabled = table.CanEditNewHistoryTableName; + tableViewModel.NewHistoryTableName.Value = table.NewHistoryTableName; + tableViewModel.ExistingHistoryTable.Enabled = table.CanEditExistingHistoryTable; + tableViewModel.ExistingHistoryTable.Value = table.SystemVersioningHistoryTable; + tableViewModel.ExistingHistoryTable.Values = table.ExistingHistoryTablePropertyOptionalValues.ToList(); foreach (var column in table.Columns.Items) { @@ -543,12 +734,21 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner columnViewModel.IsPrimaryKey.Enabled = true; // To be consistent with SSDT, any column can be a primary key. columnViewModel.Type.Value = column.DataType; columnViewModel.Type.Enabled = column.CanEditDataType; + columnViewModel.Type.Values = tableDesigner.DataTypes.ToList(); columnViewModel.IsIdentity.Enabled = column.CanEditIsIdentity; columnViewModel.IsIdentity.Checked = column.IsIdentity; columnViewModel.IdentitySeed.Enabled = column.CanEditIdentityValues; columnViewModel.IdentitySeed.Value = column.IdentitySeed?.ToString(); columnViewModel.IdentityIncrement.Enabled = column.CanEditIdentityValues; columnViewModel.IdentityIncrement.Value = column.IdentityIncrement?.ToString(); + columnViewModel.CanBeDeleted = column.CanBeDeleted; + columnViewModel.GeneratedAlwaysAs.Value = ColumnGeneratedAlwaysAsTypeUtil.Instance.GetName(column.GeneratedAlwaysAs); + columnViewModel.GeneratedAlwaysAs.Values = ColumnGeneratedAlwaysAsTypeUtil.Instance.DisplayNames; + columnViewModel.GeneratedAlwaysAs.Enabled = tableDesigner.IsTemporalTableSupported; + columnViewModel.IsHidden.Checked = column.IsHidden; + columnViewModel.IsHidden.Enabled = column.CanEditIsHidden; + columnViewModel.DefaultConstraintName.Enabled = column.CanEditDefaultConstraintName; + columnViewModel.DefaultConstraintName.Value = column.DefaultConstraintName; tableViewModel.Columns.Data.Add(columnViewModel); } @@ -557,10 +757,10 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner var foreignKeyViewModel = new ForeignKeyViewModel(); foreignKeyViewModel.Name.Value = foreignKey.Name; foreignKeyViewModel.Enabled.Checked = foreignKey.Enabled; - foreignKeyViewModel.OnDeleteAction.Value = SqlForeignKeyActionUtil.GetName(foreignKey.OnDeleteAction); - foreignKeyViewModel.OnDeleteAction.Values = SqlForeignKeyActionUtil.ActionNames; - foreignKeyViewModel.OnUpdateAction.Value = SqlForeignKeyActionUtil.GetName(foreignKey.OnUpdateAction); - foreignKeyViewModel.OnUpdateAction.Values = SqlForeignKeyActionUtil.ActionNames; + foreignKeyViewModel.OnDeleteAction.Value = SqlForeignKeyActionUtil.Instance.GetName(foreignKey.OnDeleteAction); + foreignKeyViewModel.OnDeleteAction.Values = SqlForeignKeyActionUtil.Instance.DisplayNames; + foreignKeyViewModel.OnUpdateAction.Value = SqlForeignKeyActionUtil.Instance.GetName(foreignKey.OnUpdateAction); + foreignKeyViewModel.OnUpdateAction.Values = SqlForeignKeyActionUtil.Instance.DisplayNames; foreignKeyViewModel.ForeignTable.Value = foreignKey.ForeignTable; foreignKeyViewModel.ForeignTable.Values = tableDesigner.AllTables.ToList(); foreignKeyViewModel.IsNotForReplication.Checked = foreignKey.IsNotForReplication; @@ -591,13 +791,14 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner { var indexVM = new IndexViewModel(); indexVM.Name.Value = index.Name; + indexVM.Name.Enabled = tableInfo.IsNewTable; // renaming an index is not supported, it will cause a new index to be created. indexVM.IsClustered.Checked = index.IsClustered; indexVM.Enabled.Checked = index.Enabled; indexVM.IsUnique.Checked = index.IsUnique; foreach (var columnSpec in index.Columns) { var columnSpecVM = new IndexedColumnSpecification(); - columnSpecVM.Ascending.Checked = columnSpec.isAscending; + columnSpecVM.Ascending.Checked = columnSpec.IsAscending; columnSpecVM.Column.Value = columnSpec.Column; columnSpecVM.Column.Values = tableDesigner.GetColumnsForTable(table.FullName).ToList(); indexVM.Columns.Data.Add(columnSpecVM); @@ -606,6 +807,27 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner indexVM.ColumnsDisplayValue.Enabled = false; tableViewModel.Indexes.Data.Add(indexVM); } + + foreach (var constraint in table.EdgeConstraints.Items) + { + var constraintVM = new EdgeConstraintViewModel(); + constraintVM.Name.Value = constraint.Name; + constraintVM.Enabled.Checked = constraint.Enabled; + constraintVM.OnDeleteAction.Value = SqlForeignKeyActionUtil.Instance.GetName(constraint.OnDeleteAction); + constraintVM.OnDeleteAction.Values = SqlForeignKeyActionUtil.Instance.EdgeConstraintOnDeleteActionNames; + constraintVM.ClausesDisplayValue.Value = constraint.ClausesDisplayValue; + constraintVM.ClausesDisplayValue.Enabled = false; + foreach (var clause in constraint.Clauses) + { + var clauseVM = new EdgeConstraintClause(); + clauseVM.FromTable.Value = clause.FromTable; + clauseVM.FromTable.Values = tableDesigner.AllNodeTables.ToList(); + clauseVM.ToTable.Value = clause.ToTable; + clauseVM.ToTable.Values = tableDesigner.AllNodeTables.ToList(); + constraintVM.Clauses.Data.Add(clauseVM); + } + tableViewModel.EdgeConstraints.Data.Add(constraintVM); + } tableViewModel.Script.Enabled = false; tableViewModel.Script.Value = tableDesigner.Script; return tableViewModel; @@ -613,14 +835,46 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner private TableDesignerView GetDesignerViewInfo(TableInfo tableInfo) { + var tableDesigner = this.GetTableDesigner(tableInfo); var view = new TableDesignerView(); + this.SetPrimaryKeyViewInfo(view); this.SetColumnsViewInfo(view); this.SetForeignKeysViewInfo(view); this.SetCheckConstraintsViewInfo(view); this.SetIndexesViewInfo(view); + this.SetGraphTableViewInfo(view, tableDesigner); + this.SetEdgeConstraintsViewInfo(view, tableDesigner); + this.SetTemporalTableViewInfo(view, tableDesigner); + this.SetMemoryOptimizedTableViewInfo(view, tableDesigner); return view; } + private void SetPrimaryKeyViewInfo(TableDesignerView view) + { + view.AdditionalPrimaryKeyProperties.Add(new DesignerDataPropertyInfo() + { + PropertyName = TablePropertyNames.PrimaryKeyIsClustered, + ComponentType = DesignerComponentType.Checkbox, + Description = SR.IndexIsClusteredPropertyDescription, + ComponentProperties = new CheckBoxProperties() + { + Title = SR.TableDesignerIndexIsClusteredPropertyTitle + } + }); + view.PrimaryKeyColumnSpecificationTableOptions.AdditionalProperties.Add(new DesignerDataPropertyInfo() + { + PropertyName = IndexColumnSpecificationPropertyNames.Ascending, + Description = SR.IndexColumnIsAscendingPropertyDescription, + ComponentType = DesignerComponentType.Checkbox, + ComponentProperties = new CheckBoxProperties() + { + Title = SR.IndexColumnIsAscendingPropertyTitle + } + }); + view.PrimaryKeyColumnSpecificationTableOptions.PropertiesToDisplay.Add(IndexColumnSpecificationPropertyNames.Column); + view.PrimaryKeyColumnSpecificationTableOptions.PropertiesToDisplay.Add(IndexColumnSpecificationPropertyNames.Ascending); + } + private void SetColumnsViewInfo(TableDesignerView view) { view.ColumnTableOptions.AdditionalProperties.AddRange(new DesignerDataPropertyInfo[] { @@ -656,6 +910,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner { Title = SR.TableColumnIdentityIncrementPropertyTitle } + }, + new DesignerDataPropertyInfo() + { + PropertyName = TableColumnPropertyNames.DefaultConstraintName, + Description = SR.TableColumnDefaultConstraintNamePropertyDescription, + ComponentType = DesignerComponentType.Input, + ComponentProperties = new InputBoxProperties() + { + Title = SR.TableColumnDefaultConstraintNamePropertyTitle + } } }); view.ColumnTableOptions.CanAddRows = true; @@ -774,6 +1038,261 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner view.IndexColumnSpecificationTableOptions.CanRemoveRows = true; } + private void SetGraphTableViewInfo(TableDesignerView view, Dac.TableDesigner tableDesigner) + { + if (tableDesigner.IsGraphTableSupported && (tableDesigner.IsNewTable || tableDesigner.TableViewModel.IsEdge || tableDesigner.TableViewModel.IsNode)) + { + view.AdditionalTableProperties.Add(new DesignerDataPropertyInfo() + { + PropertyName = TablePropertyNames.GraphTableType, + ComponentType = DesignerComponentType.Dropdown, + Description = SR.TableDesignerGraphTableTypeDescription, + Group = SR.TableDesignerGraphTableGroupTitle, + ComponentProperties = new DropdownProperties() + { + Title = SR.TableDesignerGraphTableTypeTitle + } + }); + } + } + + private void SetEdgeConstraintsViewInfo(TableDesignerView view, Dac.TableDesigner tableDesigner) + { + if (!(tableDesigner.TableViewModel.IsEdge && tableDesigner.IsEdgeConstraintSupported)) + { + return; + } + var tab = new DesignerTabView() + { + Title = SR.TableDesignerEdgeConstraintsTabTitle + }; + var constraintsTableProperties = new TableComponentProperties() + { + Title = SR.TableDesignerEdgeConstraintsTabTitle, + ObjectTypeDisplayName = SR.TableDesignerEdgeConstraintObjectType + }; + constraintsTableProperties.Columns.AddRange(new string[] { EdgeConstraintPropertyNames.Name, EdgeConstraintPropertyNames.ClausesDisplayValue }); + constraintsTableProperties.ItemProperties.AddRange(new DesignerDataPropertyInfo[] { + new DesignerDataPropertyInfo() + { + PropertyName = EdgeConstraintPropertyNames.Name, + Description = SR.TableDesignerEdgeConstraintNamePropertyDescription, + ComponentType = DesignerComponentType.Input, + ComponentProperties = new InputBoxProperties() + { + Width = 200, + Title = SR.TableDesignerEdgeConstraintNamePropertyTitle + } + }, + new DesignerDataPropertyInfo() + { + PropertyName = EdgeConstraintPropertyNames.ClausesDisplayValue, + ComponentType = DesignerComponentType.Input, + ShowInPropertiesView = false, + ComponentProperties = new InputBoxProperties() + { + Width = 300, + Title = SR.TableDesignerEdgeConstraintClausesPropertyTitle + } + }, + new DesignerDataPropertyInfo() + { + PropertyName = EdgeConstraintPropertyNames.Enabled, + Description = SR.TableDesignerEdgeConstraintIsEnabledPropertyDescription, + ComponentType = DesignerComponentType.Checkbox, + ComponentProperties = new CheckBoxProperties() + { + Title = SR.TableDesignerEdgeConstraintIsEnabledPropertyTitle + } + }, + new DesignerDataPropertyInfo() + { + PropertyName = EdgeConstraintPropertyNames.OnDeleteAction, + Description = SR.TableDesignerEdgeConstraintOnDeleteActionPropertyDescription, + ComponentType = DesignerComponentType.Dropdown, + ComponentProperties = new DropdownProperties() + { + Title = SR.TableDesignerEdgeConstraintOnDeleteActionPropertyTitle + } + }, + new DesignerDataPropertyInfo() + { + PropertyName = EdgeConstraintPropertyNames.Clauses, + Description = SR.TableDesignerEdgeConstraintClausesPropertyDescription, + ComponentType = DesignerComponentType.Table, + ComponentProperties = new TableComponentProperties() + { + Title = SR.TableDesignerEdgeConstraintClausesPropertyTitle, + ObjectTypeDisplayName = SR.TableDesignerEdgeConstraintClauseObjectType, + Columns = new List () { EdgeConstraintClausePropertyNames.FromTable, EdgeConstraintClausePropertyNames.ToTable}, + ItemProperties = new List() + { + new DesignerDataPropertyInfo() + { + PropertyName = EdgeConstraintClausePropertyNames.FromTable, + ComponentType = DesignerComponentType.Dropdown, + ComponentProperties = new DropdownProperties() + { + Title = SR.TableDesignerEdgeConstraintClauseFromTablePropertyName, + Width = 150 + } + }, + new DesignerDataPropertyInfo() + { + PropertyName = EdgeConstraintClausePropertyNames.ToTable, + ComponentType = DesignerComponentType.Dropdown, + ComponentProperties = new DropdownProperties() + { + Title = SR.TableDesignerEdgeConstraintClauseToTablePropertyName, + Width = 150 + } + } + } + } + } + }); + tab.Components.Add(new DesignerDataPropertyInfo() + { + PropertyName = TablePropertyNames.EdgeConstraints, + ComponentType = DesignerComponentType.Table, + ComponentProperties = constraintsTableProperties, + ShowInPropertiesView = false + }); + view.AdditionalTabs.Add(tab); + } + + private void SetTemporalTableViewInfo(TableDesignerView view, Dac.TableDesigner tableDesigner) + { + if (!tableDesigner.IsTemporalTableSupported) + { + return; + } + var table = tableDesigner.TableViewModel; + view.AdditionalTableProperties.Add(new DesignerDataPropertyInfo() + { + PropertyName = TablePropertyNames.IsSystemVersioningEnabled, + ComponentType = DesignerComponentType.Checkbox, + Description = SR.TableDesignerIsSystemVersioningEnabledDescription, + Group = SR.TableDesignerSystemVersioningGroupTitle, + ComponentProperties = new CheckBoxProperties() + { + Title = SR.TableDesignerIsSystemVersioningEnabledTitle + } + }); + + if (table.OriginalHistoryTable == null && table.SystemVersioningHistoryTable != null) + { + view.AdditionalTableProperties.Add(new DesignerDataPropertyInfo() + { + PropertyName = TablePropertyNames.AutoCreateHistoryTable, + ComponentType = DesignerComponentType.Checkbox, + Description = SR.TableDesignerAutoCreateHistoryTableDescription, + Group = SR.TableDesignerSystemVersioningGroupTitle, + ComponentProperties = new CheckBoxProperties() + { + Title = SR.TableDesignerAutoCreateHistoryTableTitle + } + }); + if (table.AutoCreateHistoryTable) + { + view.AdditionalTableProperties.Add(new DesignerDataPropertyInfo() + { + PropertyName = TablePropertyNames.NewHistoryTableTable, + ComponentType = DesignerComponentType.Input, + Description = SR.TableDesignerNewHistoryTableDescription, + Group = SR.TableDesignerSystemVersioningGroupTitle, + ComponentProperties = new InputBoxProperties() + { + Title = SR.TableDesignerNewHistoryTableTitle + } + }); + } + else + { + view.AdditionalTableProperties.Add(new DesignerDataPropertyInfo() + { + PropertyName = TablePropertyNames.ExistingHistoryTableName, + ComponentType = DesignerComponentType.Dropdown, + Description = SR.TableDesignerHistoryTableDescription, + Group = SR.TableDesignerSystemVersioningGroupTitle, + ComponentProperties = new DropdownProperties() + { + Title = SR.TableDesignerHistoryTableTitle + } + }); + } + } + else if (table.SystemVersioningHistoryTable != null) + { + view.AdditionalTableProperties.Add(new DesignerDataPropertyInfo() + { + PropertyName = TablePropertyNames.ExistingHistoryTableName, + ComponentType = DesignerComponentType.Dropdown, + Description = SR.TableDesignerHistoryTableDescription, + Group = SR.TableDesignerSystemVersioningGroupTitle, + ComponentProperties = new DropdownProperties() + { + Title = SR.TableDesignerHistoryTableTitle + } + }); + } + view.ColumnTableOptions.AdditionalProperties.Add(new DesignerDataPropertyInfo() + { + PropertyName = TableColumnPropertyNames.GeneratedAlwaysAs, + ComponentType = DesignerComponentType.Dropdown, + Description = SR.TableDesignerColumnGeneratedAlwaysAsDescription, + Group = SR.TableDesignerSystemVersioningGroupTitle, + ComponentProperties = new DropdownProperties() + { + Title = SR.TableDesignerColumnGeneratedAlwaysAsTitle + } + }); + view.ColumnTableOptions.AdditionalProperties.Add(new DesignerDataPropertyInfo() + { + PropertyName = TableColumnPropertyNames.IsHidden, + ComponentType = DesignerComponentType.Checkbox, + Description = SR.TableDesignerColumnIsHiddenDescription, + Group = SR.TableDesignerSystemVersioningGroupTitle, + ComponentProperties = new CheckBoxProperties() + { + Title = SR.TableDesignerColumnIsHiddenTitle + } + }); + } + + private void SetMemoryOptimizedTableViewInfo(TableDesignerView view, Dac.TableDesigner tableDesigner) + { + if (!tableDesigner.IsMemoryOptimizedTableSupported) + { + return; + } + view.AdditionalTableProperties.Add(new DesignerDataPropertyInfo() + { + PropertyName = TablePropertyNames.IsMemoryOptimized, + ComponentType = DesignerComponentType.Checkbox, + Description = SR.TableDesignerIsMemoryOptimizedDescription, + Group = SR.TableDesignerMemoryOptimizedGroupTitle, + ComponentProperties = new CheckBoxProperties() + { + Title = SR.TableDesignerIsMemoryOptimizedTitle + } + }); + if (tableDesigner.TableViewModel.IsMemoryOptimized) + { + view.AdditionalTableProperties.Add(new DesignerDataPropertyInfo() + { + PropertyName = TablePropertyNames.Durability, + ComponentType = DesignerComponentType.Dropdown, + Description = SR.TableDesignerDurabilityDescription, + Group = SR.TableDesignerMemoryOptimizedGroupTitle, + ComponentProperties = new DropdownProperties() + { + Title = SR.TableDesignerDurabilityTitle + } + }); + } + } + private Dac.TableDesigner CreateTableDesigner(TableInfo tableInfo) { var connectinStringbuilder = new SqlConnectionStringBuilder(tableInfo.ConnectionString); diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerValidator.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerValidator.cs index ae5c9bb4..284a16c7 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerValidator.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerValidator.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using Microsoft.Data.Tools.Sql.DesignServices.TableDesigner; using ValidationError = Microsoft.SqlTools.ServiceLayer.TableDesigner.Contracts.TableDesignerValidationError; +using System.Linq; namespace Microsoft.SqlTools.ServiceLayer.TableDesigner { public static class TableDesignerValidator @@ -17,7 +18,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner new ColumnCanOnlyAppearOnceInIndexRule(), new NoDuplicateColumnNameRule(), new NoDuplicateConstraintNameRule(), - new NoDuplicateIndexNameRule() + new NoDuplicateIndexNameRule(), + new EdgeConstraintMustHaveClausesRule(), + new EdgeConstraintNoRepeatingClausesRule(), + new MemoryOptimizedTableMustHaveNonClusteredPrimaryKeyRule(), + new TemporalTableMustHavePeriodColumns(), + new PeriodColumnsRule(), + new ColumnsInPrimaryKeyCannotBeNullableRule(), + new OnlyDurableMemoryOptimizedTableCanBeSystemVersionedRule(), + new TemporalTableMustHavePrimaryKeyRule(), + new TableMustHaveAtLeastOneColumnRule() }; /// @@ -72,7 +82,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner { errors.Add(new ValidationError() { - Message = string.Format("Foreign key '{0}' does not have any column mapping specified.", foreignKey.Name), + Message = string.Format("Foreign key '{0}' does not have any columns specified.", foreignKey.Name), PropertyPath = new object[] { TablePropertyNames.ForeignKeys, i } }); } @@ -198,6 +208,23 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner existingNames.Add(checkConstraint.Name); } } + + for (int i = 0; i < table.EdgeConstraints.Items.Count; i++) + { + var edgeConstraint = table.EdgeConstraints.Items[i]; + if (existingNames.Contains(edgeConstraint.Name)) + { + errors.Add(new ValidationError() + { + Message = 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 } + }); + } + else + { + existingNames.Add(edgeConstraint.Name); + } + } return errors; } } @@ -253,4 +280,183 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner return errors; } } + + public class EdgeConstraintMustHaveClausesRule : ITableDesignerValidationRule + { + public List Run(TableViewModel table) + { + 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() + { + Message = string.Format("Edge constraint '{0}' does not have any clauses specified.", edgeConstraint.Name), + PropertyPath = new object[] { TablePropertyNames.EdgeConstraints, i } + }); + } + } + return errors; + } + } + + public class EdgeConstraintNoRepeatingClausesRule : ITableDesignerValidationRule + { + public List Run(TableViewModel table) + { + var errors = new List(); + for (int i = 0; i < table.EdgeConstraints.Items.Count; i++) + { + var edgeConstraint = table.EdgeConstraints.Items[i]; + var existingPairs = new HashSet(); + for (int j = 0; j < edgeConstraint.Clauses.Count; j++) + { + var clause = edgeConstraint.Clauses[j]; + var pair = string.Format("{0} - {1}", clause.FromTable, clause.ToTable); + if (existingPairs.Contains(pair)) + { + errors.Add(new ValidationError() + { + Message = 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 } + }); + } + else + { + existingPairs.Add(pair); + } + } + } + return errors; + } + } + + public class MemoryOptimizedTableMustHaveNonClusteredPrimaryKeyRule : ITableDesignerValidationRule + { + public List Run(TableViewModel table) + { + var errors = new List(); + if (table.IsMemoryOptimized && (table.PrimaryKey == null || table.PrimaryKey.IsClustered)) + { + errors.Add(new ValidationError() + { + Message = "Memory-optimized table must have non-clustered primary key.", + PropertyPath = new object[] { TablePropertyNames.PrimaryKeyIsClustered } + }); + } + return errors; + } + } + + public class TemporalTableMustHavePrimaryKeyRule : ITableDesignerValidationRule + { + public List Run(TableViewModel table) + { + var errors = new List(); + if (table.SystemVersioningHistoryTable != null && table.PrimaryKey == null) + { + errors.Add(new ValidationError() + { + Message = "System versioned table must have primary key." + }); + } + return errors; + } + } + + public class TemporalTableMustHavePeriodColumns : ITableDesignerValidationRule + { + public List Run(TableViewModel table) + { + var errors = new List(); + if (table.SystemVersioningHistoryTable != null && !table.PeriodColumnsDefined) + { + errors.Add(new ValidationError() + { + Message = "System versioned table must have the period columns defined." + }); + } + return errors; + } + } + + public class PeriodColumnsRule : ITableDesignerValidationRule + { + public List Run(TableViewModel table) + { + 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() + { + Message = "Period columns (Generated Always As Row Start/End) can only be defined once." + }); + } + else if (rowEnd.Count() != rowStart.Count()) + { + errors.Add(new ValidationError() + { + Message = "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; + } + } + + public class ColumnsInPrimaryKeyCannotBeNullableRule : ITableDesignerValidationRule + { + public List Run(TableViewModel table) + { + 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() + { + Message = "Columns in primary key cannot be nullable.", + PropertyPath = new object[] { TablePropertyNames.Columns, i } + }); + } + } + return errors; + } + } + + public class OnlyDurableMemoryOptimizedTableCanBeSystemVersionedRule : ITableDesignerValidationRule + { + public List Run(TableViewModel table) + { + var errors = new List(); + if (table.Durability == TableDurability.SchemaOnly && table.IsMemoryOptimized && table.IsSystemVersioningEnabled) + { + errors.Add(new ValidationError() + { + Message = "Only durable (DURABILITY = SCHEMA_AND_DATA) memory-optimized tables can be system-versioned." + }); + } + return errors; + } + } + + public class TableMustHaveAtLeastOneColumnRule : ITableDesignerValidationRule + { + public List Run(TableViewModel table) + { + var errors = new List(); + if (!table.IsEdge && table.Columns.Items.Count == 0) + { + errors.Add(new ValidationError() + { + Message = "A table must have at least one column defined." + }); + } + return errors; + } + } } \ No newline at end of file