Skip to content

Commit

Permalink
CSV enumeration and code reusage (#600)
Browse files Browse the repository at this point in the history
* 1900 year DateTime correction

* Rewrite CSV enumeration

* Maximize code reusage

* Reuse OADate correction

* Update to latest version of CodeQL

* Update CodeQL to v3

---------

Co-authored-by: Lukasz Arciszewski <[email protected]>
  • Loading branch information
duszekmestre and Lukasz Arciszewski authored May 19, 2024
1 parent 49bc8e9 commit fdfe883
Show file tree
Hide file tree
Showing 7 changed files with 531 additions and 455 deletions.
16 changes: 16 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[*.{cs,vb}]

# IDE0009: Member access should be qualified.
dotnet_style_qualification_for_event = false

# IDE0009: Member access should be qualified.
dotnet_style_qualification_for_field = false

# IDE0009: Member access should be qualified.
dotnet_style_qualification_for_property = false

# IDE0009: Member access should be qualified.
dotnet_style_qualification_for_method = false

# IDE0065: Misplaced using directive
csharp_using_directive_placement = outside_namespace
6 changes: 3 additions & 3 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
Expand All @@ -53,7 +53,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v3

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
Expand All @@ -67,4 +67,4 @@ jobs:
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v3
172 changes: 84 additions & 88 deletions src/MiniExcel/Csv/CsvWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,97 +42,91 @@ public void SaveAs()
}

var type = _value.GetType();
Type genericType = null;

if (_value is IDataReader)
if (_value is IDataReader dataReader)
{
GenerateSheetByIDataReader(_value, seperator, newLine, _writer);
GenerateSheetByIDataReader(dataReader, seperator, newLine, _writer);
}
else if (_value is IEnumerable)
else if (_value is IEnumerable enumerable)
{
var values = _value as IEnumerable;
List<object> keys = new List<object>();
List<ExcelColumnInfo> props = null;
string mode = null;

// check mode
{
foreach (var item in values) //TODO: need to optimize
{
if (item != null && mode == null)
{
if (item is IDictionary<string, object>)
{
var item2 = item as IDictionary<string, object>;
mode = "IDictionary<string, object>";
foreach (var key in item2.Keys)
keys.Add(key);
}
else if (item is IDictionary)
{
var item2 = item as IDictionary;
mode = "IDictionary";
foreach (var key in item2.Keys)
keys.Add(key);
}
else
{
mode = "Properties";
genericType = item.GetType();
props = CustomPropertyHelper.GetSaveAsProperties(genericType, _configuration);
}

break;
}
}
}
GenerateSheetByIEnumerable(enumerable, seperator, newLine, _writer);
}
else if (_value is DataTable dataTable)
{
GenerateSheetByDataTable(_writer, dataTable, seperator, newLine);
}
else
{
throw new NotImplementedException($"Type {type?.Name} not Implemented. please issue for me.");
}

//if(mode == null)
// throw new NotImplementedException($"Type {type?.Name} & genericType {genericType?.Name} not Implemented. please issue for me.");
this._writer.Flush();
}
}

