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
39 changes: 37 additions & 2 deletions src/EFCore.PG/Infrastructure/Internal/INpgsqlOptions.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,50 @@
using System.Collections.Generic;
#region License

// The PostgreSQL License
//
// Copyright (C) 2016 The Npgsql Development Team
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
// agreement is hereby granted, provided that the above copyright notice
// and this paragraph and the following two paragraphs appear in all copies.
//
// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//
// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

#endregion

using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal
{
/// <summary>
/// Represents options for Npgsql that can only be set at the <see cref="IServiceProvider"/> singleton level.
/// </summary>
public interface INpgsqlOptions : ISingletonOptions
{
/// <summary>
/// Reflects the option set by <see cref="NpgsqlDbContextOptionsBuilder.ReverseNullOrdering" />.
/// True if reverse null ordering is enabled; otherwise, false.
/// </summary>
bool ReverseNullOrderingEnabled { get; }

/// <summary>
/// The collection of database plugins.
/// </summary>
[NotNull]
[ItemNotNull]
IReadOnlyList<NpgsqlEntityFrameworkPlugin> Plugins { get; }
}
}
99 changes: 84 additions & 15 deletions src/EFCore.PG/Infrastructure/Internal/NpgsqlOptionsExtension.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#region License

// The PostgreSQL License
//
// Copyright (C) 2016 The Npgsql Development Team
Expand All @@ -19,6 +20,7 @@
// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

#endregion

using System.Collections.Generic;
Expand All @@ -28,36 +30,76 @@
using Microsoft.Extensions.DependencyInjection;
using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities;

// ReSharper disable once CheckNamespace
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal
{
/// <summary>
/// Represents options managed by the Npgsql.
/// </summary>
public class NpgsqlOptionsExtension : RelationalOptionsExtension
{
/// <summary>
/// The collection of database plugins.
/// </summary>
[NotNull] readonly List<NpgsqlEntityFrameworkPlugin> _plugins;

/// <summary>
/// The name of the database for administrative operations.
/// </summary>
[CanBeNull]
public string AdminDatabase { get; private set; }
public bool? ReverseNullOrdering { get; private set; }
public ProvideClientCertificatesCallback ProvideClientCertificatesCallback { get; private set; }
public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; private set; }

/// <summary>
/// The collection of database plugins.
/// </summary>
[NotNull]
[ItemNotNull]
public IReadOnlyList<NpgsqlEntityFrameworkPlugin> Plugins => _plugins;

readonly List<NpgsqlEntityFrameworkPlugin> _plugins = new List<NpgsqlEntityFrameworkPlugin>();
/// <summary>
/// The specified <see cref="ProvideClientCertificatesCallback"/>.
/// </summary>
[CanBeNull]
public ProvideClientCertificatesCallback ProvideClientCertificatesCallback { get; private set; }

public NpgsqlOptionsExtension() {}
/// <summary>
/// The specified <see cref="RemoteCertificateValidationCallback"/>.
/// </summary>
[CanBeNull]
public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; private set; }

// NB: When adding new options, make sure to update the copy ctor below.
/// <summary>
/// True if reverse null ordering is enabled; otherwise, false.
/// </summary>
public bool ReverseNullOrdering { get; private set; }

public NpgsqlOptionsExtension([NotNull] NpgsqlOptionsExtension copyFrom)
: base(copyFrom)
/// <summary>
/// Initializes an instance of <see cref="NpgsqlOptionsExtension"/> with the default settings.
/// </summary>
public NpgsqlOptionsExtension()
{
_plugins = new List<NpgsqlEntityFrameworkPlugin>();
ReverseNullOrdering = false;
}

// NB: When adding new options, make sure to update the copy ctor below.
/// <summary>
/// Initializes an instance of <see cref="NpgsqlOptionsExtension"/> by copying the specified instance.
/// </summary>
/// <param name="copyFrom">The instance to copy.</param>
public NpgsqlOptionsExtension([NotNull] NpgsqlOptionsExtension copyFrom) : base(copyFrom)
{
AdminDatabase = copyFrom.AdminDatabase;
ReverseNullOrdering = copyFrom.ReverseNullOrdering;
_plugins = new List<NpgsqlEntityFrameworkPlugin>(copyFrom._plugins);
ProvideClientCertificatesCallback = copyFrom.ProvideClientCertificatesCallback;
RemoteCertificateValidationCallback = copyFrom.RemoteCertificateValidationCallback;
_plugins.AddRange(copyFrom._plugins);
ReverseNullOrdering = copyFrom.ReverseNullOrdering;
}

