44using System . Threading ;
55using System . Threading . Tasks ;
66using JsonApiDotNetCore . Configuration ;
7- using JsonApiDotNetCore . MongoDb . Extensions ;
87using JsonApiDotNetCore . Queries . Internal . QueryableBuilding ;
98using JsonApiDotNetCore . Repositories ;
109using JsonApiDotNetCore . Resources ;
1716
1817namespace JsonApiDotNetCore . MongoDb
1918{
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 >
2123 : IResourceRepository < TResource , TId >
2224 where TResource : class , IIdentifiable < TId >
2325 {
24- private readonly IMongoDatabase _db ;
26+ private readonly IMongoDatabase _mongoDatabase ;
2527 private readonly ITargetedFields _targetedFields ;
2628 private readonly IResourceContextProvider _resourceContextProvider ;
2729 private readonly IResourceFactory _resourceFactory ;
2830
29- public MongoEntityRepository (
30- IMongoDatabase db ,
31+ public MongoDbRepository (
32+ IMongoDatabase mongoDatabase ,
3133 ITargetedFields targetedFields ,
3234 IResourceContextProvider resourceContextProvider ,
3335 IResourceFactory resourceFactory )
3436 {
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 ) ) ;
3941 }
4042
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 ) ;
4344
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+ }
4653
54+ /// <inheritdoc />
4755 public virtual Task < int > CountAsync ( FilterExpression topFilter , CancellationToken cancellationToken )
4856 {
4957 var resourceContext = _resourceContextProvider . GetResourceContext < TResource > ( ) ;
@@ -55,7 +63,33 @@ public virtual Task<int> CountAsync(FilterExpression topFilter, CancellationToke
5563 var query = ApplyQueryLayer ( layer ) ;
5664 return query . CountAsync ( cancellationToken ) ;
5765 }
66+
67+ protected virtual IMongoQueryable < TResource > ApplyQueryLayer ( QueryLayer layer )
68+ {
69+ if ( layer == null ) throw new ArgumentNullException ( nameof ( layer ) ) ;
70+
71+ var source = GetAll ( ) ;
5872
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 />
5993 public virtual Task < TResource > GetForCreateAsync ( TId id , CancellationToken cancellationToken )
6094 {
6195 var resource = _resourceFactory . CreateInstance < TResource > ( ) ;
@@ -64,6 +98,7 @@ public virtual Task<TResource> GetForCreateAsync(TId id, CancellationToken cance
6498 return Task . FromResult ( resource ) ;
6599 }
66100
101+ /// <inheritdoc />
67102 public virtual Task CreateAsync ( TResource resourceFromRequest , TResource resourceForDatabase ,
68103 CancellationToken cancellationToken )
69104 {
@@ -78,76 +113,91 @@ public virtual Task CreateAsync(TResource resourceFromRequest, TResource resourc
78113 return Collection . InsertOneAsync ( resourceForDatabase , new InsertOneOptions ( ) , cancellationToken ) ;
79114 }
80115
116+ /// <inheritdoc />
81117 public virtual async Task < TResource > GetForUpdateAsync ( QueryLayer queryLayer , CancellationToken cancellationToken )
82118 {
83119 var resources = await GetAsync ( queryLayer , cancellationToken ) ;
84120 return resources . FirstOrDefault ( ) ;
85121 }
86122
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 )
88125 {
126+ if ( resourceFromRequest == null ) throw new ArgumentNullException ( nameof ( resourceFromRequest ) ) ;
127+ if ( resourceFromDatabase == null ) throw new ArgumentNullException ( nameof ( resourceFromDatabase ) ) ;
128+
89129 foreach ( var attr in _targetedFields . Attributes )
90- attr . SetValue ( databaseResource , attr . GetValue ( requestResource ) ) ;
130+ attr . SetValue ( resourceFromDatabase , attr . GetValue ( resourceFromRequest ) ) ;
91131
92132 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 ,
95135 new ReplaceOptions ( ) ,
96136 cancellationToken ) ;
97137 }
98138
139+ /// <inheritdoc />
99140 public virtual async Task DeleteAsync ( TId id , CancellationToken cancellationToken )
100141 {
101142 var result = await Collection . DeleteOneAsync (
102143 Builders < TResource > . Filter . Eq ( e => e . Id , id ) ,
103144 new DeleteOptions ( ) ,
104145 cancellationToken ) ;
105146
106- if ( ! result . IsAcknowledged || result . DeletedCount == 0 )
147+ if ( ! result . IsAcknowledged )
107148 {
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 } ") ) ;
109155 }
110156 }
111157
158+ /// <inheritdoc />
112159 public virtual Task SetRelationshipAsync ( TResource primaryResource , object secondaryResourceIds , CancellationToken cancellationToken )
113160 {
114161 throw new NotImplementedException ( ) ;
115162 }
116163
164+ /// <inheritdoc />
117165 public virtual Task AddToToManyRelationshipAsync ( TId primaryId , ISet < IIdentifiable > secondaryResourceIds , CancellationToken cancellationToken )
118166 {
119167 throw new NotImplementedException ( ) ;
120168 }
121169
122- public virtual Task RemoveFromToManyRelationshipAsync ( TResource primaryResource , ISet < IIdentifiable > secondaryResourceIds ,
170+ /// <inheritdoc />
171+ public virtual Task RemoveFromToManyRelationshipAsync ( TResource primaryResource ,
172+ ISet < IIdentifiable > secondaryResourceIds ,
123173 CancellationToken cancellationToken )
124174 {
125175 throw new NotImplementedException ( ) ;
126176 }
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 )
129191 {
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 ) ;
144192 }
145193 }
146194
147195 internal sealed class DummyModel : IModel
148196 {
149197 public static IModel Instance { get ; } = new DummyModel ( ) ;
150198
199+ public object this [ string name ] => throw new NotImplementedException ( ) ;
200+
151201 private DummyModel ( )
152202 {
153203 }
@@ -162,8 +212,6 @@ public IEnumerable<IAnnotation> GetAnnotations()
162212 throw new NotImplementedException ( ) ;
163213 }
164214
165- public object this [ string name ] => throw new NotImplementedException ( ) ;
166-
167215 public IEnumerable < IEntityType > GetEntityTypes ( )
168216 {
169217 throw new NotImplementedException ( ) ;
0 commit comments