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