Skip to content

Commit

Permalink
Merging MODM-8
Browse files Browse the repository at this point in the history
  • Loading branch information
tmm360 committed Jul 18, 2020
2 parents 809f62d + 5e3ab4e commit 86fc9fa
Show file tree
Hide file tree
Showing 40 changed files with 925 additions and 127 deletions.
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ dotnet_diagnostic.CA1303.severity = none # Don't need translated exceptions
# CA1707: Identifiers should not contain underscores
dotnet_diagnostic.CA1707.severity = none # I want to use underscore in constants

# CA1812: Avoid uninstantiated internal classes
dotnet_diagnostic.CA1812.severity = none # Doing extensive use of dependency injection

# CA1816: Dispose methods should call SuppressFinalize
dotnet_diagnostic.CA1816.severity = none

Expand Down
4 changes: 3 additions & 1 deletion src/MongODM.AspNetCore/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,15 @@ public static MongODMConfiguration UseMongODM<TProxyGenerator, TTaskRunner, TMod
* the same dbContext different components could have different instances of the same component.
*/
services.TryAddTransient<IDbCache, DbCache>();
services.TryAddTransient<IDbContextDependencies, DbContextDependencies>();
services.TryAddTransient<IDbDependencies, DbDependencies>();
services.TryAddTransient<IDbMaintainer, DbMaintainer>();
services.TryAddTransient<IDbMigrationManager, DbMigrationManager>();
services.TryAddTransient<IDocumentSchemaRegister, DocumentSchemaRegister>();
services.TryAddTransient<IRepositoryRegister, RepositoryRegister>();
services.TryAddSingleton<ISerializerModifierAccessor, SerializerModifierAccessor>();

//tasks
services.TryAddTransient<IMigrateDbContextTask, MigrateDbContextTask>();
services.TryAddTransient<IUpdateDocDependenciesTask, UpdateDocDependenciesTask>();

//castle proxy generator
Expand Down
4 changes: 2 additions & 2 deletions src/MongODM.AspNetCore/StaticConfigurationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

using Etherna.MongODM.Conventions;
using Etherna.MongODM.Operations;
using Etherna.MongODM.Models.Internal;
using Etherna.MongODM.ProxyModels;
using Etherna.MongODM.Utility;
using MongoDB.Bson;
Expand All @@ -34,7 +34,7 @@ public StaticConfigurationBuilder(IProxyGenerator proxyGenerator)

BsonSerializer.RegisterDiscriminatorConvention(typeof(TModelBase),
new HierarchicalProxyTolerantDiscriminatorConvention("_t", proxyGenerator));
BsonSerializer.RegisterDiscriminatorConvention(typeof(OperationBase),
BsonSerializer.RegisterDiscriminatorConvention(typeof(EntityModelBase),
new HierarchicalProxyTolerantDiscriminatorConvention("_t", proxyGenerator));
}
}
Expand Down
90 changes: 39 additions & 51 deletions src/MongODM.Core/DbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

using Etherna.MongODM.Migration;
using Etherna.MongODM.Models;
using Etherna.MongODM.Operations;
using Etherna.MongODM.Operations.ModelMaps;
using Etherna.MongODM.Models.Internal;
using Etherna.MongODM.Models.Internal.ModelMaps;
using Etherna.MongODM.ProxyModels;
using Etherna.MongODM.Repositories;
using Etherna.MongODM.Serialization;
Expand All @@ -39,7 +39,7 @@ public abstract class DbContext : IDbContext

