-
-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* First pass at the entity definition builder * Support for property paths on indexes * Add missing derived method for IgnoreExtraElements * Fix null reference * Remove array type * The major changes to have functional fluent in This is a rough first cut, it will need some work still. Compiles, probably won't work though. * Fix stack overflow * Fix empty string index name * Fixed invalid extra elements * Fix ID property detection * Fix stack overflow * Fix missing mapping * Mapping attribute fixes * Fix unnamed indexing grouping * Updated mapping adapter test for new exception * Re-add removed driver reset feature * Re-apply driver abstraction rules after reset * Updating definition types to records * Simplifying the entity definitions * Updated debugger display of entity definitions * Updated debugger display for traversed property * Hide debugger display properties from code coverage * Removed unused variable * Splitting EntityMapping into separate files * Moving MappingBuilder to root This mimics what is done for Entity Framework * Clean up context mapping lock * Minor cleaning of index processor After taking another look, isn't really anything to clean. It is more complex than I'd like but it is perfectly serviceable. * Move some EntityDefinitionBuilder methods to extensions Simplifies the core entity builder and, if needed, an easier path to more overloads. * Cleaning up the entity mapping builder * Minor general refactor * Whoops, missed a file * Added overloads and support unary expression unwrapping * Code fixes and other updates * Main tests for mapping builder * Updated runsettings * Added extension tests * Ensure mapping is completed only once * Support skipped mapping * Undo change to type discovery serializer
- Loading branch information
Showing
45 changed files
with
2,148 additions
and
571 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,23 @@ | ||
using System; | ||
using MongoFramework.Infrastructure.Mapping; | ||
|
||
namespace MongoFramework.Attributes | ||
namespace MongoFramework.Attributes; | ||
|
||
/// <summary> | ||
/// Applies the specific <see cref="IMappingProcessor"/> on the entity. | ||
/// Runs after attribute processing, so the adapter can override attributes. | ||
/// Adapter type must have a parameterless constructor. | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Class)] | ||
public class MappingAdapterAttribute : Attribute | ||
{ | ||
/// <summary> | ||
/// Allows an IMappingProcessor to override definitions in code. Runs after attribute processing, so the adapter can override attributes. | ||
/// Adapter type must have a parameterless constructor. | ||
/// Gets the adapter type for the attached class | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Class)] | ||
public class MappingAdapterAttribute : Attribute | ||
{ | ||
/// <summary> | ||
/// Gets the adapter type for the attached class | ||
/// </summary> | ||
public Type MappingAdapter { get; } | ||
public Type MappingAdapter { get; } | ||
|
||
public MappingAdapterAttribute(Type adapterType) | ||
{ | ||
if (!typeof(IMappingProcessor).IsAssignableFrom(adapterType)) | ||
{ | ||
throw new ArgumentException("Mapping Adapter Type must implement IMappingProcessor", nameof(adapterType)); | ||
} | ||
|
||
MappingAdapter = adapterType; | ||
} | ||
public MappingAdapterAttribute(Type adapterType) | ||
{ | ||
MappingAdapter = adapterType; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using MongoFramework.Infrastructure.Mapping; | ||
|
||
namespace MongoFramework; | ||
|
||
public static class EntityDefinitionBuilderExtensions | ||
{ | ||
private static PropertyInfo GetPropertyInfo(Type entityType, string propertyName) | ||
{ | ||
return entityType.GetProperty(propertyName) ?? throw new ArgumentException($"Property \"{propertyName}\" can not be found on \"{entityType.Name}\".", nameof(propertyName)); | ||
} | ||
|
||
public static EntityDefinitionBuilder HasKey(this EntityDefinitionBuilder definitionBuilder, string propertyName, Action<EntityKeyBuilder> builder = null) | ||
=> definitionBuilder.HasKey(GetPropertyInfo(definitionBuilder.EntityType, propertyName), builder); | ||
|
||
public static EntityDefinitionBuilder Ignore(this EntityDefinitionBuilder definitionBuilder, string propertyName) | ||
=> definitionBuilder.Ignore(GetPropertyInfo(definitionBuilder.EntityType, propertyName)); | ||
|
||
public static EntityDefinitionBuilder HasProperty(this EntityDefinitionBuilder definitionBuilder, string propertyName, Action<EntityPropertyBuilder> builder = null) | ||
=> definitionBuilder.HasProperty(GetPropertyInfo(definitionBuilder.EntityType, propertyName), builder); | ||
|
||
public static EntityDefinitionBuilder HasIndex(this EntityDefinitionBuilder definitionBuilder, IEnumerable<string> propertyPaths, Action<EntityIndexBuilder> builder = null) | ||
{ | ||
var properties = new List<IndexProperty>(); | ||
foreach (var propertyPath in propertyPaths) | ||
{ | ||
properties.Add( | ||
new IndexProperty( | ||
PropertyPath.FromString(definitionBuilder.EntityType, propertyPath) | ||
) | ||
); | ||
} | ||
|
||
return definitionBuilder.HasIndex(properties, builder); | ||
} | ||
public static EntityDefinitionBuilder HasIndex(this EntityDefinitionBuilder definitionBuilder, IEnumerable<PropertyPath> properties, Action<EntityIndexBuilder> builder = null) | ||
{ | ||
return definitionBuilder.HasIndex(properties.Select(p => new IndexProperty(p)), builder); | ||
} | ||
|
||
public static EntityDefinitionBuilder HasExtraElements(this EntityDefinitionBuilder definitionBuilder, string propertyName) | ||
=> definitionBuilder.HasExtraElements(GetPropertyInfo(definitionBuilder.EntityType, propertyName)); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,6 @@ | |
{ | ||
public interface IHaveTenantId | ||
{ | ||
string TenantId { get; set; } | ||
public string TenantId { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 34 additions & 62 deletions
96
src/MongoFramework/Infrastructure/Indexing/IndexModelBuilder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,80 +1,52 @@ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System; | ||
using System.Collections.Generic; | ||
using MongoDB.Driver; | ||
using MongoFramework.Infrastructure.Mapping; | ||
|
||
namespace MongoFramework.Infrastructure.Indexing | ||
namespace MongoFramework.Infrastructure.Indexing; | ||
|
||
public static class IndexModelBuilder<TEntity> | ||
{ | ||
public static class IndexModelBuilder<TEntity> | ||
public static IEnumerable<CreateIndexModel<TEntity>> BuildModel() | ||
{ | ||
public static IEnumerable<CreateIndexModel<TEntity>> BuildModel() | ||
{ | ||
var indexBuilder = Builders<TEntity>.IndexKeys; | ||
var indexes = EntityMapping.GetOrCreateDefinition(typeof(TEntity)).Indexes; | ||
var groupedIndexes = indexes.OrderBy(i => i.IndexPriority).GroupBy(i => i.IndexName); | ||
|
||
foreach (var indexGroup in groupedIndexes) | ||
{ | ||
if (indexGroup.Key != null) | ||
{ | ||
var indexKeys = new List<IndexKeysDefinition<TEntity>>(); | ||
CreateIndexOptions<TEntity> indexOptions = default; | ||
foreach (var index in indexGroup) | ||
{ | ||
var indexModel = CreateIndexModel(index); | ||
indexKeys.Add(indexModel.Keys); | ||
|
||
if (indexOptions == null) | ||
{ | ||
indexOptions = indexModel.Options; | ||
} | ||
} | ||
var indexBuilder = Builders<TEntity>.IndexKeys; | ||
var indexes = EntityMapping.GetOrCreateDefinition(typeof(TEntity)).Indexes; | ||
|
||
var combinedKeyDefinition = indexBuilder.Combine(indexKeys); | ||
yield return new CreateIndexModel<TEntity>(combinedKeyDefinition, indexOptions); | ||
} | ||
else | ||
{ | ||
foreach (var index in indexGroup) | ||
{ | ||
yield return CreateIndexModel(index); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private static CreateIndexModel<TEntity> CreateIndexModel(IEntityIndexDefinition indexDefinition) | ||
foreach (var index in indexes) | ||
{ | ||
var builder = Builders<TEntity>.IndexKeys; | ||
IndexKeysDefinition<TEntity> keyModel; | ||
|
||
if (indexDefinition.IndexType == IndexType.Text) | ||
var indexKeyCount = index.IndexPaths.Count + (index.IsTenantExclusive ? 1 : 0); | ||
var indexKeys = new IndexKeysDefinition<TEntity>[indexKeyCount]; | ||
for (var i = 0; i < index.IndexPaths.Count; i++) | ||
{ | ||
keyModel = builder.Text(indexDefinition.Path); | ||
indexKeys[i] = CreateIndexKey(index.IndexPaths[i]); | ||
} | ||
else if (indexDefinition.IndexType == IndexType.Geo2dSphere) | ||
|
||
if (index.IsTenantExclusive) | ||
{ | ||
keyModel = builder.Geo2DSphere(indexDefinition.Path); | ||
} | ||
else | ||
{ | ||
keyModel = indexDefinition.SortOrder == IndexSortOrder.Ascending ? | ||
builder.Ascending(indexDefinition.Path) : builder.Descending(indexDefinition.Path); | ||
} | ||
|
||
if (indexDefinition.IsTenantExclusive && typeof(IHaveTenantId).IsAssignableFrom(typeof(TEntity))) | ||
{ | ||
var tenantKey = indexDefinition.SortOrder == IndexSortOrder.Ascending ? | ||
builder.Ascending("TenantId") : builder.Descending("TenantId"); | ||
keyModel = builder.Combine(tenantKey, keyModel); | ||
indexKeys[indexKeys.Length - 1] = Builders<TEntity>.IndexKeys.Ascending(nameof(IHaveTenantId.TenantId)); | ||
} | ||
|
||
return new CreateIndexModel<TEntity>(keyModel, new CreateIndexOptions | ||
var combinedKeyDefinition = indexBuilder.Combine(indexKeys); | ||
yield return new CreateIndexModel<TEntity>(combinedKeyDefinition, new CreateIndexOptions | ||
{ | ||
Name = indexDefinition.IndexName, | ||
Unique = indexDefinition.IsUnique, | ||
Name = index.IndexName, | ||
Unique = index.IsUnique, | ||
Background = true | ||
}); | ||
} | ||
} | ||
|
||
private static IndexKeysDefinition<TEntity> CreateIndexKey(IndexPathDefinition indexPathDefinition) | ||
{ | ||
var builder = Builders<TEntity>.IndexKeys; | ||
Func<FieldDefinition<TEntity>, IndexKeysDefinition<TEntity>> builderMethod = indexPathDefinition.IndexType switch | ||
{ | ||
IndexType.Standard when indexPathDefinition.SortOrder == IndexSortOrder.Ascending => builder.Ascending, | ||
IndexType.Standard when indexPathDefinition.SortOrder == IndexSortOrder.Descending => builder.Descending, | ||
IndexType.Text => builder.Text, | ||
IndexType.Geo2dSphere => builder.Geo2DSphere, | ||
_ => throw new ArgumentException($"Unsupported index type \"{indexPathDefinition.IndexType}\"", nameof(indexPathDefinition)) | ||
}; | ||
return builderMethod(indexPathDefinition.Path); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 0 additions & 21 deletions
21
src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs
This file was deleted.
Oops, something went wrong.
21 changes: 21 additions & 0 deletions
21
src/MongoFramework/Infrastructure/Mapping/DefaultMappingProcessors.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System.Collections.Generic; | ||
using MongoFramework.Infrastructure.Mapping.Processors; | ||
|
||
namespace MongoFramework.Infrastructure.Mapping; | ||
|
||
public static class DefaultMappingProcessors | ||
{ | ||
public static readonly IReadOnlyList<IMappingProcessor> Processors = new IMappingProcessor[] | ||
{ | ||
new SkipMappingProcessor(), | ||
new CollectionNameProcessor(), | ||
new HierarchyProcessor(), | ||
new PropertyMappingProcessor(), | ||
new EntityIdProcessor(), | ||
new NestedTypeProcessor(), | ||
new ExtraElementsProcessor(), | ||
new BsonKnownTypesProcessor(), | ||
new IndexProcessor(), | ||
new MappingAdapterProcessor() | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.