Skip to content

Commit 3ff2b6b

Browse files
committed
fix: addressed pr comments
1 parent e686d6d commit 3ff2b6b

File tree

6 files changed

+98
-76
lines changed

6 files changed

+98
-76
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ bld/
4040
# Visual Studio 2017 auto generated files
4141
Generated\ Files/
4242

43-
# MTest test Results
43+
# MSTest test Results
4444
[Tt]est[Rr]esult*/
4545
[Bb]uild[Ll]og.*
4646

README.md

+9-12
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
# JsonApiDotNetCore MongoDB Repository
22

3-
Plug-n-play implementation of `IResourceRepository<TResource, TId>` allowing you to use MongoDb with your `JsonApiDotNetCore` APIs.
3+
Plug-n-play implementation of `IResourceRepository<TResource, TId>` allowing you to use MongoDB with your `JsonApiDotNetCore` APIs.
44

55
## Installation and Usage
66

7+
```bash
8+
dotnet add package JsonApiDotNetCore.MongoDb
9+
```
10+
711
### Models
812

913
```cs
@@ -47,30 +51,23 @@ public class Startup
4751
return client.GetDatabase(Configuration.GetSection("DatabaseSettings:Database").Value);
4852
});
4953

50-
services.AddScoped<IResourceRepository<Book, string>, MongoEntityRepository<Book, string>>();
51-
services.AddJsonApi(options =>
52-
{
53-
options.Namespace = "api";
54-
options.UseRelativeLinks = true;
55-
options.IncludeTotalResourceCount = true;
56-
options.SerializerSettings.Formatting = Formatting.Indented;
57-
}, resources: builder =>
54+
services.AddResourceRepository<MongoDbRepository<Book>>();
55+
56+
services.AddJsonApi(resources: builder =>
5857
{
5958
builder.Add<Book, string>();
6059
});
61-
// ...
6260
}
6361

6462
public void Configure(IApplicationBuilder app)
6563
{
6664
app.UseRouting();
6765
app.UseJsonApi();
6866
app.UseEndpoints(endpoints => endpoints.MapControllers());
69-
// ...
7067
}
7168
}
7269
```
7370

7471
## Limitations
7572

76-
- Relations are not supported
73+
- Relationships are not supported

src/JsonApiDotNetCore.MongoDb/AssemblyInfo.cs

-3
This file was deleted.

src/JsonApiDotNetCore.MongoDb/Extensions/MongoIQueryableExtensions.cs

-20
This file was deleted.

src/JsonApiDotNetCore.MongoDb/JsonApiDotNetCore.MongoDb.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<VersionPrefix>4.0.0-rc</VersionPrefix>
4+
<VersionPrefix>4.0.0</VersionPrefix>
55
<TargetFramework>$(NetCoreAppVersion)</TargetFramework>
66
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
77
</PropertyGroup>
88

99
<PropertyGroup>
1010
<PackageTags>jsonapi;json:api;dotnet;core;MongoDB</PackageTags>
11-
<Description>Persistence layer implementation for use of mongodb in applications using JsonApiDotNetCore</Description>
11+
<Description>Persistence layer implementation for use of MongoDB in applications using JsonApiDotNetCore</Description>
1212
<PackageProjectUrl>https://github.com/json-api-dotnet/JsonApiDotNetCore.MongoDb</PackageProjectUrl>
1313
<PackageLicenseExpression>MIT</PackageLicenseExpression>
1414
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>

src/JsonApiDotNetCore.MongoDb/MongoEntityRepository.cs renamed to src/JsonApiDotNetCore.MongoDb/MongoDbRepository.cs

+86-38
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System.Threading;
55
using System.Threading.Tasks;
66
using JsonApiDotNetCore.Configuration;
7-
using JsonApiDotNetCore.MongoDb.Extensions;
87
using JsonApiDotNetCore.Queries.Internal.QueryableBuilding;
98
using JsonApiDotNetCore.Repositories;
109
using JsonApiDotNetCore.Resources;
@@ -17,33 +16,42 @@
1716

1817
namespace 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

Comments
 (0)