Skip to content

Commit

Permalink
Add ConfigureDataSource() to NpgsqlDbContextOptionsBuilder
Browse files Browse the repository at this point in the history
Closes npgsql#2542
Closes npgsql#2704
  • Loading branch information
roji committed Sep 14, 2024
1 parent b11d279 commit aaae63a
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 46 deletions.
20 changes: 20 additions & 0 deletions src/EFCore.PG/Infrastructure/Internal/NpgsqlOptionsExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ public virtual Version PostgresVersion
public virtual bool IsPostgresVersionSet
=> _postgresVersion is not null;

/// <summary>
/// A lambda to configure Npgsql options on <see cref="NpgsqlDataSourceBuilder" />.
/// </summary>
public virtual Action<NpgsqlDataSourceBuilder>? DataSourceBuilderAction { get; private set; }

/// <summary>
/// The <see cref="DbDataSource" />, or <see langword="null" /> if a connection string or <see cref="DbConnection" /> was used
/// instead of a <see cref="DbDataSource" />.
Expand Down Expand Up @@ -126,6 +131,21 @@ public NpgsqlOptionsExtension(NpgsqlOptionsExtension copyFrom)
public override int? MinBatchSize
=> base.MinBatchSize ?? 2;

/// <summary>
/// Creates a new instance with all options the same as for this instance, but with the given option changed.
/// It is unusual to call this method directly. Instead use <see cref="DbContextOptionsBuilder" />.
/// </summary>
/// <param name="dataSourceBuilderAction">A lambda to configure Npgsql options on <see cref="NpgsqlDataSourceBuilder" />.</param>
/// <returns>A new instance with the option changed.</returns>
public virtual NpgsqlOptionsExtension WithDataSourceConfiguration(Action<NpgsqlDataSourceBuilder> dataSourceBuilderAction)
{
var clone = (NpgsqlOptionsExtension)Clone();

clone.DataSourceBuilderAction = dataSourceBuilderAction;

return clone;
}

/// <summary>
/// Creates a new instance with all options the same as for this instance, but with the given option changed.
/// It is unusual to call this method directly. Instead use <see cref="DbContextOptionsBuilder" />.
Expand Down
24 changes: 20 additions & 4 deletions src/EFCore.PG/Infrastructure/NpgsqlDbContextOptionsBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ public NpgsqlDbContextOptionsBuilder(DbContextOptionsBuilder optionsBuilder)
{
}

/// <summary>
/// Configures lower-level Npgsql options at the ADO.NET driver level.
/// </summary>
/// <param name="dataSourceBuilderAction">A lambda to configure Npgsql options on <see cref="NpgsqlDataSourceBuilder" />.</param>
public virtual NpgsqlDbContextOptionsBuilder ConfigureDataSource(Action<NpgsqlDataSourceBuilder> dataSourceBuilderAction)
=> WithOption(e => e.WithDataSourceConfiguration(dataSourceBuilderAction));

