Skip to content

Commit

Permalink
Based on the answer from Npgsql team it seems that's safe to use Npgs…
Browse files Browse the repository at this point in the history
…qlDataSource all ahead, so applied that Postgres Database management
  • Loading branch information
oskardudycz committed Dec 8, 2023
1 parent 9a07569 commit d8dd57f
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 59 deletions.
3 changes: 2 additions & 1 deletion src/Weasel.CommandLine.Tests/NamedTable.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using JasperFx.Core;
using Npgsql;
using Weasel.Core;
using Weasel.Core.Migrations;
using Weasel.Postgresql;
Expand Down Expand Up @@ -39,7 +40,7 @@ protected override IEnumerable<ISchemaObject> schemaObjects()
public class DatabaseWithTables: PostgresqlDatabase
{
public DatabaseWithTables(AutoCreate autoCreate, string identifier) :
base(new DefaultMigrationLogger(), autoCreate, new PostgresqlMigrator(), identifier, ConnectionSource.ConnectionString)
base(new DefaultMigrationLogger(), autoCreate, new PostgresqlMigrator(), identifier, new NpgsqlDataSourceBuilder(ConnectionSource.ConnectionString).Build())
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System;
using Shouldly;
using Weasel.Core;
using Weasel.Postgresql.Connections;

namespace Weasel.Postgresql.Tests.Migrations;

Expand Down Expand Up @@ -35,13 +36,13 @@ public async Task can_build_databases_once()

public class Databases: SingleServerDatabaseCollection<DatabaseWithTables>
{
public Databases() : base(ConnectionSource.ConnectionString)
public Databases() : base(new DefaultNpgsqlDataSourceFactory(), ConnectionSource.ConnectionString)
{
}

protected override DatabaseWithTables buildDatabase(string databaseName, string connectionString)
protected override DatabaseWithTables buildDatabase(string databaseName, NpgsqlDataSource dataSource)
{
return new DatabaseWithTables(databaseName, connectionString);
return new DatabaseWithTables(databaseName, dataSource);
}
}
}
Expand Down
23 changes: 9 additions & 14 deletions src/Weasel.Postgresql.Tests/Migrations/migration_scenario_tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class SchemaMigrationTests : IntegrationContext, IAsyncLifetime

public SchemaMigrationTests() : base("migrations")
{
theDatabase = new DatabaseWithTables(AutoCreate.None, "Migrations");
theDatabase = new DatabaseWithTables(AutoCreate.None, "Migrations", theDataSource);
}

public override Task InitializeAsync()
Expand Down Expand Up @@ -154,31 +154,26 @@ public class DatabaseWithTables: PostgresqlDatabase
public static DatabaseWithTables ForDataSource(NpgsqlDataSource dataSource)
{
var builder = new NpgsqlConnectionStringBuilder(dataSource.ConnectionString);
var identifier = builder.Database;
var identifier = builder.Database!;

return new DatabaseWithTables(identifier, dataSource);
}

public static DatabaseWithTables ForConnectionString(string connectionString)
{
var builder = new NpgsqlConnectionStringBuilder(connectionString);
var identifier = builder.Database;
var builder = new NpgsqlDataSourceBuilder(connectionString);
var identifier = builder.ConnectionStringBuilder.Database!;

return new DatabaseWithTables(identifier, connectionString);
return new DatabaseWithTables(identifier, builder.Build());
}

public DatabaseWithTables(AutoCreate autoCreate, string identifier)
: base(new DefaultMigrationLogger(), autoCreate, new PostgresqlMigrator(), identifier, ConnectionSource.ConnectionString)
{
}

public DatabaseWithTables(string identifier, string connectionString)
: base(new DefaultMigrationLogger(), AutoCreate.All, new PostgresqlMigrator(), identifier, connectionString)
public DatabaseWithTables(string identifier, NpgsqlDataSource dataSource)
: base(new DefaultMigrationLogger(), AutoCreate.All, new PostgresqlMigrator(), identifier, dataSource)
{
}