/// <inheritdoc />
[NotNull]
protected override RelationalOptionsExtension Clone() => new NpgsqlOptionsExtension(this);

/// <inheritdoc />
public override bool ApplyServices(IServiceCollection services)
{
Check.NotNull(services, nameof(services));
Expand All @@ -67,16 +109,28 @@ public override bool ApplyServices(IServiceCollection services)
return true;
}

public virtual NpgsqlOptionsExtension WithPlugin(NpgsqlEntityFrameworkPlugin plugin)
/// <summary>
/// Returns a copy of the current instance configured to use the specified <see cref="NpgsqlEntityFrameworkPlugin"/>.
/// </summary>
/// <param name="plugin">The plugin to configure.</param>
[NotNull]
public virtual NpgsqlOptionsExtension WithPlugin([NotNull] NpgsqlEntityFrameworkPlugin plugin)
{
Check.NotNull(plugin, nameof(plugin));

var clone = (NpgsqlOptionsExtension)Clone();

clone._plugins.Add(plugin);

return clone;
}

public virtual NpgsqlOptionsExtension WithAdminDatabase(string adminDatabase)
/// <summary>
/// Returns a copy of the current instance configured to use the specified administrative database.
/// </summary>
/// <param name="adminDatabase">The name of the database for administrative operations.</param>
[NotNull]
public virtual NpgsqlOptionsExtension WithAdminDatabase([CanBeNull] string adminDatabase)
{
var clone = (NpgsqlOptionsExtension)Clone();

Expand All @@ -85,6 +139,11 @@ public virtual NpgsqlOptionsExtension WithAdminDatabase(string adminDatabase)
return clone;
}

