Skip to content

Commit

Permalink
feat(connection): reuse one connection for better performance
Browse files Browse the repository at this point in the history
  • Loading branch information
JonasSchubert committed Jan 26, 2024
1 parent 1adb86c commit ce21000
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 39 deletions.
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,52 @@ public class ExamplesRepository : IExamplesRepository
}
```

You can also reuse a snowflake database connection:

```c#
using System.Data;
using System.Threading;
using System.Threading.Tasks;
using Snowflake.Data.Client;
using Snowflake.Data.Xt;

namespace SnowflakeApplication;

public class ExamplesRepository : IExamplesRepository
{
public async Task<Owner> GetByAddressAsync(string address, CancellationToken cancellationToken = default)
{
// Setup of the snowflake database connection
using var snowflakeDbConnection = new SnowflakeDbConnection
{
ConnectionString = EnvironmentExtensions.GetSnowflakeConnectionString(),
};

// If you do not open the connection here, the first command which will run, will open it for you
await snowflakeDbConnection
.OpenAsync(cancellationToken)
.ConfigureAwait(false);

var example = new SnowflakeDbCommand<Example>(snowflakeDbConnection) // Provide the snowflake database connection in the constructor
.Where(item => item.Address == address)
.FirstOrDefaultAsync([], cancellationToken)
.ConfigureAwait(false);

var owner = new SnowflakeDbCommand<Owner>(snowflakeDbConnection) // Provide the snowflake database connection in the constructor and it will be reused
.Where(item => item.Name == example.OwnerName)
.FirstOrDefaultAsync([], cancellationToken)
.ConfigureAwait(false);

// Do not forget to close the connection
await snowflakeDbConnection
.CloseAsync(cancellationToken)
.ConfigureAwait(false);

return owner;
}
}
```

#### Modifier

You can add multiple modifiers to you command:
Expand Down
33 changes: 25 additions & 8 deletions src/Command/Methods/SnowflakeCommand.FirstOrDefault.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,34 @@ public partial class SnowflakeCommand<T>
/// <returns>The first item if found, otherwise null.</returns>
public T? FirstOrDefault(IList<(string, DbType, object)>? parameterList = default)
{
this.WriteLogInformation("Performing snowflake command to retrieve one entity (FirstOrDefault).");
if (this.snowflakeDbConnection is null)
{
using var dbConnection = new SnowflakeDbConnection
{
ConnectionString = EnvironmentExtensions.GetSnowflakeConnectionString(),
};
dbConnection.Open();

var item = this.FirstOrDefault(dbConnection, parameterList);

dbConnection.Close();

using var dbConnection = new SnowflakeDbConnection
return item;
}

if (!this.snowflakeDbConnection.IsOpen())
{
ConnectionString = EnvironmentExtensions.GetSnowflakeConnectionString(),
};
dbConnection.Open();
this.snowflakeDbConnection.Open();
}

var command = dbConnection.CreateCommand();
return this.FirstOrDefault(this.snowflakeDbConnection, parameterList);
}

private T? FirstOrDefault(SnowflakeDbConnection snowflakeDbConnection, IList<(string, DbType, object)>? parameterList = default)
{
this.WriteLogInformation("Performing snowflake command to retrieve one entity (FirstOrDefault).");

var command = snowflakeDbConnection.CreateCommand();
this.WriteLogInformation(this.Sql);
command.CommandText = this.Sql;

Expand All @@ -48,8 +67,6 @@ public partial class SnowflakeCommand<T>

this.WriteLogInformation($"Found{(item is not null ? string.Empty : " no")} item for the provided query.");

dbConnection.Close();

return item;
}
}
33 changes: 25 additions & 8 deletions src/Command/Methods/SnowflakeCommand.FirstOrDefaultAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,34 @@ public partial class SnowflakeCommand<T>
/// <returns>The first item if found, otherwise null.</returns>
public async Task<T?> FirstOrDefaultAsync(IList<(string, DbType, object)>? parameterList = default, CancellationToken cancellationToken = default)
{
this.WriteLogInformation("Performing snowflake command to retrieve one entity (FirstOrDefaultAsync).");
if (this.snowflakeDbConnection is null)
{
using var dbConnection = new SnowflakeDbConnection
{
ConnectionString = EnvironmentExtensions.GetSnowflakeConnectionString(),
};
await dbConnection.OpenAsync(cancellationToken).ConfigureAwait(false);

var item = await this.FirstOrDefaultAsync(dbConnection, parameterList, cancellationToken).ConfigureAwait(false);

await dbConnection.CloseAsync(cancellationToken).ConfigureAwait(false);

using var dbConnection = new SnowflakeDbConnection
return item;
}

if (!this.snowflakeDbConnection.IsOpen())
{
ConnectionString = EnvironmentExtensions.GetSnowflakeConnectionString(),
};
await dbConnection.OpenAsync(cancellationToken).ConfigureAwait(false);
await this.snowflakeDbConnection.OpenAsync(cancellationToken).ConfigureAwait(false);
}

var command = dbConnection.CreateCommand();
return await this.FirstOrDefaultAsync(this.snowflakeDbConnection, parameterList, cancellationToken).ConfigureAwait(false);
}

private async Task<T?> FirstOrDefaultAsync(SnowflakeDbConnection snowflakeDbConnection, IList<(string, DbType, object)>? parameterList = default, CancellationToken cancellationToken = default)
{
this.WriteLogInformation("Performing snowflake command to retrieve one entity (FirstOrDefaultAsync).");

var command = snowflakeDbConnection.CreateCommand();
this.WriteLogInformation(this.Sql);
command.CommandText = this.Sql;

Expand All @@ -49,8 +68,6 @@ public partial class SnowflakeCommand<T>

this.WriteLogInformation($"Found{(item is not null ? string.Empty : " no")} item for the provided query.");

await dbConnection.CloseAsync(cancellationToken).ConfigureAwait(false);

return item;
}
}
33 changes: 25 additions & 8 deletions src/Command/Methods/SnowflakeCommand.ToList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,34 @@ public partial class SnowflakeCommand<T>
/// <returns>A list of items.</returns>
public IList<T> ToList(IList<(string, DbType, object)>? parameterList = default)
{
this.WriteLogInformation("Performing snowflake command to retrieve a list of entities (ToList).");
if (this.snowflakeDbConnection is null)
{
using var dbConnection = new SnowflakeDbConnection
{
ConnectionString = EnvironmentExtensions.GetSnowflakeConnectionString(),
};
dbConnection.Open();

var list = this.ToList(dbConnection, parameterList);

dbConnection.Close();

using var dbConnection = new SnowflakeDbConnection
return list;
}

if (!this.snowflakeDbConnection.IsOpen())
{
ConnectionString = EnvironmentExtensions.GetSnowflakeConnectionString(),
};
dbConnection.Open();
this.snowflakeDbConnection.Open();
}

var command = dbConnection.CreateCommand();
return this.ToList(this.snowflakeDbConnection, parameterList);
}

private IList<T> ToList(SnowflakeDbConnection snowflakeDbConnection, IList<(string, DbType, object)>? parameterList = default)
{
this.WriteLogInformation("Performing snowflake command to retrieve a list of entities (ToList).");

var command = snowflakeDbConnection.CreateCommand();
this.WriteLogInformation(this.Sql);
command.CommandText = this.Sql;

Expand All @@ -48,8 +67,6 @@ public IList<T> ToList(IList<(string, DbType, object)>? parameterList = default)

this.WriteLogInformation($"Found {list.Count} items for the provided query.");

dbConnection.Close();

return list;
}
}
33 changes: 25 additions & 8 deletions src/Command/Methods/SnowflakeCommand.ToListAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,34 @@ public partial class SnowflakeCommand<T>
/// <returns>A list of items.</returns>
public async Task<IList<T>> ToListAsync(IList<(string, DbType, object)>? parameterList = default, CancellationToken cancellationToken = default)
{
this.WriteLogInformation("Performing snowflake command to retrieve a list of entities (ToListAsync).");
if (this.snowflakeDbConnection is null)
{
using var dbConnection = new SnowflakeDbConnection
{
ConnectionString = EnvironmentExtensions.GetSnowflakeConnectionString(),
};
await dbConnection.OpenAsync(cancellationToken).ConfigureAwait(false);

var list = await this.ToListAsync(dbConnection, parameterList, cancellationToken).ConfigureAwait(false);

await dbConnection.CloseAsync(cancellationToken).ConfigureAwait(false);

using var dbConnection = new SnowflakeDbConnection
return list;
}

if (!this.snowflakeDbConnection.IsOpen())
{
ConnectionString = EnvironmentExtensions.GetSnowflakeConnectionString(),
};
await dbConnection.OpenAsync(cancellationToken).ConfigureAwait(false);
await this.snowflakeDbConnection.OpenAsync(cancellationToken).ConfigureAwait(false);
}

var command = dbConnection.CreateCommand();
return await this.ToListAsync(this.snowflakeDbConnection, parameterList, cancellationToken).ConfigureAwait(false);
}

private async Task<IList<T>> ToListAsync(SnowflakeDbConnection snowflakeDbConnection, IList<(string, DbType, object)>? parameterList = default, CancellationToken cancellationToken = default)
{
this.WriteLogInformation("Performing snowflake command to retrieve a list of entities (ToListAsync).");

var command = snowflakeDbConnection.CreateCommand();
this.WriteLogInformation(this.Sql);
command.CommandText = this.Sql;

Expand All @@ -49,8 +68,6 @@ public async Task<IList<T>> ToListAsync(IList<(string, DbType, object)>? paramet

this.WriteLogInformation($"Found {list.Count} items for the provided query.");

await dbConnection.CloseAsync(cancellationToken).ConfigureAwait(false);

return list;
}
}
30 changes: 23 additions & 7 deletions src/Command/SnowflakeCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Reflection;
using System.Text;
using log4net;
using Snowflake.Data.Client;

namespace Snowflake.Data.Xt;

Expand All @@ -30,6 +31,11 @@ public partial class SnowflakeCommand<T>
protected static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod()?.DeclaringType);
#pragma warning restore CA2211, MA0069, SA1306, SA1401

/// <summary>
/// The snowflake database connection.
/// </summary>
private readonly SnowflakeDbConnection? snowflakeDbConnection;

/// <summary>
/// Initializes a new instance of the <see cref="SnowflakeCommand{T}"/> class.
/// </summary>
Expand All @@ -38,8 +44,9 @@ public SnowflakeCommand()
: this(
#pragma warning disable MA0015 // Specify the parameter name in ArgumentException
Environment.GetEnvironmentVariable("SNOWFLAKE_DATABASE") ?? throw new ArgumentNullException("SNOWFLAKE_DATABASE"),
Environment.GetEnvironmentVariable("SNOWFLAKE_SCHEMA") ?? throw new ArgumentNullException("SNOWFLAKE_SCHEMA"))
Environment.GetEnvironmentVariable("SNOWFLAKE_SCHEMA") ?? throw new ArgumentNullException("SNOWFLAKE_SCHEMA"),
#pragma warning restore MA0015 // Specify the parameter name in ArgumentException
snowflakeDbConnection: null)
{
}

Expand All @@ -49,7 +56,20 @@ public SnowflakeCommand()
/// <param name="database">The database.</param>
/// <param name="schema">The schema.</param>
public SnowflakeCommand(string database, string schema)
: this(database, schema, snowflakeDbConnection: null)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="SnowflakeCommand{T}"/> class.
/// </summary>
/// <param name="database">The database.</param>
/// <param name="schema">The schema.</param>
/// <param name="snowflakeDbConnection">The snowflake database connection.</param>
public SnowflakeCommand(string database, string schema, SnowflakeDbConnection? snowflakeDbConnection)
{
this.snowflakeDbConnection = snowflakeDbConnection;

this.SqlBuilder = new StringBuilder("SELECT ");

this.Properties = typeof(T)
Expand All @@ -58,10 +78,7 @@ public SnowflakeCommand(string database, string schema)
.Select(propertyInfo =>
{
var attribute = (SnowflakeColumnAttribute)propertyInfo.GetCustomAttributes(typeof(SnowflakeColumnAttribute), inherit: true).Single();
if (string.IsNullOrWhiteSpace(attribute.Name))
{
attribute.Name = propertyInfo.Name;
}
attribute.Name = string.IsNullOrWhiteSpace(attribute.Name) ? propertyInfo.Name : attribute.Name;

return (propertyInfo, attribute);
})
Expand Down Expand Up @@ -96,12 +113,11 @@ public SnowflakeCommand(string database, string schema)
this.ValidProperties = this.Properties
.Select(property =>
{
var propertyName = property.Value.Name;
var propertyTableAlias = string.IsNullOrWhiteSpace(property.Value.Table)
? this.Table.Alias
: this.Joins.Single(join => string.Equals(join.Table, property.Value.Table, StringComparison.Ordinal)).Alias;

return $"{propertyTableAlias}.{propertyName}";
return $"{propertyTableAlias}.{property.Value.Name}";
})
.ToList();
this.ValidPropertiesRegex = new Regex($"^({string.Join('|', this.ValidProperties)})$", RegexOptions.None, TimeSpan.FromSeconds(3));
Expand Down

0 comments on commit ce21000

Please sign in to comment.