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.Linq;
11 : using cdmdotnet.Logging;
12 : using Cqrs.Configuration;
13 : using Cqrs.Domain;
14 : using Cqrs.Events;
15 : using Cqrs.Snapshots;
16 : using Microsoft.WindowsAzure.Storage.Table;
17 :
18 : namespace Cqrs.Azure.BlobStorage.Events
19 : {
20 : /// <summary>
21 : /// An Azure Storage based <see cref="SnapshotStore"/>.
22 : /// </summary>
23 : public class TableStorageSnapshotStore
24 : : SnapshotStore
25 1 : {
26 : /// <summary>
27 : /// The pattern used to generate the stream name.
28 : /// </summary>
29 : protected const string TableCqrsSnapshotStoreStreamNamePattern = "{0}.{1}";
30 :
31 : /// <summary>
32 : /// Gets or sets the underlying <see cref="TableStorageStore"/> used for persisting and reading <see cref="Snapshot"/> data.
33 : /// </summary>
34 : protected RawTableStorageSnapshotStore TableStorageStore { get; set; }
35 :
36 : /// <summary>
37 : /// Initializes a new instance of the <see cref="TableStorageEventStore{TAuthenticationToken}"/> class using the specified container.
38 : /// </summary>
39 1 : public TableStorageSnapshotStore(IConfigurationManager configurationManager, ISnapshotDeserialiser eventDeserialiser, ILogger logger, ICorrelationIdHelper correlationIdHelper, ISnapshotBuilder snapshotBuilder, ITableStorageSnapshotStoreConnectionStringFactory tableStorageSnapshotStoreConnectionStringFactory, Func<ILogger, ITableStorageSnapshotStoreConnectionStringFactory, RawTableStorageSnapshotStore> createRawTableStorageSnapshotStoreFunction = null)
40 : : base(configurationManager, eventDeserialiser, snapshotBuilder, logger, correlationIdHelper)
41 : {
42 : if (createRawTableStorageSnapshotStoreFunction == null)
43 : createRawTableStorageSnapshotStoreFunction = (logger1, tableStorageSnapshotStoreConnectionStringFactory1) => new RawTableStorageSnapshotStore(logger1, tableStorageSnapshotStoreConnectionStringFactory1);
44 : TableStorageStore = createRawTableStorageSnapshotStoreFunction(logger, tableStorageSnapshotStoreConnectionStringFactory);
45 : }
46 :
47 : #region Overrides of SnapshotStore
48 :
49 : /// <summary>
50 : /// Get the latest <see cref="Snapshot"/> from storage.
51 : /// </summary>
52 : /// <returns>The most recent <see cref="Snapshot"/> of</returns>
53 1 : protected override Snapshot Get(Type aggregateRootType, string streamName)
54 : {
55 : // Create the table query.
56 : var rangeQuery = new TableQuery<EventDataTableEntity<EventData>>().Where
57 : (
58 : TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, StorageStore<object, object>.GetSafeStorageKey(streamName))
59 : );
60 :
61 : Snapshot result = TableStorageStore.ReadableSource.ExecuteQuery(rangeQuery)
62 : .Select(eventData => eventData.EventData)
63 : .Where(eventData => eventData.AggregateId == streamName)
64 : .OrderByDescending(eventData => eventData.Version)
65 : .Take(1)
66 : .Select(EventDeserialiser.Deserialise)
67 : .SingleOrDefault();
68 :
69 : return result;
70 : }
71 :
72 : /// <summary>
73 : /// Saves the provided <paramref name="snapshot"/> into storage.
74 : /// </summary>
75 : /// <param name="snapshot">the <see cref="Snapshot"/> to save and store.</param>
76 1 : public override void Save(Snapshot snapshot)
77 : {
78 : Logger.LogDebug("Adding data to the table storage snapshot-store aggregate folder", "TableStorageStore\\Add");
79 : TableStorageStore.Add(BuildEventData(snapshot));
80 : Logger.LogDebug("Added data to the table storage snapshot-store aggregate folder", "TableStorageStore\\Save");
81 : }
82 :
83 : /// <summary>
84 : /// Generate a unique stream name based on the provided <paramref name="aggregateRootType"/> and the <paramref name="aggregateId"/>.
85 : /// </summary>
86 : /// <param name="aggregateRootType">The <see cref="Type"/> of the <see cref="IAggregateRoot{TAuthenticationToken}"/>.</param>
87 : /// <param name="aggregateId">The ID of the <see cref="IAggregateRoot{TAuthenticationToken}"/>.</param>
88 1 : protected override string GenerateStreamName(Type aggregateRootType, Guid aggregateId)
89 : {
90 : return string.Format(TableCqrsSnapshotStoreStreamNamePattern, aggregateRootType.FullName, aggregateId);
91 : }
92 :
93 : #endregion
94 :
95 : /// <summary>
96 : /// An Azure Storage based <see cref="Cqrs.Azure.BlobStorage.TableStorageStore{TData,TCollectionItemData}"/>.
97 : /// </summary>
98 : public class RawTableStorageSnapshotStore
99 : : TableStorageStore<EventDataTableEntity<EventData>, EventData>
100 1 : {
101 : private string TableName { get; set; }
102 :
103 : /// <summary>
104 : /// Initializes a new instance of the <see cref="RawTableStorageSnapshotStore"/> class using the specified container.
105 : /// </summary>
106 1 : public RawTableStorageSnapshotStore(ILogger logger, ITableStorageSnapshotStoreConnectionStringFactory tableStorageSnapshotStoreConnectionStringFactory)
107 : : base(logger)
108 : {
109 : GetContainerName = tableStorageSnapshotStoreConnectionStringFactory.GetBaseContainerName;
110 : IsContainerPublic = () => false;
111 :
112 : TableName = "SnapshotStore";
113 :
114 : // ReSharper disable DoNotCallOverridableMethodsInConstructor
115 : Initialise(tableStorageSnapshotStoreConnectionStringFactory);
116 : // ReSharper restore DoNotCallOverridableMethodsInConstructor
117 : }
118 :
119 : #region Overrides of StorageStore<EventData,CloudTable>
120 :
121 : /// <summary>
122 : /// Returns <see cref="TableName"/>.
123 : /// </summary>
124 : /// <param name="sourceName">Is not used.</param>
125 : /// <returns><see cref="TableName"/></returns>
126 1 : protected override string GetSafeSourceName(string sourceName)
127 : {
128 : return TableName;
129 : }
130 :
131 : #endregion
132 :
133 : #region Overrides of TableStorageStore<EventData>
134 :
135 : /// <summary>
136 : /// Creates a new <see cref="EventDataTableEntity{TEventData}"/>.
137 : /// </summary>
138 1 : protected override ITableEntity CreateTableEntity(EventData data)
139 : {
140 : return new EventDataTableEntity<EventData>(data);
141 : }
142 :
143 : /// <summary>
144 : /// Will mark the <paramref name="data"/> as logically (or soft).
145 : /// </summary>
146 1 : public override void Remove(EventData data)
147 : {
148 : throw new InvalidOperationException("Snapshot store entries are not deletable.");
149 : }
150 :
151 : /// <summary>
152 : /// Will throw an <see cref="InvalidOperationException"/> as this is not supported.
153 : /// </summary>
154 1 : protected override TableOperation GetUpdatableTableEntity(EventData data)
155 : {
156 : throw new InvalidOperationException("Snapshot store entries are not updateable.");
157 : }
158 :
159 : /// <summary>
160 : /// Will throw an <see cref="InvalidOperationException"/> as this is not supported.
161 : /// </summary>
162 1 : protected override TableOperation GetUpdatableTableEntity(EventDataTableEntity<EventData> data)
163 : {
164 : return GetUpdatableTableEntity(data.EventData);
165 : }
166 :
167 : #endregion
168 : }
169 : }
170 : }
|