4
4
using System . Threading ;
5
5
using System . Threading . Tasks ;
6
6
using JsonApiDotNetCore . Configuration ;
7
- using JsonApiDotNetCore . MongoDb . Extensions ;
8
7
using JsonApiDotNetCore . Queries . Internal . QueryableBuilding ;
9
8
using JsonApiDotNetCore . Repositories ;
10
9
using JsonApiDotNetCore . Resources ;
17
16
18
17
namespace JsonApiDotNetCore . MongoDb
19
18
{
20
- public class MongoEntityRepository < TResource , TId >
19
+ /// <summary>
20
+ /// Implements the foundational Repository layer in the JsonApiDotNetCore architecture that uses MongoDB.
21
+ /// </summary>
22
+ public class MongoDbRepository < TResource , TId >
21
23
: IResourceRepository < TResource , TId >
22
24
where TResource : class , IIdentifiable < TId >
23
25
{
24
- private readonly IMongoDatabase _db ;
26
+ private readonly IMongoDatabase _mongoDatabase ;
25
27
private readonly ITargetedFields _targetedFields ;
26
28
private readonly IResourceContextProvider _resourceContextProvider ;
27
29
private readonly IResourceFactory _resourceFactory ;
28
30
29
- public MongoEntityRepository (
30
- IMongoDatabase db ,
31
+ public MongoDbRepository (
32
+ IMongoDatabase mongoDatabase ,
31
33
ITargetedFields targetedFields ,
32
34
IResourceContextProvider resourceContextProvider ,
33
35
IResourceFactory resourceFactory )
34
36
{
35
- _db = db ;
36
- _targetedFields = targetedFields ;
37
- _resourceContextProvider = resourceContextProvider ;
38
- _resourceFactory = resourceFactory ;
37
+ _mongoDatabase = mongoDatabase ?? throw new ArgumentNullException ( nameof ( mongoDatabase ) ) ;
38
+ _targetedFields = targetedFields ?? throw new ArgumentNullException ( nameof ( targetedFields ) ) ;
39
+ _resourceContextProvider = resourceContextProvider ?? throw new ArgumentNullException ( nameof ( resourceContextProvider ) ) ;
40
+ _resourceFactory = resourceFactory ?? throw new ArgumentNullException ( nameof ( resourceFactory ) ) ;
39
41
}
40
42
41
- private IMongoCollection < TResource > Collection => _db . GetCollection < TResource > ( typeof ( TResource ) . Name ) ;
42
- private IMongoQueryable < TResource > Entities => Collection . AsQueryable ( ) ;
43
+ protected virtual IMongoCollection < TResource > Collection => _mongoDatabase . GetCollection < TResource > ( typeof ( TResource ) . Name ) ;
43
44
44
- public virtual async Task < IReadOnlyCollection < TResource > > GetAsync ( QueryLayer layer , CancellationToken cancellationToken ) =>
45
- await ApplyQueryLayer ( layer ) . ToListAsync ( ) ;
45
+ /// <inheritdoc />
46
+ public virtual async Task < IReadOnlyCollection < TResource > > GetAsync ( QueryLayer layer ,
47
+ CancellationToken cancellationToken )
48
+ {
49
+ if ( layer == null ) throw new ArgumentNullException ( nameof ( layer ) ) ;
50
+ var list = await ApplyQueryLayer ( layer ) . ToListAsync ( cancellationToken ) ;
51
+ return list . AsReadOnly ( ) ;
52
+ }
46
53
54
+ /// <inheritdoc />
47
55
public virtual Task < int > CountAsync ( FilterExpression topFilter , CancellationToken cancellationToken )
48
56
{
49
57
var resourceContext = _resourceContextProvider . GetResourceContext < TResource > ( ) ;
@@ -55,7 +63,33 @@ public virtual Task<int> CountAsync(FilterExpression topFilter, CancellationToke
55
63
var query = ApplyQueryLayer ( layer ) ;
56
64
return query . CountAsync ( cancellationToken ) ;
57
65
}
66
+
67
+ protected virtual IMongoQueryable < TResource > ApplyQueryLayer ( QueryLayer layer )
68
+ {
69
+ if ( layer == null ) throw new ArgumentNullException ( nameof ( layer ) ) ;
70
+
71
+ var source = GetAll ( ) ;
58
72
73
+ var nameFactory = new LambdaParameterNameFactory ( ) ;
74
+ var builder = new QueryableBuilder (
75
+ source . Expression ,
76
+ source . ElementType ,
77
+ typeof ( Queryable ) ,
78
+ nameFactory ,
79
+ _resourceFactory ,
80
+ _resourceContextProvider ,
81
+ DummyModel . Instance ) ;
82
+
83
+ var expression = builder . ApplyQuery ( layer ) ;
84
+ return ( IMongoQueryable < TResource > ) source . Provider . CreateQuery < TResource > ( expression ) ;
85
+ }
86
+
87
+ protected virtual IQueryable < TResource > GetAll ( )
88
+ {
89
+ return Collection . AsQueryable ( ) ;
90
+ }
91
+
92
+ /// <inheritdoc />
59
93
public virtual Task < TResource > GetForCreateAsync ( TId id , CancellationToken cancellationToken )
60
94
{
61
95
var resource = _resourceFactory . CreateInstance < TResource > ( ) ;
@@ -64,6 +98,7 @@ public virtual Task<TResource> GetForCreateAsync(TId id, CancellationToken cance
64
98
return Task . FromResult ( resource ) ;
65
99
}
66
100
101
+ /// <inheritdoc />
67
102
public virtual Task CreateAsync ( TResource resourceFromRequest , TResource resourceForDatabase ,
68
103
CancellationToken cancellationToken )
69
104
{
@@ -78,76 +113,91 @@ public virtual Task CreateAsync(TResource resourceFromRequest, TResource resourc
78
113
return Collection . InsertOneAsync ( resourceForDatabase , new InsertOneOptions ( ) , cancellationToken ) ;
79
114
}
80
115
116
+ /// <inheritdoc />
81
117
public virtual async Task < TResource > GetForUpdateAsync ( QueryLayer queryLayer , CancellationToken cancellationToken )
82
118
{
83
119
var resources = await GetAsync ( queryLayer , cancellationToken ) ;
84
120
return resources . FirstOrDefault ( ) ;
85
121
}
86
122
87
- public virtual async Task UpdateAsync ( TResource requestResource , TResource databaseResource , CancellationToken cancellationToken )
123
+ /// <inheritdoc />
124
+ public virtual async Task UpdateAsync ( TResource resourceFromRequest , TResource resourceFromDatabase , CancellationToken cancellationToken )
88
125
{
126
+ if ( resourceFromRequest == null ) throw new ArgumentNullException ( nameof ( resourceFromRequest ) ) ;
127
+ if ( resourceFromDatabase == null ) throw new ArgumentNullException ( nameof ( resourceFromDatabase ) ) ;
128
+
89
129
foreach ( var attr in _targetedFields . Attributes )
90
- attr . SetValue ( databaseResource , attr . GetValue ( requestResource ) ) ;
130
+ attr . SetValue ( resourceFromDatabase , attr . GetValue ( resourceFromRequest ) ) ;
91
131
92
132
await Collection . ReplaceOneAsync (
93
- Builders < TResource > . Filter . Eq ( e => e . Id , databaseResource . Id ) ,
94
- databaseResource ,
133
+ Builders < TResource > . Filter . Eq ( e => e . Id , resourceFromDatabase . Id ) ,
134
+ resourceFromDatabase ,
95
135
new ReplaceOptions ( ) ,
96
136
cancellationToken ) ;
97
137
}
98
138
139
+ /// <inheritdoc />
99
140
public virtual async Task DeleteAsync ( TId id , CancellationToken cancellationToken )
100
141
{
101
142
var result = await Collection . DeleteOneAsync (
102
143
Builders < TResource > . Filter . Eq ( e => e . Id , id ) ,
103
144
new DeleteOptions ( ) ,
104
145
cancellationToken ) ;
105
146
106
- if ( ! result . IsAcknowledged || result . DeletedCount == 0 )
147
+ if ( ! result . IsAcknowledged )
107
148
{
108
- throw new DataStoreUpdateException ( new Exception ( ) ) ;
149
+ throw new DataStoreUpdateException ( new Exception ( "Delete operation was not acknowledged by MongoDB" ) ) ;
150
+ }
151
+
152
+ if ( result . DeletedCount == 0 )
153
+ {
154
+ throw new DataStoreUpdateException ( new Exception ( $ "No documents were deleted. The id that was being sought was: { id } ") ) ;
109
155
}
110
156
}
111
157
158
+ /// <inheritdoc />
112
159
public virtual Task SetRelationshipAsync ( TResource primaryResource , object secondaryResourceIds , CancellationToken cancellationToken )
113
160
{
114
161
throw new NotImplementedException ( ) ;
115
162
}
116
163
164
+ /// <inheritdoc />
117
165
public virtual Task AddToToManyRelationshipAsync ( TId primaryId , ISet < IIdentifiable > secondaryResourceIds , CancellationToken cancellationToken )
118
166
{
119
167
throw new NotImplementedException ( ) ;
120
168
}
121
169
122
- public virtual Task RemoveFromToManyRelationshipAsync ( TResource primaryResource , ISet < IIdentifiable > secondaryResourceIds ,
170
+ /// <inheritdoc />
171
+ public virtual Task RemoveFromToManyRelationshipAsync ( TResource primaryResource ,
172
+ ISet < IIdentifiable > secondaryResourceIds ,
123
173
CancellationToken cancellationToken )
124
174
{
125
175
throw new NotImplementedException ( ) ;
126
176
}
127
-
128
- protected virtual IMongoQueryable < TResource > ApplyQueryLayer ( QueryLayer layer )
177
+ }
178
+
179
+ /// <summary>
180
+ /// Implements the foundational repository implementation that uses MongoDB.
181
+ /// </summary>
182
+ public class MongoDbRepository < TResource > : MongoDbRepository < TResource , string >
183
+ where TResource : class , IIdentifiable < string >
184
+ {
185
+ public MongoDbRepository (
186
+ IMongoDatabase mongoDatabase ,
187
+ ITargetedFields targetedFields ,
188
+ IResourceContextProvider resourceContextProvider ,
189
+ IResourceFactory resourceFactory )
190
+ : base ( mongoDatabase , targetedFields , resourceContextProvider , resourceFactory )
129
191
{
130
- var source = Entities ;
131
-
132
- var nameFactory = new LambdaParameterNameFactory ( ) ;
133
- var builder = new QueryableBuilder (
134
- source . Expression ,
135
- source . ElementType ,
136
- typeof ( Queryable ) ,
137
- nameFactory ,
138
- _resourceFactory ,
139
- _resourceContextProvider ,
140
- DummyModel . Instance ) ;
141
-
142
- var expression = builder . ApplyQuery ( layer ) ;
143
- return ( IMongoQueryable < TResource > ) source . Provider . CreateQuery < TResource > ( expression ) ;
144
192
}
145
193
}
146
194
147
195
internal sealed class DummyModel : IModel
148
196
{
149
197
public static IModel Instance { get ; } = new DummyModel ( ) ;
150
198
199
+ public object this [ string name ] => throw new NotImplementedException ( ) ;
200
+
151
201
private DummyModel ( )
152
202
{
153
203
}
@@ -162,8 +212,6 @@ public IEnumerable<IAnnotation> GetAnnotations()
162
212
throw new NotImplementedException ( ) ;
163
213
}
164
214
165
- public object this [ string name ] => throw new NotImplementedException ( ) ;
166
-
167
215
public IEnumerable < IEntityType > GetEntityTypes ( )
168
216
{
169
217
throw new NotImplementedException ( ) ;
0 commit comments