/// <summary>
 /// Constructs a new <see cref="SqliteRelationalDatabase"/>.
 /// </summary>
 /// <param name="connection">The connection to a SQLite database.</param>
 /// <param name="identifierDefaults">Default values for identifier components.</param>
 /// <param name="connectionPragma">Default values for identifier components.</param>
 /// <exception cref="ArgumentNullException">Thrown when <paramref name="connection"/>, or <paramref name="identifierDefaults"/>, or <paramref name="connectionPragma"/> are <code>null</code>.</exception>
 public SqliteRelationalDatabase(ISchematicConnection connection, IIdentifierDefaults identifierDefaults, ISqliteConnectionPragma connectionPragma)
 {
     Connection         = connection ?? throw new ArgumentNullException(nameof(connection));
     IdentifierDefaults = identifierDefaults ?? throw new ArgumentNullException(nameof(identifierDefaults));
     _tableProvider     = new SqliteRelationalDatabaseTableProvider(connection, connectionPragma, identifierDefaults);
     _viewProvider      = new SqliteDatabaseViewProvider(connection, connectionPragma, identifierDefaults);
 }
Пример #2
0
        public static void Ctor_GivenNullConnection_ThrowsArgumentNullException()
        {
            ISchematicConnection connection = null;
            const RuleLevel      level      = RuleLevel.Error;

            Assert.That(() => new InvalidViewDefinitionRule(connection, level), Throws.ArgumentNullException);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="NoValueForNullableColumnRule"/> class.
        /// </summary>
        /// <param name="connection">A database connection.</param>
        /// <param name="level">The reporting level.</param>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        public NoValueForNullableColumnRule(ISchematicConnection connection, RuleLevel level)
            : base(RuleId, RuleTitle, level)
        {
            Connection = connection ?? throw new ArgumentNullException(nameof(connection));

            _fromQuerySuffixAsync = new AsyncLazy <string>(GetFromQuerySuffixAsync);
        }
        public static void Ctor_GivenNullConnection_ThrowsArgumentNullException()
        {
            ISchematicConnection connection = null;
            const RuleLevel      level      = RuleLevel.Error;

            Assert.That(() => new NoValueForNullableColumnRule(connection, level), Throws.ArgumentNullException);
        }
Пример #5
0
 /// <summary>
 /// Ignore.
 /// </summary>
 public IEnumerable <IRule> GetRules(ISchematicConnection connection, RuleLevel level)
 {
     return(new DefaultRuleProvider()
            .GetRules(connection, level)
            .Take(RuleCount)
            .ToList());
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="PostgreSqlDatabaseSequenceProvider"/> class.
        /// </summary>
        /// <param name="connection">A schematic connection.</param>
        /// <param name="identifierDefaults">Database identifier defaults.</param>
        /// <param name="identifierResolver">An identifier resolver.</param>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> or <paramref name="identifierDefaults"/> or <paramref name="identifierResolver"/> are <c>null</c>.</exception>
        public PostgreSqlDatabaseSequenceProvider(ISchematicConnection connection, IIdentifierDefaults identifierDefaults, IIdentifierResolutionStrategy identifierResolver)
        {
            Connection         = connection ?? throw new ArgumentNullException(nameof(connection));
            IdentifierDefaults = identifierDefaults ?? throw new ArgumentNullException(nameof(identifierDefaults));
            IdentifierResolver = identifierResolver ?? throw new ArgumentNullException(nameof(identifierResolver));

            _sequenceProvider = new AsyncLazy <Option <IDatabaseSequenceProvider> >(LoadVersionedSequenceProvider);
        }
Пример #7
0
        /// <summary>
        /// Removes the logging applied to a given connection.
        /// </summary>
        /// <param name="connection">A connection.</param>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        public static void RemoveLogging(this ISchematicConnection connection)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }

            Logging.RemoveLogging(connection);
        }
Пример #8
0
        /// <summary>
        /// Gets the database display version. Usually a more user-friendly form of the database version.
        /// </summary>
        /// <param name="connection">A database connection.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <returns>A descriptive version.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        public override Task <string> GetDatabaseDisplayVersionAsync(ISchematicConnection connection, CancellationToken cancellationToken = default)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }

            return(connection.DbConnection.ExecuteScalarAsync <string>(DatabaseDisplayVersionQuerySql, cancellationToken));
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="PostgreSqlRelationalDatabase"/> class.
        /// </summary>
        /// <param name="connection">A schematic connection.</param>
        /// <param name="identifierDefaults">Database identifier defaults.</param>
        /// <param name="identifierResolver">An identifier resolver.</param>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> or <paramref name="identifierDefaults"/> or <paramref name="identifierResolver"/> are <c>null</c>.</exception>
        public PostgreSqlRelationalDatabase(ISchematicConnection connection, IIdentifierDefaults identifierDefaults, IIdentifierResolutionStrategy identifierResolver)
        {
            IdentifierDefaults = identifierDefaults ?? throw new ArgumentNullException(nameof(identifierDefaults));

            _tableProvider    = new PostgreSqlRelationalDatabaseTableProvider(connection, identifierDefaults, identifierResolver);
            _viewProvider     = new PostgreSqlDatabaseViewProvider(connection, identifierDefaults, identifierResolver);
            _sequenceProvider = new PostgreSqlDatabaseSequenceProvider(connection, identifierDefaults, identifierResolver);
            _routineProvider  = new PostgreSqlDatabaseRoutineProvider(connection.DbConnection, identifierDefaults, identifierResolver);
        }
Пример #10
0
        /// <summary>
        /// Gets the database version.
        /// </summary>
        /// <param name="connection">A database connection.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <returns>A version.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        public override Task <Version> GetDatabaseVersionAsync(ISchematicConnection connection, CancellationToken cancellationToken = default)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }

            return(GetDatabaseVersionAsyncCore(connection, cancellationToken));
        }
