Skip to content

Commit 212a0db

Browse files
committed
Merge from upstream
2 parents fbdd39f + d1a6c76 commit 212a0db

File tree

70 files changed

+702
-39375
lines changed

Some content is hidden

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

70 files changed

+702
-39375
lines changed

CHANGELOG.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,40 @@
1+
# 3.6.1 (2024-04-23)
2+
3+
## Bugs
4+
5+
* **Change feed**: Fixed an issue causing an endless change notification for all documents under certain conditions ([#200](https://github.com/matteobortolazzo/couchdb-net/pull/201))
6+
7+
# 3.6.0 (2024-03-11)
8+
9+
## Bugs
10+
11+
* **Change feed**: Fixed automatic resume at last change in continuous feed ([#198](https://github.com/matteobortolazzo/couchdb-net/issues/198))
12+
13+
# 3.5.0 (2024-02-03)
14+
15+
## Features
16+
17+
* **Find**: Added support for fetching attachments with entire content ([#194](https://github.com/matteobortolazzo/couchdb-net/issues/194))
18+
19+
# 3.4.0 (2023-06-21)
20+
21+
## Features
22+
23+
* **Database split**: Configurable field for document discrimination ([#150](https://github.com/matteobortolazzo/couchdb-net/issues/150))
24+
* **Find**: Added all options and responses ([#182](https://github.com/matteobortolazzo/couchdb-net/issues/182))
25+
* **Change feed**: Adds support for database split ([#187](https://github.com/matteobortolazzo/couchdb-net/issues/187))
26+
* **Replicas**: Adds `CreateTarget` option ([#189](https://github.com/matteobortolazzo/couchdb-net/issues/189))
27+
28+
## Bugs
29+
30+
* **Queries**: Fix when `In` is called inside `Any` ([#183](https://github.com/matteobortolazzo/couchdb-net/issues/183))
31+
* **Database split**: Fix `FirstOrDefault` without filter queries ([#185](https://github.com/matteobortolazzo/couchdb-net/issues/185))
32+
133
# 3.3.1 (2022-10-26)
234

335
## Bug Fixes
436

5-
* **Dependency Injection**: Fix dependency injection packages references ([#180](https://github.com/matteobortolazzo/couchdb-net/pull/180))
37+
* **Dependency Injection**: Fix dependency injection packages references ([#180](https://github.com/matteobortolazzo/couchdb-net/pull/180))
638

739
# 3.3.0 (2022-10-20)
840

LATEST_CHANGE.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
## Bug Fixes
1+
# 3.6.1 (2024-04-23)
22

3-
* **Dependency Injection**: Fix dependency injection packages references ([#180](https://github.com/matteobortolazzo/couchdb-net/pull/180))
3+
## Bugs
4+
5+
* **Change feed**: Fixed an issue causing an endless change notification for all documents under certain conditions ([#200](https://github.com/matteobortolazzo/couchdb-net/pull/201))

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,8 @@ public class MyDeathStarContext : CouchContext
536536
> When multiple `CouchDatabase` point to the same **database**, a `split_discriminator` field is added on document creation.
537537
>
538538
> When querying, a filter by `split_discriminator` is added automatically.
539+
>
540+
> The field name can be overriden with the `WithDatabaseSplitDiscriminator`.
539541

540542
If you are not using `CouchContext`, you can still use the database split feature:
541543
```csharp

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
<PackageProjectUrl>https://github.com/matteobortolazzo/couchdb-net</PackageProjectUrl>
99
<RepositoryUrl>https://github.com/matteobortolazzo/couchdb-net</RepositoryUrl>
1010
<PackageTags>couchdb,driver,nosql,netstandard,pouchdb,xamarin</PackageTags>
11-
<PackageReleaseNotes></PackageReleaseNotes>
1211
<ApplicationIcon />
1312
<OutputType>Library</OutputType>
1413
<StartupObject />
@@ -31,7 +30,7 @@
3130

3231
<ItemGroup>
3332
<PackageReference Include="CouchDB.NET" Version="3.3.*" />
34-
<PackageReference Include="Autofac" Version="5.2.0" />
33+
<PackageReference Include="Autofac" Version="6.5.0" />
3534
</ItemGroup>
3635

3736
</Project>

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
<PackageProjectUrl>https://github.com/matteobortolazzo/couchdb-net</PackageProjectUrl>
99
<RepositoryUrl>https://github.com/matteobortolazzo/couchdb-net</RepositoryUrl>
1010
<PackageTags>couchdb,driver,nosql,netstandard,pouchdb,xamarin</PackageTags>
11-
<PackageReleaseNotes></PackageReleaseNotes>
1211
<ApplicationIcon />
1312
<OutputType>Library</OutputType>
1413
<StartupObject />
@@ -31,7 +30,7 @@
3130

3231
<ItemGroup>
3332
<PackageReference Include="CouchDB.NET" Version="3.3.*" />
34-
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.26" />
33+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
3534
</ItemGroup>
3635

3736
</Project>

src/CouchDB.Driver/CouchClient.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ namespace CouchDB.Driver
2323
/// </summary>
2424
public partial class CouchClient : ICouchClient
2525
{
26+
public const string DefaultDatabaseSplitDiscriminator = "split_discriminator";
2627
private DateTime? _cookieCreationDate;
2728
private string? _cookieToken;
2829

@@ -91,7 +92,7 @@ private IFlurlClient GetConfiguredClient() =>
9192
{
9293
s.JsonSerializer = new NewtonsoftJsonSerializer(new JsonSerializerSettings
9394
{
94-
ContractResolver = new CouchContractResolver(_options.PropertiesCase),
95+
ContractResolver = new CouchContractResolver(_options.PropertiesCase, _options.DatabaseSplitDiscriminator),
9596
NullValueHandling = _options.NullValueHandling ?? NullValueHandling.Include
9697
});
9798
s.BeforeCallAsync = OnBeforeCallAsync;

src/CouchDB.Driver/CouchDB.Driver.csproj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
<PackageProjectUrl>https://github.com/matteobortolazzo/couchdb-net</PackageProjectUrl>
99
<RepositoryUrl>https://github.com/matteobortolazzo/couchdb-net</RepositoryUrl>
1010
<PackageTags>couchdb,driver,nosql,netstandard,pouchdb,xamarin</PackageTags>
11-
<PackageReleaseNotes></PackageReleaseNotes>
1211
<ApplicationIcon />
1312
<OutputType>Library</OutputType>
1413
<StartupObject />
@@ -30,8 +29,8 @@
3029
</PropertyGroup>
3130

3231
<ItemGroup>
33-
<PackageReference Include="Flurl.Http" Version="3.2.0" />
34-
<PackageReference Include="Humanizer.Core" Version="2.11.10" />
32+
<PackageReference Include="Flurl.Http" Version="3.2.4" />
33+
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
3534
</ItemGroup>
3635

3736
<ItemGroup>

src/CouchDB.Driver/CouchDatabase.cs

Lines changed: 133 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,10 @@ internal CouchDatabase(IFlurlClient flurlClient, CouchOptions options, QueryCont
8181
public async Task<TSource?> FindAsync(string docId, FindOptions options, CancellationToken cancellationToken = default)
8282
{
8383
IFlurlRequest request = NewRequest()
84+
.WithHeader("Accept", "application/json")
8485
.AppendPathSegment(Uri.EscapeDataString(docId));
8586

86-
if (options.Conflicts)
87-
request = request.SetQueryParam("conflicts", "true");
88-
89-
if (options.Rev != null)
90-
request = request.SetQueryParam("rev", options.Rev);
91-
92-
IFlurlResponse? response = await request
87+
IFlurlResponse? response = await SetFindOptions(request, options)
9388
.AllowHttpStatus(HttpStatusCode.NotFound)
9489
.GetAsync(cancellationToken)
9590
.ConfigureAwait(false);
@@ -512,6 +507,7 @@ private async Task UpdateAttachments(TSource document, CancellationToken cancell
512507
public async Task<ChangesFeedResponse<TSource>> GetChangesAsync(ChangesFeedOptions? options = null, ChangesFeedFilter? filter = null, CancellationToken cancellationToken = default)
513508
{
514509
IFlurlRequest request = NewRequest()
510+
.WithHeader("Accept", "application/json")
515511
.AppendPathSegment("_changes");
516512

517513
if (options?.LongPoll == true)
@@ -524,11 +520,19 @@ public async Task<ChangesFeedResponse<TSource>> GetChangesAsync(ChangesFeedOptio
524520
request = request.ApplyQueryParametersOptions(options);
525521
}
526522

527-
return filter == null
523+
ChangesFeedResponse<TSource>? response = filter == null
528524
? await request.GetJsonAsync<ChangesFeedResponse<TSource>>(cancellationToken)
529525
.ConfigureAwait(false)
530526
: await request.QueryWithFilterAsync<TSource>(_queryProvider, filter, cancellationToken)
531527
.ConfigureAwait(false);
528+
529+
if (string.IsNullOrWhiteSpace(_discriminator))
530+
{
531+
return response;
532+
}
533+
534+
response.Results = response.Results.Where(result => result.Document.SplitDiscriminator == _discriminator).ToArray();
535+
return response;
532536
}
533537

534538
/// <inheritdoc />
@@ -538,6 +542,7 @@ public async IAsyncEnumerable<ChangesFeedResponseResult<TSource>> GetContinuousC
538542
var infiniteTimeout = TimeSpan.FromMilliseconds(Timeout.Infinite);
539543
IFlurlRequest request = NewRequest()
540544
.WithTimeout(infiniteTimeout)
545+
.WithHeader("Accept", "application/json")
541546
.AppendPathSegment("_changes")
542547
.SetQueryParam("feed", "continuous");
543548

@@ -546,29 +551,45 @@ public async IAsyncEnumerable<ChangesFeedResponseResult<TSource>> GetContinuousC
546551
request = request.ApplyQueryParametersOptions(options);
547552
}
548553

549-
await using Stream stream = filter == null
550-
? await request.GetStreamAsync(cancellationToken, HttpCompletionOption.ResponseHeadersRead)
551-
.ConfigureAwait(false)
552-
: await request.QueryContinuousWithFilterAsync<TSource>(_queryProvider, filter, cancellationToken)
553-
.ConfigureAwait(false);
554+
var lastSequence = options?.Since ?? "0";
554555

555-
await foreach (var line in stream.ReadLinesAsync(cancellationToken))
556+
do
556557
{
557-
if (string.IsNullOrEmpty(line))
558-
{
559-
continue;
560-
}
558+
await using Stream stream = filter == null
559+
? await request.GetStreamAsync(cancellationToken, HttpCompletionOption.ResponseHeadersRead)
560+
.ConfigureAwait(false)
561+
: await request.QueryContinuousWithFilterAsync<TSource>(_queryProvider, filter, cancellationToken)
562+
.ConfigureAwait(false);
561563

562-
MatchCollection matches = _feedChangeLineStartPattern.Matches(line);
563-
for (var i = 0; i < matches.Count; i++)
564+
await foreach (var line in stream.ReadLinesAsync(cancellationToken))
564565
{
565-
var startIndex = matches[i].Index;
566-
var endIndex = i < matches.Count - 1 ? matches[i + 1].Index : line.Length;
567-
var lineLength = endIndex - startIndex;
568-
var substring = line.Substring(startIndex, lineLength);
569-
yield return JsonConvert.DeserializeObject<ChangesFeedResponseResult<TSource>>(substring);
566+
if (string.IsNullOrEmpty(line))
567+
{
568+
continue;
569+
}
570+
571+
MatchCollection matches = _feedChangeLineStartPattern.Matches(line);
572+
for (var i = 0; i < matches.Count; i++)
573+
{
574+
var startIndex = matches[i].Index;
575+
var endIndex = i < matches.Count - 1 ? matches[i + 1].Index : line.Length;
576+
var lineLength = endIndex - startIndex;
577+
var substring = line.Substring(startIndex, lineLength);
578+
ChangesFeedResponseResult<TSource>? result =
579+
JsonConvert.DeserializeObject<ChangesFeedResponseResult<TSource>>(substring);
580+
if (string.IsNullOrWhiteSpace(_discriminator) ||
581+
result.Document.SplitDiscriminator == _discriminator)
582+
{
583+
lastSequence = result.Seq;
584+
yield return result;
585+
}
586+
}
570587
}
571-
}
588+
589+
// stream broke, pick up listening after last successful processed sequence
590+
request = request.SetQueryParam("since", lastSequence);
591+
592+
} while (!cancellationToken.IsCancellationRequested);
572593
}
573594

574595
#endregion
@@ -788,6 +809,34 @@ public async Task<CouchDatabaseInfo> GetInfoAsync(CancellationToken cancellation
788809
.ConfigureAwait(false);
789810
}
790811

812+
/// <inheritdoc />
813+
public async Task<int> GetRevisionLimitAsync(CancellationToken cancellationToken = default)
814+
{
815+
return Convert.ToInt32(await NewRequest()
816+
.AppendPathSegment("_revs_limit")
817+
.GetStringAsync(cancellationToken)
818+
.SendRequestAsync()
819+
.ConfigureAwait(false));
820+
}
821+
822+
/// <inheritdoc />
823+
public async Task SetRevisionLimitAsync(int limit, CancellationToken cancellationToken = default)
824+
{
825+
using var content = new StringContent(limit.ToString());
826+
827+
OperationResult result = await NewRequest()
828+
.AppendPathSegment("_revs_limit")
829+
.PutAsync(content, cancellationToken)
830+
.ReceiveJson<OperationResult>()
831+
.SendRequestAsync()
832+
.ConfigureAwait(false);
833+
834+
if (!result.Ok)
835+
{
836+
throw new CouchException("Something wrong happened while updating the revision limit.");
837+
}
838+
}
839+
791840
#endregion
792841

793842
#region Override
@@ -830,6 +879,64 @@ internal IndexBuilder<TSource> NewIndexBuilder(
830879
return builder;
831880
}
832881

882+
private static IFlurlRequest SetFindOptions(IFlurlRequest request, FindOptions options)
883+
{
884+
if (options.Attachments)
885+
{
886+
request = request.SetQueryParam("attachments", "true");
887+
}
888+
if (options.AttachmentsEncodingInfo)
889+
{
890+
request = request.SetQueryParam("att_encoding_info", "true");
891+
}
892+
if (options.AttachmentsSince != null && options.AttachmentsSince.Any())
893+
{
894+
request = request.SetQueryParam("att_encoding_info", options.AttachmentsSince);
895+
}
896+
if (options.Conflicts)
897+
{
898+
request = request.SetQueryParam("conflicts", "true");
899+
}
900+
if (options.DeleteConflicts)
901+
{
902+
request = request.SetQueryParam("deleted_conflicts", "true");
903+
}
904+
if (options.DeleteConflicts)
905+
{
906+
request = request.SetQueryParam("deleted_conflicts", "true");
907+
}
908+
if (options.Latest)
909+
{
910+
request = request.SetQueryParam("latest", "true");
911+
}
912+
if (options.LocalSequence)
913+
{
914+
request = request.SetQueryParam("local_seq", "true");
915+
}
916+
if (options.Meta)
917+
{
918+
request = request.SetQueryParam("meta", "true");
919+
}
920+
if (options.OpenRevisions != null && options.OpenRevisions.Any())
921+
{
922+
request = request.SetQueryParam("open_revs", options.AttachmentsSince);
923+
}
924+
if (options.Revision != null)
925+
{
926+
request = request.SetQueryParam("rev", options.Revision);
927+
}
928+
if (options.Revisions)
929+
{
930+
request = request.SetQueryParam("revs", "true");
931+
}
932+
if (options.RevisionsInfo)
933+
{
934+
request = request.SetQueryParam("revs_info", "true");
935+
}
936+
937+
return request;
938+
}
939+
833940
#endregion
834941
}
835942
}

0 commit comments

Comments
 (0)