Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
4 changes: 4 additions & 0 deletions Frends.MicrosoftSQL.ExecuteQueryToFile/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [2.2.0] - 2026-01-14
### Fixed
- Fix unloading assembly
Comment thread
MatteoDelOmbra marked this conversation as resolved.
Outdated

## [2.1.0] - 2024-12-16
### Added
- Added Microsoft.SqlServer.Types dependency so that SqlGeography and SqlGeometry typed objects can be handled.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Definitions;

internal class CsvFileWriter
internal class CsvFileWriter : IAsyncDisposable
{
internal CsvFileWriter(SqlCommand sqlCommand, Input input, CsvOptions options)
{
Expand All @@ -30,31 +30,27 @@ internal CsvFileWriter(SqlCommand sqlCommand, Input input, CsvOptions options)

private CsvOptions Options { get; set; }

public async Task<Result> SaveQueryToCSV(CancellationToken cancellationToken)
public async ValueTask DisposeAsync()
{
var output = 0;
var encoding = GetEncoding(Options.FileEncoding, Options.EnableBom, Options.EncodingInString);

using (var writer = new StreamWriter(Input.OutputFilePath, false, encoding))
using (var csvFile = CreateCsvWriter(Options.GetFieldDelimiterAsString(), writer))
{
writer.NewLine = Options.GetLineBreakAsString();

var reader = await SqlCommand.ExecuteReaderAsync(cancellationToken);
output = DataReaderToCsv(reader, csvFile, Options, cancellationToken);
if (SqlCommand != null) await SqlCommand.DisposeAsync();
}
Comment thread
jefim marked this conversation as resolved.

csvFile.Flush();
}
public async Task<Result> SaveQueryToCsv(CancellationToken cancellationToken)
{
var encoding = GetEncoding(Options.FileEncoding, Options.EnableBom, Options.EncodingInString);
await using var writer = new StreamWriter(Input.OutputFilePath, false, encoding);
await using var csvFile = CreateCsvWriter(Options.GetFieldDelimiterAsString(), writer);
writer.NewLine = Options.GetLineBreakAsString();
var reader = await SqlCommand.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
var output = DataReaderToCsv(reader, csvFile, Options, cancellationToken);
await csvFile.FlushAsync().ConfigureAwait(false);

return new Result(output, Input.OutputFilePath, Path.GetFileName(Input.OutputFilePath));
}
Comment thread
jefim marked this conversation as resolved.

private static CsvWriter CreateCsvWriter(string delimiter, TextWriter writer)
{
var csvOptions = new CsvConfiguration(CultureInfo.InvariantCulture)
{
Delimiter = delimiter,
};
var csvOptions = new CsvConfiguration(CultureInfo.InvariantCulture) { Delimiter = delimiter, };

return new CsvWriter(writer, csvOptions);
}
Expand All @@ -63,10 +59,11 @@ private static string FormatDbHeader(string header, bool forceSpecialFormatting)
{
if (!forceSpecialFormatting) return header;

// First part of regex removes all non-alphanumeric ('_' also allowed) chars from the whole string.
// Second part removed any leading numbers or underscoress.
// The first part of regex removes all non-alphanumeric ('_' also allowed) chars from the whole string.
// The second part removed any leading numbers or underscores.
var rgx = new Regex("[^a-zA-Z0-9_-]|^[0-9_]+");
header = rgx.Replace(header, string.Empty);

return header.ToLower();
}

Expand All @@ -76,6 +73,7 @@ private static string FormatDbValue(object value, string dbTypeName, Type dotnet
{
if (dotnetType == typeof(string)) return "\"\"";
if (dotnetType == typeof(DateTime) && options.AddQuotesToDates) return "\"\"";

return string.Empty;
}

Expand All @@ -87,8 +85,10 @@ private static string FormatDbValue(object value, string dbTypeName, Type dotnet
str = str.Replace("\r\n", " ");
str = str.Replace("\r", " ");
str = str.Replace("\n", " ");

if (options.AddQuotesToStrings)
return $"\"{str}\"";

return str;
}

Expand All @@ -101,7 +101,9 @@ private static string FormatDbValue(object value, string dbTypeName, Type dotnet
"date" => dateTime.ToString(options.DateFormat, CultureInfo.InvariantCulture),
_ => dateTime.ToString(options.DateTimeFormat, CultureInfo.InvariantCulture),
};

if (options.AddQuotesToDates) return $"\"{output}\"";

return output;
}

Expand All @@ -126,8 +128,9 @@ private static int DataReaderToCsv(
CsvOptions options,
CancellationToken cancellationToken)
{
// Write header and remember column indexes to include.
// Write a header and remember column indexes to include it.
var columnIndexesToInclude = new List<int>();

for (var i = 0; i < reader.FieldCount; i++)
{
var columnName = reader.GetName(i);
Expand All @@ -153,6 +156,7 @@ private static int DataReaderToCsv(
if (options.IncludeHeadersInOutput) csvWriter.NextRecord();

int count = 0;

while (reader.Read())
{
foreach (var columnIndex in columnIndexesToInclude)
Expand All @@ -172,7 +176,10 @@ private static int DataReaderToCsv(
return count;
}

private static Encoding GetEncoding(FileEncoding optionsFileEncoding, bool optionsEnableBom, string optionsEncodingInString)
private static Encoding GetEncoding(
FileEncoding optionsFileEncoding,
bool optionsEnableBom,
string optionsEncodingInString)
{
return optionsFileEncoding switch
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Enums;
#pragma warning disable CS1591 // Self-explanatory
/// <summary>
/// File encoding used to encode the file.
/// </summary>
public enum FileEncoding
{
UTF8,
ANSI,
ASCII,
Unicode,
Other,
}
namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Enums;

#pragma warning disable CS1591 // Self-explanatory

/// <summary>
/// File encoding used to encode the file.
/// </summary>
public enum FileEncoding
{
UTF8,
ANSI,
ASCII,
Unicode,
Other,
}

#pragma warning restore CS1591 // Self-explanatory
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Enums;
#pragma warning disable CS1591 // Self-explanatory
/// <summary>
/// Enumeration for output format.
/// </summary>
public enum ReturnFormat
{
CSV,
}
namespace Frends.MicrosoftSQL.ExecuteQueryToFile.Enums;

#pragma warning disable CS1591 // Self-explanatory

/// <summary>
/// Enumeration for output format.
/// </summary>
public enum ReturnFormat
{
CSV,
}

#pragma warning restore CS1591 // Self-explanatory
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
namespace Frends.MicrosoftSQL.ExecuteQueryToFile;

using System;
using System;
using System.ComponentModel;
using System.Data;
using System.Threading;
Expand All @@ -9,6 +7,8 @@
using Frends.MicrosoftSQL.ExecuteQueryToFile.Enums;
using Microsoft.Data.SqlClient;

namespace Frends.MicrosoftSQL.ExecuteQueryToFile;

/// <summary>
/// Main class of the Task.
/// </summary>
Expand All @@ -22,45 +22,49 @@ public static class MicrosoftSQL
/// <param name="options">Options parameters.</param>
/// <param name="cancellationToken">Cancellation token given by Frends.</param>
/// <returns>Object { int EntriesWritten, string Path, string FileName }</returns>
public static async Task<Result> ExecuteQueryToFile([PropertyTab] Input input, [PropertyTab] Options options, CancellationToken cancellationToken)
public static async Task<Result> ExecuteQueryToFile(
[PropertyTab] Input input,
[PropertyTab] Options options,
CancellationToken cancellationToken)
{
Result result = new();
using (var sqlConnection = new SqlConnection(input.ConnectionString))
{
await sqlConnection.OpenAsync(cancellationToken);

using var command = sqlConnection.CreateCommand();
command.CommandTimeout = options.TimeoutSeconds;
command.CommandText = input.Query;
command.CommandType = CommandType.Text;
await using var sqlConnection = new SqlConnection(input.ConnectionString);
await sqlConnection.OpenAsync(cancellationToken).ConfigureAwait(false);

await using var command = sqlConnection.CreateCommand();
command.CommandTimeout = options.TimeoutSeconds;
command.CommandText = input.Query;
command.CommandType = CommandType.Text;

if (input.QueryParameters != null)
if (input.QueryParameters != null)
{
foreach (var parameter in input.QueryParameters)
{
foreach (var parameter in input.QueryParameters)
{
if (parameter.Value is null)
parameter.Value = DBNull.Value;
parameter.Value ??= DBNull.Value;

if (parameter.SqlDataType is SqlDataTypes.Auto)
{
command.Parameters.AddWithValue(parameterName: parameter.Name, value: parameter.Value);
}
else
{
var sqlDbType = (SqlDbType)Enum.Parse(typeof(SqlDbType), parameter.SqlDataType.ToString());
var commandParameter = command.Parameters.Add(parameter.Name, sqlDbType);
commandParameter.Value = parameter.Value;
}
if (parameter.SqlDataType is SqlDataTypes.Auto)
{
command.Parameters.AddWithValue(parameterName: parameter.Name, value: parameter.Value);
}
else
{
var sqlDbType = (SqlDbType)Enum.Parse(typeof(SqlDbType), parameter.SqlDataType.ToString());
var commandParameter = command.Parameters.Add(parameter.Name, sqlDbType);
commandParameter.Value = parameter.Value;
}
}
}

switch (options.ReturnFormat)
{
case ReturnFormat.CSV:
{
await using var csvWriter = new CsvFileWriter(command, input, options.CsvOptions);
result = await csvWriter.SaveQueryToCsv(cancellationToken).ConfigureAwait(false);

switch (options.ReturnFormat)
{
case ReturnFormat.CSV:
var csvWriter = new CsvFileWriter(command, input, options.CsvOptions);
result = await csvWriter.SaveQueryToCSV(cancellationToken);
break;
}
}
}

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>Latest</LangVersion>
<Version>2.1.0</Version>
<Version>2.2.0</Version>
Comment thread
MatteoDelOmbra marked this conversation as resolved.
Outdated
<Authors>Frends</Authors>
<Copyright>Frends</Copyright>
<Company>Frends</Company>
Expand Down
Loading