Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/MiniExcel/OpenXml/Constants/WorksheetXml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ internal class WorksheetXml
internal const string StartWorksheetWithRelationship = @"<?xml version=""1.0"" encoding=""utf-8""?><x:worksheet xmlns:r=""http://schemas.openxmlformats.org/officeDocument/2006/relationships"" xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"" >";
internal const string EndWorksheet = "</x:worksheet>";

internal const string StartDimension = @"<x:dimension ref=""";
internal const string StartDimension = "<x:dimension ref=\"";
internal const string DimensionPlaceholder = " />";
internal static string Dimension(string dimensionRef)
=> $"{StartDimension}{dimensionRef}\"/>";
internal static string Dimension(string dimensionRef) => $"{StartDimension}{dimensionRef}\" />";

internal const string StartSheetViews = "<x:sheetViews>";
internal const string EndSheetViews = "</x:sheetViews>";
Expand Down
37 changes: 25 additions & 12 deletions src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,36 @@ private async Task WriteEmptySheetAsync(MiniExcelAsyncStreamWriter writer)
await writer.WriteAsync(ExcelXml.EmptySheetXml);
}

private async Task<long> WriteDimensionPlaceholderAsync(MiniExcelAsyncStreamWriter writer)
{
var dimensionPlaceholderPostition = await writer.WriteAndFlushAsync(WorksheetXml.StartDimension);
await writer.WriteAsync(WorksheetXml.DimensionPlaceholder); // end of code will be replaced

return dimensionPlaceholderPostition;
}

private async Task WriteDimensionAsync(MiniExcelAsyncStreamWriter writer, int maxRowIndex, int maxColumnIndex, long placeholderPosition)
{
// Flush and save position so that we can get back again.
var position = await writer.FlushAsync();

writer.SetPosition(placeholderPosition);
await writer.WriteAndFlushAsync($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}""");

writer.SetPosition(position);
}

private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter writer, IDataReader reader)
{
long dimensionWritePosition = 0;
long dimensionPlaceholderPostition = 0;
await writer.WriteAsync(WorksheetXml.StartWorksheet);
var yIndex = 1;
int maxColumnIndex;
int maxRowIndex;
{
if (_configuration.FastMode)
{
dimensionWritePosition = await writer.WriteAndFlushAsync(WorksheetXml.StartDimension);
await writer.WriteAsync(WorksheetXml.DimensionPlaceholder); // end of code will be replaced
dimensionPlaceholderPostition = await WriteDimensionPlaceholderAsync(writer);
}

var props = new List<ExcelColumnInfo>();
Expand Down Expand Up @@ -139,8 +157,7 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr

if (_configuration.FastMode)
{
writer.SetPosition(dimensionWritePosition);
await writer.WriteAndFlushAsync($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}""");
await WriteDimensionAsync(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPostition);
}
}

