/// <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));
        }