Line data Source code
1 : #region Copyright
2 : // // -----------------------------------------------------------------------
3 : // // <copyright company="cdmdotnet Limited">
4 : // // Copyright cdmdotnet 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.Events;
16 : using Cqrs.MongoDB.DataStores.Indexes;
17 : using Cqrs.MongoDB.Events.Indexes;
18 : using Cqrs.MongoDB.Factories;
19 : using Cqrs.MongoDB.Serialisers;
20 : using MongoDB.Bson.Serialization;
21 : using MongoDB.Driver;
22 : using MongoDB.Driver.Linq;
23 :
24 : namespace Cqrs.MongoDB.Events
25 : {
26 : /// <summary>
27 : /// A MongoDB based <see cref="EventStore{TAuthenticationToken}"/>.
28 : /// </summary>
29 : public class MongoDbEventStore<TAuthenticationToken> : EventStore<TAuthenticationToken>
30 1 : {
31 : protected IMongoCollection<MongoDbEventData> MongoCollection { get; private set; }
32 :
33 : protected IMongoDbEventStoreConnectionStringFactory MongoDbEventStoreConnectionStringFactory { get; private set; }
34 :
35 : static MongoDbEventStore()
36 : {
37 : IDictionary<Type, IList<object>> randomCallToStartStaticProperty = MongoDbDataStoreFactory.IndexTypesByEntityType;
38 :
39 : foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
40 : {
41 : var eventTypes = assembly
42 : .GetTypes()
43 : .Where
44 : (
45 : type =>
46 : typeof(IEvent<TAuthenticationToken>).IsAssignableFrom(type)
47 : && !type.IsAbstract
48 : );
49 : foreach (Type eventType in eventTypes)
50 : BsonClassMap.LookupClassMap(eventType);
51 : }
52 : }
53 :
54 0 : public MongoDbEventStore(IEventBuilder<TAuthenticationToken> eventBuilder, IEventDeserialiser<TAuthenticationToken> eventDeserialiser, ILogger logger, IMongoDbEventStoreConnectionStringFactory mongoDbEventStoreConnectionStringFactory)
55 : : base(eventBuilder, eventDeserialiser, logger)
56 : {
57 : MongoDbEventStoreConnectionStringFactory = mongoDbEventStoreConnectionStringFactory;
58 :
59 : // ReSharper disable DoNotCallOverridableMethodsInConstructor
60 : MongoCollection = GetCollection();
61 : VerifyIndexes();
62 : // ReSharper restore DoNotCallOverridableMethodsInConstructor
63 : }
64 :
65 0 : protected virtual IMongoCollection<MongoDbEventData> GetCollection()
66 : {
67 : var mongoClient = new MongoClient(MongoDbEventStoreConnectionStringFactory.GetEventStoreConnectionString());
68 : IMongoDatabase mongoDatabase = mongoClient.GetDatabase(MongoDbEventStoreConnectionStringFactory.GetEventStoreDatabaseName());
69 :
70 : return mongoDatabase.GetCollection<MongoDbEventData>(MongoDbEventStoreConnectionStringFactory.GetEventStoreDatabaseName());
71 : }
72 :
73 0 : protected virtual void VerifyIndexes()
74 : {
75 : VerifyIndex(new ByCorrelationIdMongoDbIndex());
76 : VerifyIndex(new ByAggregateIdAndVersionMongoDbIndex());
77 : VerifyIndex(new ByTimestampMongoDbIndex());
78 : VerifyIndex(new ByTimestampAndEventTypeMongoDbIndex());
79 : }
80 :
81 0 : protected virtual void VerifyIndex(MongoDbIndex<MongoDbEventData> mongoIndex)
82 : {
83 : IndexKeysDefinitionBuilder<MongoDbEventData> indexKeysBuilder = Builders<MongoDbEventData>.IndexKeys;
84 : IndexKeysDefinition<MongoDbEventData> indexKey = null;
85 :
86 : IList<Expression<Func<MongoDbEventData, object>>> selectors = mongoIndex.Selectors.ToList();
87 : for (int i = 0; i < selectors.Count; i++)
88 : {
89 : Expression<Func<MongoDbEventData, object>> expression = selectors[i];
90 : if (mongoIndex.IsAcending)
91 : {
92 : if (i == 0)
93 : indexKey = indexKeysBuilder.Ascending(expression);
94 : else
95 : indexKey = indexKey.Ascending(expression);
96 : }
97 : else
98 : {
99 : if (i == 0)
100 : indexKey = indexKeysBuilder.Descending(expression);
101 : else
102 : indexKey = indexKey.Descending(expression);
103 : }
104 : }
105 :
106 : MongoCollection.Indexes.CreateOne
107 : (
108 : indexKey,
109 : new CreateIndexOptions
110 : {
111 : Unique = mongoIndex.IsUnique,
112 : Name = mongoIndex.Name
113 : }
114 : );
115 : }
116 :
117 : #region Overrides of EventStore<TAuthenticationToken>
118 :
119 0 : public override IEnumerable<IEvent<TAuthenticationToken>> Get(Type aggregateRootType, Guid aggregateId, bool useLastEventOnly = false, int fromVersion = -1)
120 : {
121 : string streamName = string.Format(CqrsEventStoreStreamNamePattern, aggregateRootType.FullName, aggregateId);
122 :
123 : IEnumerable<MongoDbEventData> query = MongoCollection
124 : .AsQueryable()
125 : .Where(eventData => eventData.AggregateId == streamName && eventData.Version > fromVersion)
126 : .OrderByDescending(eventData => eventData.Version);
127 :
128 : if (useLastEventOnly)
129 : query = query.AsQueryable().Take(1);
130 :
131 : return query
132 : .Select(EventDeserialiser.Deserialise)
133 : .ToList();
134 : }
135 :
136 0 : public override IEnumerable<EventData> Get(Guid correlationId)
137 : {
138 : IEnumerable<MongoDbEventData> query = MongoCollection
139 : .AsQueryable()
140 : .Where(eventData => eventData.CorrelationId == correlationId)
141 : .OrderBy(eventData => eventData.Timestamp);
142 :
143 : return query.ToList();
144 : }
145 :
146 0 : protected override void PersistEvent(EventData eventData)
147 : {
148 : var safeEventData = eventData as MongoDbEventData;
149 : if (safeEventData == null)
150 : safeEventData = new MongoDbEventData(eventData);
151 : Logger.LogDebug("Adding an event to the MongoDB database", "MongoDbEventStore\\PersistEvent");
152 : try
153 : {
154 : DateTime start = DateTime.Now;
155 : MongoCollection.InsertOne(safeEventData);
156 : DateTime end = DateTime.Now;
157 : Logger.LogDebug(string.Format("Adding data in the MongoDB database took {0}.", end - start), "MongoDbEventStore\\PersistEvent");
158 : }
159 : finally
160 : {
161 : Logger.LogDebug("Adding an event to the MongoDB database... Done", "MongoDbEventStore\\PersistEvent");
162 : }
163 : }
164 :
165 : #endregion
166 : }
167 : }
|