From 4a440af4ac2cd22b81c7555f2e2e67aa1e9bb554 Mon Sep 17 00:00:00 2001 From: Anusha Kolan Date: Thu, 22 Jan 2026 17:55:33 -0800 Subject: [PATCH 1/3] [MCP]Fixed CLI bug in ields.primary-key updation when using update entity command. --- src/Cli.Tests/UpdateEntityTests.cs | 79 ++++++++++++++++++++++++++++++ src/Cli/ConfigGenerator.cs | 6 ++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/Cli.Tests/UpdateEntityTests.cs b/src/Cli.Tests/UpdateEntityTests.cs index cac2db0a83..8c823d8eb3 100644 --- a/src/Cli.Tests/UpdateEntityTests.cs +++ b/src/Cli.Tests/UpdateEntityTests.cs @@ -1100,6 +1100,85 @@ public void TestUpdateEntityDescription() Assert.AreEqual("Updated description", updatedRuntimeConfig.Entities["MyEntity"].Description); } + /// + /// Updating a field's description without --fields.primary-key + /// should not change its existing primary-key flag. + /// + [TestMethod] + public void TestUpdateFieldDescriptionPreservesPrimaryKeyWhenNoFlagProvided() + { + string initialConfig = GetInitialConfigString() + "," + @" + ""entities"": { + ""MyEntity"": { + ""source"": ""MyTable"", + ""fields"": [ + { + ""name"": ""Id"", + ""description"": ""Primary key"", + ""primary-key"": true + } + ], + ""permissions"": [ + { + ""role"": ""anonymous"", + ""actions"": [""read""] + } + ] + } + } + }"; + + UpdateOptions options = new( + source: null, + permissions: null, + entity: "MyEntity", + sourceType: null, + sourceParameters: null, + sourceKeyFields: null, + restRoute: null, + graphQLType: null, + fieldsToInclude: null, + fieldsToExclude: null, + policyRequest: null, + policyDatabase: null, + relationship: null, + cardinality: null, + targetEntity: null, + linkingObject: null, + linkingSourceFields: null, + linkingTargetFields: null, + relationshipFields: null, + map: null, + cacheEnabled: null, + cacheTtl: null, + config: TEST_RUNTIME_CONFIG_FILE, + restMethodsForStoredProcedure: null, + graphQLOperationForStoredProcedure: null, + description: null, + parametersNameCollection: null, + parametersDescriptionCollection: null, + parametersRequiredCollection: null, + parametersDefaultCollection: null, + fieldsNameCollection: new[] { "Id" }, + fieldsAliasCollection: null, + fieldsDescriptionCollection: new[] { "Unique Key" }, + fieldsPrimaryKeyCollection: null, + mcpDmlTools: null, + mcpCustomTool: null + ); + + Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(initialConfig, out RuntimeConfig? runtimeConfig), "Parsed config file."); + Assert.IsTrue(TryUpdateExistingEntity(options, runtimeConfig!, out RuntimeConfig updatedRuntimeConfig), "Successfully updated entity in the config."); + + Entity updatedEntity = updatedRuntimeConfig.Entities["MyEntity"]; + Assert.IsNotNull(updatedEntity.Fields); + Assert.AreEqual(1, updatedEntity.Fields!.Count); + FieldMetadata field = updatedEntity.Fields[0]; + Assert.AreEqual("Id", field.Name); + Assert.AreEqual("Unique Key", field.Description); + Assert.IsTrue(field.PrimaryKey, "Primary key flag should be preserved when --fields.primary-key is not provided."); + } + private static string GetInitialConfigString() { return @"{" + diff --git a/src/Cli/ConfigGenerator.cs b/src/Cli/ConfigGenerator.cs index 648edc1950..4e5b72b2c2 100644 --- a/src/Cli/ConfigGenerator.cs +++ b/src/Cli/ConfigGenerator.cs @@ -1747,6 +1747,7 @@ public static bool TryUpdateExistingEntity(UpdateOptions options, RuntimeConfig List updatedFieldsList = ComposeFieldsFromOptions(options); Dictionary updatedFieldsDict = updatedFieldsList.ToDictionary(f => f.Name, f => f); List mergedFields = []; + bool primaryKeyOptionProvided = options.FieldsPrimaryKeyCollection?.Any() == true; foreach (FieldMetadata field in existingFields) { @@ -1757,7 +1758,10 @@ public static bool TryUpdateExistingEntity(UpdateOptions options, RuntimeConfig Name = updatedField.Name, Alias = updatedField.Alias ?? field.Alias, Description = updatedField.Description ?? field.Description, - PrimaryKey = updatedField.PrimaryKey + // If --fields.primary-key was not provided at all, + // keep the existing primary-key flag. Otherwise, + // use the value coming from updatedField. + PrimaryKey = primaryKeyOptionProvided ? updatedField.PrimaryKey : field.PrimaryKey }); updatedFieldsDict.Remove(field.Name); // Remove so only new fields remain } From c881404e9ea39f75a810068e60bf3269620b0338 Mon Sep 17 00:00:00 2001 From: Anusha Kolan Date: Mon, 26 Jan 2026 07:40:44 -0800 Subject: [PATCH 2/3] Addressed comments --- src/Cli.Tests/UpdateEntityTests.cs | 79 ++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/Cli.Tests/UpdateEntityTests.cs b/src/Cli.Tests/UpdateEntityTests.cs index 8c823d8eb3..dd084369e1 100644 --- a/src/Cli.Tests/UpdateEntityTests.cs +++ b/src/Cli.Tests/UpdateEntityTests.cs @@ -1179,6 +1179,85 @@ public void TestUpdateFieldDescriptionPreservesPrimaryKeyWhenNoFlagProvided() Assert.IsTrue(field.PrimaryKey, "Primary key flag should be preserved when --fields.primary-key is not provided."); } + /// + /// When --fields.primary-key false is explicitly provided, it should + /// change an existing primary-key flag from true to false. + /// + [TestMethod] + public void TestUpdateFieldPrimaryKeyCanBeClearedWithExplicitFalse() + { + string initialConfig = GetInitialConfigString() + "," + @" + ""entities"": { + ""MyEntity"": { + ""source"": ""MyTable"", + ""fields"": [ + { + ""name"": ""Id"", + ""description"": ""Primary key"", + ""primary-key"": true + } + ], + ""permissions"": [ + { + ""role"": ""anonymous"", + ""actions"": [""read""] + } + ] + } + } + }"; + + UpdateOptions options = new( + source: null, + permissions: null, + entity: "MyEntity", + sourceType: null, + sourceParameters: null, + sourceKeyFields: null, + restRoute: null, + graphQLType: null, + fieldsToInclude: null, + fieldsToExclude: null, + policyRequest: null, + policyDatabase: null, + relationship: null, + cardinality: null, + targetEntity: null, + linkingObject: null, + linkingSourceFields: null, + linkingTargetFields: null, + relationshipFields: null, + map: null, + cacheEnabled: null, + cacheTtl: null, + config: TEST_RUNTIME_CONFIG_FILE, + restMethodsForStoredProcedure: null, + graphQLOperationForStoredProcedure: null, + description: null, + parametersNameCollection: null, + parametersDescriptionCollection: null, + parametersRequiredCollection: null, + parametersDefaultCollection: null, + fieldsNameCollection: new[] { "Id" }, + fieldsAliasCollection: null, + fieldsDescriptionCollection: new[] { "Unique Key" }, + fieldsPrimaryKeyCollection: new[] { false }, + mcpDmlTools: null, + mcpCustomTool: null + ); + + Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(initialConfig, out RuntimeConfig? runtimeConfig), "Parsed config file."); + Assert.IsTrue(TryUpdateExistingEntity(options, runtimeConfig!, out RuntimeConfig updatedRuntimeConfig), "Successfully updated entity in the config."); + + Entity updatedEntity = updatedRuntimeConfig.Entities["MyEntity"]; + Assert.IsNotNull(updatedEntity.Fields); + Assert.AreEqual(1, updatedEntity.Fields!.Count); + FieldMetadata field = updatedEntity.Fields[0]; + Assert.AreEqual("Id", field.Name); + Assert.AreEqual("Unique Key", field.Description); + Assert.IsFalse(field.PrimaryKey, "Primary key flag should be cleared when --fields.primary-key false is provided."); + } + private static string GetInitialConfigString() { return @"{" + From 5d697f48b378f5eacc3f1dbbb00465745ac035cd Mon Sep 17 00:00:00 2001 From: Anusha Kolan Date: Wed, 28 Jan 2026 12:03:08 -0800 Subject: [PATCH 3/3] Addressed comments --- src/Cli.Tests/UpdateEntityTests.cs | 96 ++++-------------------------- 1 file changed, 12 insertions(+), 84 deletions(-) diff --git a/src/Cli.Tests/UpdateEntityTests.cs b/src/Cli.Tests/UpdateEntityTests.cs index dd084369e1..effea1fa68 100644 --- a/src/Cli.Tests/UpdateEntityTests.cs +++ b/src/Cli.Tests/UpdateEntityTests.cs @@ -1101,11 +1101,14 @@ public void TestUpdateEntityDescription() } /// - /// Updating a field's description without --fields.primary-key - /// should not change its existing primary-key flag. + /// Updating a field's description should either preserve or clear + /// the existing primary-key flag depending on whether an explicit + /// --fields.primary-key value is provided. /// - [TestMethod] - public void TestUpdateFieldDescriptionPreservesPrimaryKeyWhenNoFlagProvided() + [DataTestMethod] + [DataRow(null, true, DisplayName = "No primary-key flag: preserve existing true")] + [DataRow(false, false, DisplayName = "Explicit primary-key false: clear existing true")] + public void TestUpdateFieldDescriptionPrimaryKeyBehavior(bool? primaryKeyFlag, bool expectedPrimaryKey) { string initialConfig = GetInitialConfigString() + "," + @" ""entities"": { @@ -1128,84 +1131,9 @@ public void TestUpdateFieldDescriptionPreservesPrimaryKeyWhenNoFlagProvided() } }"; - UpdateOptions options = new( - source: null, - permissions: null, - entity: "MyEntity", - sourceType: null, - sourceParameters: null, - sourceKeyFields: null, - restRoute: null, - graphQLType: null, - fieldsToInclude: null, - fieldsToExclude: null, - policyRequest: null, - policyDatabase: null, - relationship: null, - cardinality: null, - targetEntity: null, - linkingObject: null, - linkingSourceFields: null, - linkingTargetFields: null, - relationshipFields: null, - map: null, - cacheEnabled: null, - cacheTtl: null, - config: TEST_RUNTIME_CONFIG_FILE, - restMethodsForStoredProcedure: null, - graphQLOperationForStoredProcedure: null, - description: null, - parametersNameCollection: null, - parametersDescriptionCollection: null, - parametersRequiredCollection: null, - parametersDefaultCollection: null, - fieldsNameCollection: new[] { "Id" }, - fieldsAliasCollection: null, - fieldsDescriptionCollection: new[] { "Unique Key" }, - fieldsPrimaryKeyCollection: null, - mcpDmlTools: null, - mcpCustomTool: null - ); - - Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(initialConfig, out RuntimeConfig? runtimeConfig), "Parsed config file."); - Assert.IsTrue(TryUpdateExistingEntity(options, runtimeConfig!, out RuntimeConfig updatedRuntimeConfig), "Successfully updated entity in the config."); - - Entity updatedEntity = updatedRuntimeConfig.Entities["MyEntity"]; - Assert.IsNotNull(updatedEntity.Fields); - Assert.AreEqual(1, updatedEntity.Fields!.Count); - FieldMetadata field = updatedEntity.Fields[0]; - Assert.AreEqual("Id", field.Name); - Assert.AreEqual("Unique Key", field.Description); - Assert.IsTrue(field.PrimaryKey, "Primary key flag should be preserved when --fields.primary-key is not provided."); - } - - /// - /// When --fields.primary-key false is explicitly provided, it should - /// change an existing primary-key flag from true to false. - /// - [TestMethod] - public void TestUpdateFieldPrimaryKeyCanBeClearedWithExplicitFalse() - { - string initialConfig = GetInitialConfigString() + "," + @" - ""entities"": { - ""MyEntity"": { - ""source"": ""MyTable"", - ""fields"": [ - { - ""name"": ""Id"", - ""description"": ""Primary key"", - ""primary-key"": true - } - ], - ""permissions"": [ - { - ""role"": ""anonymous"", - ""actions"": [""read""] - } - ] - } - } - }"; + IEnumerable? primaryKeyFlags = primaryKeyFlag.HasValue + ? new[] { primaryKeyFlag.Value } + : null; UpdateOptions options = new( source: null, @@ -1241,7 +1169,7 @@ public void TestUpdateFieldPrimaryKeyCanBeClearedWithExplicitFalse() fieldsNameCollection: new[] { "Id" }, fieldsAliasCollection: null, fieldsDescriptionCollection: new[] { "Unique Key" }, - fieldsPrimaryKeyCollection: new[] { false }, + fieldsPrimaryKeyCollection: primaryKeyFlags, mcpDmlTools: null, mcpCustomTool: null ); @@ -1255,7 +1183,7 @@ public void TestUpdateFieldPrimaryKeyCanBeClearedWithExplicitFalse() FieldMetadata field = updatedEntity.Fields[0]; Assert.AreEqual("Id", field.Name); Assert.AreEqual("Unique Key", field.Description); - Assert.IsFalse(field.PrimaryKey, "Primary key flag should be cleared when --fields.primary-key false is provided."); + Assert.AreEqual(expectedPrimaryKey, field.PrimaryKey); } private static string GetInitialConfigString()