// Constructors and initialization.
public DbContext(
IDbContextDependencies dependencies,
IDbDependencies dependencies,
DbContextOptions options)
{
if (dependencies is null)
Expand All @@ -50,6 +50,7 @@ public DbContext(
ApplicationVersion = options.ApplicationVersion;
DbCache = dependencies.DbCache;
DbMaintainer = dependencies.DbMaintainer;
DbMigrationManager = dependencies.DbMigrationManager;
DbOperations = new CollectionRepository<OperationBase, string>(options.DbOperationsCollectionName);
DocumentSchemaRegister = dependencies.DocumentSchemaRegister;
Identifier = options.Identifier ?? GetType().Name;
Expand All @@ -68,8 +69,9 @@ public DbContext(
Database = Client.GetDatabase(options.DbName);

// Initialize internal dependencies.
DocumentSchemaRegister.Initialize(this);
DbMaintainer.Initialize(this);
DbMigrationManager.Initialize(this);
DocumentSchemaRegister.Initialize(this);
RepositoryRegister.Initialize(this);

// Initialize repositories.
Expand All @@ -78,17 +80,17 @@ public DbContext(

// Register model maps.
//internal maps
new DbMigrationOperationMap().Register(this);
new ModelBaseMap().Register(this);
new OperationBaseMap().Register(this);
new SeedOperationMap().Register(this);

//application maps
foreach (var maps in ModelMapsCollectors)
maps.Register(this);

// Build and freeze document schema register.
DocumentSchemaRegister.Freeze();

// Check for seeding.
SeedIfNeeded();
}

// Public properties.
Expand All @@ -101,35 +103,20 @@ public DbContext(
public IMongoDatabase Database { get; }
public IDbCache DbCache { get; }
public IDbMaintainer DbMaintainer { get; }
public IDbMigrationManager DbMigrationManager { get; }
public ICollectionRepository<OperationBase, string> DbOperations { get; }
public virtual IEnumerable<MongoMigrationBase> DocumentMigrationList { get; } = Array.Empty<MongoMigrationBase>();
public IDocumentSchemaRegister DocumentSchemaRegister { get; }
public string Identifier { get; }
public bool IsMigrating { get; private set; }
public SemanticVersion LibraryVersion { get; }
public IProxyGenerator ProxyGenerator { get; }
public IRepositoryRegister RepositoryRegister { get; }
public ISerializerModifierAccessor SerializerModifierAccessor { get; }

// Protected properties.
protected virtual IEnumerable<MongoMigrationBase> MigrationTaskList { get; } = Array.Empty<MongoMigrationBase>();
protected abstract IEnumerable<IModelMapsCollector> ModelMapsCollectors { get; }

// Methods.
public async Task MigrateRepositoriesAsync(CancellationToken cancellationToken = default)
{
IsMigrating = true;

// Migrate collections.
foreach (var migration in MigrationTaskList)
await migration.MigrateAsync(cancellationToken).ConfigureAwait(false);

// Build indexes.
foreach (var repository in RepositoryRegister.ModelCollectionRepositoryMap.Values)
await repository.BuildIndexesAsync(DocumentSchemaRegister, cancellationToken).ConfigureAwait(false);

IsMigrating = false;
}

public virtual async Task SaveChangesAsync(CancellationToken cancellationToken = default)
{
/*
Expand Down Expand Up @@ -165,45 +152,46 @@ public virtual async Task SaveChangesAsync(CancellationToken cancellationToken =
// Commit updated models replacement.
foreach (var model in ChangedModelsList)
{
var modelType = model.GetType().BaseType;
if (RepositoryRegister.ModelCollectionRepositoryMap.ContainsKey(modelType)) //can't replace if is a file
var modelType = ProxyGenerator.PurgeProxyType(model.GetType());
while (modelType != typeof(object)) //try to find right collection. Can't replace model if it is stored on gridfs
{
var repository = RepositoryRegister.ModelCollectionRepositoryMap[modelType];
await repository.ReplaceAsync(model).ConfigureAwait(false);
if (RepositoryRegister.ModelCollectionRepositoryMap.ContainsKey(modelType))
{
var repository = RepositoryRegister.ModelCollectionRepositoryMap[modelType];
await repository.ReplaceAsync(model).ConfigureAwait(false);
break;
}
else
{
modelType = modelType.BaseType;
}
}
}
}

public Task<IClientSessionHandle> StartSessionAsync(CancellationToken cancellationToken = default) =>
Client.StartSessionAsync(cancellationToken: cancellationToken);

// Protected methods.
protected virtual Task Seed() =>
Task.CompletedTask;

// Helpers.
private void SeedIfNeeded()
public async Task<bool> SeedIfNeededAsync()
{
// Check if already seeded.
var queryTask = DbOperations.QueryElementsAsync(elements =>
elements.OfType<SeedOperation>().AnyAsync(sop => sop.DbContextName == Identifier));
queryTask.ConfigureAwait(false);
queryTask.Wait();

//skip if already seeded
if (queryTask.Result)
return;
if (await DbOperations.QueryElementsAsync(elements =>
elements.OfType<SeedOperation>()
.AnyAsync(sop => sop.DbContextName == Identifier)).ConfigureAwait(false))
return false;

// Seed.
var seedTask = Seed();
seedTask.ConfigureAwait(false);
seedTask.Wait();
await SeedAsync().ConfigureAwait(false);

// Report operation.
var seedOperation = new SeedOperation(this);
var createTask = DbOperations.CreateAsync(seedOperation);
createTask.ConfigureAwait(false);
createTask.Wait();
await DbOperations.CreateAsync(seedOperation).ConfigureAwait(false);

return true;
}

public Task<IClientSessionHandle> StartSessionAsync(CancellationToken cancellationToken = default) =>
Client.StartSessionAsync(cancellationToken: cancellationToken);

// Protected methods.
protected virtual Task SeedAsync() =>
Task.CompletedTask;
}
}
35 changes: 24 additions & 11 deletions src/MongODM.Core/IDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.

using Etherna.MongODM.Migration;
using Etherna.MongODM.Models.Internal;
using Etherna.MongODM.ProxyModels;
using Etherna.MongODM.Repositories;
using Etherna.MongODM.Serialization;
using Etherna.MongODM.Serialization.Modifiers;
using Etherna.MongODM.Utility;
using MongoDB.Driver;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

Expand Down Expand Up @@ -53,7 +56,22 @@ public interface IDbContext
/// Database operator interested into maintenance tasks.
/// </summary>
IDbMaintainer DbMaintainer { get; }


/// <summary>
/// Manage migrations over database context
/// </summary>
IDbMigrationManager DbMigrationManager { get; }

/// <summary>
/// Internal collection for keep db operations execution log
/// </summary>
ICollectionRepository<OperationBase, string> DbOperations { get; }

/// <summary>
/// List of registered migration tasks
/// </summary>
IEnumerable<MongoMigrationBase> DocumentMigrationList { get; }

/// <summary>
/// Container for model serialization and document schema information.
/// </summary>
Expand All @@ -64,11 +82,6 @@ public interface IDbContext
/// </summary>
string Identifier { get; }

/// <summary>
/// Flag reporting eventual current migration operation.
/// </summary>
bool IsMigrating { get; }

/// <summary>
/// Current MongODM library version
/// </summary>
Expand All @@ -91,16 +104,16 @@ public interface IDbContext

// Methods.
/// <summary>
/// Start a database migration process.
/// Save current model changes on db.
/// </summary>
/// <param name="cancellationToken">Cancellation token</param>
Task MigrateRepositoriesAsync(CancellationToken cancellationToken = default);
Task SaveChangesAsync(CancellationToken cancellationToken = default);

/// <summary>
/// Save current model changes on db.
/// Seed database context if still not seeded
/// </summary>
/// <param name="cancellationToken">Cancellation token</param>
Task SaveChangesAsync(CancellationToken cancellationToken = default);
/// <returns>True if seed has been executed. False otherwise</returns>
Task<bool> SeedIfNeededAsync();

/// <summary>
/// Start a new database transaction session.
Expand Down
40 changes: 40 additions & 0 deletions src/MongODM.Core/Migration/MigrationResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2020-present Etherna Sagl
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Etherna.MongODM.Migration
{
public class MigrationResult
{
// Constructors.
private MigrationResult() { }

// Properties.
public bool Succeded { get; private set; }
public long MigratedDocuments { get; private set; }

// Methods.
public static MigrationResult Failed() =>
new MigrationResult
{
Succeded = false
};

public static MigrationResult Succeeded(long migratedDocuments) =>
new MigrationResult
{
Succeded = true,
MigratedDocuments = migratedDocuments
};
}
}
Loading

0 comments on commit 86fc9fa

Please sign in to comment.