Expand Down Expand Up @@ -210,14 +227,12 @@ private async Task GenerateSheetByEnumerableAsync(MiniExcelAsyncStreamWriter wri

await writer.WriteAsync(WorksheetXml.StartWorksheetWithRelationship);

long dimensionWritePosition = 0;
long dimensionPlaceholderPostition = 0;

// We can write the dimensions directly if the row count is known
if (_configuration.FastMode && rowCount == null)
{
// Write a placeholder for the table dimensions and save thee position for later
dimensionWritePosition = await writer.WriteAndFlushAsync(WorksheetXml.StartDimension);
await writer.WriteAsync(WorksheetXml.DimensionPlaceholder);
dimensionPlaceholderPostition = await WriteDimensionPlaceholderAsync(writer);
}
else
{
Expand Down Expand Up @@ -269,9 +284,7 @@ private async Task GenerateSheetByEnumerableAsync(MiniExcelAsyncStreamWriter wri
// The dimension has already been written if row count is defined
if (_configuration.FastMode && rowCount == null)
{
// Seek back and write the dimensions of the table
writer.SetPosition(dimensionWritePosition);
await writer.WriteAndFlushAsync($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}""");
await WriteDimensionAsync(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPostition);
}
}

Expand Down
38 changes: 25 additions & 13 deletions src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,36 @@ private void WriteEmptySheet(MiniExcelStreamWriter writer)
writer.Write(ExcelXml.EmptySheetXml);
}

private long WriteDimensionPlaceholder(MiniExcelStreamWriter writer)
{
var dimensionPlaceholderPostition = writer.WriteAndFlush(WorksheetXml.StartDimension);
writer.Write(WorksheetXml.DimensionPlaceholder); // end of code will be replaced

return dimensionPlaceholderPostition;
}

private void WriteDimension(MiniExcelStreamWriter writer, int maxRowIndex, int maxColumnIndex, long placeholderPosition)
{
// Flush and save position so that we can get back again.
var position = writer.Flush();

writer.SetPosition(placeholderPosition);
writer.WriteAndFlush($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}""");

writer.SetPosition(position);
}

private void GenerateSheetByIDataReader(MiniExcelStreamWriter writer, IDataReader reader)
{
long dimensionWritePosition = 0;
long dimensionPlaceholderPosition = 0;
writer.Write(WorksheetXml.StartWorksheet);
var yIndex = 1;
int maxColumnIndex;
int maxRowIndex;
{

if (_configuration.FastMode)
{
dimensionWritePosition = writer.WriteAndFlush(WorksheetXml.StartDimension);
writer.Write(WorksheetXml.DimensionPlaceholder); // end of code will be replaced
dimensionPlaceholderPosition = WriteDimensionPlaceholder(writer);
}

var props = new List<ExcelColumnInfo>();
Expand Down Expand Up @@ -177,8 +194,7 @@ private void GenerateSheetByIDataReader(MiniExcelStreamWriter writer, IDataReade

if (_configuration.FastMode)
{
writer.SetPosition(dimensionWritePosition);
writer.WriteAndFlush($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}""");
WriteDimension(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPosition);
}
}

Expand Down Expand Up @@ -248,14 +264,12 @@ private void GenerateSheetByEnumerable(MiniExcelStreamWriter writer, IEnumerable

writer.Write(WorksheetXml.StartWorksheetWithRelationship);

long dimensionWritePosition = 0;
long dimensionPlaceholderPostition = 0;

// We can write the dimensions directly if the row count is known
if (_configuration.FastMode && rowCount == null)
{
// Write a placeholder for the table dimensions and save thee position for later
dimensionWritePosition = writer.WriteAndFlush(WorksheetXml.StartDimension);
writer.Write(WorksheetXml.DimensionPlaceholder);
dimensionPlaceholderPostition = WriteDimensionPlaceholder(writer);
}
else
{
Expand Down Expand Up @@ -310,9 +324,7 @@ private void GenerateSheetByEnumerable(MiniExcelStreamWriter writer, IEnumerable
// The dimension has already been written if row count is defined
if (_configuration.FastMode && rowCount == null)
{
// Seek back and write the dimensions of the table
writer.SetPosition(dimensionWritePosition);
writer.WriteAndFlush($@"{GetDimensionRef(maxRowIndex, maxColumnIndex)}""");
WriteDimension(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPostition);
}
}

Expand Down
77 changes: 77 additions & 0 deletions tests/MiniExcelTests/MiniExcelIssueTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3734,5 +3734,82 @@ public void Issue632_1()
MiniExcel.SaveAs( path, values, excelType: ExcelType.XLSX, configuration: config, overwriteFile: true );

}

private class Issue658TestData
{
public string FirstName { get; set; }
public string LastName { get; set; }
}

/// <summary>
/// https://github.com/mini-software/MiniExcel/issues/658
/// </summary>
[Fact]
public void Issue_658()
{
static IEnumerable<Issue658TestData> GetTestData()
{
yield return new() { FirstName = "Unit", LastName = "Test" };
yield return new() { FirstName = "Unit1", LastName = "Test1" };
yield return new() { FirstName = "Unit2", LastName = "Test2" };
}

using var memoryStream = new MemoryStream();
var testData = GetTestData();
memoryStream.SaveAs(testData, configuration: new OpenXmlConfiguration
{
FastMode = true,
});

memoryStream.Position = 0;

var queryData = memoryStream.Query<Issue658TestData>().ToList();

Assert.Equal(testData.Count(), queryData.Count);

var i = 0;
foreach (var data in testData)
{
Assert.Equal(data.FirstName, queryData[i].FirstName);
Assert.Equal(data.LastName, queryData[i].LastName);
i++;
}
}

/// <summary>
/// https://github.com/mini-software/MiniExcel/issues/658
/// </summary>
/// <returns></returns>
[Fact]
public async Task Issue_658_async()
{
static IEnumerable<Issue658TestData> GetTestData()
{
yield return new() { FirstName = "Unit", LastName = "Test" };
yield return new() { FirstName = "Unit1", LastName = "Test1" };
yield return new() { FirstName = "Unit2", LastName = "Test2" };
}

using var memoryStream = new MemoryStream();
var testData = GetTestData();
await memoryStream.SaveAsAsync(testData, configuration: new OpenXmlConfiguration
{
FastMode = true,
});

memoryStream.Position = 0;

var queryData = (await memoryStream.QueryAsync<Issue658TestData>()).ToList();

Assert.Equal(testData.Count(), queryData.Count);

var i = 0;
foreach (var data in testData)
{
Assert.Equal(data.FirstName, queryData[i].FirstName);
Assert.Equal(data.LastName, queryData[i].LastName);
i++;
}
}
}
}