Skip to content

Commit 14b2d58

Browse files
authored
Merge pull request #176 from JohnCampionJr/code-config
Add a Mapping Processor Adapter
2 parents 82bff60 + ab5c236 commit 14b2d58

File tree

4 files changed

+177
-1
lines changed

4 files changed

+177
-1
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using MongoFramework.Infrastructure.Mapping;
4+
5+
namespace MongoFramework.Attributes
6+
{
7+
/// <summary>
8+
/// Allows an IMappingProcessor to override definitions in code. Runs after attribute processing, so the adapter can override attributes.
9+
/// Adapter type must have a parameterless constructor.
10+
/// </summary>
11+
[AttributeUsage(AttributeTargets.Class)]
12+
public class MappingAdapterAttribute : Attribute
13+
{
14+
/// <summary>
15+
/// Gets the adapter type for the attached class
16+
/// </summary>
17+
public Type MappingAdapter { get; }
18+
19+
public MappingAdapterAttribute(Type adapterType)
20+
{
21+
if (!typeof(IMappingProcessor).IsAssignableFrom(adapterType))
22+
{
23+
throw new ArgumentException("Mapping Adapter Type must implement IMappingProcessor", nameof(adapterType));
24+
}
25+
26+
MappingAdapter = adapterType;
27+
}
28+
}
29+
}

src/MongoFramework/Infrastructure/Mapping/DefaultMappingPack.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ public static class DefaultProcessors
1616
new DecimalSerializationProcessor(),
1717
new TypeDiscoveryProcessor(),
1818
new BsonKnownTypesProcessor(),
19-
new IndexProcessor()
19+
new IndexProcessor(),
20+
new MappingAdapterProcessor()
2021
};
2122
}
2223
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel.DataAnnotations.Schema;
4+
using System.Reflection;
5+
using System.Text;
6+
using MongoDB.Bson.Serialization;
7+
using MongoFramework.Attributes;
8+
9+
namespace MongoFramework.Infrastructure.Mapping.Processors
10+
{
11+
public class MappingAdapterProcessor : IMappingProcessor
12+
{
13+
public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap)
14+
{
15+
var adapterAttribute = definition.EntityType.GetCustomAttribute<MappingAdapterAttribute>();
16+
17+
if (adapterAttribute == null)
18+
{
19+
return;
20+
}
21+
22+
var instance = (IMappingProcessor)Activator.CreateInstance(adapterAttribute.MappingAdapter);
23+
24+
if (instance != null)
25+
{
26+
instance.ApplyMapping(definition, classMap);
27+
}
28+
29+
}
30+
}
31+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using MongoDB.Bson;
3+
using MongoDB.Bson.Serialization;
4+
using MongoDB.Bson.Serialization.IdGenerators;
5+
using MongoFramework.Attributes;
6+
using MongoFramework.Infrastructure.Mapping;
7+
using MongoFramework.Infrastructure.Mapping.Processors;
8+
using System;
9+
using System.Collections.Generic;
10+
using System.ComponentModel.DataAnnotations;
11+
using System.ComponentModel.DataAnnotations.Schema;
12+
using System.Linq;
13+
14+
namespace MongoFramework.Tests.Infrastructure.Mapping.Processors
15+
{
16+
[TestClass]
17+
public class MappingAdapterProcessorTests : MappingTestBase
18+
{
19+
20+
public class AdapterTestModelMappingAdapter : IMappingProcessor
21+
{
22+
public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap)
23+
{
24+
definition.CollectionName = "Custom";
25+
26+
var definitionIndexes = definition.Indexes.ToList();
27+
28+
definitionIndexes.Add(new EntityIndex
29+
{
30+
Property = definition.GetProperty("UserName"),
31+
IsUnique = true,
32+
SortOrder = IndexSortOrder.Ascending
33+
});
34+
35+
definition.Indexes = definitionIndexes;
36+
}
37+
}
38+
39+
[Table("TestModels")]
40+
[MappingAdapter(typeof(AdapterTestModelMappingAdapter))]
41+
public class AdapterTestModel
42+
{
43+
public Guid MyCustomId { get; set; }
44+
public string UserName { get; set; }
45+
46+
}
47+
48+
public class AdapterTestModelMappingAdapterNoInterface
49+
{
50+
// no interface
51+
}
52+
53+
[MappingAdapter(typeof(AdapterTestModelMappingAdapterNoInterface))]
54+
public class AdapterTestModelNoInterface
55+
{
56+
// broken adapter
57+
}
58+
59+
public class AdapterTestModelMappingAdapterConstructor : IMappingProcessor
60+
{
61+
public AdapterTestModelMappingAdapterConstructor(string test)
62+
{
63+
64+
}
65+
66+
public void ApplyMapping(IEntityDefinition definition, BsonClassMap classMap)
67+
{
68+
throw new NotImplementedException();
69+
}
70+
}
71+
72+
[MappingAdapter(typeof(AdapterTestModelMappingAdapterConstructor))]
73+
public class AdapterTestModelConstructor
74+
{
75+
// broken adapter
76+
}
77+
78+
[TestMethod]
79+
public void AdapterRequiresIMappingProcessor()
80+
{
81+
EntityMapping.AddMappingProcessor(new CollectionNameProcessor());
82+
EntityMapping.AddMappingProcessor(new PropertyMappingProcessor());
83+
EntityMapping.AddMappingProcessor(new EntityIdProcessor());
84+
EntityMapping.AddMappingProcessor(new MappingAdapterProcessor());
85+
Assert.ThrowsException<ArgumentException>(() => EntityMapping.RegisterType(typeof(AdapterTestModelNoInterface)));
86+
}
87+
88+
[TestMethod]
89+
public void AdapterRequiresParameterlessConstructor()
90+
{
91+
EntityMapping.AddMappingProcessor(new CollectionNameProcessor());
92+
EntityMapping.AddMappingProcessor(new PropertyMappingProcessor());
93+
EntityMapping.AddMappingProcessor(new EntityIdProcessor());
94+
EntityMapping.AddMappingProcessor(new MappingAdapterProcessor());
95+
Assert.ThrowsException<MissingMethodException>(() => EntityMapping.RegisterType(typeof(AdapterTestModelConstructor)));
96+
}
97+
98+
[TestMethod]
99+
public void AdapterOverridesAttributes()
100+
{
101+
EntityMapping.AddMappingProcessor(new CollectionNameProcessor());
102+
EntityMapping.AddMappingProcessor(new PropertyMappingProcessor());
103+
EntityMapping.AddMappingProcessor(new EntityIdProcessor());
104+
EntityMapping.AddMappingProcessor(new MappingAdapterProcessor());
105+
var definition = EntityMapping.RegisterType(typeof(AdapterTestModel));
106+
107+
Assert.AreEqual("Custom", definition.CollectionName);
108+
Assert.AreEqual(1, definition.Indexes.Count());
109+
110+
111+
112+
}
113+
114+
}
115+
}

0 commit comments

Comments
 (0)