using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using Keyapis.EF.DataAnnotations; using Keyapis.EF.Extensions; using Keyapis.EF.ValueConverters; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; // ReSharper disable once CheckNamespace namespace Keyapis.EF.Bell.V1.Data.BellDb; public interface IBellDbContext : IAsyncDisposable, IDisposable { public DbSet Notifications { get; set; } public Task SaveChangesAsync(CancellationToken cancellationToken = default); } public abstract class BellDbContextBase : DbContext, IBellDbContext { protected BellDbContextBase(DbContextOptions options) : base(options) { } public DbSet Notifications { get; set; } = null!; protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.HasPostgresExtension("pg_trgm"); foreach(var entity in builder.Model.GetEntityTypes()) { foreach(var property in entity.GetProperties()) { var memberInfo = property.PropertyInfo ?? (MemberInfo ?)property.FieldInfo; if (memberInfo == null) continue; var customRangeAttribute = memberInfo.GetCustomAttribute(); if (customRangeAttribute != null) { var actualType = Nullable.GetUnderlyingType(property.ClrType) ?? property.ClrType; if (actualType == typeof(string) || typeof(IEnumerable).IsAssignableFrom(actualType)) { property.SetMaxLength(customRangeAttribute.Maximum > int.MaxValue ? int.MaxValue : (int)customRangeAttribute.Maximum); } } var customRequiredAttribute = memberInfo.GetCustomAttribute(); if (customRequiredAttribute != null) { property.IsNullable = false; } } } builder.Entity(e => { // Для поля id дополнительные конфигурации свойства не нужны // Для поля id сопоствалений с фильтром и сортировкой не найденно // WARNING Для поля Notification.orpon не указан диапазон // Для поля orpon дополнительные конфигурации свойства не нужны // Найдено сопоставление: model.orpon ~ filter.orpons e.HasIndex(p => p.Orpon) .IsDescending(); // Для поля app_title дополнительные конфигурации свойства не нужны // Для поля app_title сопоствалений с фильтром и сортировкой не найденно // Для поля room_number дополнительные конфигурации свойства не нужны // Найдено сопоставление: model.room_number ~ filter.room_numbers e.HasIndex(p => p.RoomNumber) .IsDescending(); // Для поля header дополнительные конфигурации свойства не нужны // Для поля header сопоствалений с фильтром и сортировкой не найденно // Для поля text дополнительные конфигурации свойства не нужны // Для поля text сопоствалений с фильтром и сортировкой не найденно e.Property(p => p.StatusType) .HasMaxLength(32) .HasConversion(new EnumToStringConverter()); // Найдено сопоставление: model.status_type ~ filter.status_types e.HasIndex(p => p.StatusType) .IsDescending(); e.Property(p => p.CreatedAt) .HasColumnType("timestamp without time zone") .HasConversion(DateTimeUtcConverter.Instance); // Найдено сопоставление: model.created_at ~ order.CREATED_AT e.HasIndex(p => p.CreatedAt) .HasMethod("btree") .IsDescending(); e.Property(p => p.StatusChangedAt) .HasColumnType("timestamp without time zone") .HasConversion(DateTimeUtcConverter.Instance); // Найдено сопоставление: model.status_changed_at ~ order.STATUS_CHANGED_AT e.HasIndex(p => p.StatusChangedAt) .HasMethod("btree") .IsDescending(); e.Property(p => p.Payload) .HasColumnType("jsonb") .HasConversion(new CustomJsonConverter>(), new ValueComparer>( (c1, c2) => (c1 != null && c2 != null && c1.SequenceEqual(c2)), c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())), c => new Dictionary(c) )) .HasDefaultValue(new Dictionary()); e.HasIndex(p => p.Payload) .HasMethod("gin") .HasOperators("jsonb_ops"); }); builder.HasDefaultSchema("bell"); } } /// /// Уведомление. /// # Описание модели /// [ Display(Name = @"Уведомление"), Description(@"Описание модели") ] public partial class NotificationModel { /// /// Идентификатор. /// Создаётся сервером. /// # Тип: Guid /// [ Display(Name = @"Идентификатор"), Description(@"Создаётся сервером. Тип: Guid"), CustomPattern(@"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"), Editable(false) ] public Guid Id { get; set; } /// /// ОРПОН. /// # Диапазон 1..9223372036854775807 /// [ Display(Name = @"ОРПОН"), Description(@"Диапазон 1..9223372036854775807"), CustomRequired ] public long Orpon { get; set; } /// /// Наименование приложения-отправителя. /// # Диапазон: 3..256 /// [ Display(Name = @"Наименование приложения-отправителя"), Description(@"Диапазон: 3..256"), CustomRange(3, 256) ] public string? AppTitle { get; set; } /// /// Номер квартиры. /// # Диапазон: 1..4 /// [ Display(Name = @"Номер квартиры"), Description(@"Диапазон: 1..4"), CustomRequired, CustomRange(1, 4) ] public string RoomNumber { get; set; } = null!; /// /// Заголовок. /// # Диапазон: 3..128 /// [ Display(Name = @"Заголовок"), Description(@"Диапазон: 3..128"), CustomRequired, CustomRange(3, 128) ] public string Header { get; set; } = null!; /// /// Тело. /// # Диапазон: 3..256 /// [ Display(Name = @"Тело"), Description(@"Диапазон: 3..256"), CustomRequired, CustomRange(3, 256) ] public string Text { get; set; } = null!; /// /// Статус /// [ Display(Name = @"Статус"), Editable(false) ] public NotificationModel.NotificationStatusType StatusType { get; set; } /// /// Дата создания. /// # Тип: DateTime /// [ Display(Name = @"Дата создания"), Description(@"Тип: DateTime"), Editable(false) ] public DateTime CreatedAt { get; set; } /// /// Дата последнего изменения статуса. /// Заполняется и обновляется сервером. /// # Тип: DateTime /// [ Display(Name = @"Дата последнего изменения статуса"), Description(@"Заполняется и обновляется сервером. Тип: DateTime"), Editable(false) ] public DateTime StatusChangedAt { get; set; } /// /// Полезная нагрузка /// [ Display(Name = @"Полезная нагрузка") ] public Dictionary Payload { get; set; } = new(0); /// /// Статус /// public enum NotificationStatusType { /// /// Значение не указано /// [ Display(Name = @"Значение не указано"), JsonPropertyName("STATUS_TYPE_UNKNOWN") ] Unknown = 0, /// /// Новый. /// Устанавливается по умолчанию /// [ Display(Name = @"Новый"), Description(@"Устанавливается по умолчанию"), JsonPropertyName("NEW") ] New = 1, /// /// Доставлен /// [ Display(Name = @"Доставлен"), JsonPropertyName("DELIVERED") ] Delivered = 2, /// /// Просмотрен /// [ Display(Name = @"Просмотрен"), JsonPropertyName("VIEWED") ] Viewed = 3, } } /// /// Фильтр уведомлений /// [ Display(Name = @"Фильтр уведомлений") ] public partial class NotificationFilterModel { /// /// По ОРПОН /// [ Display(Name = @"По ОРПОН") ] public List Orpons { get; set; } = new(0); /// /// По номерам квартир /// [ Display(Name = @"По номерам квартир") ] public List RoomNumbers { get; set; } = new(0); /// /// По статусам /// [ Display(Name = @"По статусам") ] public List StatusTypes { get; set; } = new(0); } /// /// Ошибки валидации. /// Эти проверки выполняются до обращения в базу данных /// [ Display(Name = @"Ошибки валидации"), Description(@"Эти проверки выполняются до обращения в базу данных") ] public partial class ValidationErrorModel { /// /// Путь к полю в формате наименования прото /// [ Display(Name = @"Путь к полю в формате наименования прото"), CustomRequired ] public string Path { get; set; } = null!; /// /// Валидационное сообщение /// [ Display(Name = @"Валидационное сообщение"), CustomRequired ] public string Message { get; set; } = null!; } /// /// Задача на отправку уведомления. /// Очередь key.bell.send_push_notification /// [ Display(Name = @"Задача на отправку уведомления"), Description(@"Очередь key.bell.send_push_notification") ] public partial class SendPushNotificationTaskModel { /// /// Идентификатор запроса /// [ Display(Name = @"Идентификатор запроса"), CustomRequired ] public string RequestId { get; set; } = null!; // WARNING Не удалось найти свойство навигации для поля SendPushNotificationTask.request_id /// /// ОРПОН /// [ Display(Name = @"ОРПОН"), CustomRequired ] public long Orpon { get; set; } /// /// Номер квартиры /// [ Display(Name = @"Номер квартиры"), CustomRequired ] public string RoomNumber { get; set; } = null!; /// /// Заголовок уведомления /// [ Display(Name = @"Заголовок уведомления"), CustomRequired ] public string Header { get; set; } = null!; /// /// Текст уведомления /// [ Display(Name = @"Текст уведомления"), CustomRequired ] public string Text { get; set; } = null!; /// /// Полезная нагрузка /// [ Display(Name = @"Полезная нагрузка") ] public Dictionary Payload { get; set; } = new(0); } /// /// Запрос получения количества уведомлений /// [ Display(Name = @"Запрос получения количества уведомлений") ] public partial class GetNotificationCountRequestModel { /// /// Фильтр /// [ Display(Name = @"Фильтр") ] public NotificationFilterModel? Filter { get; set; } } /// /// Ответ на запрос на получение количества уведомлений /// [ Display(Name = @"Ответ на запрос на получение количества уведомлений") ] public partial class GetNotificationCountResponseModel { /// /// Количество уведомлений /// [ Display(Name = @"Количество уведомлений") ] public int Data { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public GetNotificationCountResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка запроса на получение количества уведомлений /// [ Display(Name = @"Ошибка запроса на получение количества уведомлений") ] public partial class ErrorModel { /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Запрос получения списка уведомлений /// [ Display(Name = @"Запрос получения списка уведомлений") ] public partial class GetNotificationListRequestModel { /// /// Фильтр /// [ Display(Name = @"Фильтр") ] public NotificationFilterModel? Filter { get; set; } /// /// Стандартный постраничный вывод /// [ Display(Name = @"Стандартный постраничный вывод") ] public NotificationPagingModel? Paging { get; set; } } /// /// Ответ на запрос на получение списка уведомлений /// [ Display(Name = @"Ответ на запрос на получение списка уведомлений") ] public partial class GetNotificationListResponseModel { /// /// Уведомление /// [ Display(Name = @"Уведомление") ] public NotificationModel? Data { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public GetNotificationListResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка запроса на получение списка уведомлений /// [ Display(Name = @"Ошибка запроса на получение списка уведомлений") ] public partial class ErrorModel { /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Запрос получения уведомления /// [ Display(Name = @"Запрос получения уведомления") ] public partial class GetNotificationRequestModel { /// /// Идентификатор уведомления. /// # Тип: Guid /// [ Display(Name = @"Идентификатор уведомления"), Description(@"Тип: Guid"), CustomRequired, CustomPattern(@"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$") ] public Guid Id { get; set; } } /// /// Ответ на запрос на получение уведомления /// [ Display(Name = @"Ответ на запрос на получение уведомления") ] public partial class GetNotificationResponseModel { /// /// Уведомление /// [ Display(Name = @"Уведомление") ] public NotificationModel? Data { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public GetNotificationResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка запроса на получение уведомления /// [ Display(Name = @"Ошибка запроса на получение уведомления") ] public partial class ErrorModel { /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Постраничный вывод /// [ Display(Name = @"Постраничный вывод") ] public partial class NotificationPagingModel { /// /// Тип значения сортировки. /// Если значение не передано, то будет взято значение по умолчанию. /// # По умолчанию: CREATED_AT /// [ Display(Name = @"Тип значения сортировки"), Description(@"Если значение не передано, то будет взято значение по умолчанию. По умолчанию: CREATED_AT") ] public NotificationPagingModel.NotificationPagingOrderByType OrderByType { get; set; } = NotificationPagingOrderByType.CreatedAt; /// /// Тип направления сортировки. /// # По умолчанию: DESC /// [ Display(Name = @"Тип направления сортировки"), Description(@"По умолчанию: DESC") ] public NotificationPagingModel.NotificationPagingDirectionType DirectionType { get; set; } = NotificationPagingDirectionType.Desc; /// /// Количество записей на страницу. /// Если значение 0 (не передано), то будет взято значение по умолчанию. /// # Диапазон: 0..100. /// # По умолчанию: 20 /// [ Display(Name = @"Количество записей на страницу"), Description(@"Если значение 0 (не передано), то будет взято значение по умолчанию. Диапазон: 0..100. По умолчанию: 20"), CustomRange(0, 100) ] public int Limit { get; set; } = 20; /// /// Сдвиг. /// # Диапазон: 0..2147483647 /// [ Display(Name = @"Сдвиг"), Description(@"Диапазон: 0..2147483647"), CustomRange(0, 2147483647) ] public int Offset { get; set; } /// /// Справочник типов значений сортировки. /// # Тип: byte /// [ Description("Тип: byte") ] public enum NotificationPagingOrderByType : byte { /// /// Значение не указано /// [ Display(Name = @"Значение не указано"), JsonPropertyName("ORDER_BY_TYPE_UNKNOWN") ] Unknown = 0, /// /// По дате создания /// [ Display(Name = @"По дате создания"), JsonPropertyName("CREATED_AT") ] CreatedAt = 1, /// /// По дате последнего изменения статуса /// [ Display(Name = @"По дате последнего изменения статуса"), JsonPropertyName("STATUS_CHANGED_AT") ] StatusChangedAt = 2, } /// /// Справочник типов направлений сортировки. /// # Тип: byte /// [ Description("Тип: byte") ] public enum NotificationPagingDirectionType : byte { /// /// Значение не указано /// [ Display(Name = @"Значение не указано"), JsonPropertyName("DIRECTION_TYPE_UNKNOWN") ] Unknown = 0, /// /// От большего к меньшему /// [ Display(Name = @"От большего к меньшему"), JsonPropertyName("DESC") ] Desc = 1, /// /// От меньшего к большему /// [ Display(Name = @"От меньшего к большему"), JsonPropertyName("ASC") ] Asc = 2, } } /// /// Запрос сохранения уведомления /// [ Display(Name = @"Запрос сохранения уведомления") ] public partial class PostNotificationRequestModel { /// /// Уведомление /// [ Display(Name = @"Уведомление"), CustomRequired ] public NotificationModel Data { get; set; } = null!; } /// /// Ответ на запрос сохранения уведомления /// [ Display(Name = @"Ответ на запрос сохранения уведомления") ] public partial class PostNotificationResponseModel { /// /// Уведомление /// [ Display(Name = @"Уведомление") ] public NotificationModel? Data { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public PostNotificationResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка сохранения уведомления /// [ Display(Name = @"Ошибка сохранения уведомления") ] public partial class ErrorModel { /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Запрос на изменение статуса уведомлений на \"Просмотрено\" по ОРПОНу и номеру квартиры /// [ Display(Name = @"Запрос на изменение статуса уведомлений на ""Просмотрено"" по ОРПОНу и номеру квартиры") ] public partial class PostNotificationViewOrponRoomNumberRequestModel { /// /// ОРПОН. /// # Диапазон: 1..9223372036854775807 /// [ Display(Name = @"ОРПОН"), Description(@"Диапазон: 1..9223372036854775807"), CustomRequired, CustomRange(1, 9223372036854775807) ] public long Orpon { get; set; } /// /// Номер квартиры. /// # Диапазон: 1..4 /// [ Display(Name = @"Номер квартиры"), Description(@"Диапазон: 1..4"), CustomRequired, CustomRange(1, 4) ] public string RoomNumber { get; set; } = null!; } /// /// Ответ на изменение статуса уведомлений на \"Просмотрено\" по ОРПОНу и номеру квартиры /// [ Display(Name = @"Ответ на изменение статуса уведомлений на ""Просмотрено"" по ОРПОНу и номеру квартиры") ] public partial class PostNotificationViewOrponRoomNumberResponseModel { /// /// Количество изменённых уведомлений /// [ Display(Name = @"Количество изменённых уведомлений") ] public int Data { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public PostNotificationViewOrponRoomNumberResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public partial class ErrorModel { /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Запрос на изменение статуса уведомления на \"Просмотрено\" уведомления /// [ Display(Name = @"Запрос на изменение статуса уведомления на ""Просмотрено"" уведомления") ] public partial class PostNotificationViewRequestModel { /// /// Идентификатор уведомления. /// # Тип: Guid /// [ Display(Name = @"Идентификатор уведомления"), Description(@"Тип: Guid"), CustomRequired, CustomPattern(@"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$") ] public Guid Id { get; set; } } /// /// Ответ на изменение статуса уведомления на \"Просмотрено\" уведомления /// [ Display(Name = @"Ответ на изменение статуса уведомления на ""Просмотрено"" уведомления") ] public partial class PostNotificationViewResponseModel { /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public PostNotificationViewResponseModel.ErrorModel? Error { get; set; } /// /// Ошибка /// [ Display(Name = @"Ошибка") ] public partial class ErrorModel { /// /// Ошибка валидации /// [ Display(Name = @"Ошибка валидации") ] public ValidationErrorModel? Validation { get; set; } } } /// /// Запрос проверки доступности сервиса /// [ Display(Name = @"Запрос проверки доступности сервиса") ] public partial class GetSystemStatusRequestModel { } /// /// Ответ на запрос проверки доступности сервиса /// [ Display(Name = @"Ответ на запрос проверки доступности сервиса") ] public partial class GetSystemStatusResponseModel { }