25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

277 lines
9.6KB

  1. using System.Data.Common;
  2. using System.Data.OleDb;
  3. using System.Runtime.Versioning;
  4. using Campaign_Tracker.Server.LegacyData.Models;
  5. namespace Campaign_Tracker.Server.LegacyData;
  6. /// <summary>
  7. /// Read-only OleDb implementation for legacy Access-derived data.
  8. /// All SQL is parameterized and validated as SELECT-only before execution.
  9. /// </summary>
  10. [SupportedOSPlatform("windows")]
  11. public sealed class OleDbLegacyDataAccess : ILegacyDataAccess
  12. {
  13. private readonly string _connectionString;
  14. public OleDbLegacyDataAccess(string connectionString)
  15. {
  16. if (string.IsNullOrWhiteSpace(connectionString))
  17. {
  18. throw new ArgumentException("Legacy database connection string is required.", nameof(connectionString));
  19. }
  20. _connectionString = connectionString;
  21. }
  22. public async Task<LegacyJurisdiction?> GetJurisdictionAsync(
  23. string jCode,
  24. CancellationToken cancellationToken = default)
  25. {
  26. const string sql = """
  27. SELECT JCode, Name, Mailing_Address, CSZ, IMB, IMB_Digits
  28. FROM Jurisdiction
  29. WHERE Trim(JCode) = ?
  30. """;
  31. var results = await QueryAsync(sql, [jCode.Trim()], MapJurisdiction, cancellationToken);
  32. return results.FirstOrDefault();
  33. }
  34. public Task<IReadOnlyList<LegacyJurisdiction>> GetAllJurisdictionsAsync(
  35. CancellationToken cancellationToken = default)
  36. {
  37. const string sql = """
  38. SELECT JCode, Name, Mailing_Address, CSZ, IMB, IMB_Digits
  39. FROM Jurisdiction
  40. ORDER BY JCode
  41. """;
  42. return QueryAsync(sql, [], MapJurisdiction, cancellationToken);
  43. }
  44. public async Task<LegacyContact?> GetContactByIdAsync(
  45. int id,
  46. CancellationToken cancellationToken = default)
  47. {
  48. const string sql = """
  49. SELECT ID, JURISCODE, ContactName, Title, Email, Phone1, Phone2,
  50. MailingAddress, MailingAddress2, MailingAddress3,
  51. BusinessAddress, BusinessAddress2, BusinessAddress3,
  52. TownshipName, TownshipNum
  53. FROM Contacts
  54. WHERE ID = ?
  55. """;
  56. var results = await QueryAsync(sql, [id], MapContact, cancellationToken);
  57. return results.FirstOrDefault();
  58. }
  59. public Task<IReadOnlyList<LegacyContact>> GetContactsByJurisdictionAsync(
  60. string jCode,
  61. CancellationToken cancellationToken = default)
  62. {
  63. const string sql = """
  64. SELECT ID, JURISCODE, ContactName, Title, Email, Phone1, Phone2,
  65. MailingAddress, MailingAddress2, MailingAddress3,
  66. BusinessAddress, BusinessAddress2, BusinessAddress3,
  67. TownshipName, TownshipNum
  68. FROM Contacts
  69. WHERE Trim(JURISCODE) = ?
  70. ORDER BY ID
  71. """;
  72. return QueryAsync(sql, [jCode.Trim()], MapContact, cancellationToken);
  73. }
  74. public async Task<LegacyKit?> GetKitByIdAsync(
  75. int id,
  76. CancellationToken cancellationToken = default)
  77. {
  78. const string sql = """
  79. SELECT ID, Jcode, JobNumber, JobType, Status, Filename, Cass, InkJetJob,
  80. CreatedOn, ExportedToSnailWorks, LabelsPrinted, OfficeCopiesAmount,
  81. InboundStid, OutboundStid
  82. FROM Kit
  83. WHERE ID = ?
  84. """;
  85. var results = await QueryAsync(sql, [id], MapKit, cancellationToken);
  86. return results.FirstOrDefault();
  87. }
  88. public Task<IReadOnlyList<LegacyKit>> GetKitsByJurisdictionAsync(
  89. string jCode,
  90. CancellationToken cancellationToken = default)
  91. {
  92. const string sql = """
  93. SELECT ID, Jcode, JobNumber, JobType, Status, Filename, Cass, InkJetJob,
  94. CreatedOn, ExportedToSnailWorks, LabelsPrinted, OfficeCopiesAmount,
  95. InboundStid, OutboundStid
  96. FROM Kit
  97. WHERE Trim(Jcode) = ?
  98. ORDER BY ID
  99. """;
  100. return QueryAsync(sql, [jCode.Trim()], MapKit, cancellationToken);
  101. }
  102. public Task<IReadOnlyList<LegacyKitLabel>> GetKitLabelsByKitAsync(
  103. int kitId,
  104. CancellationToken cancellationToken = default)
  105. {
  106. const string sql = """
  107. SELECT ID, KitID, InBoundImb, InBoundImbDigits, InBoundSerial,
  108. OutboundImb, OutboundImbDigits, OutboundSerial, SetNumber
  109. FROM KitLabels
  110. WHERE KitID = ?
  111. ORDER BY ID
  112. """;
  113. return QueryAsync(sql, [kitId], MapKitLabel, cancellationToken);
  114. }
  115. private async Task<IReadOnlyList<T>> QueryAsync<T>(
  116. string sql,
  117. IReadOnlyList<object> parameters,
  118. Func<DbDataReader, T> map,
  119. CancellationToken cancellationToken)
  120. {
  121. ReadOnlyCommandGuard.Validate(sql);
  122. try
  123. {
  124. await using var connection = new OleDbConnection(_connectionString);
  125. await connection.OpenAsync(cancellationToken);
  126. await using var command = connection.CreateCommand();
  127. command.CommandText = sql;
  128. foreach (var parameter in parameters)
  129. {
  130. command.Parameters.AddWithValue(string.Empty, parameter);
  131. }
  132. var results = new List<T>();
  133. await using var reader = await command.ExecuteReaderAsync(cancellationToken);
  134. while (await reader.ReadAsync(cancellationToken))
  135. {
  136. results.Add(map(reader));
  137. }
  138. return results;
  139. }
  140. catch (LegacyDataAccessException)
  141. {
  142. throw;
  143. }
  144. catch (Exception ex)
  145. {
  146. throw new LegacyDataAccessException("Legacy read operation failed.", ex);
  147. }
  148. }
  149. private static LegacyJurisdiction MapJurisdiction(DbDataReader reader) =>
  150. new(
  151. GetRequiredString(reader, "JCode"),
  152. GetString(reader, "Name"),
  153. GetString(reader, "Mailing_Address"),
  154. GetString(reader, "CSZ"),
  155. GetString(reader, "IMB"),
  156. GetString(reader, "IMB_Digits"));
  157. private static LegacyContact MapContact(DbDataReader reader) =>
  158. new(
  159. GetRequiredInt(reader, "ID"),
  160. GetRequiredString(reader, "JURISCODE"),
  161. GetString(reader, "ContactName"),
  162. GetString(reader, "Title"),
  163. GetString(reader, "Email"),
  164. GetString(reader, "Phone1"),
  165. GetString(reader, "Phone2"),
  166. GetString(reader, "MailingAddress"),
  167. GetString(reader, "MailingAddress2"),
  168. GetString(reader, "MailingAddress3"),
  169. GetString(reader, "BusinessAddress"),
  170. GetString(reader, "BusinessAddress2"),
  171. GetString(reader, "BusinessAddress3"),
  172. GetString(reader, "TownshipName"),
  173. GetString(reader, "TownshipNum"));
  174. private static LegacyKit MapKit(DbDataReader reader) =>
  175. new(
  176. GetRequiredInt(reader, "ID"),
  177. GetRequiredString(reader, "Jcode"),
  178. GetString(reader, "JobNumber"),
  179. GetString(reader, "JobType"),
  180. GetString(reader, "Status"),
  181. GetString(reader, "Filename"),
  182. GetBool(reader, "Cass"),
  183. GetBool(reader, "InkJetJob"),
  184. GetDateTime(reader, "CreatedOn"),
  185. GetDateTime(reader, "ExportedToSnailWorks"),
  186. GetDateTime(reader, "LabelsPrinted"),
  187. GetInt(reader, "OfficeCopiesAmount"),
  188. GetString(reader, "InboundStid"),
  189. GetString(reader, "OutboundStid"));
  190. private static LegacyKitLabel MapKitLabel(DbDataReader reader) =>
  191. new(
  192. GetRequiredInt(reader, "ID"),
  193. GetRequiredInt(reader, "KitID"),
  194. GetString(reader, "InBoundImb"),
  195. GetString(reader, "InBoundImbDigits"),
  196. GetString(reader, "InBoundSerial"),
  197. GetString(reader, "OutboundImb"),
  198. GetString(reader, "OutboundImbDigits"),
  199. GetString(reader, "OutboundSerial"),
  200. GetDouble(reader, "SetNumber"));
  201. private static string GetRequiredString(DbDataReader reader, string name)
  202. {
  203. var value = GetString(reader, name)?.Trim();
  204. return string.IsNullOrWhiteSpace(value)
  205. ? throw new LegacyDataAccessException($"Required legacy join key {name} was null or empty.")
  206. : value;
  207. }
  208. private static int GetRequiredInt(DbDataReader reader, string name) =>
  209. GetInt(reader, name)
  210. ?? throw new LegacyDataAccessException($"Required legacy join key {name} was null.");
  211. private static string? GetString(DbDataReader reader, string name)
  212. {
  213. var value = GetValue(reader, name);
  214. return value is null ? null : Convert.ToString(value);
  215. }
  216. private static int? GetInt(DbDataReader reader, string name)
  217. {
  218. var value = GetValue(reader, name);
  219. return value is null ? null : Convert.ToInt32(value);
  220. }
  221. private static double? GetDouble(DbDataReader reader, string name)
  222. {
  223. var value = GetValue(reader, name);
  224. return value is null ? null : Convert.ToDouble(value);
  225. }
  226. private static bool GetBool(DbDataReader reader, string name)
  227. {
  228. var value = GetValue(reader, name);
  229. return value is not null && Convert.ToBoolean(value);
  230. }
  231. private static DateTime? GetDateTime(DbDataReader reader, string name)
  232. {
  233. var value = GetValue(reader, name);
  234. return value is null ? null : Convert.ToDateTime(value);
  235. }
  236. private static object? GetValue(DbDataReader reader, string name)
  237. {
  238. var ordinal = reader.GetOrdinal(name);
  239. return reader.IsDBNull(ordinal) ? null : reader.GetValue(ordinal);
  240. }
  241. }

Powered by TurnKey Linux.