Skip to content

Commit 010ca6c

Browse files
Merge pull request #119 from matteobortolazzo/dev
v3.0.0
2 parents a2f5ad0 + 4a340d5 commit 010ca6c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1239
-297
lines changed

CHANGELOG.md

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
1-
# 2.0.1 (2020-09-19)
1+
# 3.0.0 (2020-03-09)
2+
3+
## Breaking Changes
4+
* Update to [Flurl 3](https://github.com/tmenier/Flurl/releases/tag/Flurl.Http.3.0.0). There should be no differences for the end user, but keep in mind.
5+
6+
## Features
7+
* **Table Splitting**: Ability to use the same database for different document with automatic filtering. ([#106](https://github.com/matteobortolazzo/couchdb-net/issues/106))
8+
* **Views**: Ability to get views. Thanks to [panoukos41](https://github.com/panoukos41)
9+
10+
## Improvements
11+
* **Logical Expressions Prune**: If expressions are constant booleans, they are removed automatically keeping the query valid. ([#113](https://github.com/matteobortolazzo/couchdb-net/issues/113))
12+
* **IsUpAsync**: Returns false on timeout and on not successful codes. ([#107](https://github.com/matteobortolazzo/couchdb-net/issues/107))
13+
* **FindAsync**: Faster when document is not found. ([#92](https://github.com/matteobortolazzo/couchdb-net/issues/92))
14+
15+
# 2.1.0 (2020-09-19)
216

317
## Features
418
* **Indexes"**: Ability to create indexes. ([#102](https://github.com/matteobortolazzo/couchdb-net/issues/102))

LATEST_CHANGE.md

+10-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
## Features
2-
* **Indexes"**: Ability to create indexes. ([#102](https://github.com/matteobortolazzo/couchdb-net/issues/102))
3-
* **Null values"**: New `SetNullValueHandling` method for `CouchOptionsBuilder` to set how to handle null values. ([#101](https://github.com/matteobortolazzo/couchdb-net/issues/101))
4-
* **Query"**: New `Select` and `Convert` methods to select specific fields.
1+
## Breaking Changes
2+
* Update to [Flurl 3](https://github.com/tmenier/Flurl/releases/tag/Flurl.Http.3.0.0). There should be no differences for the end user, but keep in mind.
53

6-
## Bug Fixes
7-
* **Conflicts**: Fix the query parameter value to get conflicts. ([#100](https://github.com/matteobortolazzo/couchdb-net/issues/100))
8-
* **Query**: Fix queries when variables are used. ([#104](https://github.com/matteobortolazzo/couchdb-net/issues/104))
4+
## Features
5+
* **Table Splitting**: Ability to use the same database for different document with automatic filtering. ([#106](https://github.com/matteobortolazzo/couchdb-net/issues/106))
6+
* **Views**: Ability to get views. Thanks to [panoukos41](https://github.com/panoukos41)
7+
8+
## Improvements
9+
* **Logical Expressions Prune**: If expressions are constant booleans, they are removed automatically keeping the query valid. ([#113](https://github.com/matteobortolazzo/couchdb-net/issues/113))
10+
* **IsUpAsync**: Returns false on timeout and on not successful codes. ([#107](https://github.com/matteobortolazzo/couchdb-net/issues/107))
11+
* **FindAsync**: Faster when document is not found. ([#92](https://github.com/matteobortolazzo/couchdb-net/issues/92))

README.md

+47-10
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ The produced Mango JSON:
104104
* [Indexing](#indexing)
105105
* [Index Options](#index-options)
106106
* [Partial Indexes](#partial-indexes)
107+
* [Database Splitting](#database-splitting)
108+
* [Views](#views)
107109
* [Local (non-replicating) Documents](#local-(non-replicating)-documents)
108110
* [Bookmark and Execution stats](#bookmark-and-execution-stats)
109111
* [Users](#users)
@@ -487,16 +489,7 @@ public class MyDeathStarContext : CouchContext
487489
{
488490
public CouchDatabase<Rebel> Rebels { get; set; }
489491

490-
protected override void OnConfiguring(CouchOptionsBuilder optionsBuilder)
491-
{
492-
optionsBuilder
493-
.UseEndpoint("http://localhost:5984/")
494-
.UseBasicAuthentication("admin", "admin")
495-
// If it finds a index with the same name and ddoc (or null)
496-
// but with different fields and/or sort order,
497-
// it will override the index
498-
.OverrideExistingIndexes();
499-
}
492+
// OnConfiguring(CouchOptionsBuilder optionsBuilder) { ... }
500493
501494
protected override void OnDatabaseCreating(CouchDatabaseBuilder databaseBuilder)
502495
{
@@ -506,6 +499,48 @@ public class MyDeathStarContext : CouchContext
506499
}
507500
```
508501

502+
## Database Splitting
503+
504+
It is possible to use the same database for multiple types:
505+
```csharp
506+
public class MyDeathStarContext : CouchContext
507+
{
508+
public CouchDatabase<Rebel> Rebels { get; set; }
509+
public CouchDatabase<Vehicle> Vehicles { get; set; }
510+
511+
// OnConfiguring(CouchOptionsBuilder optionsBuilder) { ... }
512+
513+
protected override void OnDatabaseCreating(CouchDatabaseBuilder databaseBuilder)
514+
{
515+
databaseBuilder.Document<Rebel>().ToDatabase("troups");
516+
databaseBuilder.Document<Vehicle>().ToDatabase("troups");
517+
}
518+
}
519+
```
520+
> When multiple `CouchDatabase` point to the same **database**, a `_discriminator` field is added on documents creation.
521+
>
522+
> When querying, a filter by `discriminator` is added automatically.
523+
524+
If you are not using `CouchContext`, you can still use the database slit feature:
525+
```csharp
526+
var rebels = client.GetDatabase<Rebel>("troups", nameof(Rebel));
527+
var vehicles = client.GetDatabase<Vehicle>("troups", nameof(Vehicle));
528+
```
529+
530+
## Views
531+
532+
It's possible to query a view with the following:
533+
```csharp
534+
var options = new CouchViewOptions<string[]>
535+
{
536+
StartKey = new[] {"Luke", "Skywalker"},
537+
IncludeDocs = true
538+
};
539+
var viewRows = await _rebels.GetViewAsync<string[], RebelView>("jedi", "by_name", options);
540+
// OR
541+
var details = await _rebels.GetDetailedViewAsync<int, BattleView>("battle", "by_name", options);
542+
```
543+
509544
## Local (non-replicating) Documents
510545

511546
The Local (non-replicating) document interface allows you to create local documents that are not replicated to other databases.
@@ -630,3 +665,5 @@ Thanks to [Ben Origas](https://github.com/borigas) for features, ideas and tests
630665
Thanks to [n9](https://github.com/n9) for proxy authentication, some bug fixes, suggestions and the great feedback on the changes feed feature!
631666
632667
Thanks to [Marc](https://github.com/bender-ristone) for NullValueHandling, bug fixes and suggestions!
668+
669+
Thanks to [Panos](https://github.com/panoukos41) for the help with Views and Table splitting.

src/CouchDB.Driver.DependencyInjection/CouchDB.Driver.DependencyInjection.csproj

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<NeutralLanguage>en</NeutralLanguage>
1717
<LangVersion>8.0</LangVersion>
1818
<Nullable>enable</Nullable>
19-
<Version>2.0.0</Version>
19+
<Version>3.0.0</Version>
2020
<PackageIcon>icon.png</PackageIcon>
2121
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
2222
</PropertyGroup>
@@ -32,8 +32,8 @@
3232
</ItemGroup>
3333

3434
<ItemGroup>
35-
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" PrivateAssets="All" Version="3.0.0" />
36-
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" />
35+
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" PrivateAssets="All" Version="3.3.1" />
36+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.12" />
3737
</ItemGroup>
3838

3939
<ItemGroup>

src/CouchDB.Driver/ChangesFeed/ChangesFeedStyle.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ public class ChangesFeedStyle
99
/// <summary>
1010
/// The feed will only return the current "winning" revision;
1111
/// </summary>
12-
public static ChangesFeedStyle MainOnly => new ChangesFeedStyle("main_only");
12+
public static ChangesFeedStyle MainOnly => new("main_only");
1313

1414
/// <summary>
1515
/// The feed will return all leaf revisions (including conflicts and deleted former conflicts).
1616
/// </summary>
17-
public static ChangesFeedStyle AllDocs => new ChangesFeedStyle("all_docs");
17+
public static ChangesFeedStyle AllDocs => new("all_docs");
1818

1919
private ChangesFeedStyle(string value)
2020
{

src/CouchDB.Driver/CouchClient.cs

+45-27
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
using CouchDB.Driver.DTOs;
1212
using CouchDB.Driver.Exceptions;
1313
using Newtonsoft.Json;
14-
using System.Net.Http;
1514
using System.Net;
1615
using System.Threading;
1716
using CouchDB.Driver.Options;
@@ -26,8 +25,10 @@ public partial class CouchClient : ICouchClient
2625
{
2726
private DateTime? _cookieCreationDate;
2827
private string? _cookieToken;
29-
private readonly CouchOptions _options;
28+
29+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2213:Disposable fields should be disposed", Justification = "<Pending>")]
3030
private readonly IFlurlClient _flurlClient;
31+
private readonly CouchOptions _options;
3132
private readonly string[] _systemDatabases = { "_users", "_replicator", "_global_changes" };
3233
public Uri Endpoint { get; }
3334

@@ -107,28 +108,28 @@ private IFlurlClient GetConfiguredClient() =>
107108
#region CRUD
108109

109110
/// <inheritdoc />
110-
public ICouchDatabase<TSource> GetDatabase<TSource>(string database) where TSource : CouchDocument
111+
public ICouchDatabase<TSource> GetDatabase<TSource>(string database, string? discriminator = null) where TSource : CouchDocument
111112
{
112113
CheckDatabaseName(database);
113114
var queryContext = new QueryContext(Endpoint, database);
114-
return new CouchDatabase<TSource>(_flurlClient, _options, queryContext);
115+
return new CouchDatabase<TSource>(_flurlClient, _options, queryContext, discriminator);
115116
}
116117

117118
/// <inheritdoc />
118119
public async Task<ICouchDatabase<TSource>> CreateDatabaseAsync<TSource>(string database,
119-
int? shards = null, int? replicas = null, CancellationToken cancellationToken = default)
120+
int? shards = null, int? replicas = null, string? discriminator = null, CancellationToken cancellationToken = default)
120121
where TSource : CouchDocument
121122
{
122123
QueryContext queryContext = NewQueryContext(database);
123-
HttpResponseMessage response = await CreateDatabaseAsync(queryContext, shards, replicas, cancellationToken)
124+
IFlurlResponse response = await CreateDatabaseAsync(queryContext, shards, replicas, cancellationToken)
124125
.ConfigureAwait(false);
125126

126-
if (response.IsSuccessStatusCode)
127+
if (response.IsSuccessful())
127128
{
128-
return new CouchDatabase<TSource>(_flurlClient, _options, queryContext);
129+
return new CouchDatabase<TSource>(_flurlClient, _options, queryContext, discriminator);
129130
}
130131

131-
if (response.StatusCode == HttpStatusCode.PreconditionFailed)
132+
if (response.StatusCode == (int)HttpStatusCode.PreconditionFailed)
132133
{
133134
throw new CouchException($"Database with name {database} already exists.");
134135
}
@@ -138,16 +139,16 @@ public async Task<ICouchDatabase<TSource>> CreateDatabaseAsync<TSource>(string d
138139

139140
/// <inheritdoc />
140141
public async Task<ICouchDatabase<TSource>> GetOrCreateDatabaseAsync<TSource>(string database,
141-
int? shards = null, int? replicas = null, CancellationToken cancellationToken = default)
142+
int? shards = null, int? replicas = null, string? discriminator = null, CancellationToken cancellationToken = default)
142143
where TSource : CouchDocument
143144
{
144145
QueryContext queryContext = NewQueryContext(database);
145-
HttpResponseMessage response = await CreateDatabaseAsync(queryContext, shards, replicas, cancellationToken)
146+
IFlurlResponse response = await CreateDatabaseAsync(queryContext, shards, replicas, cancellationToken)
146147
.ConfigureAwait(false);
147148

148-
if (response.IsSuccessStatusCode || response.StatusCode == HttpStatusCode.PreconditionFailed)
149+
if (response.IsSuccessful() || response.StatusCode == (int)HttpStatusCode.PreconditionFailed)
149150
{
150-
return new CouchDatabase<TSource>(_flurlClient, _options, queryContext);
151+
return new CouchDatabase<TSource>(_flurlClient, _options, queryContext, discriminator);
151152
}
152153

153154
throw new CouchException($"Something wrong happened while creating database {database}.");
@@ -171,7 +172,7 @@ public async Task DeleteDatabaseAsync(string database, CancellationToken cancell
171172
}
172173
}
173174

174-
private Task<HttpResponseMessage> CreateDatabaseAsync(QueryContext queryContext,
175+
private Task<IFlurlResponse> CreateDatabaseAsync(QueryContext queryContext,
175176
int? shards = null, int? replicas = null, CancellationToken cancellationToken = default)
176177
{
177178
IFlurlRequest request = NewRequest()
@@ -204,17 +205,17 @@ public ICouchDatabase<TSource> GetDatabase<TSource>() where TSource : CouchDocum
204205
}
205206

206207
/// <inheritdoc />
207-
public Task<ICouchDatabase<TSource>> CreateDatabaseAsync<TSource>(int? shards = null, int? replicas = null,
208+
public Task<ICouchDatabase<TSource>> CreateDatabaseAsync<TSource>(int? shards = null, int? replicas = null, string? discriminator = null,
208209
CancellationToken cancellationToken = default) where TSource : CouchDocument
209210
{
210-
return CreateDatabaseAsync<TSource>(GetClassName<TSource>(), shards, replicas, cancellationToken);
211+
return CreateDatabaseAsync<TSource>(GetClassName<TSource>(), shards, replicas, discriminator, cancellationToken);
211212
}
212213

213214
/// <inheritdoc />
214-
public Task<ICouchDatabase<TSource>> GetOrCreateDatabaseAsync<TSource>(int? shards = null, int? replicas = null,
215+
public Task<ICouchDatabase<TSource>> GetOrCreateDatabaseAsync<TSource>(int? shards = null, int? replicas = null, string? discriminator = null,
215216
CancellationToken cancellationToken = default) where TSource : CouchDocument
216217
{
217-
return GetOrCreateDatabaseAsync<TSource>(GetClassName<TSource>(), shards, replicas, cancellationToken);
218+
return GetOrCreateDatabaseAsync<TSource>(GetClassName<TSource>(), shards, replicas, discriminator, cancellationToken);
218219
}
219220

220221
/// <inheritdoc />
@@ -242,13 +243,13 @@ public ICouchDatabase<TUser> GetUsersDatabase<TUser>() where TUser : CouchUser
242243
/// <inheritdoc />
243244
public Task<ICouchDatabase<CouchUser>> GetOrCreateUsersDatabaseAsync(CancellationToken cancellationToken = default)
244245
{
245-
return GetOrCreateDatabaseAsync<CouchUser>(null, null, cancellationToken);
246+
return GetOrCreateDatabaseAsync<CouchUser>(null, null, null, cancellationToken);
246247
}
247248

248249
/// <inheritdoc />
249250
public Task<ICouchDatabase<TUser>> GetOrCreateUsersDatabaseAsync<TUser>(CancellationToken cancellationToken = default) where TUser : CouchUser
250251
{
251-
return GetOrCreateDatabaseAsync<TUser>(null, null, cancellationToken);
252+
return GetOrCreateDatabaseAsync<TUser>(null, null, null, cancellationToken);
252253
}
253254

254255
#endregion
@@ -259,12 +260,12 @@ public Task<ICouchDatabase<TUser>> GetOrCreateUsersDatabaseAsync<TUser>(Cancella
259260
public async Task<bool> ExistsAsync(string database, CancellationToken cancellationToken = default)
260261
{
261262
QueryContext queryContext = NewQueryContext(database);
262-
HttpResponseMessage? response = await NewRequest()
263+
IFlurlResponse? response = await NewRequest()
263264
.AllowHttpStatus(HttpStatusCode.NotFound)
264265
.AppendPathSegment(queryContext.EscapedDatabaseName)
265266
.HeadAsync(cancellationToken)
266267
.ConfigureAwait(false);
267-
return response.IsSuccessStatusCode;
268+
return response.IsSuccessful();
268269
}
269270

270271
/// <inheritdoc />
@@ -273,13 +274,14 @@ public async Task<bool> IsUpAsync(CancellationToken cancellationToken = default)
273274
try
274275
{
275276
StatusResult result = await NewRequest()
277+
.AllowAnyHttpStatus()
276278
.AppendPathSegment("/_up")
277279
.GetJsonAsync<StatusResult>(cancellationToken)
278280
.SendRequestAsync()
279281
.ConfigureAwait(false);
280-
return result.Status == "ok";
282+
return result?.Status == "ok";
281283
}
282-
catch (CouchNotFoundException)
284+
catch (CouchException)
283285
{
284286
return false;
285287
}
@@ -337,18 +339,34 @@ private void CheckDatabaseName(string database)
337339
/// </summary>
338340
public async ValueTask DisposeAsync()
339341
{
340-
if (_options.AuthenticationType == AuthenticationType.Cookie && _options.LogOutOnDispose)
342+
await DisposeAsync(true).ConfigureAwait(false);
343+
GC.SuppressFinalize(this);
344+
}
345+
346+
protected virtual async Task DisposeAsync(bool disposing)
347+
{
348+
if (disposing && _flurlClient != null)
341349
{
342-
await LogoutAsync().ConfigureAwait(false);
350+
if (_options.AuthenticationType == AuthenticationType.Cookie && _options.LogOutOnDispose)
351+
{
352+
await LogoutAsync().ConfigureAwait(false);
353+
}
354+
355+
_flurlClient.Dispose();
343356
}
344-
_flurlClient.Dispose();
345357
}
346358

347359
#endregion
348360

349361
private string GetClassName<TSource>()
350362
{
351363
Type type = typeof(TSource);
364+
return GetClassName(type);
365+
}
366+
367+
public string GetClassName(Type type)
368+
{
369+
Check.NotNull(type, nameof(type));
352370
return type.GetName(_options);
353371
}
354372
}

0 commit comments

Comments
 (0)