Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 23 additions & 12 deletions src/Core/Configurations/RuntimeConfigValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,18 +96,6 @@ public void ValidateConfigProperties()
ValidateLoggerFilters(runtimeConfig);
ValidateAzureLogAnalyticsAuth(runtimeConfig);
ValidateFileSinkPath(runtimeConfig);

// Running these graphQL validations only in development mode to ensure
// fast startup of engine in production mode.
if (runtimeConfig.IsDevelopmentMode())
{
ValidateEntityConfiguration(runtimeConfig);

if (runtimeConfig.IsGraphQLEnabled)
{
ValidateEntitiesDoNotGenerateDuplicateQueriesOrMutation(runtimeConfig.DataSource.DatabaseType, runtimeConfig.Entities);
}
}
}

/// <summary>
Expand Down Expand Up @@ -499,6 +487,7 @@ public async Task ValidateEntitiesMetadata(RuntimeConfig runtimeConfig, ILoggerF
// Only used for validation so we don't need the handler which is for hot reload scenarios.
MetadataProviderFactory metadataProviderFactory = new(
runtimeConfigProvider: _runtimeConfigProvider,
runtimeConfigValidator: this,
queryManagerFactory: queryManagerFactory,
logger: loggerFactory.CreateLogger<ISqlMetadataProvider>(),
fileSystem: _fileSystem,
Expand Down Expand Up @@ -1594,4 +1583,26 @@ private static bool IsLoggerFilterValid(string loggerFilter)

return false;
}

/// <summary>
/// Checks that all of the entities created with the Entities and Autoentities properties
/// are valid by having unique paths for both REST and GraphQL, that there are no duplicate
/// Queries or Mutation entities, and ensure the semantic correctness of all the entities.
/// </summary>
/// <param name="runtimeConfig">The runtime configuration.</param>
public void ValidateEntityAndAutoentityConfigurations(RuntimeConfig runtimeConfig)
{
if (runtimeConfig.IsDevelopmentMode())
{
ValidateEntityConfiguration(runtimeConfig);

if (runtimeConfig.IsGraphQLEnabled)
{
ValidateEntitiesDoNotGenerateDuplicateQueriesOrMutation(runtimeConfig.DataSource.DatabaseType, runtimeConfig.Entities);
}

// Running only in developer mode to ensure fast and smooth startup in production.
ValidatePermissionsInConfig(runtimeConfig);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public class CosmosSqlMetadataProvider : ISqlMetadataProvider

public List<Exception> SqlMetadataExceptions { get; private set; } = new();

public CosmosSqlMetadataProvider(RuntimeConfigProvider runtimeConfigProvider, IFileSystem fileSystem)
public CosmosSqlMetadataProvider(RuntimeConfigProvider runtimeConfigProvider, RuntimeConfigValidator runtimeConfigValidator, IFileSystem fileSystem)
{
RuntimeConfig runtimeConfig = runtimeConfigProvider.GetConfig();
_fileSystem = fileSystem;
Expand All @@ -76,6 +76,8 @@ public CosmosSqlMetadataProvider(RuntimeConfigProvider runtimeConfigProvider, IF
subStatusCode: DataApiBuilderException.SubStatusCodes.ErrorInInitialization);
}

runtimeConfigValidator.ValidateEntityAndAutoentityConfigurations(runtimeConfig);

_cosmosDb = cosmosDb;
ParseSchemaGraphQLDocument();

Expand Down
13 changes: 8 additions & 5 deletions src/Core/Services/MetadataProviders/MetadataProviderFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ public class MetadataProviderFactory : IMetadataProviderFactory
{
private readonly IDictionary<string, ISqlMetadataProvider> _metadataProviders;
private readonly RuntimeConfigProvider _runtimeConfigProvider;
private readonly RuntimeConfigValidator _runtimeConfigValidator;
private readonly IAbstractQueryManagerFactory _queryManagerFactory;
private readonly ILogger<ISqlMetadataProvider> _logger;
private readonly IFileSystem _fileSystem;
private readonly bool _isValidateOnly;

public MetadataProviderFactory(
RuntimeConfigProvider runtimeConfigProvider,
RuntimeConfigValidator runtimeConfigValidator,
IAbstractQueryManagerFactory queryManagerFactory,
ILogger<ISqlMetadataProvider> logger,
IFileSystem fileSystem,
Expand All @@ -34,6 +36,7 @@ public MetadataProviderFactory(
{
handler?.Subscribe(METADATA_PROVIDER_FACTORY_ON_CONFIG_CHANGED, OnConfigChanged);
_runtimeConfigProvider = runtimeConfigProvider;
_runtimeConfigValidator = runtimeConfigValidator;
_queryManagerFactory = queryManagerFactory;
_logger = logger;
_fileSystem = fileSystem;
Expand All @@ -48,11 +51,11 @@ private void ConfigureMetadataProviders()
{
ISqlMetadataProvider metadataProvider = dataSource.DatabaseType switch
{
DatabaseType.CosmosDB_NoSQL => new CosmosSqlMetadataProvider(_runtimeConfigProvider, _fileSystem),
DatabaseType.MSSQL => new MsSqlMetadataProvider(_runtimeConfigProvider, _queryManagerFactory, _logger, dataSourceName, _isValidateOnly),
DatabaseType.DWSQL => new MsSqlMetadataProvider(_runtimeConfigProvider, _queryManagerFactory, _logger, dataSourceName, _isValidateOnly),
DatabaseType.PostgreSQL => new PostgreSqlMetadataProvider(_runtimeConfigProvider, _queryManagerFactory, _logger, dataSourceName, _isValidateOnly),
DatabaseType.MySQL => new MySqlMetadataProvider(_runtimeConfigProvider, _queryManagerFactory, _logger, dataSourceName, _isValidateOnly),
DatabaseType.CosmosDB_NoSQL => new CosmosSqlMetadataProvider(_runtimeConfigProvider, _runtimeConfigValidator, _fileSystem),
DatabaseType.MSSQL => new MsSqlMetadataProvider(_runtimeConfigProvider, _runtimeConfigValidator, _queryManagerFactory, _logger, dataSourceName, _isValidateOnly),
DatabaseType.DWSQL => new MsSqlMetadataProvider(_runtimeConfigProvider, _runtimeConfigValidator, _queryManagerFactory, _logger, dataSourceName, _isValidateOnly),
DatabaseType.PostgreSQL => new PostgreSqlMetadataProvider(_runtimeConfigProvider, _runtimeConfigValidator, _queryManagerFactory, _logger, dataSourceName, _isValidateOnly),
DatabaseType.MySQL => new MySqlMetadataProvider(_runtimeConfigProvider, _runtimeConfigValidator, _queryManagerFactory, _logger, dataSourceName, _isValidateOnly),
_ => throw new NotSupportedException(dataSource.DatabaseTypeNotSupportedMessage),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ public class MsSqlMetadataProvider :

public MsSqlMetadataProvider(
RuntimeConfigProvider runtimeConfigProvider,
RuntimeConfigValidator runtimeConfigValidator,
IAbstractQueryManagerFactory queryManagerFactory,
ILogger<ISqlMetadataProvider> logger,
string dataSourceName,
bool isValidateOnly = false)
: base(runtimeConfigProvider, queryManagerFactory, logger, dataSourceName, isValidateOnly)
: base(runtimeConfigProvider, runtimeConfigValidator, queryManagerFactory, logger, dataSourceName, isValidateOnly)
{
_runtimeConfigProvider = runtimeConfigProvider;
}
Expand Down Expand Up @@ -374,7 +375,7 @@ protected override async Task GenerateAutoentitiesIntoEntities(IReadOnlyDictiona

if (addedEntities == 0)
{
_logger.LogWarning($"No new entities were generated from the autoentity {autoentityName} defined in the configuration.");
_logger.LogWarning("No new entities were generated from the autoentity {autoentityName} defined in the configuration.", autoentityName);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ public class MySqlMetadataProvider : SqlMetadataProvider<MySqlConnection, MySqlD

public MySqlMetadataProvider(
RuntimeConfigProvider runtimeConfigProvider,
RuntimeConfigValidator runtimeConfigValidator,
IAbstractQueryManagerFactory queryManagerFactory,
ILogger<ISqlMetadataProvider> logger,
string dataSourceName,
bool isValidateOnly = false)
: base(runtimeConfigProvider, queryManagerFactory, logger, dataSourceName, isValidateOnly)
: base(runtimeConfigProvider, runtimeConfigValidator, queryManagerFactory, logger, dataSourceName, isValidateOnly)
{
try
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ public class PostgreSqlMetadataProvider :

public PostgreSqlMetadataProvider(
RuntimeConfigProvider runtimeConfigProvider,
RuntimeConfigValidator runtimeConfigValidator,
IAbstractQueryManagerFactory queryManagerFactory,
ILogger<ISqlMetadataProvider> logger,
string dataSourceName,
bool isValidateOnly = false)
: base(runtimeConfigProvider, queryManagerFactory, logger, dataSourceName, isValidateOnly)
: base(runtimeConfigProvider, runtimeConfigValidator, queryManagerFactory, logger, dataSourceName, isValidateOnly)
{
}

Expand Down
21 changes: 16 additions & 5 deletions src/Core/Services/MetadataProviders/SqlMetadataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ public abstract class SqlMetadataProvider<ConnectionT, DataAdapterT, CommandT> :

private RuntimeConfigProvider _runtimeConfigProvider;

private RuntimeConfigValidator _runtimeConfigValidator;

private Dictionary<string, Dictionary<string, string>> EntityBackingColumnsToExposedNames { get; } = new();

private Dictionary<string, Dictionary<string, string>> EntityExposedNamesToBackingColumnNames { get; } = new();
Expand Down Expand Up @@ -108,13 +110,15 @@ private void HandleOrRecordException(Exception e)

public SqlMetadataProvider(
RuntimeConfigProvider runtimeConfigProvider,
RuntimeConfigValidator runtimeConfigValidator,
IAbstractQueryManagerFactory engineFactory,
ILogger<ISqlMetadataProvider> logger,
string dataSourceName,
bool isValidateOnly = false)
{
RuntimeConfig runtimeConfig = runtimeConfigProvider.GetConfig();
_runtimeConfigProvider = runtimeConfigProvider;
_runtimeConfigValidator = runtimeConfigValidator;
_dataSourceName = dataSourceName;
_databaseType = runtimeConfig.GetDataSourceFromDataSourceName(dataSourceName).DatabaseType;
_logger = logger;
Expand Down Expand Up @@ -310,12 +314,7 @@ public string GetEntityName(string graphQLType)
public async Task InitializeAsync()
{
System.Diagnostics.Stopwatch timer = System.Diagnostics.Stopwatch.StartNew();
if (GetDatabaseType() == DatabaseType.MSSQL)
{
await GenerateAutoentitiesIntoEntities(Autoentities);
}

GenerateDatabaseObjectForEntities();
if (_isValidateOnly)
{
// Currently Validate mode only support single datasource,
Expand All @@ -332,6 +331,18 @@ public async Task InitializeAsync()
}
}

if (GetDatabaseType() == DatabaseType.MSSQL)
{
await GenerateAutoentitiesIntoEntities(Autoentities);
}

// Running these graphQL validations only in development mode to ensure
// fast startup of engine in production mode.
RuntimeConfig runtimeConfig = _runtimeConfigProvider.GetConfig();
_runtimeConfigValidator.ValidateEntityAndAutoentityConfigurations(runtimeConfig);

GenerateDatabaseObjectForEntities();

await PopulateObjectDefinitionForEntities();
GenerateExposedToBackingColumnMapsForEntities();
// When IsLateConfigured is true we are in a hosted scenario and do not reveal primary key information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.IO.Abstractions;
using System.Net;
using System.Reflection;
using System.Text.Json;
Expand Down Expand Up @@ -699,10 +700,14 @@ private static Mock<SqlQueryStructure> CreateMockSqlQueryStructure(string entity
entityToDatabaseObject.Add(entityName, new DatabaseTable());

Mock<RuntimeConfigProvider> mockRuntimeConfigProvider = CreateMockRuntimeConfigProvider(entityName);
IFileSystem fileSystem = new FileSystem();
Mock<ILogger<RuntimeConfigValidator>> loggerValidator = new();
RuntimeConfigValidator runtimeConfigValidator = new(mockRuntimeConfigProvider.Object, fileSystem, loggerValidator.Object);
Mock<IAbstractQueryManagerFactory> mockQueryFactory = new();
Mock<ILogger<ISqlMetadataProvider>> mockLogger = new();
Mock<MsSqlMetadataProvider> mockSqlMetadataProvider = new(
mockRuntimeConfigProvider.Object,
runtimeConfigValidator,
mockQueryFactory.Object,
mockLogger.Object,
dataSourceName,
Expand Down
Loading