/// <summary>
/// Connect to this database for administrative operations (creating/dropping databases).
/// </summary>
Expand Down Expand Up @@ -48,6 +55,8 @@ public virtual NpgsqlDbContextOptionsBuilder SetPostgresVersion(int major, int m
public virtual NpgsqlDbContextOptionsBuilder UseRedshift(bool useRedshift = true)
=> WithOption(e => e.WithRedshift(useRedshift));

#region MapRange

/// <summary>
/// Maps a user-defined PostgreSQL range type for use.
/// </summary>
Expand Down Expand Up @@ -95,6 +104,10 @@ public virtual NpgsqlDbContextOptionsBuilder MapRange(
string? subtypeName = null)
=> WithOption(e => e.WithUserRangeDefinition(rangeName, schemaName, subtypeClrType, subtypeName));

#endregion MapRange

#region MapEnum

/// <summary>
/// Maps a PostgreSQL enum type for use.
/// </summary>
Expand Down Expand Up @@ -122,6 +135,8 @@ public virtual NpgsqlDbContextOptionsBuilder MapEnum(
INpgsqlNameTranslator? nameTranslator = null)
=> WithOption(e => e.WithEnumMapping(clrType, enumName, schemaName, nameTranslator));

#endregion MapEnum

/// <summary>
/// Appends NULLS FIRST to all ORDER BY clauses. This is important for the tests which were written
/// for SQL Server. Note that to fully implement null-first ordering indexes also need to be generated
Expand All @@ -131,32 +146,33 @@ public virtual NpgsqlDbContextOptionsBuilder MapEnum(
internal virtual NpgsqlDbContextOptionsBuilder ReverseNullOrdering(bool reverseNullOrdering = true)
=> WithOption(e => e.WithReverseNullOrdering(reverseNullOrdering));

#region Authentication
#region Authentication (obsolete)

/// <summary>
/// Configures the <see cref="DbContext" /> to use the specified <see cref="ProvideClientCertificatesCallback" />.
/// </summary>
/// <param name="callback">The callback to use.</param>
[Obsolete("Call ConfigureDataSource() and configure the client certificates on the NpgsqlDataSourceBuilder, or pass an externally-built, pre-configured NpgsqlDataSource to UseNpgsql().")]
public virtual NpgsqlDbContextOptionsBuilder ProvideClientCertificatesCallback(ProvideClientCertificatesCallback? callback)
=> WithOption(e => e.WithProvideClientCertificatesCallback(callback));

/// <summary>
/// Configures the <see cref="DbContext" /> to use the specified <see cref="RemoteCertificateValidationCallback" />.
/// </summary>
/// <param name="callback">The callback to use.</param>
[Obsolete("Call ConfigureDataSource() and configure remote certificate validation on the NpgsqlDataSourceBuilder, or pass an externally-built, pre-configured NpgsqlDataSource to UseNpgsql().")]
public virtual NpgsqlDbContextOptionsBuilder RemoteCertificateValidationCallback(RemoteCertificateValidationCallback? callback)
=> WithOption(e => e.WithRemoteCertificateValidationCallback(callback));

/// <summary>
/// Configures the <see cref="DbContext" /> to use the specified <see cref="ProvidePasswordCallback" />.
/// </summary>
/// <param name="callback">The callback to use.</param>
#pragma warning disable CS0618 // ProvidePasswordCallback is obsolete
[Obsolete("Call ConfigureDataSource() and configure the password callback on the NpgsqlDataSourceBuilder, or pass an externally-built, pre-configured NpgsqlDataSource to UseNpgsql().")]
public virtual NpgsqlDbContextOptionsBuilder ProvidePasswordCallback(ProvidePasswordCallback? callback)
=> WithOption(e => e.WithProvidePasswordCallback(callback));
#pragma warning restore CS0618

#endregion Authentication
#endregion Authentication (obsolete)

#region Retrying execution strategy

Expand Down
5 changes: 5 additions & 0 deletions src/EFCore.PG/Storage/Internal/NpgsqlDataSourceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public NpgsqlDataSourceManager(IEnumerable<INpgsqlDataSourceConfigurationPlugin>
{ ConnectionString: null } or null => null,

// The following are features which require an NpgsqlDataSource, since they require configuration on NpgsqlDataSourceBuilder.
{ DataSourceBuilderAction: not null } => GetSingletonDataSource(npgsqlOptionsExtension),
{ EnumDefinitions.Count: > 0 } => GetSingletonDataSource(npgsqlOptionsExtension),
_ when _plugins.Any() => GetSingletonDataSource(npgsqlOptionsExtension),

Expand Down Expand Up @@ -139,6 +140,10 @@ enumDefinition.StoreTypeSchema is null
dataSourceBuilder.UseUserCertificateValidationCallback(npgsqlOptionsExtension.RemoteCertificateValidationCallback);
}

// Finally, if the user has provided a data source builder configuration action, invoke it.
// Do this last, to allow the user to override anything set above.
npgsqlOptionsExtension.DataSourceBuilderAction?.Invoke(dataSourceBuilder);

return dataSourceBuilder.Build();
}

Expand Down
Loading

0 comments on commit aaae63a

Please sign in to comment.