Пример #11
0
        /// <summary>
        /// Retrieves the set of identifier defaults for the given database connection.
        /// </summary>
        /// <param name="connection">A database connection.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <returns>A set of identifier defaults.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        public override Task <IIdentifierDefaults> GetIdentifierDefaultsAsync(ISchematicConnection connection, CancellationToken cancellationToken = default)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }

            return(GetIdentifierDefaultsAsyncCore());
        }
Пример #12
0
        /// <summary>
        /// Sets the maximum number of concurrent queries to perform with the given connection.
        /// </summary>
        /// <param name="connection">A connection.</param>
        /// <param name="maxQueries">The maximum number of queries. Zero indicates no limitation on the number of concurrent queries.</param>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        public static void SetMaxConcurrentQueries(this ISchematicConnection connection, uint maxQueries)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }

            var maxQueryCount = maxQueries > 0 ? maxQueries : long.MaxValue;
            var semaphore     = new AsyncSemaphore(maxQueryCount);

            QueryContext.SetMaxConcurrentQueries(connection.DbConnection, semaphore);
        }
Пример #13
0
        /// <summary>
        /// Removes logging from a database connection.
        /// </summary>
        /// <param name="connection">A database connection.</param>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        public static void RemoveLogging(ISchematicConnection connection)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }

            if (ConnectionLoggerLookup.TryGetValue(connection.DbConnection, out _))
            {
                ConnectionLoggerLookup.Remove(connection.DbConnection);
            }
        }
Пример #14
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MySqlRelationalDatabase"/> class.
        /// </summary>
        /// <param name="connection">A database connection.</param>
        /// <param name="identifierDefaults">Identifier defaults for the associated database.</param>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c> or <paramref name="identifierDefaults"/> is <c>null</c>.</exception>
        public MySqlRelationalDatabase(ISchematicConnection connection, IIdentifierDefaults identifierDefaults)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }

            IdentifierDefaults = identifierDefaults ?? throw new ArgumentNullException(nameof(identifierDefaults));

            _tableProvider   = new MySqlRelationalDatabaseTableProvider(connection, identifierDefaults);
            _viewProvider    = new MySqlDatabaseViewProvider(connection, identifierDefaults);
            _routineProvider = new MySqlDatabaseRoutineProvider(connection, identifierDefaults);
        }
