From 4be0126f20111aad4e41e79fb009917fa944ef32 Mon Sep 17 00:00:00 2001 From: Ruben Cerna Date: Fri, 24 Apr 2026 15:23:29 -0700 Subject: [PATCH 1/4] Change default value --- schemas/dab.draft.schema.json | 4 ++-- src/Config/ObjectModel/AutoentityPatterns.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/schemas/dab.draft.schema.json b/schemas/dab.draft.schema.json index f8a06fe61c..b655ff2a03 100644 --- a/schemas/dab.draft.schema.json +++ b/schemas/dab.draft.schema.json @@ -845,8 +845,8 @@ }, "name": { "type": "string", - "description": "Entity name interpolation pattern using {schema} and {object}. Null defaults to {object}. Must be unique for every entity inside the pattern", - "default": "{object}" + "description": "Entity name interpolation pattern using {schema} and {object}. Null defaults to {schema}_{object}. Must be unique for every entity inside the pattern", + "default": "{schema}_{object}" } } }, diff --git a/src/Config/ObjectModel/AutoentityPatterns.cs b/src/Config/ObjectModel/AutoentityPatterns.cs index d287c56109..818eaa61b6 100644 --- a/src/Config/ObjectModel/AutoentityPatterns.cs +++ b/src/Config/ObjectModel/AutoentityPatterns.cs @@ -51,7 +51,7 @@ public AutoentityPatterns( } else { - this.Name = "{object}"; + this.Name = "{schema}_{object}"; } } From 44b073cee7e4dcc31ca59825036475ba181e2dfa Mon Sep 17 00:00:00 2001 From: Ruben Cerna Date: Mon, 27 Apr 2026 11:53:31 -0700 Subject: [PATCH 2/4] Add missing test --- src/Cli/Commands/AutoConfigOptions.cs | 2 +- .../Configuration/ConfigurationTests.cs | 107 ++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/Cli/Commands/AutoConfigOptions.cs b/src/Cli/Commands/AutoConfigOptions.cs index 41be943303..2e273eeee4 100644 --- a/src/Cli/Commands/AutoConfigOptions.cs +++ b/src/Cli/Commands/AutoConfigOptions.cs @@ -58,7 +58,7 @@ public AutoConfigOptions( [Option("patterns.exclude", Required = false, HelpText = "T-SQL LIKE pattern(s) to exclude database objects. Space-separated array of patterns. Default: null")] public IEnumerable? PatternsExclude { get; } - [Option("patterns.name", Required = false, HelpText = "Interpolation syntax for entity naming (must be unique for each generated entity). Default: '{object}'")] + [Option("patterns.name", Required = false, HelpText = "Interpolation syntax for entity naming (must be unique for each generated entity). Default: '{schema}_{object}'")] public string? PatternsName { get; } [Option("template.mcp.dml-tools", Required = false, HelpText = "Enable/disable DML tools for generated entities. Allowed values: true, false. Default: true")] diff --git a/src/Service.Tests/Configuration/ConfigurationTests.cs b/src/Service.Tests/Configuration/ConfigurationTests.cs index e9182927ae..eca03300d4 100644 --- a/src/Service.Tests/Configuration/ConfigurationTests.cs +++ b/src/Service.Tests/Configuration/ConfigurationTests.cs @@ -5597,6 +5597,113 @@ public async Task TestAutoentitiesAreGeneratedIntoEntities(bool useEntities, int } } + /// + /// This test validates that multiple autoentities with the same object name + /// but different schemas can be generated and accessed properly with the + /// default 'property.name' which should generate entities named '{schema}_{object}'. + /// + [TestCategory(TestCategory.MSSQL)] + [TestMethod] + public async Task TestAutoentitiesWithSameObjectDifferentSchemas() + { + // Arrange + Dictionary autoentityMap = new() + { + { + "PublisherAutoEntity", new Autoentity( + Patterns: new AutoentityPatterns( + Include: null, + Exclude: null, + Name: null + ), + Template: new AutoentityTemplate( + Rest: new EntityRestOptions(Enabled: true), + GraphQL: new EntityGraphQLOptions( + Singular: string.Empty, + Plural: string.Empty, + Enabled: true + ), + Health: null, + Cache: null + ), + Permissions: new[] { GetMinimalPermissionConfig(AuthorizationResolver.ROLE_ANONYMOUS) } + ) + } + }; + + // Create DataSource for MSSQL connection + DataSource dataSource = new(DatabaseType.MSSQL, + GetConnectionStringFromEnvironmentConfig(environment: TestCategory.MSSQL), Options: null); + + // Build complete runtime configuration with autoentities + RuntimeConfig configuration = new( + Schema: "TestAutoentitiesSchema", + DataSource: dataSource, + Runtime: new( + Rest: new(Enabled: true), + GraphQL: new(Enabled: true), + Mcp: new(Enabled: false), + Host: new( + Cors: null, + Authentication: new Config.ObjectModel.AuthenticationOptions( + Provider: nameof(EasyAuthType.StaticWebApps), + Jwt: null + ) + ) + ), + Entities: new(new Dictionary()), + Autoentities: new RuntimeAutoentities(autoentityMap) + ); + + File.WriteAllText(CUSTOM_CONFIG_FILENAME, configuration.ToJson()); + + string[] args = new[] { $"--ConfigFileName={CUSTOM_CONFIG_FILENAME}" }; + + using (TestServer server = new(Program.CreateWebHostBuilder(args))) + using (HttpClient client = server.CreateClient()) + { + // Act + RuntimeConfigProvider configProvider = server.Services.GetService(); + + using HttpRequestMessage restFooRequest = new(HttpMethod.Get, "/api/foo_magazines"); + using HttpResponseMessage restFooResponse = await client.SendAsync(restFooRequest); + + using HttpRequestMessage restBarRequest = new(HttpMethod.Get, "/api/bar_magazines"); + using HttpResponseMessage restBarResponse = await client.SendAsync(restBarRequest); + + string graphqlQuery = @" + { + foo_magazines { + items { + id + issue_number + } + } + bar_magazines { + items { + comic_name + issue + } + } + }"; + + object graphqlPayload = new { query = graphqlQuery }; + HttpRequestMessage graphqlRequest = new(HttpMethod.Post, "/graphql") + { + Content = JsonContent.Create(graphqlPayload) + }; + HttpResponseMessage graphqlResponse = await client.SendAsync(graphqlRequest); + + // Assert + // Verify REST response + Assert.AreEqual(HttpStatusCode.OK, restFooResponse.StatusCode, "REST request to auto-generated entity 'foo_magazines' should succeed"); + Assert.AreEqual(HttpStatusCode.OK, restBarResponse.StatusCode, "REST request to auto-generated entity 'bar_magazines' should succeed"); + + // Verify GraphQL response + Assert.AreEqual(HttpStatusCode.OK, graphqlResponse.StatusCode, "GraphQL request to auto-generated entity should succeed"); + } + } + /// /// /// From 85da395dfb2718782bde83c6ca9be712ad213a8b Mon Sep 17 00:00:00 2001 From: Ruben Cerna Date: Mon, 27 Apr 2026 12:12:47 -0700 Subject: [PATCH 3/4] Changes based on copilot --- src/Service.Tests/Configuration/ConfigurationTests.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Service.Tests/Configuration/ConfigurationTests.cs b/src/Service.Tests/Configuration/ConfigurationTests.cs index 5161e286c4..623f5d442c 100644 --- a/src/Service.Tests/Configuration/ConfigurationTests.cs +++ b/src/Service.Tests/Configuration/ConfigurationTests.cs @@ -5592,12 +5592,12 @@ public async Task TestAutoentitiesAreGeneratedIntoEntities(bool useEntities, int { // Act RuntimeConfigProvider configProvider = server.Services.GetService(); - using HttpRequestMessage restRequest = new(HttpMethod.Get, "/api/publishers"); + using HttpRequestMessage restRequest = new(HttpMethod.Get, "/api/dbo_publishers"); using HttpResponseMessage restResponse = await client.SendAsync(restRequest); string graphqlQuery = @" { - publishers { + dbo_publishers { items { id name @@ -5701,8 +5701,6 @@ public async Task TestAutoentitiesWithSameObjectDifferentSchemas() using (HttpClient client = server.CreateClient()) { // Act - RuntimeConfigProvider configProvider = server.Services.GetService(); - using HttpRequestMessage restFooRequest = new(HttpMethod.Get, "/api/foo_magazines"); using HttpResponseMessage restFooResponse = await client.SendAsync(restFooRequest); From 18aa157ea6c2d9872744a1cf2c8facb6553ece88 Mon Sep 17 00:00:00 2001 From: Ruben Cerna Date: Tue, 28 Apr 2026 09:48:40 -0700 Subject: [PATCH 4/4] Fix test --- src/Service.Tests/Configuration/ConfigurationTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Service.Tests/Configuration/ConfigurationTests.cs b/src/Service.Tests/Configuration/ConfigurationTests.cs index 623f5d442c..0b00af003e 100644 --- a/src/Service.Tests/Configuration/ConfigurationTests.cs +++ b/src/Service.Tests/Configuration/ConfigurationTests.cs @@ -5751,10 +5751,10 @@ public async Task TestAutoentitiesWithSameObjectDifferentSchemas() /// [TestCategory(TestCategory.MSSQL)] [DataTestMethod] - [DataRow("publishers", "uniqueSingularPublisher", "uniquePluralPublishers", "/unique/publisher", "Entity 'publishers' conflicts with autoentity pattern 'PublisherAutoEntity'. Use --patterns.exclude to skip it.", DisplayName = "Autoentities fail due to entity name")] - [DataRow("UniquePublisher", "publishers", "uniquePluralPublishers", "/unique/publisher", "Entity publishers generates queries/mutation that already exist", DisplayName = "Autoentities fail due to graphql singular type")] - [DataRow("UniquePublisher", "uniqueSingularPublisher", "publishers", "/unique/publisher", "Entity publishers generates queries/mutation that already exist", DisplayName = "Autoentities fail due to graphql plural type")] - [DataRow("UniquePublisher", "uniqueSingularPublisher", "uniquePluralPublishers", "/publishers", "The rest path: publishers specified for entity: publishers is already used by another entity.", DisplayName = "Autoentities fail due to rest path")] + [DataRow("dbo_publishers", "uniqueSingularPublisher", "uniquePluralPublishers", "/unique/publisher", "Entity 'dbo_publishers' conflicts with autoentity pattern 'PublisherAutoEntity'. Use --patterns.exclude to skip it.", DisplayName = "Autoentities fail due to entity name")] + [DataRow("UniquePublisher", "dbo_publishers", "uniquePluralPublishers", "/unique/publisher", "Entity dbo_publishers generates queries/mutation that already exist", DisplayName = "Autoentities fail due to graphql singular type")] + [DataRow("UniquePublisher", "uniqueSingularPublisher", "dbo_publishers", "/unique/publisher", "Entity dbo_publishers generates queries/mutation that already exist", DisplayName = "Autoentities fail due to graphql plural type")] + [DataRow("UniquePublisher", "uniqueSingularPublisher", "uniquePluralPublishers", "/dbo_publishers", "The rest path: dbo_publishers specified for entity: dbo_publishers is already used by another entity.", DisplayName = "Autoentities fail due to rest path")] public async Task ValidateAutoentityGenerationConflicts(string entityName, string singular, string plural, string path, string exceptionMessage) { // Arrange