Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static void CreateIndex(this DatabaseFacade databaseFacade, IIndex index)
{
ArgumentNullException.ThrowIfNull(index);

((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context.GetService<IMongoClientWrapper>().CreateIndex(index);
GetDatabaseCreator(databaseFacade).CreateIndex(index);
}

/// <summary>
Expand All @@ -57,8 +57,7 @@ public static Task CreateIndexAsync(this DatabaseFacade databaseFacade, IIndex i
{
ArgumentNullException.ThrowIfNull(index);

return ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context.GetService<IMongoClientWrapper>()
.CreateIndexAsync(index, cancellationToken);
return GetDatabaseCreator(databaseFacade).CreateIndexAsync(index, cancellationToken);
}

/// <summary>
Expand All @@ -67,21 +66,15 @@ public static Task CreateIndexAsync(this DatabaseFacade databaseFacade, IIndex i
/// </summary>
/// <param name="databaseFacade">The <see cref="DatabaseFacade"/> from the EF Core <see cref="Microsoft.EntityFrameworkCore.DbContext"/>.</param>
public static void CreateMissingIndexes(this DatabaseFacade databaseFacade)
{
var context = ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context;
context.GetService<IMongoClientWrapper>().CreateMissingIndexes(context.GetService<IDesignTimeModel>().Model);
}
=> GetDatabaseCreator(databaseFacade).CreateMissingIndexes();

/// <summary>
/// Creates missing Atlas vector indexes in the MongoDB database for all <see cref="IIndex"/> definitions in the EF Core model for
/// which there is not already an index in the database.
/// </summary>
/// <param name="databaseFacade">The <see cref="DatabaseFacade"/> from the EF Core <see cref="Microsoft.EntityFrameworkCore.DbContext"/>.</param>
public static void CreateMissingVectorIndexes(this DatabaseFacade databaseFacade)
{
var context = ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context;
context.GetService<IMongoClientWrapper>().CreateMissingVectorIndexes(context.GetService<IDesignTimeModel>().Model);
}
=> GetDatabaseCreator(databaseFacade).CreateMissingVectorIndexes();

/// <summary>
/// Creates indexes in the MongoDB database for all <see cref="IIndex"/> definitions in the EF Core model for which there
Expand All @@ -91,10 +84,7 @@ public static void CreateMissingVectorIndexes(this DatabaseFacade databaseFacade
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel this asynchronous request.</param>
/// <returns>A <see cref="Task"/> to track this async operation.</returns>
public static Task CreateMissingIndexesAsync(this DatabaseFacade databaseFacade, CancellationToken cancellationToken = default)
{
var context = ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context;
return context.GetService<IMongoClientWrapper>().CreateMissingIndexesAsync(context.GetService<IDesignTimeModel>().Model, cancellationToken);
}
=> GetDatabaseCreator(databaseFacade).CreateMissingIndexesAsync(cancellationToken);

/// <summary>
/// Creates missing Atlas vector indexes in the MongoDB database for all <see cref="IIndex"/> definitions in the EF Core model for
Expand All @@ -104,10 +94,7 @@ public static Task CreateMissingIndexesAsync(this DatabaseFacade databaseFacade,
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel this asynchronous request.</param>
/// <returns>A <see cref="Task"/> to track this async operation.</returns>
public static Task CreateMissingVectorIndexesAsync(this DatabaseFacade databaseFacade, CancellationToken cancellationToken = default)
{
var context = ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context;
return context.GetService<IMongoClientWrapper>().CreateMissingVectorIndexesAsync(context.GetService<IDesignTimeModel>().Model, cancellationToken);
}
=> GetDatabaseCreator(databaseFacade).CreateMissingVectorIndexesAsync(cancellationToken);

/// <summary>
/// Blocks until all vector indexes in the mapped collections are reporting the 'READY' state.
Expand All @@ -117,10 +104,7 @@ public static Task CreateMissingVectorIndexesAsync(this DatabaseFacade databaseF
/// The default is 15 seconds. Zero seconds means no timeout.</param>
/// <exception cref="InvalidOperationException">if the timeout expires before all indexes are 'READY'.</exception>
public static void WaitForVectorIndexes(this DatabaseFacade databaseFacade, TimeSpan? timeout = null)
{
var context = ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context;
context.GetService<IMongoClientWrapper>().WaitForVectorIndexes(context.GetService<IDesignTimeModel>().Model, timeout);
}
=> GetDatabaseCreator(databaseFacade).WaitForVectorIndexes(timeout);

/// <summary>
/// Blocks until all vector indexes in the mapped collections are reporting the 'READY' state.
Expand All @@ -132,10 +116,7 @@ public static void WaitForVectorIndexes(this DatabaseFacade databaseFacade, Time
/// <returns>A <see cref="Task"/> to track this async operation.</returns>
/// <exception cref="InvalidOperationException">if the timeout expires before all indexes are 'READY'.</exception>
public static Task WaitForVectorIndexesAsync(this DatabaseFacade databaseFacade, TimeSpan? timeout = null, CancellationToken cancellationToken = default)
{
var context = ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context;
return context.GetService<IMongoClientWrapper>().WaitForVectorIndexesAsync(context.GetService<IDesignTimeModel>().Model, timeout, cancellationToken);
}
=> GetDatabaseCreator(databaseFacade).WaitForVectorIndexesAsync(timeout, cancellationToken);

/// <summary>
/// Ensures that the database for the context exists. If it exists, no action is taken. If it does not
Expand All @@ -146,7 +127,7 @@ public static Task WaitForVectorIndexesAsync(this DatabaseFacade databaseFacade,
/// <param name="options">An <see cref="MongoDatabaseCreationOptions"/> object specifying additional actions to be taken.</param>
/// <returns><see langword="true" /> if the database is created, <see langword="false" /> if it already existed.</returns>
public static bool EnsureCreated(this DatabaseFacade databaseFacade, MongoDatabaseCreationOptions options)
=> ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context.GetService<IMongoDatabaseCreator>().EnsureCreated(options);
=> GetDatabaseCreator(databaseFacade).EnsureCreated(options);

/// <summary>
/// Asynchronously ensures that the database for the context exists. If it exists, no action is taken. If it does not
Expand Down Expand Up @@ -188,4 +169,7 @@ public static Task<IDbContextTransaction> BeginTransactionAsync(

private static IMongoTransactionManager GetMongoTransactionManager(DatabaseFacade databaseFacade)
=> (IMongoTransactionManager)((IDatabaseFacadeDependenciesAccessor)databaseFacade).Dependencies.TransactionManager;

private static IMongoDatabaseCreator GetDatabaseCreator(DatabaseFacade databaseFacade)
=> ((IDatabaseFacadeDependenciesAccessor)databaseFacade).Context.GetService<IMongoDatabaseCreator>();
}
157 changes: 15 additions & 142 deletions src/MongoDB.EntityFrameworkCore/Storage/IMongoClientWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Metadata;
using MongoDB.Driver;
using MongoDB.EntityFrameworkCore.Metadata;
using MongoDB.EntityFrameworkCore.Query;

namespace MongoDB.EntityFrameworkCore.Storage;
Expand All @@ -31,6 +29,21 @@ namespace MongoDB.EntityFrameworkCore.Storage;
/// </summary>
public interface IMongoClientWrapper
{
/// <summary>
/// The underlying <see cref="IMongoClient"/>. May cause the underlying client to be created.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably want to put the word "Accessing this" before "May"?

/// </summary>
public IMongoClient Client { get; }

/// <summary>
/// The underlying <see cref="IMongoDatabase"/>. May cause the underlying client to be created.
/// </summary>
public IMongoDatabase Database { get; }

/// <summary>
/// Gets the name of the underlying <see cref="IMongoDatabase"/>. May cause the underlying client to be created.
/// </summary>
public string DatabaseName { get; }

/// <summary>
/// Get an <see cref="IMongoCollection{T}"/> for the given <paramref name="collectionName"/>.
/// </summary>
Expand All @@ -49,146 +62,6 @@ public interface IMongoClientWrapper
/// <returns>An <see cref="IEnumerable{T}"/> containing the items returned by the query.</returns>
IEnumerable<T> Execute<T>(MongoExecutableQuery executableQuery, out Action log);

/// <summary>
/// Create a new database with the name specified in the connection options.
/// </summary>
/// <remarks>If the database already exists only new collections will be created.</remarks>
/// <param name="model">The <see cref="IDesignTimeModel"/> that informs how the database should be created.</param>
/// <returns><see langword="true" /> if the database was created from scratch, <see langword="false" /> if it already existed.</returns>
bool CreateDatabase(IDesignTimeModel model);

/// <summary>
/// Create a new database with the name specified in the connection options.
/// </summary>
/// <remarks>If the database already exists only new collections will be created.</remarks>
/// <param name="model">The <see cref="IDesignTimeModel"/> that informs how the database should be created.</param>
/// <param name="options">An <see cref="MongoDatabaseCreationOptions"/> object specifying additional actions to be taken.</param>
/// <param name="seed">A delegate called to seed the database before any Atlas indexes are created.</param>
/// <returns><see langword="true" /> if the database was created from scratch, <see langword="false" /> if it already existed.</returns>
bool CreateDatabase(IDesignTimeModel model, MongoDatabaseCreationOptions options, Action? seed);

/// <summary>
/// Create a new database with the name specified in the connection options asynchronously.
/// </summary>
/// <remarks>If the database already exists only new collections will be created.</remarks>
/// <param name="model">The <see cref="IDesignTimeModel"/> that informs how the database should be created.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel this asynchronous request.</param>
/// <returns>
/// A <see cref="Task"/> that, when resolved, will be
/// <see langword="true" /> if the database was created from scratch, <see langword="false" /> if it already existed.
/// </returns>
Task<bool> CreateDatabaseAsync(IDesignTimeModel model, CancellationToken cancellationToken = default);

/// <summary>
/// Create a new database with the name specified in the connection options asynchronously.
/// </summary>
/// <remarks>If the database already exists only new collections will be created.</remarks>
/// <param name="model">The <see cref="IDesignTimeModel"/> that informs how the database should be created.</param>
/// <param name="options">An <see cref="MongoDatabaseCreationOptions"/> object specifying additional actions to be taken.</param>
/// <param name="seedAsync">A delegate called to seed the database before any Atlas indexes are created.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel this asynchronous request.</param>
/// <returns>
/// A <see cref="Task"/> that, when resolved, will be
/// <see langword="true" /> if the database was created from scratch, <see langword="false" /> if it already existed.
/// </returns>
Task<bool> CreateDatabaseAsync(IDesignTimeModel model, MongoDatabaseCreationOptions options, Func<CancellationToken, Task>? seedAsync, CancellationToken cancellationToken = default);

/// <summary>
/// Delete the database specified in the connection options.
/// </summary>
/// <returns><see langword="true" /> if the database was deleted, <see langword="false" /> if it did not exist.</returns>
bool DeleteDatabase();

/// <summary>
/// Delete the database specified in the connection options asynchronously.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel this asynchronous request.</param>
/// <returns>
/// A <see cref="Task"/> that, when resolved, will be
/// <see langword="true" /> if the database was deleted, <see langword="false" /> if it already existed.
/// </returns>
Task<bool> DeleteDatabaseAsync(CancellationToken cancellationToken = default);

/// <summary>
/// Determine if the database already exists or not.
/// </summary>
/// <returns><see langword="true" /> if the database exists, <see langword="false" /> if it does not.</returns>
bool DatabaseExists();

/// <summary>
/// Determine if the database already exists or not asynchronously.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel this asynchronous request.</param>
/// <returns>
/// A <see cref="Task"/> that, when resolved, will be
/// <see langword="true" /> if the database exists, <see langword="false" /> if it does not.
/// </returns>
Task<bool> DatabaseExistsAsync(CancellationToken cancellationToken = default);

/// <summary>
/// Creates an index in MongoDB based on the EF Core <see cref="IIndex"/> definition. No attempt is made to check that the index
/// does not already exist and can therefore be created. The index may be an Atlas index or a normal MongoDB index.
/// </summary>
/// <param name="index">The <see cref="IIndex"/> definition.</param>
void CreateIndex(IIndex index);

/// <summary>
/// Creates an index in MongoDB based on the EF Core <see cref="IIndex"/> definition. No attempt is made to check that the index
/// does not already exist and can therefore be created. The index may be an Atlas index or a normal MongoDB index.
/// </summary>
/// <param name="index">The <see cref="IIndex"/> definition.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel this asynchronous request.</param>
/// <returns>A <see cref="Task"/> to track this async operation.</returns>
Task CreateIndexAsync(IIndex index, CancellationToken cancellationToken = default);

/// <summary>
/// Creates any non-Atlas MongoDB indexes defined in the EF Core model that do not already exist.
/// </summary>
/// <param name="model">The EF Core <see cref="IModel"/>.</param>
void CreateMissingIndexes(IModel model);

/// <summary>
/// Creates any non-Atlas MongoDB indexes defined in the EF Core model that do not already exist.
/// </summary>
/// <param name="model">The EF Core <see cref="IModel"/>.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel this asynchronous request.</param>
/// <returns>A <see cref="Task"/> to track this async operation.</returns>
Task CreateMissingIndexesAsync(IModel model, CancellationToken cancellationToken = default);

/// <summary>
/// Creates any MongoDB Atlas vector indexes defined in the EF Core model that do not already exist.
/// </summary>
/// <param name="model">The EF Core <see cref="IModel"/>.</param>
void CreateMissingVectorIndexes(IModel model);

/// <summary>
/// Creates any MongoDB Atlas vector indexes defined in the EF Core model that do not already exist.
/// </summary>
/// <param name="model">The EF Core <see cref="IModel"/>.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel this asynchronous request.</param>
/// <returns>A <see cref="Task"/> to track this async operation.</returns>
Task CreateMissingVectorIndexesAsync(IModel model, CancellationToken cancellationToken = default);

/// <summary>
/// Blocks until all vector indexes in the mapped collections are reporting the 'READY' state.
/// </summary>
/// <param name="model">The EF Core <see cref="IModel"/></param>
/// <param name="timeout">The minimum amount of time to wait for all indexes to be 'READY' before aborting.
/// The default is 15 seconds. Zero seconds means no timeout.</param>
/// <exception cref="InvalidOperationException">if the timeout expires before all indexes are 'READY'.</exception>
void WaitForVectorIndexes(IModel model, TimeSpan? timeout = null);

/// <summary>
/// Blocks until all vector indexes in the mapped collections are reporting the 'READY' state.
/// </summary>
/// <param name="model">The EF Core <see cref="IModel"/></param>
/// <param name="timeout">The minimum amount of time to wait for all indexes to be 'READY' before aborting.
/// The default is 15 seconds. Zero seconds means no timeout.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel this asynchronous request.</param>
/// <returns>A <see cref="Task"/> to track this async operation.</returns>
/// <exception cref="InvalidOperationException">if the timeout expires before all indexes are 'READY'.</exception>
Task WaitForVectorIndexesAsync(IModel model, TimeSpan? timeout = null, CancellationToken cancellationToken = default);

/// <summary>
/// Start a new client session.
/// </summary>
Expand Down
Loading
Loading