Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,9 @@ protected override async Task GenerateAutoentitiesIntoEntities(IReadOnlyDictiona
continue;
}

// Sanitize the entity name by ensuring all whitespace characters are removed.
entityName = SanitizeGeneratedEntityName(entityName);

// Create the entity using the template settings and permissions from the autoentity configuration.
// Currently the source type is always Table for auto-generated entities from database objects.
Entity generatedEntity = new(
Expand Down Expand Up @@ -386,6 +389,12 @@ protected override async Task GenerateAutoentitiesIntoEntities(IReadOnlyDictiona
_runtimeConfigProvider.AddMergedEntitiesToConfig(entities);
}

/// <summary>
/// Queries the database for autoentities based on the provided autoentity definition.
/// </summary>
/// <param name="autoentityName">The name of the autoentity definition.</param>
/// <param name="autoentity">The autoentity definition containing patterns for inclusion, exclusion, and name.</param>
/// <returns>A JsonArray containing the queried autoentities, or an empty array if none are found.</returns>
public async Task<JsonArray?> QueryAutoentitiesAsync(string autoentityName, Autoentity autoentity)
{
string include = string.Join(",", autoentity.Patterns.Include);
Expand Down
25 changes: 25 additions & 0 deletions src/Core/Services/MetadataProviders/SqlMetadataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,31 @@ private void RemoveGeneratedAutoentities()
_runtimeConfigProvider.RemoveGeneratedAutoentitiesFromConfig();
}

/// <summary>
/// Sanitizes the generated entity name by removing whitespace and capitalizing the next character after whitespace.
/// </summary>
/// <param name="name">The entity name to be sanitized.</param>
/// <returns>The sanitized entity name.</returns>
protected static string SanitizeGeneratedEntityName(string name)
{
StringBuilder sanitizedName = new(name.Length);
bool capitalizeNext = false;

foreach (char character in name)
{
if (char.IsWhiteSpace(character))
{
capitalizeNext = true;
continue;
}

sanitizedName.Append(capitalizeNext ? char.ToUpperInvariant(character) : character);
capitalizeNext = false;
}

return sanitizedName.ToString();
}

protected void PopulateDatabaseObjectForEntity(
Entity entity,
string entityName,
Expand Down
39 changes: 30 additions & 9 deletions src/Service.Tests/Configuration/ConfigurationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5759,16 +5759,17 @@ public async Task TestAutoentitiesWithSameObjectDifferentSchemas()
}

/// <summary>
/// Ensures that autoentities are properly generated into in-memory entities when entities have non-default schemas.
/// Ensures that autoentities are properly generated into in-memory entities when entities have unusual elements such as non-default schemas or spaces in their names.
/// </summary>
/// <param name="includePattern">The pattern to include for autoentities</param>
/// <param name="isPatternFoo">Boolean that indicates if the pattern is for the foo schema</param>
/// <param name="patternType">Integer that indicates which input pattern is being used</param>
/// <returns></returns>
Comment thread
RubenCerna2079 marked this conversation as resolved.
[TestCategory(TestCategory.MSSQL)]
[DataTestMethod]
[DataRow("foo.%", true, DisplayName = "Test Autoentities with foo schema")]
[DataRow("bar.%", false, DisplayName = "Test Autoentities with bar schema")]
public async Task TestAutoentitiesGeneratedWithDifferentSchemas(string includePattern, bool isPatternFoo)
[DataRow("foo.%", 0, DisplayName = "Test Autoentities with foo schema")]
[DataRow("bar.%", 1, DisplayName = "Test Autoentities with bar schema")]
[DataRow("dbo.Order Items", 2, DisplayName = "Test Autoentities with object with spaces")]
public async Task TestAutoentitiesGeneratedWithUnusualElements(string includePattern, int patternType)
Comment thread
RubenCerna2079 marked this conversation as resolved.
{
// Arrange
Dictionary<string, Autoentity> autoentityMap = new()
Expand Down Expand Up @@ -5826,11 +5827,33 @@ public async Task TestAutoentitiesGeneratedWithDifferentSchemas(string includePa
using (HttpClient client = server.CreateClient())
{
// Act
string path = isPatternFoo ? "foo_magazines" : "bar_magazines";
string path;
string item;
string expectedResponseFragment;
switch (patternType)
{
case 0:
path = "foo_magazines";
item = "title";
expectedResponseFragment = @"""title"":""Vogue""";
break;
case 1:
path = "bar_magazines";
item = "comic_name";
expectedResponseFragment = @"""comic_name"":""NotVogue""";
break;
case 2:
path = "dbo_OrderItems";
item = "productname";
expectedResponseFragment = @"""productname"":""Sample Product""";
break;
default:
throw new ArgumentException("Invalid pattern type");
}

using HttpRequestMessage restRequest = new(HttpMethod.Get, $"/api/{path}");
using HttpResponseMessage restResponse = await client.SendAsync(restRequest);

string item = isPatternFoo ? "title" : "comic_name";
string graphqlQuery = $@"
{{
{path} {{
Expand All @@ -5848,8 +5871,6 @@ public async Task TestAutoentitiesGeneratedWithDifferentSchemas(string includePa
HttpResponseMessage graphqlResponse = await client.SendAsync(graphqlRequest);

// Assert
string expectedResponseFragment = isPatternFoo ? @"""title"":""Vogue""" : @"""comic_name"":""NotVogue""";

// Verify REST response
Assert.AreEqual(HttpStatusCode.OK, restResponse.StatusCode, "REST request to auto-generated entity should succeed");

Expand Down
37 changes: 24 additions & 13 deletions src/Service.Tests/DatabaseSchema-MsSql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ DROP TABLE IF EXISTS date_only_table;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS user_profiles;
DROP TABLE IF EXISTS default_books;
DROP TABLE IF EXISTS [Order Items];
DROP SCHEMA IF EXISTS [foo];
DROP SCHEMA IF EXISTS [bar];
COMMIT;
Expand Down Expand Up @@ -321,21 +322,23 @@ CREATE TABLE mappedbookmarks
bkname nvarchar(50) NOT NULL
)

create Table fte_data(
id int IDENTITY(5001,1),
u_id int DEFAULT 2,
name varchar(50),
position varchar(20),
salary int default 20,
PRIMARY KEY(id, u_id)
create Table fte_data
(
id int IDENTITY(5001,1),
u_id int DEFAULT 2,
name varchar(50),
position varchar(20),
salary int default 20,
PRIMARY KEY(id, u_id)
);

create Table intern_data(
id int,
months int default 2 NOT NULL,
name varchar(50),
salary int default 15,
PRIMARY KEY(id, months)
create Table intern_data
(
id int,
months int default 2 NOT NULL,
name varchar(50),
salary int default 15,
PRIMARY KEY(id, months)
);

create table books_sold
Expand Down Expand Up @@ -394,6 +397,11 @@ CREATE TABLE default_books(
title NVARCHAR(100)
);

CREATE TABLE [Order Items](
id INT PRIMARY KEY,
productname VARCHAR(100)
);
Comment thread
RubenCerna2079 marked this conversation as resolved.

ALTER TABLE books
ADD CONSTRAINT book_publisher_fk
FOREIGN KEY (publisher_id)
Expand Down Expand Up @@ -826,3 +834,6 @@ INSERT INTO date_only_table( event_date, event_time, event_timestamp)
VALUES ('2023-01-01', '08:30:00', '2023-01-01 08:30:00'),
('2023-02-15', '12:45:00', '2023-02-15 12:45:00'),
('2023-03-30', '17:15:00', '2023-03-30 17:15:00');

INSERT INTO [Order Items](id, productname)
VALUES (1, 'Sample Product');