Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix DbConnectionValidator when Shell Settings from database #12342

Merged
merged 15 commits into from
Sep 9, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ private async Task AssertConnectionValidityAndApplyErrorsAsync(string databasePr
case DbConnectionValidatorResult.InvalidConnection:
errors.Add(new ModelError(nameof(TenantViewModel.ConnectionString), S["The provided connection string is invalid or server is unreachable."]));
break;
case DbConnectionValidatorResult.DocumentFound:
case DbConnectionValidatorResult.ShellDescriptorDocumentFound:
case DbConnectionValidatorResult.DocumentTableFound:
errors.Add(new ModelError(nameof(TenantViewModel.TablePrefix), S["The provided table prefix already exists."]));
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
namespace OrchardCore.Data;

/// <summary>
/// 'Unknown' indicates that the connection string status is unknown or was not validated.
/// 'NoProvider' indicated that the database provider is missing.
/// 'DocumentTableNotFound' indicates that the connection string was valid, while the Document table does not exists.
/// 'DocumentFound' indicates that the connection string was valid, while the Document table exists.
/// 'ShellDescriptorDocumentFound' indicates that the connection string was valid and the document table exists with at least one shell-descriptor document.
/// 'InvalidConnection' unable to open a connection to the given connection string.
/// 'UnsupportedProvider' indicates invalid or unsupported database provider.
/// </summary>
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
public enum DbConnectionValidatorResult
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
{
// Unknown indicates that the connection string status is unknown or was not yet validated
Unknown,

// NoProvider indicated that the provider is missing
NoProvider,

// DocumentNotFound indicates that the connection string was valid, yet the Document table does not exist
DocumentNotFound,

// DocumentFound indicates that the connection string was valid, yet the Document table exist
DocumentFound,

// InvalidConnection unable to open a connection to the given connection string
DocumentTableNotFound,
DocumentTableFound,
ShellDescriptorDocumentFound,
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
InvalidConnection,

// UnsupportedProvider indicated invalid or unsupported database provider
UnsupportedProvider
}
24 changes: 15 additions & 9 deletions src/OrchardCore/OrchardCore.Data.YesSql/DbConnectionValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public async Task<DbConnectionValidatorResult> ValidateAsync(string databaseProv

if (provider != null && !provider.HasConnectionString)
{
return DbConnectionValidatorResult.DocumentNotFound;
return DbConnectionValidatorResult.DocumentTableNotFound;
}

if (String.IsNullOrWhiteSpace(connectionString))
Expand Down Expand Up @@ -80,25 +80,31 @@ public async Task<DbConnectionValidatorResult> ValidateAsync(string databaseProv

using var result = await selectCommand.ExecuteReaderAsync();

// at this point the query succeeded and the table exists
return DbConnectionValidatorResult.DocumentFound;
// At this point, the query work and the 'Document' table exists.
if (result.HasRows)
{
// At this point we know that the Document table and the ShellDescriptor record exists.
return DbConnectionValidatorResult.ShellDescriptorDocumentFound;
}

// At this point the Document table exists with no ShellDescriptor document.
return DbConnectionValidatorResult.DocumentTableFound;
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
}
catch
{
// at this point we know that the document table does not exist

return DbConnectionValidatorResult.DocumentNotFound;
// At this point we know that the document table does not exist.
return DbConnectionValidatorResult.DocumentTableNotFound;
}
}

private ISqlBuilder GetSelectBuilderForDocumentTable(string tablePrefix, DatabaseProviderName providerName)
{
var selectBuilder = GetSqlBuilder(providerName, tablePrefix);

selectBuilder.Select();
selectBuilder.AddSelector("*");
selectBuilder.Table(_tableNameConvention.GetDocumentTable());
selectBuilder.Take("1");
selectBuilder.WhereAnd("Type = 'OrchardCore.Shells.Database.Models.DatabaseShellsSettings, OrchardCore.Infrastructure'");
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved

return selectBuilder;
}
Expand All @@ -111,7 +117,7 @@ private static IConnectionFactory GetFactory(DatabaseProviderName providerName,
DatabaseProviderName.MySql => new DbConnectionFactory<MySqlConnection>(connectionString),
DatabaseProviderName.Sqlite => new DbConnectionFactory<SqliteConnection>(connectionString),
DatabaseProviderName.Postgres => new DbConnectionFactory<NpgsqlConnection>(connectionString),
_ => throw new ArgumentOutOfRangeException("Unsupported Database Provider"),
_ => throw new ArgumentOutOfRangeException(nameof(providerName), "Unsupported Database Provider"),
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
};
}

Expand All @@ -123,7 +129,7 @@ private ISqlBuilder GetSqlBuilder(DatabaseProviderName providerName, string tabl
DatabaseProviderName.MySql => new MySqlDialect(),
DatabaseProviderName.Sqlite => new SqliteDialect(),
DatabaseProviderName.Postgres => new PostgreSqlDialect(),
_ => throw new ArgumentOutOfRangeException("Unsupported Database Provider"),
_ => throw new ArgumentOutOfRangeException(nameof(providerName), "Unsupported Database Provider"),
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
};

var prefix = String.Empty;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using OrchardCore.Data;

namespace OrchardCore.Shells.Database.Configuration
{
public class DatabaseShellsStorageOptions
{
public bool MigrateFromFiles { get; set; }
public string DatabaseProvider { get; set; }
public DatabaseProviderName DatabaseProvider { get; set; }
public string ConnectionString { get; set; }
public string TablePrefix { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using OrchardCore.Data;
using OrchardCore.Environment.Shell;
using OrchardCore.Environment.Shell.Builders;
using OrchardCore.Environment.Shell.Descriptor.Models;
Expand All @@ -12,7 +13,7 @@ public static class DatabaseShellContextFactoryExtensions
{
internal static Task<ShellContext> GetDatabaseContextAsync(this IShellContextFactory shellContextFactory, DatabaseShellsStorageOptions options)
{
if (options.DatabaseProvider == null)
if (options.DatabaseProvider == DatabaseProviderName.None)
{
throw new ArgumentNullException(nameof(options.DatabaseProvider),
"The 'OrchardCore.Shells.Database' configuration section should define a 'DatabaseProvider'");
Expand All @@ -24,7 +25,7 @@ internal static Task<ShellContext> GetDatabaseContextAsync(this IShellContextFac
State = TenantState.Running
};

settings["DatabaseProvider"] = options.DatabaseProvider;
settings["DatabaseProvider"] = options.DatabaseProvider.ToString();
settings["ConnectionString"] = options.ConnectionString;
settings["TablePrefix"] = options.TablePrefix;

Expand Down
2 changes: 1 addition & 1 deletion src/OrchardCore/OrchardCore.Setup.Core/SetupService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ private async Task<string> SetupInternalAsync(SetupContext context)
case DbConnectionValidatorResult.InvalidConnection:
context.Errors.Add(String.Empty, S["The provided connection string is invalid or server is unreachable."]);
break;
case DbConnectionValidatorResult.DocumentFound:
case DbConnectionValidatorResult.DocumentTableFound:
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
context.Errors.Add(String.Empty, S["The provided database table is already in use."]);
break;
}
Expand Down