/// <summary>
/// Returns a copy of the current instance configured with the specified value..
/// </summary>
/// <param name="reverseNullOrdering">True to enable reverse null ordering; otherwise, false.</param>
[NotNull]
internal virtual NpgsqlOptionsExtension WithReverseNullOrdering(bool reverseNullOrdering)
{
var clone = (NpgsqlOptionsExtension)Clone();
Expand All @@ -96,7 +155,12 @@ internal virtual NpgsqlOptionsExtension WithReverseNullOrdering(bool reverseNull

#region Authentication

public virtual NpgsqlOptionsExtension WithProvideClientCertificatesCallback(ProvideClientCertificatesCallback callback)
/// <summary>
/// Returns a copy of the current instance with the specified <see cref="ProvideClientCertificatesCallback"/>.
/// </summary>
/// <param name="callback">The specified callback.</param>
[NotNull]
public virtual NpgsqlOptionsExtension WithProvideClientCertificatesCallback([CanBeNull] ProvideClientCertificatesCallback callback)
{
var clone = (NpgsqlOptionsExtension)Clone();

Expand All @@ -105,7 +169,12 @@ public virtual NpgsqlOptionsExtension WithProvideClientCertificatesCallback(Prov
return clone;
}

public virtual NpgsqlOptionsExtension WithRemoteCertificateValidationCallback(RemoteCertificateValidationCallback callback)
/// <summary>
/// Returns a copy of the current instance with the specified <see cref="RemoteCertificateValidationCallback"/>.
/// </summary>
/// <param name="callback">The specified callback.</param>
[NotNull]
public virtual NpgsqlOptionsExtension WithRemoteCertificateValidationCallback([CanBeNull] RemoteCertificateValidationCallback callback)
{
var clone = (NpgsqlOptionsExtension)Clone();

Expand Down
64 changes: 48 additions & 16 deletions src/EFCore.PG/Infrastructure/NpgsqlDbContextOptionsBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#region License

// The PostgreSQL License
//
// Copyright (C) 2016 The Npgsql Development Team
Expand All @@ -19,6 +20,7 @@
// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

#endregion

using System;
Expand All @@ -30,65 +32,95 @@
using Microsoft.EntityFrameworkCore.Storage;
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal;

// ReSharper disable once CheckNamespace
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure
{
/// <summary>
/// Allows for options specific to PostgreSQL to be configured for a <see cref="DbContext"/>.
/// </summary>
public class NpgsqlDbContextOptionsBuilder
: RelationalDbContextOptionsBuilder<NpgsqlDbContextOptionsBuilder, NpgsqlOptionsExtension>
{
/// <summary>
/// Initializes a new instance of the <see cref="NpgsqlDbContextOptionsBuilder"/> class.
/// </summary>
/// <param name="optionsBuilder"> The core options builder.</param>
public NpgsqlDbContextOptionsBuilder([NotNull] DbContextOptionsBuilder optionsBuilder)
: base(optionsBuilder)
{
}
: base(optionsBuilder) {}

public virtual void UsePlugin(NpgsqlEntityFrameworkPlugin plugin)
/// <summary>
/// Configures the <see cref="DbContext"/> to use the specified <see cref="NpgsqlEntityFrameworkPlugin"/>.
/// </summary>
/// <param name="plugin">The plugin to configure.</param>
public virtual void UsePlugin([NotNull] NpgsqlEntityFrameworkPlugin plugin)
=> WithOption(e => e.WithPlugin(plugin));

/// <summary>
/// Connect to this database for administrative operations (creating/dropping databases).
/// Defaults to 'postgres'.
/// </summary>
public virtual void UseAdminDatabase(string dbName) => WithOption(e => e.WithAdminDatabase(dbName));
/// <param name="dbName">The name of the database for administrative operations.</param>
public virtual void UseAdminDatabase([CanBeNull] string dbName)
=> WithOption(e => e.WithAdminDatabase(dbName));

/// <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
/// accordingly, and since this isn't done this feature isn't publicly exposed.
/// </summary>
/// <param name="reverseNullOrdering"></param>
/// <param name="reverseNullOrdering">True to enable reverse null ordering; otherwise, false.</param>
internal virtual void ReverseNullOrdering(bool reverseNullOrdering = true)
=> WithOption(e => e.WithReverseNullOrdering(reverseNullOrdering));

#region Authentication

public virtual void ProvideClientCertificatesCallback(ProvideClientCertificatesCallback callback)
/// <summary>
/// Configures the <see cref="DbContext"/> to use the specified <see cref="ProvideClientCertificatesCallback"/>.
/// </summary>
/// <param name="callback">The callback to use.</param>
public virtual void ProvideClientCertificatesCallback([CanBeNull] ProvideClientCertificatesCallback callback)
=> WithOption(e => e.WithProvideClientCertificatesCallback(callback));

public virtual void RemoteCertificateValidationCallback(RemoteCertificateValidationCallback callback)
/// <summary>
/// Configures the <see cref="DbContext"/> to use the specified <see cref="RemoteCertificateValidationCallback"/>.
/// </summary>
/// <param name="callback">The callback to use.</param>
public virtual void RemoteCertificateValidationCallback([CanBeNull] RemoteCertificateValidationCallback callback)
=> WithOption(e => e.WithRemoteCertificateValidationCallback(callback));

#endregion Authentication

#region Retrying execution strategy

/// <summary>
/// Configures the context to use the default retrying <see cref="IExecutionStrategy" />.
/// Configures the context to use the default retrying <see cref="IExecutionStrategy" />.
/// </summary>
/// <returns>
/// An instance of <see cref="NpgsqlDbContextOptionsBuilder"/> configured to use
/// the default retrying <see cref="IExecutionStrategy" />.
/// </returns>
[NotNull]
public virtual NpgsqlDbContextOptionsBuilder EnableRetryOnFailure()
=> ExecutionStrategy(c => new NpgsqlRetryingExecutionStrategy(c));

/// <summary>
/// Configures the context to use the default retrying <see cref="IExecutionStrategy" />.
/// Configures the context to use the default retrying <see cref="IExecutionStrategy" />.
/// </summary>
/// <returns>
/// An instance of <see cref="NpgsqlDbContextOptionsBuilder"/> with the specified parameters.
/// </returns>
[NotNull]
public virtual NpgsqlDbContextOptionsBuilder EnableRetryOnFailure(int maxRetryCount)
=> ExecutionStrategy(c => new NpgsqlRetryingExecutionStrategy(c, maxRetryCount));

/// <summary>
/// Configures the context to use the default retrying <see cref="IExecutionStrategy" />.
/// Configures the context to use the default retrying <see cref="IExecutionStrategy" />.
/// </summary>
/// <param name="maxRetryCount"> The maximum number of retry attempts. </param>
/// <param name="maxRetryDelay"> The maximum delay between retries. </param>
/// <param name="errorCodesToAdd"> Additional error codes that should be considered transient. </param>
/// <param name="maxRetryCount">The maximum number of retry attempts.</param>
/// <param name="maxRetryDelay">The maximum delay between retries.</param>
/// <param name="errorCodesToAdd">Additional error codes that should be considered transient.</param>
/// <returns>
/// An instance of <see cref="NpgsqlDbContextOptionsBuilder"/> with the specified parameters.
/// </returns>
[NotNull]
public virtual NpgsqlDbContextOptionsBuilder EnableRetryOnFailure(
int maxRetryCount,
TimeSpan maxRetryDelay,
Expand Down
Loading