Line data Source code
1 : #region Copyright
2 : // // -----------------------------------------------------------------------
3 : // // <copyright company="Chinchilla Software Limited">
4 : // // Copyright Chinchilla Software Limited. All rights reserved.
5 : // // </copyright>
6 : // // -----------------------------------------------------------------------
7 : #endregion
8 :
9 : using System;
10 : using System.Collections.Generic;
11 : using System.Linq;
12 : using System.Linq.Expressions;
13 : using System.Reflection;
14 : using cdmdotnet.Logging;
15 : using Cqrs.DataStores;
16 : using Cqrs.MongoDB.DataStores.Indexes;
17 : using Cqrs.MongoDB.Serialisers;
18 : using MongoDB.Driver;
19 : using MongoDB.Bson.Serialization;
20 :
21 : namespace Cqrs.MongoDB.Factories
22 : {
23 : /// <summary>
24 : /// A factory for obtaining <see cref="IDataStore{TData}"/> collections from MongoDB
25 : /// </summary>
26 : public class MongoDbDataStoreFactory
27 1 : {
28 : internal static IDictionary<Type, IList<object>> IndexTypesByEntityType { get; set; }
29 :
30 : /// <summary>
31 : /// Gets or sets the <see cref="ILogger"/>.
32 : /// </summary>
33 : protected ILogger Logger { get; private set; }
34 :
35 : /// <summary>
36 : /// Gets or sets the <see cref="IMongoDbDataStoreConnectionStringFactory"/>.
37 : /// </summary>
38 : protected IMongoDbDataStoreConnectionStringFactory MongoDbDataStoreConnectionStringFactory { get; private set; }
39 :
40 : /// <summary>
41 : /// Instantiates a new instance of <see cref="MongoDbDataStoreFactory"/>.
42 : /// </summary>
43 1 : public MongoDbDataStoreFactory(ILogger logger, IMongoDbDataStoreConnectionStringFactory mongoDbDataStoreConnectionStringFactory)
44 : {
45 : Logger = logger;
46 : MongoDbDataStoreConnectionStringFactory = mongoDbDataStoreConnectionStringFactory;
47 : }
48 :
49 : static MongoDbDataStoreFactory()
50 : {
51 : var typeSerializer = new TypeSerialiser();
52 : BsonSerializer.RegisterSerializer(typeof(Type), typeSerializer);
53 : BsonSerializer.RegisterSerializer(Type.GetType("System.RuntimeType"), typeSerializer);
54 :
55 : IndexTypesByEntityType = new Dictionary<Type, IList<object>>();
56 : foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
57 : {
58 : var mongoIndexTypes = assembly
59 : .GetTypes()
60 : .Where
61 : (
62 : type =>
63 : (
64 : // base is NOT an abstract index
65 : (
66 : type.BaseType != null &&
67 : type.BaseType.IsGenericType &&
68 : typeof(MongoDbIndex<>).IsAssignableFrom(type.BaseType.GetGenericTypeDefinition())
69 : )
70 : ||
71 : // base is an abstract index
72 : (
73 : type.BaseType != null &&
74 : type.BaseType.BaseType != null &&
75 : type.BaseType.BaseType.IsGenericType &&
76 : typeof(MongoDbIndex<>).IsAssignableFrom(type.BaseType.BaseType.GetGenericTypeDefinition())
77 : )
78 : ||
79 : // a deeper inheritance model
80 : (
81 : type.BaseType != null &&
82 : type.BaseType.BaseType != null &&
83 : type.BaseType.BaseType.BaseType != null &&
84 : type.BaseType.BaseType.BaseType.IsGenericType &&
85 : typeof(MongoDbIndex<>).IsAssignableFrom(type.BaseType.BaseType.BaseType.GetGenericTypeDefinition())
86 : )
87 : ||
88 : // an even deeper inheritance model
89 : (
90 : type.BaseType != null &&
91 : type.BaseType.BaseType != null &&
92 : type.BaseType.BaseType.BaseType != null &&
93 : type.BaseType.BaseType.BaseType.BaseType != null &&
94 : type.BaseType.BaseType.BaseType.BaseType.IsGenericType &&
95 : typeof(MongoDbIndex<>).IsAssignableFrom(type.BaseType.BaseType.BaseType.BaseType.GetGenericTypeDefinition())
96 : )
97 : )
98 : && !type.IsAbstract
99 : );
100 : foreach (Type mongoIndexType in mongoIndexTypes)
101 : {
102 : Type genericType = mongoIndexType;
103 : while (genericType != null && !genericType.IsGenericType)
104 : {
105 : genericType = genericType.BaseType;
106 : }
107 : genericType = genericType.GetGenericArguments().Single();
108 :
109 : IList<object> indexTypes;
110 : if (!IndexTypesByEntityType.TryGetValue(genericType, out indexTypes))
111 : IndexTypesByEntityType.Add(genericType, indexTypes = new List<object>());
112 : object mongoIndex = Activator.CreateInstance(mongoIndexType, true);
113 : indexTypes.Add(mongoIndex);
114 : }
115 : }
116 : }
117 :
118 : /// <summary>
119 : /// Get a <see cref="IMongoCollection{TEntity}"/>
120 : /// </summary>
121 1 : protected virtual IMongoCollection<TEntity> GetCollection<TEntity>()
122 : {
123 : var mongoClient = new MongoClient(MongoDbDataStoreConnectionStringFactory.GetDataStoreConnectionString());
124 : IMongoDatabase mongoDatabase = mongoClient.GetDatabase(MongoDbDataStoreConnectionStringFactory.GetDataStoreDatabaseName());
125 :
126 : return mongoDatabase.GetCollection<TEntity>(typeof(TEntity).FullName);
127 : }
128 :
129 : /// <summary>
130 : /// Verify all required <see cref="MongoDbIndex{TEntity}"/> are defined and ready to go.
131 : /// </summary>
132 1 : protected virtual void VerifyIndexes<TEntity>(IMongoCollection<TEntity> collection)
133 : {
134 : Type entityType = typeof (TEntity);
135 : if (IndexTypesByEntityType.ContainsKey(entityType))
136 : {
137 : foreach (object untypedIndexType in IndexTypesByEntityType[entityType])
138 : {
139 : var mongoIndex = (MongoDbIndex<TEntity>)untypedIndexType;
140 :
141 : IndexKeysDefinitionBuilder<TEntity> indexKeysBuilder = Builders<TEntity>.IndexKeys;
142 : IndexKeysDefinition<TEntity> indexKey = null;
143 :
144 : IList<Expression<Func<TEntity, object>>> selectors = mongoIndex.Selectors.ToList();
145 : for (int i = 0; i < selectors.Count; i++)
146 : {
147 : Expression<Func<TEntity, object>> expression = selectors[i];
148 : if (mongoIndex.IsAcending)
149 : {
150 : if (i == 0)
151 : indexKey = indexKeysBuilder.Ascending(expression);
152 : else
153 : indexKey = indexKey.Ascending(expression);
154 : }
155 : else
156 : {
157 : if (i == 0)
158 : indexKey = indexKeysBuilder.Descending(expression);
159 : else
160 : indexKey = indexKey.Descending(expression);
161 : }
162 : }
163 :
164 : collection.Indexes.CreateOne
165 : (
166 : indexKey,
167 : new CreateIndexOptions
168 : {
169 : Unique = mongoIndex.IsUnique,
170 : Name = mongoIndex.Name
171 : }
172 : );
173 : }
174 : }
175 : }
176 : }
177 : }
|