Пример #15
0
        /// <summary>
        /// Retrieves an empty set of rules used for reporting.
        /// </summary>
        /// <param name="connection">A schematic connection.</param>
        /// <param name="level">The level used for reporting.</param>
        /// <returns>An empty set of rules.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException"><paramref name="level"/> does not have a valid enum value.</exception>
        public IEnumerable <IRule> GetRules(ISchematicConnection connection, RuleLevel level)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }
            if (!level.IsValid())
            {
                throw new ArgumentException($"The { nameof(RuleLevel) } provided must be a valid enum.", nameof(level));
            }

            return(Array.Empty <IRule>());
        }
Пример #16
0
        /// <summary>
        /// Gets the database display version. Usually a more user-friendly form of the database version.
        /// </summary>
        /// <param name="connection">A database connection.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <returns>A descriptive version.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        public override Task <string> GetDatabaseDisplayVersionAsync(ISchematicConnection connection, CancellationToken cancellationToken = default)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }

            var versionInfoOption = connection.DbConnection.QueryFirstOrNone <DatabaseVersion>(DatabaseVersionQuerySql, cancellationToken);

            return(versionInfoOption.MatchUnsafe(
                       vInfo => vInfo.ProductName + vInfo.VersionNumber,
                       () => string.Empty
                       ));
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="SqlServerRelationalDatabase"/> class.
        /// </summary>
        /// <param name="connection">A schematic connection.</param>
        /// <param name="identifierDefaults">Database identifier defaults.</param>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> or <paramref name="identifierDefaults"/> are <c>null</c>.</exception>
        public SqlServerRelationalDatabase(ISchematicConnection connection, IIdentifierDefaults identifierDefaults)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }

            IdentifierDefaults = identifierDefaults ?? throw new ArgumentNullException(nameof(identifierDefaults));

            _tableProvider    = new SqlServerRelationalDatabaseTableProvider(connection, identifierDefaults);
            _viewProvider     = new SqlServerDatabaseViewProvider(connection, identifierDefaults);
            _sequenceProvider = new SqlServerDatabaseSequenceProvider(connection.DbConnection, identifierDefaults);
            _synonymProvider  = new SqlServerDatabaseSynonymProvider(connection.DbConnection, identifierDefaults);
            _routineProvider  = new SqlServerDatabaseRoutineProvider(connection.DbConnection, identifierDefaults);
        }
Пример #18
0
        /// <summary>
        /// Retrieves the rules used to analyze database objects.
        /// </summary>
        /// <param name="connection">A schematic connection.</param>
        /// <param name="level">The level used for reporting.</param>
        /// <returns>Rules used for analyzing database objects.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException"><paramref name="level"/> does not have a valid enum value.</exception>
        public IEnumerable <IRule> GetRules(ISchematicConnection connection, RuleLevel level)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }
            if (!level.IsValid())
            {
                throw new ArgumentException($"The { nameof(RuleLevel) } provided must be a valid enum.", nameof(level));
            }

            return(RuleProviders
                   .SelectMany(rp => rp.GetRules(connection, level))
                   .ToList());
        }
Пример #19
0
        /// <summary>
        /// Gets the database version.
        /// </summary>
        /// <param name="connection">A database connection.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <returns>A version.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        public override Task <Version> GetDatabaseVersionAsync(ISchematicConnection connection, CancellationToken cancellationToken = default)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }

            var versionInfoOption = connection.DbConnection.QueryFirstOrNone <DatabaseVersion>(DatabaseVersionQuerySql, cancellationToken);

            return(versionInfoOption
                   .Bind(dbv => TryParseLongVersionString(dbv.VersionNumber).ToAsync())
                   .MatchUnsafeAsync(
                       v => v,
                       () => Task.FromResult(new Version(0, 0))
                       ));
        }
Пример #20
0
        /// <summary>
        /// Initializes a new instance of the <see cref="OracleDatabaseViewProvider"/> class.
        /// </summary>
        /// <param name="connection">A schematic connection.</param>
        /// <param name="identifierDefaults">Database identifier defaults.</param>
        /// <param name="identifierResolver">An identifier resolver.</param>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> or <paramref name="identifierDefaults"/> or <paramref name="identifierResolver"/> are <c>null</c>.</exception>
        public OracleDatabaseViewProvider(ISchematicConnection connection, IIdentifierDefaults identifierDefaults, IIdentifierResolutionStrategy identifierResolver)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }
            if (identifierDefaults == null)
            {
                throw new ArgumentNullException(nameof(identifierDefaults));
            }
            if (identifierResolver == null)
            {
                throw new ArgumentNullException(nameof(identifierResolver));
            }

            QueryViewProvider        = new OracleDatabaseQueryViewProvider(connection, identifierDefaults, identifierResolver);
            MaterializedViewProvider = new OracleDatabaseMaterializedViewProvider(connection, identifierDefaults, identifierResolver);
        }
