Skip to content
This repository was archived by the owner on Jan 27, 2022. It is now read-only.

Commit cc88d94

Browse files
iscottb122Iain Scott
authored andcommitted
Added support for value objects.
1 parent d288599 commit cc88d94

7 files changed

Lines changed: 548 additions & 3 deletions

File tree

src/Winton.DomainModelling.DocumentDb/EntityFacade.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ namespace Winton.DomainModelling.DocumentDb
1212
{
1313
/// <inheritdoc />
1414
/// <summary>
15-
/// An abstraction layer over <see cref="Entity{TEntityId}" /> CRUD operations in DocumentDb. Allows multiple entity
16-
/// types to be transparently stored in one collection using a 'wrapper' document type with a type discriminator and
17-
/// namespaced ID.
15+
/// An abstraction layer over <see cref="Entity{TEntityId}" /> CRUD operations in DocumentDb. Allows multiple types to
16+
/// be transparently stored in one collection using a 'wrapper' document type with a type discriminator and namespaced
17+
/// ID.
1818
/// </summary>
1919
public sealed class EntityFacade : IEntityFacade
2020
{
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) Winton. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
using System;
5+
using System.Linq;
6+
using System.Threading.Tasks;
7+
8+
namespace Winton.DomainModelling.DocumentDb
9+
{
10+
/// <summary>
11+
/// An abstraction layer over Value Object operations in DocumentDb.
12+
/// </summary>
13+
public interface IValueObjectFacade
14+
{
15+
/// <summary>
16+
/// Create a Value Object of a specified type.
17+
/// </summary>
18+
/// <typeparam name="TValueObject">The type of the Value Object.</typeparam>
19+
/// <param name="valueObject">The Value Object to persist.</param>
20+
/// <returns>A Task.</returns>
21+
Task Create<TValueObject>(TValueObject valueObject)
22+
where TValueObject : struct, IEquatable<TValueObject>;
23+
24+
/// <summary>
25+
/// Delete a Value Object of a specified type.
26+
/// </summary>
27+
/// <typeparam name="TValueObject">The type of the Value Object.</typeparam>
28+
/// <param name="valueObject">The Value Object to delete.</param>
29+
/// <returns>A Task.</returns>
30+
Task Delete<TValueObject>(TValueObject valueObject)
31+
where TValueObject : struct, IEquatable<TValueObject>;
32+
33+
/// <summary>
34+
/// Query Value Objects of a specified type.
35+
/// </summary>
36+
/// <typeparam name="TValueObject">The type of the Value Objects.</typeparam>
37+
/// <returns>An <see cref="IQueryable{TValueObject}" />.</returns>
38+
IQueryable<TValueObject> Query<TValueObject>()
39+
where TValueObject : struct, IEquatable<TValueObject>;
40+
}
41+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) Winton. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
using System;
5+
using Newtonsoft.Json;
6+
7+
namespace Winton.DomainModelling.DocumentDb
8+
{
9+
internal sealed class ValueObjectDocument<TValueObject>
10+
where TValueObject : struct, IEquatable<TValueObject>
11+
{
12+
public ValueObjectDocument(TValueObject valueObject)
13+
{
14+
ValueObject = valueObject;
15+
}
16+
17+
[JsonProperty(PropertyName = "id")]
18+
public string Id { get; set; }
19+
20+
public string Type => GetDocumentType();
21+
22+
public TValueObject ValueObject { get; }
23+
24+
public static string GetDocumentType()
25+
{
26+
return typeof(TValueObject).Name;
27+
}
28+
}
29+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright (c) Winton. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
using System;
5+
using System.Linq;
6+
using System.Threading.Tasks;
7+
using Microsoft.Azure.Documents;
8+
using Microsoft.Azure.Documents.Client;
9+
10+
namespace Winton.DomainModelling.DocumentDb
11+
{
12+
/// <inheritdoc />
13+
/// <summary>
14+
/// An abstraction layer over Value Object operations in DocumentDb. Allows multiple types to be transparently stored
15+
/// in one collection using a 'wrapper' document type with a type discriminator.
16+
/// </summary>
17+
public sealed class ValueObjectFacade : IValueObjectFacade
18+
{
19+
private readonly Database _database;
20+
private readonly IDocumentClient _documentClient;
21+
private readonly DocumentCollection _documentCollection;
22+
23+
/// <summary>
24+
/// Initializes a new instance of the <see cref="ValueObjectFacade" /> class.
25+
/// </summary>
26+
/// <param name="database">The DocumentDb database.</param>
27+
/// <param name="documentCollection">The DocumentDb collection. Partitioned collections are not supported.</param>
28+
/// <param name="documentClient">A document client implementation.</param>
29+
public ValueObjectFacade(
30+
Database database,
31+
DocumentCollection documentCollection,
32+
IDocumentClient documentClient)
33+
{
34+
if (documentCollection.PartitionKey.Paths.Any())
35+
{
36+
throw new NotSupportedException("Partitioned collections not supported.");
37+
}
38+
39+
_database = database;
40+
_documentCollection = documentCollection;
41+
_documentClient = documentClient;
42+
}
43+
44+
/// <inheritdoc />
45+
/// <summary>
46+
/// Create a Value Object of a specified type.
47+
/// </summary>
48+
/// <typeparam name="TValueObject">The type of the Value Object.</typeparam>
49+
/// <param name="valueObject">The Value Object to persist.</param>
50+
/// <returns>A Task.</returns>
51+
public async Task Create<TValueObject>(TValueObject valueObject)
52+
where TValueObject : struct, IEquatable<TValueObject>
53+
{
54+
string valueObjectType = ValueObjectDocument<TValueObject>.GetDocumentType();
55+
56+
ValueObjectDocument<TValueObject> document =
57+
_documentClient.CreateDocumentQuery<ValueObjectDocument<TValueObject>>(GetUri())
58+
.Where(x => x.Type == valueObjectType)
59+
.AsEnumerable()
60+
.SingleOrDefault(x => x.ValueObject.Equals(valueObject));
61+
62+
if (document == null)
63+
{
64+
document = new ValueObjectDocument<TValueObject>(valueObject);
65+
66+
await _documentClient.CreateDocumentAsync(GetUri(), document);
67+
}
68+
}
69+
70+
/// <inheritdoc />
71+
/// <summary>
72+
/// Delete a Value Object of a specified type.
73+
/// </summary>
74+
/// <typeparam name="TValueObject">The type of the Value Object.</typeparam>
75+
/// <param name="valueObject">The Value Object to delete.</param>
76+
/// <returns>A Task.</returns>
77+
public async Task Delete<TValueObject>(TValueObject valueObject)
78+
where TValueObject : struct, IEquatable<TValueObject>
79+
{
80+
string valueObjectType = ValueObjectDocument<TValueObject>.GetDocumentType();
81+
82+
ValueObjectDocument<TValueObject> document =
83+
_documentClient.CreateDocumentQuery<ValueObjectDocument<TValueObject>>(GetUri())
84+
.Where(x => x.Type == valueObjectType)
85+
.AsEnumerable()
86+
.SingleOrDefault(x => x.ValueObject.Equals(valueObject));
87+
88+
if (document != null)
89+
{
90+
await _documentClient.DeleteDocumentAsync(GetUri(document.Id));
91+
}
92+
}
93+
94+
/// <inheritdoc />
95+
/// <summary>
96+
/// Query Value Objects of a specified type.
97+
/// </summary>
98+
/// <typeparam name="TValueObject">The type of the Value Objects.</typeparam>
99+
/// <returns>An <see cref="T:System.Linq.IQueryable`1" />.</returns>
100+
public IQueryable<TValueObject> Query<TValueObject>()
101+
where TValueObject : struct, IEquatable<TValueObject>
102+
{
103+
string valueObjectType = ValueObjectDocument<TValueObject>.GetDocumentType();
104+
105+
return _documentClient.CreateDocumentQuery<ValueObjectDocument<TValueObject>>(GetUri())
106+
.Where(x => x.Type == valueObjectType)
107+
.Select(x => x.ValueObject);
108+
}
109+
110+
private Uri GetUri()
111+
{
112+
return UriFactory.CreateDocumentCollectionUri(_database.Id, _documentCollection.Id);
113+
}
114+
115+
private Uri GetUri(string id)
116+
{
117+
return UriFactory.CreateDocumentUri(_database.Id, _documentCollection.Id, id);
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)