You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 line
3.9KB

  1. using System.Data;
  2. using System.Data.OleDb;
  3. using System.Runtime.Versioning;
  4. namespace Campaign_Tracker.Server.LegacyData.Schema;
  5. [SupportedOSPlatform("windows")]
  6. public sealed class OleDbLegacySchemaInspector : ILegacySchemaInspector
  7. {
  8. private readonly string _connectionString;
  9. public OleDbLegacySchemaInspector(string connectionString)
  10. {
  11. if (string.IsNullOrWhiteSpace(connectionString))
  12. {
  13. throw new ArgumentException("Legacy database connection string is required.", nameof(connectionString));
  14. }
  15. _connectionString = connectionString;
  16. }
  17. public async Task<IReadOnlyList<LegacyTableDefinition>> GetCurrentSchemaAsync(
  18. CancellationToken cancellationToken = default)
  19. {
  20. await using var connection = new OleDbConnection(_connectionString);
  21. await connection.OpenAsync(cancellationToken);
  22. var schema = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, null)
  23. ?? throw new InvalidOperationException("OleDb provider did not return column schema metadata.");
  24. var tables = schema.Rows
  25. .Cast<DataRow>()
  26. .GroupBy(row => GetRequiredString(row, "TABLE_NAME"), StringComparer.OrdinalIgnoreCase)
  27. .OrderBy(group => group.Key, StringComparer.OrdinalIgnoreCase)
  28. .Select(group => new LegacyTableDefinition(
  29. group.Key,
  30. group
  31. .OrderBy(row => GetOrdinal(row))
  32. .Select(row => new LegacyColumnDefinition(
  33. GetRequiredString(row, "COLUMN_NAME"),
  34. GetRequiredInt(row, "DATA_TYPE"),
  35. GetNullableInt(row, "CHARACTER_MAXIMUM_LENGTH"),
  36. GetNullableBool(row, "IS_NULLABLE") ?? true)
  37. {
  38. Constraints = GetColumnConstraints(row),
  39. })
  40. .ToArray()))
  41. .ToArray();
  42. return tables;
  43. }
  44. private static int GetOrdinal(DataRow row) =>
  45. GetNullableInt(row, "ORDINAL_POSITION") ?? int.MaxValue;
  46. private static IReadOnlyList<string> GetColumnConstraints(DataRow row)
  47. {
  48. var constraints = new List<string>();
  49. return constraints;
  50. }
  51. private static string GetRequiredString(DataRow row, string columnName)
  52. {
  53. var value = row.Table.Columns.Contains(columnName) ? row[columnName] : null;
  54. var text = value is null or DBNull ? null : Convert.ToString(value);
  55. return string.IsNullOrWhiteSpace(text)
  56. ? throw new InvalidOperationException($"OleDb schema row is missing required field {columnName}.")
  57. : text;
  58. }
  59. private static int GetRequiredInt(DataRow row, string columnName) =>
  60. GetNullableInt(row, columnName)
  61. ?? throw new InvalidOperationException($"OleDb schema row is missing required field {columnName}.");
  62. private static int? GetNullableInt(DataRow row, string columnName)
  63. {
  64. if (!row.Table.Columns.Contains(columnName) || row[columnName] is DBNull)
  65. {
  66. return null;
  67. }
  68. return Convert.ToInt32(row[columnName]);
  69. }
  70. private static bool? GetNullableBool(DataRow row, string columnName)
  71. {
  72. if (!row.Table.Columns.Contains(columnName) || row[columnName] is DBNull)
  73. {
  74. return null;
  75. }
  76. var value = row[columnName];
  77. if (value is bool flag)
  78. {
  79. return flag;
  80. }
  81. var text = Convert.ToString(value);
  82. if (string.Equals(text, "YES", StringComparison.OrdinalIgnoreCase) ||
  83. string.Equals(text, "TRUE", StringComparison.OrdinalIgnoreCase))
  84. {
  85. return true;
  86. }
  87. if (string.Equals(text, "NO", StringComparison.OrdinalIgnoreCase) ||
  88. string.Equals(text, "FALSE", StringComparison.OrdinalIgnoreCase))
  89. {
  90. return false;
  91. }
  92. return null;
  93. }
  94. }

Powered by TurnKey Linux.