Пример #21
0
        /// <summary>
        /// Retrieves the set of rules used to analyze database objects for reporting.
        /// </summary>
        /// <param name="connection">A schematic connection.</param>
        /// <param name="level">The level used for reporting.</param>
        /// <returns>Rules used for analyzing database objects.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException"><paramref name="level"/> does not have a valid enum value.</exception>
        public IEnumerable <IRule> GetRules(ISchematicConnection connection, RuleLevel level)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }
            if (!level.IsValid())
            {
                throw new ArgumentException($"The { nameof(RuleLevel) } provided must be a valid enum.", nameof(level));
            }

            var ruleProvider = new RuleProviderBuilder()
                               .AddRuleProvider <DefaultHtmlRuleProvider>()
                               .AddRuleProvider <PluginProvider>()
                               .Build();

            return(ruleProvider.GetRules(connection, level));
        }
Пример #22
0
        /// <summary>
        /// Enables query logging on a database connection for Schematic queries.
        /// </summary>
        /// <param name="connection">A database connection.</param>
        /// <param name="logger">A logger.</param>
        /// <param name="logLevel">The log level that should be applied to query logs.</param>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> or <paramref name="logger"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException"><paramref name="logLevel"/> is an invalid value.</exception>
        public static void AddLogging(ISchematicConnection connection, ILogger logger, LogLevel logLevel)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (!logLevel.IsValid())
            {
                throw new ArgumentException($"The { nameof(LogLevel) } provided must be a valid enum.", nameof(logLevel));
            }

            var loggingConfig = new LoggingConfiguration(logger, logLevel);

            ConnectionLoggerLookup.AddOrUpdate(connection.DbConnection, loggingConfig);
        }
Пример #23
0
        /// <summary>
        /// Adds logging to a database connection. Logs when queries occur using the given database connection.
        /// </summary>
        /// <param name="connection">A connection.</param>
        /// <param name="loggerFactory">A logger factory.</param>
        /// <param name="level">A logging level.</param>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> or <paramref name="loggerFactory"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException"><paramref name="level"/> is not a valid enum value.</exception>
        public static void AddLogging(this ISchematicConnection connection, ILoggerFactory loggerFactory, LogLevel level)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }
            if (loggerFactory == null)
            {
                throw new ArgumentNullException(nameof(loggerFactory));
            }
            if (!level.IsValid())
            {
                throw new ArgumentException($"The { nameof(LogLevel) } provided must be a valid enum.", nameof(level));
            }

            var logger = loggerFactory.CreateLogger("Schematic");

            Logging.AddLogging(connection, logger, level);
        }
Пример #24
0
        /// <summary>
        /// Dynamically retrieves the rules used to analyze database objects. Searches the currently executing directory to obtain other rules.
        /// </summary>
        /// <param name="connection">A schematic connection.</param>
        /// <param name="level">The level used for reporting.</param>
        /// <returns>Rules used for analyzing database objects.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException"><paramref name="level"/> is not a valid enum value.</exception>
        public IEnumerable <IRule> GetRules(ISchematicConnection connection, RuleLevel level)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }
            if (!level.IsValid())
            {
                throw new ArgumentException($"The { nameof(RuleLevel) } provided must be a valid enum.", nameof(level));
            }

            var dialectType = connection.Dialect.GetType();

            return(LoadPluginAssemblies()
                   .SelectMany(a => LoadRequiredTypes(a, dialectType))
                   .Select(t => Array.Find(t.GetConstructors(), c => c.IsPublic && c.GetParameters().Length == 0))
                   .SelectMany(c => GetRules(c, connection, level))
                   .ToList());
        }
