using System.Linq.Expressions; using NPoco; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence; using Umbraco.Cms.Infrastructure.Persistence.Dtos; using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; using Umbraco.Cms.Infrastructure.Runtime; using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence; internal static class UmbracoDatabaseExtensions { public static UmbracoDatabase AsUmbracoDatabase(this IUmbracoDatabase database) { if (database is not UmbracoDatabase asDatabase) { throw new Exception("oops: database."); } return asDatabase; } /// /// Gets a dictionary of key/values directly from the database, no scope, nothing. /// /// Used by to determine the runtime state. public static IReadOnlyDictionary? GetFromKeyValueTable( this IUmbracoDatabase? database, string keyPrefix) { if (database is null) { return null; } // create the wildcard where clause ISqlSyntaxProvider sqlSyntax = database.SqlContext.SqlSyntax; var whereParam = sqlSyntax.GetStringColumnWildcardComparison( sqlSyntax.GetColumn(database.SqlContext.DatabaseType, KeyValueDto.TableName, "key", null), 0, TextColumnType.NVarchar); Sql? sql = database.SqlContext.Sql() .Select() .From() .Where(whereParam, keyPrefix + sqlSyntax.GetWildcardPlaceholder()); return database.Fetch(sql) .ToDictionary(x => x.Key, x => x.Value); } /// /// Returns true if the database contains the specified table /// /// /// /// public static bool HasTable(this IUmbracoDatabase database, string tableName) { try { return database.SqlContext.SqlSyntax.GetTablesInSchema(database) .Any(table => table.InvariantEquals(tableName)); } catch (Exception) { return false; // will occur if the database cannot connect } } /// /// Returns true if the database contains no tables /// /// /// public static bool IsDatabaseEmpty(this IUmbracoDatabase database) => database.SqlContext.SqlSyntax.GetTablesInSchema(database).Any() == false; public static long Count(this IUmbracoDatabase database, Sql sql) { // We need to copy the sql into a new object, to avoid this method from changing the sql. var query = new Sql().Select("COUNT(*)").From().Append("(").Append(new Sql(sql.SQL, sql.Arguments)).Append(") as count_query"); return database.ExecuteScalar(query); } public static async Task CountAsync(this IUmbracoDatabase database, Sql sql) { // We need to copy the sql into a new object, to avoid this method from changing the sql. Sql query = new Sql().Select("COUNT(*)").From().Append("(").Append(new Sql(sql.SQL, sql.Arguments)).Append(") as count_query"); return await database.ExecuteScalarAsync(query); } public static async Task> PagedAsync( this IUmbracoDatabase database, Sql sql, int skip, int take, Action> sortingAction, Func mapper) { ArgumentOutOfRangeException.ThrowIfLessThan(skip, 0, nameof(skip)); ArgumentOutOfRangeException.ThrowIfLessThan(take, 0, nameof(take)); var count = await database.CountAsync(sql); if (take == 0 || skip >= count) { return new PagedModel { Total = count, Items = [], }; } sortingAction(sql); List results = await database.SkipTakeAsync( skip, take, sql); return new PagedModel { Total = count, Items = results.Select(mapper), }; } }