您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

196 行
5.9KB

  1. using Campaign_Tracker.Server.Seed.Models;
  2. namespace Campaign_Tracker.Server.Seed;
  3. public sealed class InMemorySeedDataStore : ISeedDataStore
  4. {
  5. private readonly object _sync = new();
  6. private readonly SeedDataSnapshot _snapshot = new();
  7. public Task UpsertSeedDataAsync(SeedDataSet seedData, CancellationToken cancellationToken = default)
  8. {
  9. cancellationToken.ThrowIfCancellationRequested();
  10. lock (_sync)
  11. {
  12. UpsertMissing(_snapshot.ReferenceValues, seedData.ReferenceValues, Clone);
  13. UpsertMissing(_snapshot.RequiredFieldRules, seedData.RequiredFieldRules, Clone);
  14. UpsertMissing(_snapshot.EscalationRules, seedData.EscalationRules, Clone);
  15. }
  16. return Task.CompletedTask;
  17. }
  18. public Task<IReadOnlyList<ReferenceValue>> GetReferenceValuesAsync(CancellationToken cancellationToken = default)
  19. {
  20. cancellationToken.ThrowIfCancellationRequested();
  21. lock (_sync)
  22. {
  23. return Task.FromResult<IReadOnlyList<ReferenceValue>>(
  24. _snapshot.ReferenceValues.Select(Clone).ToArray());
  25. }
  26. }
  27. public Task<IReadOnlyList<RequiredFieldRule>> GetRequiredFieldRulesAsync(CancellationToken cancellationToken = default)
  28. {
  29. cancellationToken.ThrowIfCancellationRequested();
  30. lock (_sync)
  31. {
  32. return Task.FromResult<IReadOnlyList<RequiredFieldRule>>(
  33. _snapshot.RequiredFieldRules.Select(Clone).ToArray());
  34. }
  35. }
  36. public Task<IReadOnlyList<EscalationRule>> GetEscalationRulesAsync(CancellationToken cancellationToken = default)
  37. {
  38. cancellationToken.ThrowIfCancellationRequested();
  39. lock (_sync)
  40. {
  41. return Task.FromResult<IReadOnlyList<EscalationRule>>(
  42. _snapshot.EscalationRules.Select(Clone).ToArray());
  43. }
  44. }
  45. public Task SaveReferenceValueAsync(ReferenceValue referenceValue, CancellationToken cancellationToken = default)
  46. {
  47. cancellationToken.ThrowIfCancellationRequested();
  48. lock (_sync)
  49. {
  50. ReplaceBySeedKey(_snapshot.ReferenceValues, referenceValue, Clone);
  51. }
  52. return Task.CompletedTask;
  53. }
  54. public Task SaveRequiredFieldRuleAsync(RequiredFieldRule rule, CancellationToken cancellationToken = default)
  55. {
  56. cancellationToken.ThrowIfCancellationRequested();
  57. lock (_sync)
  58. {
  59. ReplaceBySeedKey(_snapshot.RequiredFieldRules, rule, Clone);
  60. }
  61. return Task.CompletedTask;
  62. }
  63. public Task SaveEscalationRuleAsync(EscalationRule rule, CancellationToken cancellationToken = default)
  64. {
  65. cancellationToken.ThrowIfCancellationRequested();
  66. lock (_sync)
  67. {
  68. ReplaceBySeedKey(_snapshot.EscalationRules, rule, Clone);
  69. }
  70. return Task.CompletedTask;
  71. }
  72. internal static void UpsertMissing<T>(
  73. List<T> target,
  74. IEnumerable<T> defaults,
  75. Func<T, T> clone)
  76. where T : class
  77. {
  78. foreach (var item in defaults)
  79. {
  80. var key = GetSeedKey(item);
  81. if (target.Any(existing => SameSeedKey(GetSeedKey(existing), key)))
  82. {
  83. continue;
  84. }
  85. target.Add(clone(item));
  86. }
  87. }
  88. internal static void ReplaceBySeedKey<T>(
  89. List<T> target,
  90. T item,
  91. Func<T, T> clone)
  92. where T : class
  93. {
  94. var key = GetSeedKey(item);
  95. var existingIndex = target.FindIndex(existing => SameSeedKey(GetSeedKey(existing), key));
  96. if (existingIndex >= 0)
  97. {
  98. target[existingIndex] = clone(item);
  99. }
  100. else
  101. {
  102. target.Add(clone(item));
  103. }
  104. }
  105. internal static ReferenceValue Clone(ReferenceValue value) => new()
  106. {
  107. Id = value.Id,
  108. SeedKey = value.SeedKey,
  109. Category = value.Category,
  110. Name = value.Name,
  111. Description = value.Description,
  112. Value = value.Value,
  113. Source = value.Source,
  114. IsActive = value.IsActive,
  115. CreatedAt = value.CreatedAt,
  116. UpdatedAt = value.UpdatedAt,
  117. };
  118. internal static RequiredFieldRule Clone(RequiredFieldRule rule) => new()
  119. {
  120. Id = rule.Id,
  121. SeedKey = rule.SeedKey,
  122. Name = rule.Name,
  123. Description = rule.Description,
  124. EntityType = rule.EntityType,
  125. FieldPath = rule.FieldPath,
  126. ReadinessFeatureKey = rule.ReadinessFeatureKey,
  127. IsRequired = rule.IsRequired,
  128. Source = rule.Source,
  129. IsActive = rule.IsActive,
  130. CreatedAt = rule.CreatedAt,
  131. UpdatedAt = rule.UpdatedAt,
  132. };
  133. internal static EscalationRule Clone(EscalationRule rule) => new()
  134. {
  135. Id = rule.Id,
  136. SeedKey = rule.SeedKey,
  137. Name = rule.Name,
  138. Description = rule.Description,
  139. Scenario = rule.Scenario,
  140. TriggerCondition = rule.TriggerCondition,
  141. Action = rule.Action,
  142. MilestoneBasis = rule.MilestoneBasis,
  143. AlertWindow = rule.AlertWindow,
  144. Priority = rule.Priority,
  145. Source = rule.Source,
  146. IsActive = rule.IsActive,
  147. CreatedAt = rule.CreatedAt,
  148. UpdatedAt = rule.UpdatedAt,
  149. };
  150. private static string GetSeedKey<T>(T item) where T : class =>
  151. item switch
  152. {
  153. ReferenceValue value => value.SeedKey,
  154. RequiredFieldRule rule => rule.SeedKey,
  155. EscalationRule rule => rule.SeedKey,
  156. _ => throw new InvalidOperationException($"Unsupported seed item type {typeof(T).Name}."),
  157. };
  158. private static bool SameSeedKey(string left, string right) =>
  159. string.Equals(left, right, StringComparison.OrdinalIgnoreCase);
  160. internal sealed class SeedDataSnapshot
  161. {
  162. public List<ReferenceValue> ReferenceValues { get; init; } = [];
  163. public List<RequiredFieldRule> RequiredFieldRules { get; init; } = [];
  164. public List<EscalationRule> EscalationRules { get; init; } = [];
  165. }
  166. }

Powered by TurnKey Linux.