PageRenderTime 386ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/Sources/DataAccess/DataTable.cs

https://github.com/tpwalke2/DataTable
C# | 129 lines | 66 code | 13 blank | 50 comment | 6 complexity | 2773e2b04d6cea6b8d59178443dcdc61 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.IO;
  5. using System.Diagnostics;
  6. using System.Text.RegularExpressions;
  7. using System.Linq;
  8. namespace DataAccess
  9. {
  10. /// <summary>
  11. /// Represents a table of data.
  12. /// This is primary an IEnumerable{Row} collection.
  13. /// The table may be just read-only streaming over the rows, which is ideal for large files of millions of rows.
  14. /// Or it may have loaded the entire table into memory, which can be ideal for mutation.
  15. /// </summary>
  16. public abstract class DataTable
  17. {
  18. /// <summary>
  19. /// Name of this data table. The semantics of the name are determined by the function that
  20. /// creates the table. Name can also be empty.
  21. /// It could be a filename, an excel sheet name, a URL, or even a human readable description
  22. /// of how the table was created.
  23. /// Name is primarily a debugging tool. You can't programaticaly rely on the name property unless you created the table.
  24. /// </summary>
  25. public string Name { get; set; }
  26. /// <summary>
  27. /// Name of columns in the table. Columns should be case-insensitive.
  28. /// If this is a mutable table, columns may be added, removed, or reordered.
  29. /// </summary>
  30. public abstract IEnumerable<string> ColumnNames { get; }
  31. /// <summary>
  32. /// Enumeration of rows in the table.
  33. /// Each row has a (possibly empty) value for each column.
  34. /// </summary>
  35. public abstract IEnumerable<Row> Rows { get; }
  36. /// <summary>
  37. /// Enumeration of rows as strongly types. The default implementation here is
  38. /// to just to parse the results of <see cref="Rows"/>.
  39. /// </summary>
  40. /// <typeparam name="T">Target object type to parse.</typeparam>
  41. /// <returns>enumeration of rows as strongly typed object</returns>
  42. public virtual IEnumerable<T> RowsAs<T>() where T : class, new()
  43. {
  44. Func<Row, T> parser;
  45. // Get cached version of the function.
  46. // This is optimized assuming that all reads are for the same schema.
  47. // This code should be thread safe.
  48. {
  49. parser = _parserFunc as Func<Row, T>;
  50. if (parser == null)
  51. {
  52. parser = StrongTypeBinder.BuildMethod<T>(this.ColumnNames);
  53. _parserFunc = parser;
  54. }
  55. }
  56. // Use the local parser function, not the field, in case the field is switched on us by another thread.
  57. var result = from row in Rows select parser(row);
  58. return result;
  59. }
  60. // Cache the parser function.
  61. private object _parserFunc;
  62. private readonly static DataTableBuilder _builder = new DataTableBuilder();
  63. /// <summary>
  64. /// Provides access to extension methods for creating a table. Tables can be created in many ways, such as reading CSV files,
  65. /// building around .NET objects, filtering existing tables, etc.
  66. /// </summary>
  67. public static DataTableBuilder New
  68. {
  69. get { return _builder; }
  70. }
  71. /// <summary>
  72. /// Return true if the table has the given column name. Comparison is case insensitive.
  73. /// </summary>
  74. /// <param name="name">name of column to look for.</param>
  75. /// <returns>true iff the column is present. False if name is null.</returns>
  76. public bool HasColumnName(string name)
  77. {
  78. if (name == null)
  79. return false;
  80. foreach (var c in this.ColumnNames)
  81. {
  82. if (string.Compare(name, c, true) == 0)
  83. {
  84. return true;
  85. }
  86. }
  87. return false;
  88. }
  89. /// <summary>
  90. /// Save the table to the given stream, using a CSV format. The first line will be the headers, and then each subsequent line will be a row.
  91. /// This will escape characters as needed.
  92. /// </summary>
  93. /// <param name="output">textwrite to write out to.</param>
  94. public virtual void SaveToStream(TextWriter output)
  95. {
  96. using (var writer = new CsvWriter(output, this.ColumnNames))
  97. {
  98. foreach (var row in this.Rows)
  99. {
  100. writer.WriteRow(row);
  101. }
  102. }
  103. }
  104. /// <summary>
  105. /// Save the table as a CSV to the given filename
  106. /// </summary>
  107. /// <param name="outputFilename">filename on disk to save to.</param>
  108. public void SaveCSV(string outputFilename)
  109. {
  110. using (StreamWriter sw = new StreamWriter(outputFilename))
  111. {
  112. SaveToStream(sw);
  113. }
  114. }
  115. }
  116. }