public DatabaseWithTables(string identifier, NpgsqlDataSource dataSource)
: base(new DefaultMigrationLogger(), AutoCreate.All, new PostgresqlMigrator(), identifier, dataSource)
public DatabaseWithTables(AutoCreate autoCreate, string identifier, NpgsqlDataSource dataSource)
: base(new DefaultMigrationLogger(), autoCreate, new PostgresqlMigrator(), identifier, dataSource)
{
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using JasperFx.Core;
using Npgsql;

namespace Weasel.Postgresql.Connections;

public class DefaultNpgsqlDataSourceFactory: INpgsqlDataSourceFactory
{
private readonly Cache<string, NpgsqlDataSourceBuilder> builderCache = new();

public DefaultNpgsqlDataSourceFactory(Func<string, NpgsqlDataSourceBuilder> dataSourceBuilderFactory)
{
builderCache.OnMissing = dataSourceBuilderFactory;
}

public DefaultNpgsqlDataSourceFactory(): this(connectionString => new NpgsqlDataSourceBuilder(connectionString))
{
}

public NpgsqlDataSource Create(string connectionString)
{
var builder = builderCache[connectionString];

return builder.Build();
}

public NpgsqlDataSource Create(string masterConnectionString, string databaseName)
{
var connectionString = new NpgsqlConnectionStringBuilder(masterConnectionString) { Database = databaseName }
.ConnectionString;

var builder = builderCache[connectionString];

return builder.Build();
}
}
11 changes: 11 additions & 0 deletions src/Weasel.Postgresql/Connections/INpgsqlDataSourceFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Npgsql;

namespace Weasel.Postgresql.Connections;

public interface INpgsqlDataSourceFactory
{
NpgsqlDataSource Create(string connectionString);


NpgsqlDataSource Create(string masterConnectionString, string databaseName);
}
43 changes: 22 additions & 21 deletions src/Weasel.Postgresql/Migrations/SingleServerDatabaseCollection.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using JasperFx.Core;
using Npgsql;
using Weasel.Core.Migrations;
using Weasel.Postgresql.Connections;

namespace Weasel.Postgresql.Migrations;

Expand All @@ -11,23 +12,25 @@ namespace Weasel.Postgresql.Migrations;
/// <typeparam name="T"></typeparam>
public abstract class SingleServerDatabaseCollection<T> where T : PostgresqlDatabase
{
private readonly NpgsqlDataSource? npgsqlDataSource;
private readonly INpgsqlDataSourceFactory dataSourceFactory;
private readonly NpgsqlDataSource masterDataSource;
private readonly TimedLock _lock = new();
private readonly string _masterConnectionString;
private ImHashMap<string, T> _databases = ImHashMap<string, T>.Empty;
private ImHashMap<string, T> databases = ImHashMap<string, T>.Empty;

protected SingleServerDatabaseCollection(NpgsqlDataSource npgsqlDataSource)
protected SingleServerDatabaseCollection(INpgsqlDataSourceFactory dataSourceFactory,
NpgsqlDataSource masterDataSource)
{
this.npgsqlDataSource = npgsqlDataSource;
_masterConnectionString = npgsqlDataSource.ConnectionString;
this.dataSourceFactory = dataSourceFactory;
this.masterDataSource = masterDataSource;
}

protected SingleServerDatabaseCollection(string masterConnectionString)
protected SingleServerDatabaseCollection(INpgsqlDataSourceFactory dataSourceFactory, string masterConnectionString)
: this(dataSourceFactory, dataSourceFactory.Create(masterConnectionString))
{
_masterConnectionString = masterConnectionString;
}

private DatabaseSpecification Specification { get; } = new();
static
private DatabaseSpecification Specification { get; } = new();

/// <summary>
/// Force the database to be dropped and re-created
Expand All @@ -36,28 +39,26 @@ protected SingleServerDatabaseCollection(string masterConnectionString)

public IReadOnlyList<T> AllDatabases()
{
return _databases.Enumerate().Select(x => x.Value).ToList();
return databases.Enumerate().Select(x => x.Value).ToList();
}

protected abstract T buildDatabase(string databaseName, string connectionString);
protected abstract T buildDatabase(string databaseName, NpgsqlDataSource dataSource);

public virtual async ValueTask<T> FindOrCreateDatabase(string databaseName, CancellationToken ct = default)
{
if (_databases.TryFind(databaseName, out var database))
if (databases.TryFind(databaseName, out var database))
{
return database;
}

using (await _lock.Lock(5.Seconds(), ct).ConfigureAwait(false))
{
if (_databases.TryFind(databaseName, out database))
if (databases.TryFind(databaseName, out database))
{
return database;
}

await using var conn =
npgsqlDataSource?.CreateConnection()
?? new NpgsqlConnection(_masterConnectionString);
await using var conn = masterDataSource.CreateConnection();
await conn.OpenAsync(ct).ConfigureAwait(false);

if (DropAndRecreate)
Expand All @@ -70,12 +71,12 @@ public virtual async ValueTask<T> FindOrCreateDatabase(string databaseName, Canc
await Specification.BuildDatabase(conn, databaseName, ct).ConfigureAwait(false);
}

var builder = new NpgsqlConnectionStringBuilder(_masterConnectionString) { Database = databaseName };
database = buildDatabase(
databaseName,
dataSourceFactory.Create(masterDataSource.ConnectionString, databaseName)
);

var connectionString = builder.ConnectionString;
database = buildDatabase(databaseName, connectionString);

_databases = _databases.AddOrUpdate(databaseName, database);
databases = databases.AddOrUpdate(databaseName, database);

return database;
}
Expand Down
20 changes: 0 additions & 20 deletions src/Weasel.Postgresql/PostgresqlDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,6 @@ namespace Weasel.Postgresql;

public abstract class PostgresqlDatabase: DatabaseBase<NpgsqlConnection>
{
protected PostgresqlDatabase(
IMigrationLogger logger,
AutoCreate autoCreate,
PostgresqlMigrator migrator,
string identifier,
string connectionString
): base(logger, autoCreate, migrator, identifier, connectionString)
{
}

protected PostgresqlDatabase(
IMigrationLogger logger,
AutoCreate autoCreate,
Expand All @@ -27,16 +17,6 @@ NpgsqlDataSource dataSource
{
}

protected PostgresqlDatabase(
IMigrationLogger logger,
AutoCreate autoCreate,
PostgresqlMigrator migrator,
string identifier,
Func<NpgsqlConnection> connectionSource
): base(logger, autoCreate, migrator, identifier, connectionSource)
{
}

public async Task<Function?> DefinitionForFunction(DbObjectName function, CancellationToken ct = default)
{
await using var conn = CreateConnection();
Expand Down

0 comments on commit d8dd57f

Please sign in to comment.