if (keys.Count == 0 && props == null)
{
_writer.Write(newLine);
this._writer.Flush();
return;
}
private void GenerateSheetByIEnumerable(IEnumerable values, string seperator, string newLine, StreamWriter writer)
{
Type genericType = null;
List<ExcelColumnInfo> props = null;
string mode = null;

if (this._printHeader)
{
if (props != null)
{
_writer.Write(string.Join(seperator, props.Select(s => CsvHelpers.ConvertToCsvValue(s?.ExcelColumnName, _configuration.AlwaysQuote, _configuration.Seperator))));
_writer.Write(newLine);
}
else if (keys.Count > 0)
{
_writer.Write(string.Join(seperator, keys.Select(s => CsvHelpers.ConvertToCsvValue(s.ToString(), _configuration.AlwaysQuote, _configuration.Seperator))));
_writer.Write(newLine);
}
else
{
throw new InvalidOperationException("Please issue for me.");
}
}
var enumerator = values.GetEnumerator();
var empty = !enumerator.MoveNext();
if (empty)
{
// only when empty IEnumerable need to check this issue #133 https://github.com/shps951023/MiniExcel/issues/133
genericType = TypeHelper.GetGenericIEnumerables(values).FirstOrDefault();
if (genericType == null || genericType == typeof(object) // sometime generic type will be object, e.g: https://user-images.githubusercontent.com/12729184/132812859-52984314-44d1-4ee8-9487-2d1da159f1f0.png
|| typeof(IDictionary<string, object>).IsAssignableFrom(genericType)
|| typeof(IDictionary).IsAssignableFrom(genericType)
|| typeof(KeyValuePair<string, object>).IsAssignableFrom(genericType))
{
_writer.Write(newLine);
this._writer.Flush();
return;
}

if (mode == "IDictionary<string, object>") //Dapper Row
GenerateSheetByDapperRow(_writer, _value as IEnumerable, keys.Cast<string>().ToList(), seperator, newLine);
else if (mode == "IDictionary") //IDictionary
GenerateSheetByIDictionary(_writer, _value as IEnumerable, keys, seperator, newLine);
else if (mode == "Properties")
GenerateSheetByProperties(_writer, _value as IEnumerable, props, seperator, newLine);
else
throw new NotImplementedException($"Type {type?.Name} & genericType {genericType?.Name} not Implemented. please issue for me.");
mode = "Properties";
props = CustomPropertyHelper.GetSaveAsProperties(genericType, _configuration);
}
else
{
var firstItem = enumerator.Current;
if (firstItem is IDictionary<string, object> genericDic)
{
mode = "IDictionary<string, object>";
props = CustomPropertyHelper.GetDictionaryColumnInfo(genericDic, null, _configuration);
}
else if (_value is DataTable)
else if (firstItem is IDictionary dic)
{
GenerateSheetByDataTable(_writer, _value as DataTable, seperator, newLine);
mode = "IDictionary";
props = CustomPropertyHelper.GetDictionaryColumnInfo(null, dic, _configuration);
mode = "IDictionary";
}
else
{
throw new NotImplementedException($"Type {type?.Name} & genericType {genericType?.Name} not Implemented. please issue for me.");
mode = "Properties";
genericType = firstItem.GetType();
props = CustomPropertyHelper.GetSaveAsProperties(genericType, _configuration);
}
this._writer.Flush();
}

if (this._printHeader)
{
_writer.Write(string.Join(seperator, props.Select(s => CsvHelpers.ConvertToCsvValue(s?.ExcelColumnName, _configuration.AlwaysQuote, _configuration.Seperator))));
_writer.Write(newLine);
}

if (!empty)
{
if (mode == "IDictionary<string, object>") //Dapper Row
GenerateSheetByDapperRow(_writer, enumerator, props.Select(x => x.Key.ToString()).ToList(), seperator, newLine);
else if (mode == "IDictionary") //IDictionary
GenerateSheetByIDictionary(_writer, enumerator, props.Select(x => x.Key).ToList(), seperator, newLine);
else if (mode == "Properties")
GenerateSheetByProperties(_writer, enumerator, props, seperator, newLine);
else
throw new NotImplementedException($"Mode for genericType {genericType?.Name} not Implemented. please issue for me.");
}
}

Expand Down Expand Up @@ -202,34 +196,37 @@ private void GenerateSheetByDataTable(StreamWriter writer, DataTable dt, string
}
}

private void GenerateSheetByProperties(StreamWriter writer, IEnumerable value, List<ExcelColumnInfo> props, string seperator, string newLine)
private void GenerateSheetByProperties(StreamWriter writer, IEnumerator value, List<ExcelColumnInfo> props, string seperator, string newLine)
{
foreach (var v in value)
do
{
var v = value.Current;
var values = props.Select(s => CsvHelpers.ConvertToCsvValue(ToCsvString(s?.Property.GetValue(v), s), _configuration.AlwaysQuote, _configuration.Seperator));
writer.Write(string.Join(seperator, values));
writer.Write(newLine);
}
} while (value.MoveNext());
}

private void GenerateSheetByIDictionary(StreamWriter writer, IEnumerable value, List<object> keys, string seperator, string newLine)
private void GenerateSheetByIDictionary(StreamWriter writer, IEnumerator value, List<object> keys, string seperator, string newLine)
{
foreach (IDictionary v in value)
do
{
var v = (IDictionary)value.Current;
var values = keys.Select(key => CsvHelpers.ConvertToCsvValue(ToCsvString(v[key], null), _configuration.AlwaysQuote, _configuration.Seperator));
writer.Write(string.Join(seperator, values));
writer.Write(newLine);
}
} while (value.MoveNext());
}

private void GenerateSheetByDapperRow(StreamWriter writer, IEnumerable value, List<string> keys, string seperator, string newLine)
private void GenerateSheetByDapperRow(StreamWriter writer, IEnumerator value, List<string> keys, string seperator, string newLine)
{
foreach (IDictionary<string, object> v in value)
do
{
var v = (IDictionary<string, object>)value.Current;
var values = keys.Select(key => CsvHelpers.ConvertToCsvValue(ToCsvString(v[key], null), _configuration.AlwaysQuote, _configuration.Seperator));
writer.Write(string.Join(seperator, values));
writer.Write(newLine);
}
} while (value.MoveNext());
}

public string ToCsvString(object value, ExcelColumnInfo p)
Expand Down Expand Up @@ -283,5 +280,4 @@ public void Dispose()
GC.SuppressFinalize(this);
}
}

}
}
Loading

0 comments on commit fdfe883

Please sign in to comment.