Пример #25
0
        /// <summary>
        /// Retrieves the default set of rules used to analyze database objects.
        /// </summary>
        /// <param name="connection">A schematic connection.</param>
        /// <param name="level">The level used for reporting.</param>
        /// <returns>Rules used for analyzing database objects.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="connection"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException"><paramref name="level"/> does not have a valid enum value.</exception>
        public IEnumerable <IRule> GetRules(ISchematicConnection connection, RuleLevel level)
        {
            if (connection == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }
            if (!level.IsValid())
            {
                throw new ArgumentException($"The { nameof(RuleLevel) } provided must be a valid enum.", nameof(level));
            }

            return(new IRule[]
            {
                new CandidateKeyMissingRule(level),
                new ColumnWithNullDefaultValueRule(level),
                new ColumnWithNumericSuffix(level),
                new DisabledObjectsRule(level),
                new ForeignKeyColumnTypeMismatchRule(level),
                new ForeignKeyIndexRule(level),
                new ForeignKeyIsPrimaryKeyRule(level),
                new ForeignKeyMissingRule(level),
                new ForeignKeyRelationshipCycleRule(level),
                new InvalidViewDefinitionRule(connection, level),
                new NoIndexesPresentOnTableRule(level),
                new NoNonNullableColumnsPresentRule(level),
                new NoSurrogatePrimaryKeyRule(level),
                new NoValueForNullableColumnRule(connection, level),
                new OnlyOneColumnPresentRule(level),
                new OrphanedTableRule(level),
                new PrimaryKeyColumnNotFirstColumnRule(level),
                new PrimaryKeyNotIntegerRule(level),
                new RedundantIndexesRule(level),
                new ReservedKeywordNameRule(connection.Dialect, level),
                new TooManyColumnsRule(level),
                new UniqueIndexWithNullableColumnsRule(level),
                new WhitespaceNameRule(level)
            });
        }
Пример #26
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PostgreSqlRelationalDatabaseTableProvider"/> class.
 /// </summary>
 /// <param name="connection">A schematic connection.</param>
 /// <param name="identifierDefaults">Database identifier defaults.</param>
 /// <param name="identifierResolver">A database identifier resolver.</param>
 /// <exception cref="ArgumentNullException"><paramref name="connection"/> or <paramref name="identifierDefaults"/> or <paramref name="identifierResolver"/> is <c>null</c>.</exception>
 public PostgreSqlRelationalDatabaseTableProvider(ISchematicConnection connection, IIdentifierDefaults identifierDefaults, IIdentifierResolutionStrategy identifierResolver)
     : base(connection, identifierDefaults, identifierResolver)
 {
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="MySqlDatabaseRoutineProvider"/> class.
 /// </summary>
 /// <param name="connection">A database connection.</param>
 /// <param name="identifierDefaults">Identifier defaults for the associated database.</param>
 /// <exception cref="ArgumentNullException"><paramref name="connection"/> or <paramref name="identifierDefaults"/> are <c>null</c>.</exception>
 public MySqlDatabaseRoutineProvider(ISchematicConnection connection, IIdentifierDefaults identifierDefaults)
 {
     Connection         = connection ?? throw new ArgumentNullException(nameof(connection));
     IdentifierDefaults = identifierDefaults ?? throw new ArgumentNullException(nameof(identifierDefaults));
 }
Пример #28
0
 public ReportGenerator(ISchematicConnection connection, IRelationalDatabase database, DirectoryInfo directory)
 {
     Connection      = connection ?? throw new ArgumentNullException(nameof(connection));
     Database        = database ?? throw new ArgumentNullException(nameof(database));
     ExportDirectory = directory ?? throw new ArgumentNullException(nameof(directory));
 }
Пример #29
0
 public ReportGenerator(ISchematicConnection connection, IRelationalDatabase database, string directory)
     : this(connection, database, new DirectoryInfo(directory))
 {
 }
Пример #30
0
        private static async Task <Version> GetDatabaseVersionAsyncCore(ISchematicConnection connection, CancellationToken cancellationToken)
        {
            var versionStr = await connection.DbConnection.ExecuteScalarAsync <string>(DatabaseDisplayVersionQuerySql, cancellationToken).ConfigureAwait(false);

            return(Version.Parse(versionStr));
        }