-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDataModels.cs
More file actions
338 lines (317 loc) · 10.3 KB
/
DataModels.cs
File metadata and controls
338 lines (317 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
namespace Bring.Models;
/// <summary>
/// Represents a generic SharePoint list item with common metadata.
/// </summary>
/// <remarks>
/// <para>Uses init-only properties for immutability while allowing object initializers.</para>
/// <para><strong>With-expressions for non-destructive mutation:</strong></para>
/// <code>
/// var original = new SharePointListItem
/// {
/// Id = 1,
/// Title = "Initial Title",
/// Created = DateTime.UtcNow
/// };
///
/// // Create a modified copy with updated title
/// var updated = original with { Title = "Updated Title" };
///
/// // Chain multiple with-expressions
/// var furtherUpdated = updated with
/// {
/// Modified = DateTime.UtcNow,
/// Author = "admin@contoso.com"
/// };
///
/// // Original remains unchanged (immutability)
/// Console.WriteLine(original.Title); // "Initial Title"
/// Console.WriteLine(updated.Title); // "Updated Title"
/// </code>
/// </remarks>
public record SharePointListItem
{
/// <summary>
/// The unique identifier of the list item.
/// </summary>
public int Id { get; init; }
/// <summary>
/// The title/display name of the list item.
/// </summary>
public string Title { get; init; } = string.Empty;
/// <summary>
/// The timestamp when the item was created in SharePoint.
/// </summary>
public DateTime Created { get; init; }
/// <summary>
/// The timestamp when the item was last modified in SharePoint.
/// </summary>
public DateTime? Modified { get; init; }
/// <summary>
/// The user principal name (email) of the item author.
/// </summary>
public string? Author { get; init; }
/// <summary>
/// Additional custom fields stored as key-value pairs.
/// </summary>
public Dictionary<string, object?>? CustomFields { get; init; }
}
/// <summary>
/// Represents a sync operation execution with timing and metrics.
/// Uses positional record syntax for concise declaration.
/// </summary>
/// <remarks>
/// <para>Positional records provide automatic properties, constructor, and deconstruction:</para>
/// <code>
/// var op = new SyncOperation(
/// Guid.NewGuid(),
/// SyncType.Daily,
/// DateTime.UtcNow,
/// null,
/// 0,
/// "Running"
/// );
///
/// // Deconstruction
/// var (opId, type, start, _, _, status) = op;
///
/// // With-expression for updates
/// var completed = op with
/// {
/// EndTime = DateTime.UtcNow,
/// ItemsProcessed = 1500,
/// Status = "Completed"
/// };
/// </code>
/// </remarks>
/// <param name="OperationId">Unique identifier for the sync operation.</param>
/// <param name="Type">Type of sync operation (Daily or Monthly).</param>
/// <param name="StartTime">When the operation started.</param>
/// <param name="EndTime">When the operation completed (null if still running).</param>
/// <param name="ItemsProcessed">Number of items processed during the operation.</param>
/// <param name="Status">Current status of the operation.</param>
public record SyncOperation(
Guid OperationId,
SyncType Type,
DateTime StartTime,
DateTime? EndTime,
int ItemsProcessed,
string Status
)
{
/// <summary>
/// Gets the duration of the operation. Returns null if not yet completed.
/// </summary>
public TimeSpan? Duration => EndTime.HasValue ? EndTime.Value - StartTime : null;
/// <summary>
/// Gets whether the operation is currently running.
/// </summary>
public bool IsRunning => EndTime is null && Status == "Running";
}
/// <summary>
/// Type of synchronization operation.
/// </summary>
public enum SyncType
{
/// <summary>Daily incremental sync.</summary>
Daily,
/// <summary>Monthly full sync.</summary>
Monthly,
/// <summary>Manual on-demand sync.</summary>
Manual
}
/// <summary>
/// Represents a data quality issue found during sync operations.
/// Demonstrates pattern matching capabilities with records.
/// </summary>
/// <remarks>
/// <para><strong>Pattern matching examples:</strong></para>
/// <code>
/// var issue = new DataQualityIssue(
/// "CustomerList",
/// 123,
/// "Email",
/// "InvalidFormat",
/// "Email address missing @ symbol",
/// Severity.High
/// );
///
/// // Property pattern matching
/// var severity = issue switch
/// {
/// { Severity: Severity.Critical } => "URGENT",
/// { Severity: Severity.High, IssueType: "InvalidFormat" } => "Fix Format",
/// { Severity: Severity.Medium } => "Review",
/// _ => "Log Only"
/// };
///
/// // Positional pattern matching
/// var action = issue switch
/// {
/// ("CustomerList", _, "Email", _, _, Severity.Critical) => "Block sync",
/// (_, _, _, "MissingRequired", _, _) => "Skip item",
/// _ => "Continue"
/// };
///
/// // Relational pattern
/// var priority = issue switch
/// {
/// { Severity: >= Severity.High } => 1,
/// { Severity: Severity.Medium } => 2,
/// _ => 3
/// };
/// </code>
/// </remarks>
/// <param name="ListName">Name of the SharePoint list where issue was found.</param>
/// <param name="ItemId">ID of the affected list item.</param>
/// <param name="FieldName">Name of the field with the issue.</param>
/// <param name="IssueType">Type/category of the data quality issue.</param>
/// <param name="Description">Detailed description of the issue.</param>
/// <param name="Severity">Severity level of the issue.</param>
public record DataQualityIssue(
string ListName,
int ItemId,
string FieldName,
string IssueType,
string Description,
Severity Severity
)
{
/// <summary>
/// Gets a formatted error message for logging.
/// </summary>
public string ErrorMessage =>
$"[{Severity}] {ListName}[{ItemId}].{FieldName}: {IssueType} - {Description}";
/// <summary>
/// Determines if this issue should block sync operations.
/// </summary>
public bool ShouldBlockSync => Severity is Severity.Critical;
}
/// <summary>
/// Severity level for data quality issues.
/// </summary>
public enum Severity
{
/// <summary>Informational only.</summary>
Low = 1,
/// <summary>Should be reviewed.</summary>
Medium = 2,
/// <summary>Needs attention.</summary>
High = 3,
/// <summary>Blocks operations.</summary>
Critical = 4
}
/// <summary>
/// Aggregated statistics for a sync operation.
/// Demonstrates calculated properties using expression body syntax.
/// </summary>
/// <param name="TotalItems">Total number of items in the sync scope.</param>
/// <param name="Successful">Number of items successfully synced.</param>
/// <param name="Failed">Number of items that failed to sync.</param>
/// <param name="Duration">Total duration of the sync operation.</param>
public record SyncStatistics(
int TotalItems,
int Successful,
int Failed,
TimeSpan Duration
)
{
/// <summary>
/// Gets the success rate as a percentage (0-100).
/// </summary>
public double SuccessRate => TotalItems > 0
? (Successful / (double)TotalItems) * 100
: 0;
/// <summary>
/// Gets the failure rate as a percentage (0-100).
/// </summary>
public double FailureRate => TotalItems > 0
? (Failed / (double)TotalItems) * 100
: 0;
/// <summary>
/// Gets the throughput in items per second.
/// </summary>
public double Throughput => Duration.TotalSeconds > 0
? Successful / Duration.TotalSeconds
: 0;
/// <summary>
/// Gets the average processing time per item.
/// </summary>
public TimeSpan AverageTimePerItem => Successful > 0
? TimeSpan.FromTicks(Duration.Ticks / Successful)
: TimeSpan.Zero;
/// <summary>
/// Gets whether the sync operation met quality standards (>95% success rate).
/// </summary>
public bool MeetsQualityStandards => SuccessRate >= 95.0;
/// <summary>
/// Gets a human-readable summary of the statistics.
/// </summary>
public string Summary =>
$"{Successful}/{TotalItems} items synced ({SuccessRate:F1}%) in {Duration.TotalSeconds:F1}s @ {Throughput:F2} items/sec";
}
/// <summary>
/// Contains connection information for SharePoint and SQL database.
/// Demonstrates value-based equality behavior of records.
/// </summary>
/// <remarks>
/// <para><strong>Value equality demonstration:</strong></para>
/// <code>
/// var conn1 = new ConnectionInfo(
/// "portal.contoso.com",
/// "SharePointDB",
/// "Production",
/// DateTime.Parse("2024-01-15T10:30:00Z")
/// );
///
/// var conn2 = new ConnectionInfo(
/// "portal.contoso.com",
/// "SharePointDB",
/// "Production",
/// DateTime.Parse("2024-01-15T10:30:00Z")
/// );
///
/// // Reference equality (different objects)
/// Console.WriteLine(ReferenceEquals(conn1, conn2)); // False
///
/// // Value equality (same property values)
/// Console.WriteLine(conn1 == conn2); // True
/// Console.WriteLine(conn1.Equals(conn2)); // True
/// Console.WriteLine(conn1.GetHashCode() == conn2.GetHashCode()); // True
///
/// // Useful for collections
/// var connections = new HashSet<ConnectionInfo> { conn1 };
/// connections.Add(conn2); // Won't add duplicate due to value equality
/// Console.WriteLine(connections.Count); // 1
///
/// // Modified copy breaks equality
/// var conn3 = conn1 with { Environment = "Development" };
/// Console.WriteLine(conn1 == conn3); // False
/// </code>
/// </remarks>
/// <param name="SiteName">SharePoint site name or URL.</param>
/// <param name="DatabaseName">SQL Server database name.</param>
/// <param name="Environment">Environment identifier (Development, Staging, Production).</param>
/// <param name="LastSync">Timestamp of the last successful sync operation.</param>
public record ConnectionInfo(
string SiteName,
string DatabaseName,
string Environment,
DateTime? LastSync
)
{
/// <summary>
/// Gets whether the connection is to a production environment.
/// </summary>
public bool IsProduction => Environment.Equals("Production", StringComparison.OrdinalIgnoreCase);
/// <summary>
/// Gets the time elapsed since the last sync.
/// </summary>
public TimeSpan? TimeSinceLastSync => LastSync.HasValue
? DateTime.UtcNow - LastSync.Value
: null;
/// <summary>
/// Gets a formatted connection description.
/// </summary>
public string Description =>
$"{SiteName} → {DatabaseName} ({Environment})";
}