├── tests
├── CouchDB.Driver.E2ETests
│ ├── Assets
│ │ └── luke.txt
│ ├── README.txt
│ ├── _Models
│ │ ├── RebelSettings.cs
│ │ └── Rebel.cs
│ ├── CouchDB.Driver.E2ETests.csproj
│ └── MyDeathStarContext.cs
├── CouchDB.Driver.UnitTests
│ ├── Assets
│ │ └── luke.txt
│ ├── _Models
│ │ ├── NewRebel.cs
│ │ ├── Species.cs
│ │ ├── Vehicle.cs
│ │ ├── RebelView.cs
│ │ ├── OtherRebel.cs
│ │ ├── Battle.cs
│ │ └── Rebel.cs
│ ├── _Helpers
│ │ └── HttpCallEssertionExtensions.cs
│ ├── Find
│ │ ├── Find_Unsupported.cs
│ │ ├── Find_Sort.cs
│ │ └── Find_Optimized.cs
│ ├── CouchDB.Driver.UnitTests.csproj
│ ├── Feed
│ │ └── ChangesFeedOptions_Tests.cs
│ ├── Index_Tests.cs
│ ├── ChangesFeed_DesignDocumentFilter_Tests.cs
│ └── Attachments_Tests.cs
└── CouchDB.Driver.Example
│ ├── Views
│ ├── _ViewStart.cshtml
│ ├── _ViewImports.cshtml
│ ├── Home
│ │ ├── Privacy.cshtml
│ │ └── Index.cshtml
│ ├── Shared
│ │ ├── _ValidationScriptsPartial.cshtml
│ │ ├── Error.cshtml
│ │ └── _Layout.cshtml
│ └── Rebels
│ │ ├── Details.cshtml
│ │ ├── Delete.cshtml
│ │ ├── Index.cshtml
│ │ ├── Edit.cshtml
│ │ └── Create.cshtml
│ ├── wwwroot
│ ├── favicon.ico
│ ├── js
│ │ └── site.js
│ └── css
│ │ └── site.css
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── Models
│ ├── ErrorViewModel.cs
│ └── Rebel.cs
│ ├── Program.cs
│ ├── Controllers
│ └── HomeController.cs
│ ├── MyDeathStarContext.cs
│ ├── Startup.cs
│ └── CouchDB.Driver.Example.csproj
├── src
├── CouchDB.Driver
│ ├── Images
│ │ └── icon.png
│ ├── ChangesFeed
│ │ ├── Filters
│ │ │ ├── DesignChangesFeedFilter.cs
│ │ │ ├── ViewChangesFeedFilter.cs
│ │ │ ├── DocumentIdsChangesFeedFilter.cs
│ │ │ ├── ChangesFeedFilterDocuments.cs
│ │ │ ├── SelectorChangesFeedFilter.cs
│ │ │ └── DesignDocumentChangesFeedFilter.cs
│ │ ├── Responses
│ │ │ ├── ChangesFeedResponseResultChange.cs
│ │ │ ├── ChangesFeedResponse.cs
│ │ │ └── ChangesFeedResponseResult.cs
│ │ ├── ChangesFeedStyle.cs
│ │ ├── StreamExtensions.cs
│ │ └── ChangesFeedFilter.cs
│ ├── Options
│ │ ├── AuthenticationType.cs
│ │ ├── CouchOptions`.cs
│ │ ├── CouchDocumentBuilder.cs
│ │ ├── IndexSetupDefinition.cs
│ │ ├── CouchDatabaseBuilder.cs
│ │ ├── CaseType.cs
│ │ ├── DocumentCaseType.cs
│ │ ├── CouchDocumentBuilder`.cs
│ │ ├── CouchOptions.cs
│ │ └── PropertyCaseType.cs
│ ├── Query
│ │ ├── IQueryTranslator.cs
│ │ ├── IQueryOptimizer.cs
│ │ ├── IQuerySender.cs
│ │ ├── IQueryCompiler.cs
│ │ ├── IAsyncQueryProvider.cs
│ │ ├── QueryContext.cs
│ │ ├── Extensions
│ │ │ ├── ExpressionExtensions.cs
│ │ │ ├── StringQueryExtensions.cs
│ │ │ ├── EnumerableQueryExtensions.cs
│ │ │ └── ObjectQueryExtensions.cs
│ │ ├── Translators
│ │ │ ├── MemberExpressionTranslator.cs
│ │ │ ├── UnaryExpressionTranslator.cs
│ │ │ └── ConstantExpressionTranslator.cs
│ │ ├── QueryTranslator.cs
│ │ ├── CouchQueryProvider.cs
│ │ └── QuerySender.cs
│ ├── Indexes
│ │ ├── IndexOptions.cs
│ │ ├── IIndexBuilderBase.cs
│ │ ├── IOrderedIndexBuilder.cs
│ │ ├── IOrderedDescendingIndexBuilder.cs
│ │ ├── IIndexBuilder.cs
│ │ ├── IndexDefinition.cs
│ │ └── IndexBuilder.cs
│ ├── DTOs
│ │ ├── CouchError.cs
│ │ ├── IndexDefinitionInfo.cs
│ │ ├── OperationResult.cs
│ │ ├── GetIndexesResult.cs
│ │ ├── StatusResult.cs
│ │ ├── AttachmentResult.cs
│ │ ├── CreateIndexResult.cs
│ │ ├── BulkGetResultItem.cs
│ │ ├── DocumentSaveResponse.cs
│ │ ├── BulkGetResult.cs
│ │ ├── BulkGetResultDoc.cs
│ │ ├── CouchViewQueryResult.cs
│ │ ├── FindResult.cs
│ │ └── AllDocsResult.cs
│ ├── AssemblyInfo.cs
│ ├── Types
│ │ ├── IndexFieldDirection.cs
│ │ ├── RevisionInfo.cs
│ │ ├── CouchReplicationAuth.cs
│ │ ├── Revisions.cs
│ │ ├── CouchReplicationHost.cs
│ │ ├── DocumentId.cs
│ │ ├── CouchDocumentInfo.cs
│ │ ├── CouchReplicationBasicCredentials.cs
│ │ ├── Sizes.cs
│ │ ├── Cluster.cs
│ │ ├── CouchReplication.cs
│ │ ├── CouchPartitionInfo.cs
│ │ ├── CouchList.cs
│ │ ├── CouchType.cs
│ │ ├── IndexInfo.cs
│ │ ├── ExecutionStats.cs
│ │ ├── CouchUser.cs
│ │ ├── CouchActiveTask.cs
│ │ ├── CouchDatabaseInfo.cs
│ │ └── CouchAttachmentsCollection.cs
│ ├── Helpers
│ │ ├── Check.cs
│ │ ├── CertClientFactory.cs
│ │ ├── MicrosecondEpochConverter.cs
│ │ ├── RequestsHelper.cs
│ │ └── CouchContractResolver.cs
│ ├── Local
│ │ ├── LocalDocumentsResult.cs
│ │ ├── LocalDocumentsOptions.cs
│ │ └── ILocalDocuments.cs
│ ├── Exceptions
│ │ ├── CouchDBQueryWarningException.cs
│ │ ├── CouchDeleteException.cs
│ │ ├── CouchConflictException.cs
│ │ ├── CouchNoIndexException.cs
│ │ ├── CouchNotFoundException.cs
│ │ └── CouchException.cs
│ ├── Extensions
│ │ ├── CouchDocumentExtensions.cs
│ │ ├── CouchDatabaseExtensions.cs
│ │ ├── MemberInfoExtensions.cs
│ │ └── FlurlRequestExtensions.cs
│ ├── DatabaseApiMethodOptions
│ │ ├── AddOptions.cs
│ │ ├── AddOrUpdateOptions.cs
│ │ └── FindOptions.cs
│ ├── Security
│ │ ├── ICouchSecurity.cs
│ │ ├── CouchSecurityInfoType.cs
│ │ ├── CouchSecurityInfo.cs
│ │ └── CouchSecurity.cs
│ ├── Views
│ │ ├── StableStyle.cs
│ │ ├── UpdateStyle.cs
│ │ ├── CouchView.cs
│ │ └── CouchViewList.cs
│ ├── License
│ │ └── LICENSE.txt
│ ├── Converters
│ │ └── AttachmentsParsedConverter.cs
│ ├── CouchDB.Driver.csproj
│ ├── CouchQueryable.cs
│ └── Shared
│ │ ├── OptionsHelper.cs
│ │ └── SupportedMethodsProvider.cs
├── CouchDB.Driver.DependencyInjection
│ ├── Images
│ │ └── icon.png
│ ├── ServiceCollectionExtensions.cs
│ ├── License
│ │ └── LICENSE.txt
│ └── CouchDB.Driver.DependencyInjection.csproj
├── CouchDB.Driver.DependencyInjection.Autofac
│ ├── Images
│ │ └── icon.png
│ ├── AutofacRegistrationExtensions.cs
│ ├── License
│ │ └── LICENSE.txt
│ └── CouchDB.Driver.DependencyInjection.Autofac.csproj
└── CouchDB.sln.DotSettings
├── LATEST_CHANGE.md
├── LICENSE
└── .github
└── workflows
└── build-and-release.yml
/tests/CouchDB.Driver.E2ETests/Assets/luke.txt:
--------------------------------------------------------------------------------
1 | Hi, I am Luke Skywalker
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/Assets/luke.txt:
--------------------------------------------------------------------------------
1 | Hi, I am Luke Skywalker
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Views/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "_Layout";
3 | }
4 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matteobortolazzo/couchdb-net/HEAD/src/CouchDB.Driver/Images/icon.png
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matteobortolazzo/couchdb-net/HEAD/tests/CouchDB.Driver.Example/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/_Models/NewRebel.cs:
--------------------------------------------------------------------------------
1 | namespace CouchDB.UnitTests.Models
2 | {
3 | public class NewRebel : Rebel
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver.DependencyInjection/Images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matteobortolazzo/couchdb-net/HEAD/src/CouchDB.Driver.DependencyInjection/Images/icon.png
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/_Models/Species.cs:
--------------------------------------------------------------------------------
1 | namespace CouchDB.UnitTests.Models
2 | {
3 | public enum Species
4 | {
5 | Human, Droid
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver.DependencyInjection.Autofac/Images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matteobortolazzo/couchdb-net/HEAD/src/CouchDB.Driver.DependencyInjection.Autofac/Images/icon.png
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Views/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using CouchDB.Driver.Example
2 | @using CouchDB.Driver.Example.Models
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/ChangesFeed/Filters/DesignChangesFeedFilter.cs:
--------------------------------------------------------------------------------
1 | namespace CouchDB.Driver.ChangesFeed.Filters
2 | {
3 | internal class DesignChangesFeedFilter : ChangesFeedFilter { }
4 | }
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/_Models/Vehicle.cs:
--------------------------------------------------------------------------------
1 | namespace CouchDB.UnitTests.Models
2 | {
3 | public class Vehicle
4 | {
5 | public bool CanFly { get; set; }
6 | }
7 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Options/AuthenticationType.cs:
--------------------------------------------------------------------------------
1 | namespace CouchDB.Driver.Options
2 | {
3 | internal enum AuthenticationType
4 | {
5 | None, Basic, Cookie, Proxy, Jwt
6 | }
7 | }
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Views/Home/Privacy.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Privacy Policy";
3 | }
4 |
@ViewData["Title"]
5 |
6 | Use this page to detail your site's privacy policy.
7 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/IQueryTranslator.cs:
--------------------------------------------------------------------------------
1 | using System.Linq.Expressions;
2 |
3 | namespace CouchDB.Driver.Query
4 | {
5 | internal interface IQueryTranslator
6 | {
7 | string Translate(Expression e);
8 | }
9 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Indexes/IndexOptions.cs:
--------------------------------------------------------------------------------
1 | namespace CouchDB.Driver.Indexes
2 | {
3 | public class IndexOptions
4 | {
5 | public string? DesignDocument { get; set; }
6 | public bool? Partitioned { get; set; }
7 | }
8 | }
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.E2ETests/README.txt:
--------------------------------------------------------------------------------
1 | You need a CouchDB database engine running on http://localhost:5984/.
2 |
3 | If you have a docker execute:
4 | ```
5 | docker run -p 5984:5984 -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=admin -d couchdb
6 | ```
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Views/Shared/_ValidationScriptsPartial.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/IQueryOptimizer.cs:
--------------------------------------------------------------------------------
1 | using System.Linq.Expressions;
2 |
3 | namespace CouchDB.Driver.Query
4 | {
5 | internal interface IQueryOptimizer
6 | {
7 | Expression Optimize(Expression e, string? discriminator);
8 | }
9 | }
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/IQuerySender.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 |
3 | namespace CouchDB.Driver.Query
4 | {
5 | internal interface IQuerySender
6 | {
7 | TResult Send(string body, bool async, CancellationToken cancellationToken);
8 | }
9 | }
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.E2ETests/_Models/RebelSettings.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.Types;
2 |
3 | namespace CouchDB.Driver.E2ETests.Models
4 | {
5 | public class RebelSettings: CouchDocument
6 | {
7 | public bool IsActive { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/CouchError.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | namespace CouchDB.Driver.DTOs
3 | {
4 | internal class CouchError
5 | {
6 | public string Error { get; set; }
7 | public string Reason { get; set; }
8 | }
9 | }
10 | #nullable restore
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/wwwroot/js/site.js:
--------------------------------------------------------------------------------
1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | // for details on configuring this project to bundle and minify static web assets.
3 |
4 | // Write your JavaScript code.
5 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | [assembly: InternalsVisibleTo("CouchDB.Driver.UnitTests")]
4 | [assembly: InternalsVisibleTo("CouchDB.NET.DependencyInjection")]
5 | [assembly: InternalsVisibleTo("CouchDB.NET.DependencyInjection.Autofac")]
6 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Options/CouchOptions`.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CouchDB.Driver.Options
4 | {
5 | public class CouchOptions : CouchOptions
6 | where TContext : CouchContext
7 | {
8 | public override Type ContextType => typeof(TContext);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/IndexFieldDirection.cs:
--------------------------------------------------------------------------------
1 | namespace CouchDB.Driver.Types
2 | {
3 | ///
4 | /// Represent the direction of the index.
5 | ///
6 | public enum IndexFieldDirection
7 | {
8 | Ascending = 0,
9 | Descending = 1,
10 | }
11 | }
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Views/Home/Index.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Home Page";
3 | }
4 |
5 |
9 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Models/ErrorViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CouchDB.Driver.Example.Models
4 | {
5 | public class ErrorViewModel
6 | {
7 | public string RequestId { get; set; }
8 |
9 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/_Models/RebelView.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.UnitTests.Models;
2 | using CouchDB.Driver.Views;
3 |
4 | #nullable disable
5 |
6 | namespace CouchDB.Driver.UnitTests._Models
7 | {
8 | public class RebelView
9 | {
10 | public int NumberOfBattles { get; set; }
11 | }
12 | }
13 | #nullable restore
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/_Models/OtherRebel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace CouchDB.UnitTests.Models
5 | {
6 | [JsonObject("custom_rebels")]
7 | public class OtherRebel : Rebel
8 | {
9 | [JsonProperty("rebel_bith_date")]
10 | public DateTime BirthDate { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/ChangesFeed/Responses/ChangesFeedResponseResultChange.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using Newtonsoft.Json;
3 |
4 | namespace CouchDB.Driver.ChangesFeed.Responses
5 | {
6 | public class ChangesFeedResponseResultChange
7 | {
8 | [JsonProperty("rev")]
9 | public string Rev { get; set; }
10 | }
11 | }
12 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/ChangesFeed/Filters/ViewChangesFeedFilter.cs:
--------------------------------------------------------------------------------
1 | namespace CouchDB.Driver.ChangesFeed.Filters
2 | {
3 | internal class ViewChangesFeedFilter : ChangesFeedFilter
4 | {
5 | public string Value { get; }
6 |
7 | public ViewChangesFeedFilter(string value)
8 | {
9 | Value = value;
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/IndexDefinitionInfo.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using System.Collections.Generic;
3 | using Newtonsoft.Json;
4 |
5 | namespace CouchDB.Driver.DTOs
6 | {
7 | internal class IndexDefinitionInfo
8 | {
9 | [JsonProperty("fields")]
10 | public Dictionary[] Fields { get; set; }
11 | }
12 | }
13 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/OperationResult.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace CouchDB.Driver.DTOs
4 | {
5 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes")]
6 | internal class OperationResult
7 | {
8 | [JsonProperty("ok")]
9 | public bool Ok { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/GetIndexesResult.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using System.Collections.Generic;
3 | using CouchDB.Driver.Types;
4 | using Newtonsoft.Json;
5 |
6 | namespace CouchDB.Driver.DTOs
7 | {
8 | internal class GetIndexesResult
9 | {
10 | [JsonProperty("indexes")]
11 | public List Indexes { get; set; }
12 | }
13 | }
14 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Helpers/Check.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CouchDB.Driver.Helpers
4 | {
5 | internal static class Check
6 | {
7 | public static void NotNull(object value, string name)
8 | {
9 | if (value == null)
10 | {
11 | throw new ArgumentNullException(name);
12 | }
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Local/LocalDocumentsResult.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using CouchDB.Driver.Types;
3 | using Newtonsoft.Json;
4 |
5 | namespace CouchDB.Driver.Local
6 | {
7 | #nullable disable
8 | internal class LocalDocumentsResult
9 | {
10 | [JsonProperty("rows")]
11 | public IList Rows { get; set; }
12 | }
13 | #nullable restore
14 | }
15 |
--------------------------------------------------------------------------------
/src/CouchDB.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/StatusResult.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using Newtonsoft.Json;
3 |
4 | namespace CouchDB.Driver.DTOs
5 | {
6 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes")]
7 | internal class StatusResult
8 | {
9 | [JsonProperty("status")]
10 | public string Status { get; set; }
11 | }
12 | }
13 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Exceptions/CouchDBQueryWarningException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CouchDB.Driver.Exceptions
4 | {
5 | ///
6 | /// The exception that is thrown if the query returns a warning.
7 | ///
8 | public class CouchDBQueryWarningException : Exception
9 | {
10 | public CouchDBQueryWarningException(string message) : base(message) { }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/IQueryCompiler.cs:
--------------------------------------------------------------------------------
1 | using System.Linq.Expressions;
2 | using System.Threading;
3 |
4 | namespace CouchDB.Driver.Query
5 | {
6 | internal interface IQueryCompiler
7 | {
8 | string ToString(Expression query);
9 | TResult Execute(Expression query);
10 | TResult ExecuteAsync(Expression query, CancellationToken cancellationToken);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Options/CouchDocumentBuilder.cs:
--------------------------------------------------------------------------------
1 | namespace CouchDB.Driver.Options
2 | {
3 | public abstract class CouchDocumentBuilder
4 | {
5 | internal string? Database { get; set; }
6 | internal int? Shards { get; set; }
7 | internal int? Replicas { get; set; }
8 | internal bool Partitioned { get; set; }
9 | internal string? Discriminator { get; set; }
10 | }
11 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/IAsyncQueryProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Linq.Expressions;
3 | using System.Threading;
4 |
5 | namespace CouchDB.Driver.Query
6 | {
7 | internal interface IAsyncQueryProvider: IQueryProvider
8 | {
9 | TResult ExecuteAsync(Expression expression, CancellationToken cancellationToken = default);
10 | string ToString(Expression expression);
11 | }
12 | }
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.E2ETests/_Models/Rebel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using CouchDB.Driver.Types;
3 |
4 | namespace CouchDB.Driver.E2ETests.Models
5 | {
6 | public class Rebel : CouchDocument
7 | {
8 | public string Name { get; set; }
9 | public string Surname { get; set; }
10 | public int Age { get; set; }
11 | public List Skills { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Models/Rebel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using CouchDB.Driver.Types;
3 |
4 | namespace CouchDB.Driver.Example.Models
5 | {
6 | public class Rebel : CouchDocument
7 | {
8 | public string Name { get; set; }
9 | public string Surname { get; set; }
10 | public int Age { get; set; }
11 | public List Skills { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/_Models/Battle.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace CouchDB.UnitTests.Models
5 | {
6 | public class Battle
7 | {
8 | public bool DidWin { get; set; }
9 | public string Planet { get; set; }
10 | public DateTime Date { get; set; }
11 | public List Vehicles { get; set; } = new List();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/ChangesFeed/Filters/DocumentIdsChangesFeedFilter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace CouchDB.Driver.ChangesFeed.Filters
4 | {
5 | internal class DocumentIdsChangesFeedFilter : ChangesFeedFilter
6 | {
7 | public IList Value { get; }
8 |
9 | public DocumentIdsChangesFeedFilter(IList value)
10 | {
11 | Value = value;
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/RevisionInfo.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using System.Runtime.Serialization;
3 | using Newtonsoft.Json;
4 |
5 | namespace CouchDB.Driver.Types;
6 |
7 | public class RevisionInfo
8 | {
9 | [DataMember]
10 | [JsonProperty("rev")]
11 | public string Rev { get; internal set; }
12 |
13 | [DataMember]
14 | [JsonProperty("status")]
15 | public string Status { get; internal set; }
16 | }
17 |
18 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/CouchReplicationAuth.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Runtime.Serialization;
5 | using System.Text;
6 |
7 | namespace CouchDB.Driver.Types
8 | {
9 | public class CouchReplicationAuth
10 | {
11 | [DataMember]
12 | [JsonProperty("basic")]
13 | public CouchReplicationBasicCredentials? BasicCredentials { get; internal set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/AttachmentResult.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace CouchDB.Driver.DTOs
4 | {
5 | #nullable disable
6 | internal class AttachmentResult
7 | {
8 | [JsonProperty("id")]
9 | public string Id { get; set; }
10 |
11 | [JsonProperty("ok")]
12 | public bool Ok { get; set; }
13 |
14 | [JsonProperty("rev")]
15 | public string Rev { get; set; }
16 | }
17 | #nullable restore
18 | }
19 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/CreateIndexResult.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using Newtonsoft.Json;
3 |
4 | namespace CouchDB.Driver.DTOs
5 | {
6 | internal class CreateIndexResult
7 | {
8 | [JsonProperty("result")]
9 | public string Result { get; set; }
10 |
11 | [JsonProperty("id")]
12 | public string Id { get; set; }
13 |
14 | [JsonProperty("name")]
15 | public string Name { get; set; }
16 | }
17 | }
18 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/BulkGetResultItem.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using CouchDB.Driver.Types;
3 | using Newtonsoft.Json;
4 |
5 | namespace CouchDB.Driver.DTOs
6 | {
7 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes")]
8 | internal class BulkGetResultItem where TSource : CouchDocument
9 | {
10 | [JsonProperty("ok")]
11 | public TSource Item { get; set; }
12 | }
13 | }
14 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/ChangesFeed/Filters/ChangesFeedFilterDocuments.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json;
3 |
4 | namespace CouchDB.Driver.ChangesFeed.Filters
5 | {
6 | internal class ChangesFeedFilterDocuments
7 | {
8 | public ChangesFeedFilterDocuments(IList documentIds)
9 | {
10 | DocumentIds = documentIds;
11 | }
12 |
13 | [JsonProperty("doc_ids")]
14 | public IList DocumentIds { get; set; }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/DocumentSaveResponse.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | namespace CouchDB.Driver.DTOs
3 | {
4 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes")]
5 | internal class DocumentSaveResponse
6 | {
7 | public bool Ok { get; set; }
8 | public string Id { get; set; }
9 | public string Rev { get; set; }
10 | public string Error { get; set; }
11 | public string Reason { get; set; }
12 | }
13 | }
14 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Exceptions/CouchDeleteException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CouchDB.Driver.Exceptions
4 | {
5 | public class CouchDeleteException : CouchException
6 | {
7 | public CouchDeleteException() : base("Something went wrong.", null, "Something went wrong during the delete operation.") { }
8 |
9 | public CouchDeleteException(string message) : base(message) { }
10 |
11 | public CouchDeleteException(string message, Exception innerException) : base(message, innerException) { }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/BulkGetResult.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using CouchDB.Driver.Types;
3 | using Newtonsoft.Json;
4 | using System.Collections.Generic;
5 |
6 | namespace CouchDB.Driver.DTOs
7 | {
8 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes")]
9 | internal class BulkGetResult where TSource : CouchDocument
10 | {
11 | [JsonProperty("results")]
12 | public List> Results { get; set; }
13 | }
14 | }
15 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/BulkGetResultDoc.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using System.Collections.Generic;
3 | using CouchDB.Driver.Types;
4 | using Newtonsoft.Json;
5 |
6 | namespace CouchDB.Driver.DTOs
7 | {
8 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes")]
9 | internal class BulkGetResultDoc where TSource : CouchDocument
10 | {
11 | [JsonProperty("docs")]
12 | public List> Docs { get; set; }
13 | }
14 | }
15 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/Revisions.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using System.Collections.Generic;
3 | using System.Runtime.Serialization;
4 | using Newtonsoft.Json;
5 |
6 | namespace CouchDB.Driver.Types;
7 |
8 | public class Revisions
9 | {
10 | [DataMember, JsonProperty("start")] public int Start { get; internal set; }
11 |
12 | [JsonIgnore] public IReadOnlyCollection IDs { get; private set; }
13 | [DataMember, JsonProperty("ids")] private List IdsOther { set { IDs = value?.AsReadOnly(); } }
14 | }
15 |
16 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/ChangesFeed/Filters/SelectorChangesFeedFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 | using CouchDB.Driver.Types;
4 |
5 | namespace CouchDB.Driver.ChangesFeed.Filters
6 | {
7 | internal class SelectorChangesFeedFilter : ChangesFeedFilter
8 | where TSource : CouchDocument
9 | {
10 | public Expression> Value { get; }
11 |
12 | public SelectorChangesFeedFilter(Expression> value)
13 | {
14 | Value = value;
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/CouchReplicationHost.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Runtime.Serialization;
5 | using System.Text;
6 |
7 | namespace CouchDB.Driver.Types
8 | {
9 | public class CouchReplicationHost
10 | {
11 | [DataMember]
12 | [JsonProperty("url")]
13 | public string? Url { get; internal set; }
14 |
15 | [DataMember]
16 | [JsonProperty("auth")]
17 | public CouchReplicationAuth? Auth { get; internal set; }
18 |
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/CouchViewQueryResult.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.Types;
2 | using CouchDB.Driver.Views;
3 | using Newtonsoft.Json;
4 | using System.Collections.Generic;
5 |
6 | #nullable disable
7 | namespace CouchDB.Driver.DTOs
8 | {
9 | internal class CouchViewQueryResult
10 | where TDoc : CouchDocument
11 | {
12 | ///
13 | /// The results in the same order as the queries.
14 | ///
15 | [JsonProperty("results")]
16 | public CouchViewList[] Results { get; set; }
17 | }
18 | }
19 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Extensions/CouchDocumentExtensions.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.DTOs;
2 | using CouchDB.Driver.Exceptions;
3 | using CouchDB.Driver.Types;
4 |
5 | namespace CouchDB.Driver.Extensions
6 | {
7 | internal static class CouchDocumentExtensions
8 | {
9 | public static void ProcessSaveResponse(this CouchDocument item, DocumentSaveResponse response)
10 | {
11 | if (!response.Ok)
12 | {
13 | throw new CouchException(response.Error, null, response.Reason);
14 | }
15 |
16 | item.Id = response.Id;
17 | item.Rev = response.Rev;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/DocumentId.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.Types;
2 |
3 | namespace CouchDB.Driver;
4 |
5 | public class DocumentId
6 | {
7 | public DocumentId(string id, string rev)
8 | {
9 | Id = id;
10 | Rev = rev;
11 | }
12 |
13 | public DocumentId(CouchDocument document)
14 | {
15 | Id = document.Id;
16 | Rev = document.Rev;
17 | }
18 |
19 | public string Id { get; }
20 | public string Rev { get; }
21 |
22 | public static explicit operator DocumentId(CouchDocument documentId)
23 | {
24 | return new DocumentId(documentId.Id, documentId.Rev);
25 | }
26 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/ChangesFeed/Responses/ChangesFeedResponse.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using System.Collections.Generic;
3 | using CouchDB.Driver.Types;
4 | using Newtonsoft.Json;
5 |
6 | namespace CouchDB.Driver.ChangesFeed.Responses
7 | {
8 | public class ChangesFeedResponse where TSource : CouchDocument
9 | {
10 | [JsonProperty("last_seq")]
11 | public string LastSequence { get; set; }
12 |
13 | [JsonProperty("pending")]
14 | public int Pending { get; set; }
15 |
16 | [JsonProperty("results")]
17 | public IList> Results { get; internal set; }
18 | }
19 | }
20 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/QueryContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CouchDB.Driver.Query
4 | {
5 | public class QueryContext
6 | {
7 | public Uri Endpoint { get; set; }
8 | public string DatabaseName { get; set; }
9 | public string EscapedDatabaseName { get; set; }
10 |
11 | public bool ThrowOnQueryWarning { get; set; }
12 |
13 | public QueryContext(Uri endpoint, string databaseName, bool throwOnQueryWarning)
14 | {
15 | Endpoint = endpoint;
16 | DatabaseName = databaseName;
17 | EscapedDatabaseName = Uri.EscapeDataString(databaseName);
18 | ThrowOnQueryWarning = throwOnQueryWarning;
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Exceptions/CouchConflictException.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.DTOs;
2 | using System;
3 |
4 | namespace CouchDB.Driver.Exceptions
5 | {
6 | ///
7 | /// The exception that is thrown when there is a conflict.
8 | ///
9 | public class CouchConflictException : CouchException
10 | {
11 | internal CouchConflictException(CouchError couchError, Exception innerException) : base(couchError, innerException) { }
12 |
13 | public CouchConflictException() { }
14 |
15 | public CouchConflictException(string message) : base(message) { }
16 |
17 | public CouchConflictException(string message, Exception innerException) : base(message, innerException) { }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Exceptions/CouchNoIndexException.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.DTOs;
2 | using System;
3 |
4 | namespace CouchDB.Driver.Exceptions
5 | {
6 | ///
7 | /// The exception that is thrown when there is no index for the query.
8 | ///
9 | public class CouchNoIndexException : CouchException
10 | {
11 | internal CouchNoIndexException(CouchError couchError, Exception innerException) : base(couchError, innerException) { }
12 |
13 | public CouchNoIndexException() { }
14 |
15 | public CouchNoIndexException(string message) : base(message) { }
16 | public CouchNoIndexException(string message, Exception innerException) : base(message, innerException) { }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Options/IndexSetupDefinition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using CouchDB.Driver.Indexes;
3 | using CouchDB.Driver.Types;
4 |
5 | namespace CouchDB.Driver.Options
6 | {
7 | internal class IndexSetupDefinition
8 | where TSource : CouchDocument
9 | {
10 | public IndexSetupDefinition(string name, Action> indexBuilderAction, IndexOptions? options)
11 | {
12 | Name = name;
13 | IndexBuilderAction = indexBuilderAction;
14 | Options = options;
15 | }
16 |
17 | public string Name { get; }
18 | public Action> IndexBuilderAction { get; }
19 | public IndexOptions? Options { get; }
20 | }
21 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Exceptions/CouchNotFoundException.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.DTOs;
2 | using System;
3 |
4 | namespace CouchDB.Driver.Exceptions
5 | {
6 | ///
7 | /// The exception that is thrown when something is not found.
8 | ///
9 | public class CouchNotFoundException : CouchException
10 | {
11 | internal CouchNotFoundException(CouchError couchError, Exception innerException) : base(couchError, innerException) { }
12 |
13 | public CouchNotFoundException() { }
14 |
15 | public CouchNotFoundException(string message) : base(message) { }
16 |
17 | public CouchNotFoundException(string message, Exception innerException) : base(message, innerException) { }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/_Helpers/HttpCallEssertionExtensions.cs:
--------------------------------------------------------------------------------
1 | using Flurl.Http.Testing;
2 | using Newtonsoft.Json;
3 | using System;
4 |
5 | namespace CouchDB.Driver.UnitTests._Helpers
6 | {
7 | public static class HttpCallEssertionExtensions
8 | {
9 | public static HttpCallAssertion WithJsonBody(this HttpCallAssertion assertion, Func assert)
10 | {
11 | return assertion
12 | .WithContentType("application/json")
13 | .With(call =>
14 | {
15 | var body = JsonConvert.DeserializeObject(call.RequestBody);
16 | return assert(body);
17 | });
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/LATEST_CHANGE.md:
--------------------------------------------------------------------------------
1 | # 3.7.0 (2025-12-01)
2 |
3 | ## Features
4 |
5 | * **Partitions**: Add comprehensive support for partitions ([#213](https://github.com/matteobortolazzo/couchdb-net/pull/213))
6 | * **Get/SetRevisionLimit**: Added method to get the revision limit of a database ([#202](https://github.com/matteobortolazzo/couchdb-net/pull/202))
7 | * **ThrowOnQueryWarning**: Added option to throw exception on query warnings ([#205](https://github.com/matteobortolazzo/couchdb-net/pull/205))
8 |
9 | ## Bugs
10 |
11 | * **IncludeExecutionStats**: Fixed deserialization exception ([#204](https://github.com/matteobortolazzo/couchdb-net/pull/204))
12 | * **Local Docs**: Fixed ID encoding ([#206](https://github.com/matteobortolazzo/couchdb-net/pull/206))
13 |
14 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/Extensions/ExpressionExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Linq.Expressions;
2 |
3 | namespace CouchDB.Driver.Query.Extensions
4 | {
5 | internal static class ExpressionExtensions
6 | {
7 | public static bool IsTrue(this Expression expression)
8 | {
9 | return expression is ConstantExpression { Value: bool b } && b;
10 | }
11 |
12 | public static bool IsFalse(this Expression expression)
13 | {
14 | return expression is ConstantExpression { Value: bool b } && !b;
15 | }
16 |
17 | public static bool IsBoolean(this Expression expression)
18 | {
19 | return expression is ConstantExpression { Value: bool };
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/Extensions/StringQueryExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 |
3 | namespace CouchDB.Driver.Query.Extensions
4 | {
5 | public static class StringQueryExtensions
6 | {
7 | ///
8 | /// Indicates whether the regular expression finds a match in the input string.
9 | ///
10 | /// The string to search for a match.
11 | /// The regular expression pattern to match.
12 | /// true if the regular expression finds a match; otherwise, false.
13 | public static bool IsMatch(this string input, string pattern)
14 | {
15 | return new Regex(pattern).IsMatch(input);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/FindResult.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using CouchDB.Driver.Types;
3 | using Newtonsoft.Json;
4 | using System.Collections.Generic;
5 |
6 | namespace CouchDB.Driver.DTOs
7 | {
8 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes")]
9 | internal class FindResult
10 | {
11 | [JsonProperty("docs")]
12 | public IEnumerable Docs { get; internal set; }
13 |
14 | [JsonProperty("bookmark")]
15 | public string Bookmark { get; internal set; }
16 |
17 | [JsonProperty("execution_stats")]
18 | public ExecutionStats ExecutionStats { get; internal set; }
19 |
20 | [JsonProperty("warning")]
21 | public string Warning { get; internal set; }
22 | }
23 | }
24 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DatabaseApiMethodOptions/AddOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace CouchDB.Driver.DatabaseApiMethodOptions
6 | {
7 | ///
8 | /// Options relevant to saving a new document (supported by both PUT /{db}/{docid} and POST /{db}).
9 | /// Check https://docs.couchdb.org/en/stable/api/database/common.html#post--db
10 | /// Check https://docs.couchdb.org/en/stable/api/document/common.html#put--db-docid
11 | ///
12 | public class AddOptions
13 | {
14 | ///
15 | /// Stores document in batch mode. Check https://docs.couchdb.org/en/stable/api/database/common.html#api-doc-batch-writes
16 | ///
17 | public bool Batch { get; set; } = false;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Security/ICouchSecurity.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace CouchDB.Driver.Security
4 | {
5 | public interface ICouchSecurity
6 | {
7 | ///
8 | /// Gets security information about the database.
9 | ///
10 | /// A task that represents the asynchronous operation. The task result contains the database security information.
11 | Task GetInfoAsync();
12 |
13 | ///
14 | /// Sets security information about the database.
15 | ///
16 | /// The security object to set.
17 | /// A task that represents the asynchronous operation.
18 | Task SetInfoAsync(CouchSecurityInfo info);
19 | }
20 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Indexes/IIndexBuilderBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 | using CouchDB.Driver.Types;
4 |
5 | namespace CouchDB.Driver.Indexes
6 | {
7 | ///
8 | /// Builder to configure CouchDB indexes.
9 | ///
10 | /// The type of the document.
11 | public interface IIndexBuilderBase
12 | where TSource : CouchDocument
13 | {
14 | ///
15 | /// Creates a partial index which excludes documents based on the predicate at index time.
16 | ///
17 | /// Function to filter documents.
18 | /// Returns the current instance to chain calls.
19 | void Where(Expression> predicate);
20 | }
21 | }
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/Find/Find_Unsupported.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using CouchDB.UnitTests.Models;
4 | using Xunit;
5 |
6 | namespace CouchDB.Driver.UnitTests.Find
7 | {
8 | public class Find_Unsupported
9 | {
10 | private readonly ICouchDatabase _rebels;
11 |
12 | public Find_Unsupported()
13 | {
14 | var client = new CouchClient("http://localhost");
15 | _rebels = client.GetDatabase();
16 | }
17 |
18 | [Fact]
19 | public void ToList_WhereCount_Exception()
20 | {
21 | void CountQuery() => _rebels
22 | .Where(u => u.Battles.Count > 0)
23 | .ToString();
24 |
25 | Assert.Throws(CountQuery);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace CouchDB.Driver.Example
11 | {
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IHostBuilder CreateHostBuilder(string[] args) =>
20 | Host.CreateDefaultBuilder(args)
21 | .ConfigureWebHostDefaults(webBuilder =>
22 | {
23 | webBuilder.UseStartup();
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/ChangesFeed/Filters/DesignDocumentChangesFeedFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace CouchDB.Driver.ChangesFeed.Filters
5 | {
6 | internal class DesignDocumentChangesFeedFilter : ChangesFeedFilter
7 | {
8 | public string FilterName { get; }
9 | public Dictionary? QueryParameters { get; }
10 |
11 | public DesignDocumentChangesFeedFilter(string filterName, Dictionary? queryParameters = null)
12 | {
13 | if (string.IsNullOrWhiteSpace(filterName))
14 | {
15 | throw new ArgumentException("Filter name cannot be null or empty.", nameof(filterName));
16 | }
17 |
18 | FilterName = filterName;
19 | QueryParameters = queryParameters;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Security/CouchSecurityInfoType.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json;
3 |
4 | namespace CouchDB.Driver.Security
5 | {
6 | ///
7 | /// Represents list of users and/or roles that have rights to the database.
8 | ///
9 | public sealed class CouchSecurityInfoType
10 | {
11 | public CouchSecurityInfoType()
12 | {
13 | Names = new List();
14 | Roles = new List();
15 | }
16 |
17 | ///
18 | /// List of CouchDB user names.
19 | ///
20 | [JsonProperty("names")]
21 | public List Names { get; }
22 |
23 | ///
24 | /// List of users roles.
25 | ///
26 | [JsonProperty("roles")]
27 | public List Roles { get; }
28 | }
29 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DatabaseApiMethodOptions/AddOrUpdateOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace CouchDB.Driver.DatabaseApiMethodOptions
6 | {
7 | ///
8 | /// Options relevant to saving a document (supported by PUT HTTP-method).
9 | /// Check https://docs.couchdb.org/en/stable/api/document/common.html#put--db-docid
10 | ///
11 | public class AddOrUpdateOptions
12 | {
13 | ///
14 | /// Stores document in batch mode. Check https://docs.couchdb.org/en/stable/api/database/common.html#api-doc-batch-writes
15 | ///
16 | public bool Batch { get; set; } = false;
17 |
18 | ///
19 | /// Document’s revision if updating an existing document.
20 | ///
21 | public string? Rev { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/CouchDocumentInfo.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using System.Runtime.Serialization;
3 | using Newtonsoft.Json;
4 |
5 | namespace CouchDB.Driver.Types
6 | {
7 | ///
8 | /// Represents a CouchDB document info.
9 | ///
10 | public class CouchDocumentInfo
11 | {
12 | [DataMember]
13 | [JsonProperty("id")]
14 | public string Id { get; private set; }
15 |
16 | [DataMember]
17 | [JsonProperty("key")]
18 | public string Key { get; private set; }
19 |
20 | [DataMember]
21 | [JsonProperty("value")]
22 | private CouchDocumentInfoValue Value { get; set; }
23 |
24 | public string Rev => Value.Rev;
25 |
26 | private class CouchDocumentInfoValue
27 | {
28 | [JsonProperty("rev")]
29 | public string Rev { get; set; }
30 | }
31 | }
32 | }
33 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Views/StableStyle.cs:
--------------------------------------------------------------------------------
1 | namespace CouchDB.Driver.Views
2 | {
3 | ///
4 | /// Whether or not the view results should be returned from a stable set of shards.
5 | ///
6 | public class StableStyle
7 | {
8 | private readonly string _value;
9 |
10 | ///
11 | /// The view results will be returned from a stable set of shards.
12 | ///
13 | public static StableStyle True => new("true");
14 |
15 | ///
16 | /// The view results will be returned from an unstable set of shards.
17 | ///
18 | public static StableStyle False => new("false");
19 |
20 | private StableStyle(string value)
21 | {
22 | _value = value;
23 | }
24 |
25 | public override string ToString()
26 | {
27 | return _value;
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/CouchReplicationBasicCredentials.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.Helpers;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Runtime.Serialization;
6 | using System.Text;
7 | using System.Xml.Linq;
8 |
9 | namespace CouchDB.Driver.Types
10 | {
11 | public class CouchReplicationBasicCredentials
12 | {
13 | public CouchReplicationBasicCredentials(string username, string password)
14 | {
15 | Check.NotNull(username, nameof(username));
16 | Check.NotNull(password, nameof(password));
17 |
18 | Username = username;
19 | Password = password;
20 | }
21 |
22 | [DataMember]
23 | [JsonProperty("username")]
24 | public string Username { get; set; }
25 |
26 | [DataMember]
27 | [JsonProperty("password")]
28 | public string Password { get; set; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/Sizes.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace CouchDB.Driver.Types
4 | {
5 | ///
6 | /// Represents size information.
7 | ///
8 | public sealed class Sizes
9 | {
10 | ///
11 | /// The size of the database file on disk in bytes. Views indexes are not included in the calculation.
12 | ///
13 | [JsonProperty("file")]
14 | public long File { get; internal set; }
15 |
16 | ///
17 | /// The uncompressed size of database contents in bytes.
18 | ///
19 | [JsonProperty("external")]
20 | public long External { get; internal set; }
21 |
22 | ///
23 | /// The size of live data inside the database, in bytes.
24 | ///
25 | [JsonProperty("active")]
26 | public long Active { get; internal set; }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/ChangesFeed/ChangesFeedStyle.cs:
--------------------------------------------------------------------------------
1 | namespace CouchDB.Driver.ChangesFeed
2 | {
3 | ///
4 | /// Represents the style of changes feed
5 | ///
6 | public class ChangesFeedStyle
7 | {
8 | private readonly string _value;
9 | ///
10 | /// The feed will only return the current "winning" revision;
11 | ///
12 | public static ChangesFeedStyle MainOnly => new("main_only");
13 |
14 | ///
15 | /// The feed will return all leaf revisions (including conflicts and deleted former conflicts).
16 | ///
17 | public static ChangesFeedStyle AllDocs => new("all_docs");
18 |
19 | private ChangesFeedStyle(string value)
20 | {
21 | _value = value;
22 | }
23 |
24 | public override string ToString()
25 | {
26 | return _value;
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Exceptions/CouchException.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.DTOs;
2 | using System;
3 |
4 | namespace CouchDB.Driver.Exceptions
5 | {
6 | ///
7 | /// The exception that is thrown when CouchDB return an error.
8 | ///
9 | public class CouchException : Exception
10 | {
11 | public string? Reason { get; }
12 |
13 | public CouchException() { }
14 |
15 | public CouchException(string message) : base(message) { }
16 |
17 | public CouchException(string message, Exception? innerException) : base(message, innerException) { }
18 |
19 | public CouchException(string message, Exception? innerException, string reason) : base(message, innerException)
20 | {
21 | Reason = reason;
22 | }
23 |
24 | internal CouchException(CouchError couchError, Exception innerException) : this(couchError.Error, innerException, couchError.Reason) { }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/Translators/MemberExpressionTranslator.cs:
--------------------------------------------------------------------------------
1 | using System.Linq.Expressions;
2 | using CouchDB.Driver.Extensions;
3 | using CouchDB.Driver.Types;
4 |
5 | namespace CouchDB.Driver.Query
6 | {
7 | internal partial class QueryTranslator
8 | {
9 | protected override Expression VisitMember(MemberExpression m)
10 | {
11 | // Override database split if needed
12 | if (m.Member.DeclaringType == typeof(CouchDocument) &&
13 | m.Member.Name == nameof(CouchDocument.SplitDiscriminator) &&
14 | !string.IsNullOrWhiteSpace(_options.DatabaseSplitDiscriminator))
15 | {
16 | _sb.Append($"\"{_options.DatabaseSplitDiscriminator}\"");
17 | return m;
18 | }
19 |
20 | var propName = m.GetPropertyName(_options);
21 | _sb.Append($"\"{propName}\"");
22 | return m;
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Indexes/IOrderedIndexBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 | using CouchDB.Driver.Types;
4 |
5 | namespace CouchDB.Driver.Indexes
6 | {
7 | ///
8 | /// Builder to configure CouchDB indexes.
9 | ///
10 | /// The type of the document.
11 | public interface IOrderedIndexBuilder : IIndexBuilderBase
12 | where TSource : CouchDocument
13 | {
14 | ///
15 | /// Adds a field for the index sort in ascending order.
16 | ///
17 | /// The type of the selected property.
18 | /// Function to select a property.
19 | /// Returns the current instance to chain calls.
20 | IOrderedIndexBuilder ThenBy(Expression> selector);
21 | }
22 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Options/CouchDatabaseBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using CouchDB.Driver.Types;
4 |
5 | namespace CouchDB.Driver.Options
6 | {
7 | public class CouchDatabaseBuilder
8 | {
9 | internal readonly Dictionary DocumentBuilders;
10 |
11 | internal CouchDatabaseBuilder()
12 | {
13 | DocumentBuilders = new Dictionary();
14 | }
15 |
16 | public CouchDocumentBuilder Document()
17 | where TSource : CouchDocument
18 | {
19 | Type documentType = typeof(TSource);
20 | if (!DocumentBuilders.ContainsKey(documentType))
21 | {
22 | DocumentBuilders.Add(documentType, new CouchDocumentBuilder());
23 | }
24 |
25 | return (CouchDocumentBuilder)DocumentBuilders[documentType];
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver.DependencyInjection/ServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using CouchDB.Driver.Helpers;
3 | using CouchDB.Driver.Options;
4 | using Microsoft.Extensions.DependencyInjection;
5 |
6 | namespace CouchDB.Driver.DependencyInjection
7 | {
8 | public static class ServiceCollectionExtensions
9 | {
10 | public static IServiceCollection AddCouchContext(this IServiceCollection services,
11 | Action> optionBuilderAction)
12 | where TContext : CouchContext
13 | {
14 | Check.NotNull(services, nameof(services));
15 | Check.NotNull(optionBuilderAction, nameof(optionBuilderAction));
16 |
17 | var builder = new CouchOptionsBuilder();
18 | optionBuilderAction?.Invoke(builder);
19 | return services
20 | .AddSingleton(builder.Options)
21 | .AddSingleton();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Views/Shared/Error.cshtml:
--------------------------------------------------------------------------------
1 | @model ErrorViewModel
2 | @{
3 | ViewData["Title"] = "Error";
4 | }
5 |
6 | Error.
7 | An error occurred while processing your request.
8 |
9 | @if (Model.ShowRequestId)
10 | {
11 |
12 | Request ID: @Model.RequestId
13 |
14 | }
15 |
16 | Development Mode
17 |
18 | Swapping to Development environment will display more detailed information about the error that occurred.
19 |
20 |
21 | The Development environment shouldn't be enabled for deployed applications.
22 | It can result in displaying sensitive information from exceptions to end users.
23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
24 | and restarting the app.
25 |
26 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Indexes/IOrderedDescendingIndexBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 | using CouchDB.Driver.Types;
4 |
5 | namespace CouchDB.Driver.Indexes
6 | {
7 | ///
8 | /// Builder to configure CouchDB indexes.
9 | ///
10 | /// The type of the document.
11 | public interface IOrderedDescendingIndexBuilder : IIndexBuilderBase
12 | where TSource : CouchDocument
13 | {
14 | ///
15 | /// Adds a field for the index sort in descending order.
16 | ///
17 | /// The type of the selected property.
18 | /// Function to select a property.
19 | /// Returns the current instance to chain calls.
20 | IOrderedDescendingIndexBuilder ThenByDescending(Expression> selector);
21 | }
22 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Options/CaseType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using CouchDB.Driver.Helpers;
3 |
4 | namespace CouchDB.Driver.Options
5 | {
6 | ///
7 | /// A helper class for specify a case format for strings.
8 | ///
9 | public class CaseType
10 | {
11 | ///
12 | /// Name of the case format type.
13 | ///
14 | public string Value { get; }
15 |
16 | protected CaseType(string value)
17 | {
18 | Check.NotNull(value, nameof(value));
19 | Value = value;
20 | }
21 |
22 | internal virtual string Convert(string str)
23 | {
24 | throw new NotImplementedException();
25 | }
26 |
27 | public override bool Equals(object obj)
28 | {
29 | return obj is CaseType item && Value == item.Value;
30 | }
31 |
32 | public override int GetHashCode()
33 | {
34 | return Value.GetHashCode(StringComparison.InvariantCultureIgnoreCase);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Helpers/CertClientFactory.cs:
--------------------------------------------------------------------------------
1 | using Flurl.Http.Configuration;
2 | using System;
3 | using System.Net.Http;
4 | using System.Net.Security;
5 | using System.Security.Cryptography.X509Certificates;
6 |
7 | namespace CouchDB.Driver.Helpers
8 | {
9 | internal class CertClientFactory : DefaultHttpClientFactory
10 | {
11 | private readonly Func _serverCertificateCustomValidationCallback;
12 |
13 | public CertClientFactory(Func serverCertificateCustomValidationCallback)
14 | {
15 | _serverCertificateCustomValidationCallback = serverCertificateCustomValidationCallback;
16 | }
17 |
18 | public override HttpMessageHandler CreateMessageHandler()
19 | {
20 | return new HttpClientHandler()
21 | {
22 | ServerCertificateCustomValidationCallback = _serverCertificateCustomValidationCallback
23 | };
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Views/UpdateStyle.cs:
--------------------------------------------------------------------------------
1 | namespace CouchDB.Driver.Views
2 | {
3 | ///
4 | /// Whether or not the view should be updated prior to responding to the user.
5 | ///
6 | public class UpdateStyle
7 | {
8 | private readonly string _value;
9 |
10 | ///
11 | /// Updates the view prior to responding to the user.
12 | ///
13 | public static UpdateStyle True => new("true");
14 |
15 | ///
16 | /// Doesn't the view update prior to responding to the user.
17 | ///
18 | public static UpdateStyle False => new("false");
19 |
20 | ///
21 | /// Updates the view lazily when responding to the user.
22 | ///
23 | public static UpdateStyle Lazy => new("lazy");
24 |
25 | private UpdateStyle(string value)
26 | {
27 | _value = value;
28 | }
29 |
30 | public override string ToString()
31 | {
32 | return _value;
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Views/Rebels/Details.cshtml:
--------------------------------------------------------------------------------
1 | @model CouchDB.Driver.Example.Models.Rebel
2 |
3 | @{
4 | ViewData["Title"] = "Details";
5 | }
6 |
7 | Details
8 |
9 |
10 |
Rebel
11 |
12 |
13 | -
14 | @Html.DisplayNameFor(model => model.Name)
15 |
16 | -
17 | @Html.DisplayFor(model => model.Name)
18 |
19 | -
20 | @Html.DisplayNameFor(model => model.Surname)
21 |
22 | -
23 | @Html.DisplayFor(model => model.Surname)
24 |
25 | -
26 | @Html.DisplayNameFor(model => model.Age)
27 |
28 | -
29 | @Html.DisplayFor(model => model.Age)
30 |
31 |
32 |
33 |
34 | @Html.ActionLink("Edit", "Edit", new { /* id = Model.PrimaryKey */ }) |
35 |
Back to List
36 |
37 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/Extensions/EnumerableQueryExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using CouchDB.Driver.Helpers;
4 |
5 | namespace CouchDB.Driver.Query.Extensions
6 | {
7 | public static class EnumerableQueryExtensions
8 | {
9 | ///
10 | /// Determines whether a sequence contains all specified elements by using the default equality comparer.
11 | ///
12 | /// The type of the elements of source.
13 | /// A sequence in which to locate a value.
14 | /// Values to locate in the sequence.
15 | /// true if the source sequence contains all elements that has specified values; otherwise, false.
16 | public static bool Contains(this IEnumerable source, IEnumerable input)
17 | {
18 | Check.NotNull(source, nameof(source));
19 | Check.NotNull(input, nameof(input));
20 |
21 | return input.All(source.Contains!);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver.DependencyInjection.Autofac/AutofacRegistrationExtensions.cs:
--------------------------------------------------------------------------------
1 | using Autofac;
2 | using CouchDB.Driver.Options;
3 | using System;
4 | using CouchDB.Driver.Helpers;
5 |
6 | namespace CouchDB.Driver.DependencyInjection.Autofac
7 | {
8 | public static class AutofacRegistrationExtensions
9 | {
10 | public static ContainerBuilder AddCouchContext(this ContainerBuilder builder,
11 | Action> optionBuilderAction)
12 | where TContext : CouchContext
13 | {
14 | Check.NotNull(builder, nameof(builder));
15 | Check.NotNull(optionBuilderAction, nameof(optionBuilderAction));
16 |
17 | var optionsBuilder = new CouchOptionsBuilder();
18 | optionBuilderAction?.Invoke(optionsBuilder);
19 |
20 | builder
21 | .RegisterInstance(optionsBuilder.Options)
22 | .AsSelf();
23 |
24 | builder
25 | .RegisterType()
26 | .SingleInstance();
27 |
28 | return builder;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Matteo Bortolazzo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Controllers/HomeController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.Extensions.Logging;
8 | using CouchDB.Driver.Example.Models;
9 |
10 | namespace CouchDB.Driver.Example.Controllers
11 | {
12 | public class HomeController : Controller
13 | {
14 | private readonly ILogger _logger;
15 |
16 | public HomeController(ILogger logger)
17 | {
18 | _logger = logger;
19 | }
20 |
21 | public IActionResult Index()
22 | {
23 | return View();
24 | }
25 |
26 | public IActionResult Privacy()
27 | {
28 | return View();
29 | }
30 |
31 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
32 | public IActionResult Error()
33 | {
34 | return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/Cluster.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace CouchDB.Driver.Types
4 | {
5 | ///
6 | /// Represents cluster information.
7 | ///
8 | public sealed class Cluster
9 | {
10 | ///
11 | /// The number of copies of every document.
12 | ///
13 | [JsonProperty("n")]
14 | public int Replicas { get; internal set; }
15 |
16 | ///
17 | /// The number of range partitions.
18 | ///
19 | [JsonProperty("q")]
20 | public int Shards { get; internal set; }
21 |
22 | ///
23 | /// The number of consistent copies of a document that need to be read before a successful reply.
24 | ///
25 | [JsonProperty("r")]
26 | public int ReadQuorum { get; internal set; }
27 |
28 | ///
29 | /// The number of copies of a document that need to be written before a successful reply.
30 | ///
31 | [JsonProperty("w")]
32 | public int WriteQuorum { get; internal set; }
33 | }
34 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/License/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Matteo Bortolazzo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Views/CouchView.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | #nullable disable
4 | namespace CouchDB.Driver.Views
5 | {
6 | ///
7 | /// Base class for a view.
8 | ///
9 | /// The type of the key
10 | /// The type of the value
11 | /// The type of the document.
12 | public sealed class CouchView
13 | {
14 | ///
15 | /// The document ID.
16 | ///
17 | [JsonProperty("id")]
18 | public string Id { get; set; }
19 |
20 | ///
21 | /// The view key.
22 | ///
23 | [JsonProperty("key")]
24 | public TKey Key { get; set; }
25 |
26 | ///
27 | /// The view key.
28 | ///
29 | [JsonProperty("value")]
30 | public TValue Value { get; set; }
31 |
32 | ///
33 | /// The document.
34 | ///
35 | [JsonProperty("doc")]
36 | public TDoc Document { get; set; }
37 | }
38 | }
39 | #nullable restore
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Views/Rebels/Delete.cshtml:
--------------------------------------------------------------------------------
1 | @model CouchDB.Driver.Example.Models.Rebel
2 |
3 | @{
4 | ViewData["Title"] = "Delete";
5 | }
6 |
7 | Delete
8 |
9 | Are you sure you want to delete this?
10 |
11 |
Rebel
12 |
13 |
14 | -
15 | @Html.DisplayNameFor(model => model.Name)
16 |
17 | -
18 | @Html.DisplayFor(model => model.Name)
19 |
20 | -
21 | @Html.DisplayNameFor(model => model.Surname)
22 |
23 | -
24 | @Html.DisplayFor(model => model.Surname)
25 |
26 | -
27 | @Html.DisplayNameFor(model => model.Age)
28 |
29 | -
30 | @Html.DisplayFor(model => model.Age)
31 |
32 |
33 |
34 |
38 |
39 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver.DependencyInjection/License/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Matteo Bortolazzo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DTOs/AllDocsResult.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Collections.Generic;
3 |
4 | namespace CouchDB.Driver.DTOs
5 | {
6 | internal class AllDocsResult
7 | {
8 | [JsonProperty("total_rows")]
9 | public int TotalRows { get; internal set; }
10 |
11 | [JsonProperty("offset")]
12 | public int Offset { get; internal set; }
13 |
14 | [JsonProperty("rows")]
15 | public IEnumerable> Rows { get; internal set; } = new List>();
16 | }
17 |
18 | internal class AllDocsRow
19 | {
20 | [JsonProperty("id")]
21 | public string Id { get; internal set; } = string.Empty;
22 |
23 | [JsonProperty("key")]
24 | public string Key { get; internal set; } = string.Empty;
25 |
26 | [JsonProperty("value")]
27 | public AllDocsValue Value { get; internal set; } = new AllDocsValue();
28 |
29 | [JsonProperty("doc")]
30 | public T? Doc { get; internal set; }
31 | }
32 |
33 | internal class AllDocsValue
34 | {
35 | [JsonProperty("rev")]
36 | public string Rev { get; internal set; } = string.Empty;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/_Models/Rebel.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.Types;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace CouchDB.UnitTests.Models
6 | {
7 | public class SimpleRebel : CouchDocument
8 | {
9 | public string Name { get; set; }
10 | public int Age { get; set; }
11 | }
12 |
13 | public class Rebel : CouchDocument
14 | {
15 | public string Name { get; set; }
16 | public string Surname { get; set; }
17 | public int Age { get; set; }
18 | public bool IsJedi { get; set; }
19 | public Species Species { get; set; }
20 | public Guid Guid { get; set; }
21 | public List Skills { get; set; }
22 | public List Battles { get; set; }
23 | public Vehicle Vehicle { get; set; }
24 |
25 | public override bool Equals(object obj)
26 | {
27 | if (obj is Rebel r)
28 | {
29 | return r.Id == Id;
30 | }
31 | return base.Equals(obj);
32 | }
33 |
34 | public override int GetHashCode()
35 | {
36 | return base.GetHashCode();
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver.DependencyInjection.Autofac/License/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Matteo Bortolazzo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/ChangesFeed/Responses/ChangesFeedResponseResult.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using System;
3 | using System.Collections.Generic;
4 | using CouchDB.Driver.Types;
5 | using Newtonsoft.Json;
6 |
7 | namespace CouchDB.Driver.ChangesFeed.Responses
8 | {
9 | public class ChangesFeedResponseResult where TSource: CouchDocument
10 | {
11 | [JsonProperty("seq")]
12 | public string Seq { get; set; }
13 |
14 | [JsonProperty("id")]
15 | public string Id { get; set; }
16 |
17 | [JsonProperty("deleted")]
18 | public bool Deleted { get; set; }
19 |
20 | [JsonProperty("changes")]
21 | public IList Changes { get; internal set; }
22 |
23 | [JsonProperty("roleIds")]
24 | public IList RoleIds { get; internal set; }
25 |
26 | [JsonProperty("createdAt")]
27 | public DateTime CreatedAt { get; set; }
28 |
29 | [JsonProperty("createdBy")]
30 | public string CreatedBy { get; set; }
31 |
32 | [JsonProperty("doc", NullValueHandling = NullValueHandling.Ignore)]
33 | public TSource Document { get; set; }
34 | }
35 | }
36 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Converters/AttachmentsParsedConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using CouchDB.Driver.Types;
5 | using Newtonsoft.Json;
6 |
7 | namespace CouchDB.Driver.Converters
8 | {
9 | internal class AttachmentsParsedConverter : JsonConverter>
10 | {
11 | public override void WriteJson(JsonWriter writer, Dictionary? value,
12 | JsonSerializer serializer)
13 | {
14 | if (value == null)
15 | {
16 | return;
17 | }
18 |
19 | serializer.Serialize(writer, value
20 | .Where(kvp => kvp.Value.FileInfo is null)
21 | .ToDictionary(k => k.Key, v => v.Value)
22 | );
23 | }
24 |
25 | public override bool CanRead => false;
26 |
27 | public override Dictionary ReadJson(JsonReader reader, Type objectType,
28 | Dictionary? existingValue, bool hasExistingValue,
29 | JsonSerializer serializer)
30 | {
31 | throw new NotImplementedException();
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Helpers/MicrosecondEpochConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Converters;
4 |
5 | namespace CouchDB.Driver.Helpers
6 | {
7 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes")]
8 | internal class MicrosecondEpochConverter : DateTimeConverterBase
9 | {
10 | private static readonly DateTime Epoch = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
11 |
12 | public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
13 | {
14 | if (value == null)
15 | {
16 | writer.WriteNull();
17 | return;
18 | }
19 |
20 | writer.WriteRawValue(((DateTime)value - Epoch).TotalMilliseconds + "000");
21 | }
22 |
23 | public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
24 | {
25 | Check.NotNull(reader, nameof(reader));
26 |
27 | return reader.Value != null ?
28 | Epoch.AddMilliseconds((long)reader.Value / 1000d) :
29 | null;
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/CouchReplication.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Runtime.Serialization;
5 | using System.Text;
6 |
7 | namespace CouchDB.Driver.Types
8 | {
9 | [JsonObject("_replication")]
10 | public class CouchReplication : CouchDocument
11 | {
12 | [DataMember]
13 | [JsonProperty("source")]
14 | public object? Source { get; internal set; }
15 |
16 | public CouchReplicationBasicCredentials? SourceCredentials { get; set; }
17 |
18 | [DataMember]
19 | [JsonProperty("target")]
20 | public object? Target { get; internal set; }
21 |
22 | public CouchReplicationBasicCredentials? TargetCredentials { get; set; }
23 |
24 | [DataMember]
25 | [JsonProperty("continuous")]
26 | public bool Continuous { get; set; }
27 |
28 | [DataMember]
29 | [JsonProperty("selector")]
30 | public object? Selector { get; set; }
31 |
32 | [DataMember]
33 | [JsonProperty("cancel")]
34 | public bool Cancel { get; internal set; }
35 |
36 | [DataMember]
37 | [JsonProperty("create_target")]
38 | public bool CreateTarget{ get; set; }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Helpers/RequestsHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Threading.Tasks;
3 | using CouchDB.Driver.DTOs;
4 | using CouchDB.Driver.Exceptions;
5 | using Flurl.Http;
6 |
7 | namespace CouchDB.Driver.Helpers
8 | {
9 | internal static class RequestsHelper
10 | {
11 | public static async Task SendRequestAsync(this Task asyncRequest)
12 | {
13 | try
14 | {
15 | return await asyncRequest.ConfigureAwait(false);
16 | }
17 | catch (FlurlHttpException ex)
18 | {
19 | CouchError couchError = await ex.GetResponseJsonAsync().ConfigureAwait(false) ?? new CouchError();
20 |
21 | throw (HttpStatusCode?)ex.StatusCode switch
22 | {
23 | HttpStatusCode.Conflict => new CouchConflictException(couchError, ex),
24 | HttpStatusCode.NotFound => new CouchNotFoundException(couchError, ex),
25 | HttpStatusCode.BadRequest when couchError.Error == "no_usable_index" => new CouchNoIndexException(
26 | couchError, ex),
27 | _ => new CouchException(couchError, ex)
28 | };
29 | }
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Security/CouchSecurityInfo.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace CouchDB.Driver.Security
4 | {
5 | ///
6 | /// Represents two compulsory elements, admins and members, which are used to specify the list of users and/or roles that have admin and members rights to the database.
7 | ///
8 | public sealed class CouchSecurityInfo
9 | {
10 | public CouchSecurityInfo()
11 | {
12 | Members = new CouchSecurityInfoType();
13 | Admins = new CouchSecurityInfoType();
14 | }
15 |
16 | ///
17 | /// They can read all types of documents from the DB, and they can write (and edit) documents to the DB except for design documents.
18 | ///
19 | [JsonProperty("members")]
20 | public CouchSecurityInfoType Members { get; set; }
21 | ///
22 | /// They have all the privileges of members plus the privileges:
23 | /// write (and edit) design documents, add/remove database admins and members and set the database revisions limit.
24 | /// They can not create a database nor delete a database.
25 | ///
26 | [JsonProperty("admins")]
27 | public CouchSecurityInfoType Admins { get; set; }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.E2ETests/CouchDB.Driver.E2ETests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net10.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 | all
13 | runtime; build; native; contentfiles; analyzers; buildtransitive
14 |
15 |
16 | all
17 | runtime; build; native; contentfiles; analyzers; buildtransitive
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Always
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/CouchDB.Driver.UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net10.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | all
14 | runtime; build; native; contentfiles; analyzers; buildtransitive
15 |
16 |
17 | all
18 | runtime; build; native; contentfiles; analyzers; buildtransitive
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Always
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/CouchPartitionInfo.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace CouchDB.Driver.Types
4 | {
5 | ///
6 | /// Represents information about a specific partition in a partitioned database.
7 | ///
8 | public sealed class CouchPartitionInfo
9 | {
10 | ///
11 | /// The name of the database.
12 | ///
13 | [JsonProperty("db_name")]
14 | public string DbName { get; internal set; } = string.Empty;
15 |
16 | ///
17 | /// A count of the documents in the specified partition.
18 | ///
19 | [JsonProperty("doc_count")]
20 | public int DocCount { get; internal set; }
21 |
22 | ///
23 | /// Number of deleted documents in the partition.
24 | ///
25 | [JsonProperty("doc_del_count")]
26 | public int DocDelCount { get; internal set; }
27 |
28 | ///
29 | /// The partition key.
30 | ///
31 | [JsonProperty("partition")]
32 | public string Partition { get; internal set; } = string.Empty;
33 |
34 | ///
35 | /// Size information for the partition.
36 | ///
37 | [JsonProperty("sizes")]
38 | public Sizes Sizes { get; internal set; } = new Sizes();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Views/Rebels/Index.cshtml:
--------------------------------------------------------------------------------
1 | @model IEnumerable
2 |
3 | @{
4 | ViewData["Title"] = "View";
5 | }
6 |
7 | View
8 |
9 |
10 | Create New
11 |
12 |
13 |
14 |
15 | |
16 | @Html.DisplayNameFor(model => model.Name)
17 | |
18 |
19 | @Html.DisplayNameFor(model => model.Surname)
20 | |
21 |
22 | @Html.DisplayNameFor(model => model.Age)
23 | |
24 | |
25 |
26 |
27 |
28 | @foreach (var item in Model) {
29 |
30 | |
31 | @Html.DisplayFor(modelItem => item.Name)
32 | |
33 |
34 | @Html.DisplayFor(modelItem => item.Surname)
35 | |
36 |
37 | @Html.DisplayFor(modelItem => item.Age)
38 | |
39 |
40 | @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
41 | @Html.ActionLink("Details", "Details", new { id = item.Id }) |
42 | @Html.ActionLink("Delete", "Delete", new { id = item.Id })
43 | |
44 |
45 | }
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Indexes/IIndexBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 | using CouchDB.Driver.Types;
4 |
5 | namespace CouchDB.Driver.Indexes
6 | {
7 | ///
8 | /// Builder to configure CouchDB indexes.
9 | ///
10 | /// The type of the document.
11 | public interface IIndexBuilder
12 | where TSource : CouchDocument
13 | {
14 | ///
15 | /// Select a field for the index sort in ascending order.
16 | ///
17 | /// The type of the selected property.
18 | /// Function to select a property.
19 | /// Returns the current instance to chain calls.
20 | IOrderedIndexBuilder IndexBy(Expression> selector);
21 |
22 | ///
23 | /// Select a field for the index sort in descending order.
24 | ///
25 | /// The type of the selected property.
26 | /// Function to select a property.
27 | /// Returns the current instance to chain calls.
28 | IOrderedDescendingIndexBuilder IndexByDescending(Expression> selector);
29 | }
30 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/CouchList.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 |
4 | namespace CouchDB.Driver.Types
5 | {
6 | ///
7 | /// Represents a Couch query response.
8 | ///
9 | ///
10 | public class CouchList : IReadOnlyList
11 | {
12 | private readonly IReadOnlyList _source;
13 |
14 | ///
15 | /// An opaque string used for paging.
16 | ///
17 | public string Bookmark { get; }
18 | ///
19 | /// Execution statistics.
20 | ///
21 | public ExecutionStats ExecutionStats { get; }
22 |
23 | public int Count => _source.Count;
24 | public bool IsReadOnly => true;
25 | public TSource this[int index] => _source[index];
26 |
27 | public CouchList(IReadOnlyList source, string bookmark, ExecutionStats executionStats)
28 | {
29 | _source = source;
30 | Bookmark = bookmark;
31 | ExecutionStats = executionStats;
32 | }
33 |
34 | public IEnumerator GetEnumerator()
35 | {
36 | return _source.GetEnumerator();
37 | }
38 |
39 | IEnumerator IEnumerable.GetEnumerator()
40 | {
41 | return _source.GetEnumerator();
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/MyDeathStarContext.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Threading.Tasks;
3 | using CouchDB.Driver.Example.Models;
4 | using CouchDB.Driver.Extensions;
5 | using CouchDB.Driver.Options;
6 |
7 | namespace CouchDB.Driver.Example
8 | {
9 | public class MyDeathStarContext : CouchContext
10 | {
11 | public MyDeathStarContext(CouchOptions options)
12 | : base(options)
13 | {
14 | SeedDataAsync().GetAwaiter().GetResult();
15 | }
16 |
17 | private async Task SeedDataAsync()
18 | {
19 | var docs = await Rebels.ToListAsync();
20 | if (docs.All(d => d.Id != "luke"))
21 | {
22 | await Rebels.AddOrUpdateAsync(new Rebel
23 | {
24 | Id = "luke",
25 | Name = "Luke",
26 | Surname = "Skywalker",
27 | Age = 19
28 | });
29 | }
30 |
31 | if (docs.All(d => d.Id != "leia"))
32 | {
33 | await Rebels.AddOrUpdateAsync(new Rebel
34 | {
35 | Id = "leia",
36 | Name = "Leia",
37 | Surname = "Organa",
38 | Age = 19
39 | });
40 | }
41 | }
42 |
43 | public CouchDatabase Rebels { get; set; }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Views/CouchViewList.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using CouchDB.Driver.Types;
3 | using Newtonsoft.Json;
4 |
5 | #nullable disable
6 | #pragma warning disable CA2227 // Collection properties should be read only
7 | namespace CouchDB.Driver.Views
8 | {
9 | ///
10 | /// Result of a view query.
11 | ///
12 | /// The type of the key.
13 | /// The type of the value.
14 | /// The type of the document.
15 | public class CouchViewList
16 | where TDoc : CouchDocument
17 | {
18 | ///
19 | /// Number of documents in the database/view.
20 | ///
21 | [JsonProperty("total_rows")]
22 | public int TotalRows { get; set; }
23 |
24 | ///
25 | /// Offset where the document list started.
26 | ///
27 | [JsonProperty("offset")]
28 | public int Offset { get; set; }
29 |
30 | ///
31 | /// Array of view row objects. This result contains the document ID, value and the documents.
32 | ///
33 | [JsonProperty("rows")]
34 | public List> Rows { get; set; }
35 | }
36 | }
37 | #pragma warning restore CA2227 // Collection properties should be read only
38 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Security/CouchSecurity.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.DTOs;
2 | using CouchDB.Driver.Exceptions;
3 | using CouchDB.Driver.Helpers;
4 | using Flurl.Http;
5 | using System;
6 | using System.Threading.Tasks;
7 |
8 | namespace CouchDB.Driver.Security
9 | {
10 | internal class CouchSecurity: ICouchSecurity
11 | {
12 | private readonly Func _newRequest;
13 |
14 | internal CouchSecurity(Func newRequest)
15 | {
16 | _newRequest = newRequest;
17 | }
18 |
19 | public async Task GetInfoAsync()
20 | {
21 | return await _newRequest()
22 | .AppendPathSegment("_security")
23 | .GetJsonAsync()
24 | .SendRequestAsync()
25 | .ConfigureAwait(false);
26 | }
27 |
28 | public async Task SetInfoAsync(CouchSecurityInfo info)
29 | {
30 | Check.NotNull(info, nameof(info));
31 |
32 | OperationResult result = await _newRequest()
33 | .AppendPathSegment("_security")
34 | .PutJsonAsync(info)
35 | .ReceiveJson()
36 | .SendRequestAsync()
37 | .ConfigureAwait(false);
38 |
39 | if (!result.Ok)
40 | {
41 | throw new CouchDeleteException();
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Indexes/IndexDefinition.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Text;
3 | using CouchDB.Driver.Types;
4 |
5 | namespace CouchDB.Driver.Indexes
6 | {
7 | internal class IndexDefinition
8 | {
9 | public IndexDefinition(Dictionary fields, string? partialSelector)
10 | {
11 | Fields = fields;
12 | PartialSelector = partialSelector;
13 | }
14 |
15 | public Dictionary Fields { get; }
16 | public string? PartialSelector { get; }
17 |
18 | public override string ToString()
19 | {
20 | var sb = new StringBuilder();
21 |
22 | sb.Append('{');
23 |
24 | // Partial Selector
25 | if (PartialSelector != null)
26 | {
27 | sb.Append(PartialSelector);
28 | sb.Append(',');
29 | }
30 |
31 | // Fields
32 | sb.Append("\"fields\":[");
33 |
34 | foreach ((var fieldName, IndexFieldDirection fieldDirection) in Fields)
35 | {
36 | var fieldString = fieldDirection == IndexFieldDirection.Ascending
37 | ? $"\"{fieldName}\","
38 | : $"{{\"{fieldName}\":\"desc\"}},";
39 |
40 | sb.Append(fieldString);
41 | }
42 |
43 | sb.Length--;
44 | sb.Append("]}");
45 |
46 | return sb.ToString();
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Extensions/CouchDatabaseExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using CouchDB.Driver.Helpers;
4 | using CouchDB.Driver.Types;
5 |
6 | namespace CouchDB.Driver.Extensions
7 | {
8 | public static class CouchDatabaseExtensions
9 | {
10 | ///
11 | /// Change the password of the given user.
12 | ///
13 | /// The type of user.
14 | /// The users database.
15 | /// The user to update.
16 | /// The password.
17 | /// A to observe while waiting for the task to complete.
18 | /// A task that represents the asynchronous operation. The task result contains the updated user.
19 | public static Task ChangeUserPassword(this ICouchDatabase database, TCouchUser user,
20 | string password, CancellationToken cancellationToken = default)
21 | where TCouchUser : CouchUser
22 | {
23 | Check.NotNull(database, nameof(database));
24 | Check.NotNull(user, nameof(user));
25 | Check.NotNull(password, nameof(password));
26 |
27 | user.Password = password;
28 | return database.AddOrUpdateAsync(user, false, cancellationToken);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver.DependencyInjection/CouchDB.Driver.DependencyInjection.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | CouchDB.NET.DependencyInjection
6 | Matteo Bortolazzo
7 | Dependency injection utilities for CouchDB.NET
8 | https://github.com/matteobortolazzo/couchdb-net
9 | https://github.com/matteobortolazzo/couchdb-net
10 | couchdb,driver,nosql,netstandard,pouchdb,xamarin
11 |
12 | Library
13 |
14 | en
15 | 8.0
16 | enable
17 | icon.png
18 | LICENSE.txt
19 |
20 |
21 |
22 | true
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver.DependencyInjection.Autofac/CouchDB.Driver.DependencyInjection.Autofac.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | CouchDB.NET.DependencyInjection.Autofac
6 | Matteo Bortolazzo
7 | Dependency injection utilities for CouchDB.NET with Autofac container support.
8 | https://github.com/matteobortolazzo/couchdb-net
9 | https://github.com/matteobortolazzo/couchdb-net
10 | couchdb,driver,nosql,netstandard,pouchdb,xamarin
11 |
12 | Library
13 |
14 | en
15 | 8.0
16 | enable
17 | icon.png
18 | LICENSE.txt
19 |
20 |
21 |
22 | true
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/CouchType.cs:
--------------------------------------------------------------------------------
1 | namespace CouchDB.Driver.Types
2 | {
3 | ///
4 | /// Represents a document field type.
5 | ///
6 | public sealed class CouchType
7 | {
8 | ///
9 | /// Represents the CouchDB type value.
10 | ///
11 | public string Value { get; }
12 |
13 | private CouchType(string value)
14 | {
15 | Value = value;
16 | }
17 |
18 | ///
19 | /// Represents the "null" type.
20 | ///
21 | public static readonly CouchType CNull = new CouchType("null");
22 |
23 | ///
24 | /// Represents the "boolean" type.
25 | ///
26 | public static readonly CouchType CBoolean = new CouchType("boolean");
27 |
28 | ///
29 | /// Represents the "number" type.
30 | ///
31 | public static readonly CouchType CNumber = new CouchType("number");
32 |
33 | ///
34 | /// Represents the "string" type.
35 | ///
36 | public static readonly CouchType CString = new CouchType("string");
37 |
38 | ///
39 | /// Represents the "array" type.
40 | ///
41 | public static readonly CouchType CArray = new CouchType("array");
42 |
43 | ///
44 | /// Represents the "object" type.
45 | ///
46 | public static readonly CouchType CObject = new CouchType("object");
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Views/Rebels/Edit.cshtml:
--------------------------------------------------------------------------------
1 | @model CouchDB.Driver.Example.Models.Rebel
2 |
3 | @{
4 | ViewData["Title"] = "Edit";
5 | }
6 |
7 | Edit
8 |
9 | Rebel
10 |
11 |
36 |
37 |
40 |
41 | @section Scripts {
42 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
43 | }
44 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Views/Rebels/Create.cshtml:
--------------------------------------------------------------------------------
1 | @model CouchDB.Driver.Example.Models.Rebel
2 |
3 | @{
4 | ViewData["Title"] = "Create";
5 | }
6 |
7 | Create
8 |
9 | Rebel
10 |
11 |
36 |
37 |
40 |
41 | @section Scripts {
42 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
43 | }
44 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Options/DocumentCaseType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Humanizer;
3 |
4 | namespace CouchDB.Driver.Options
5 | {
6 | ///
7 | /// A helper class for specify a case format for documents.
8 | /// Every string will be at least convert to lowercase.
9 | ///
10 | public class DocumentCaseType : CaseType
11 | {
12 | private DocumentCaseType(string value) : base(value) { }
13 |
14 | ///
15 | /// Represents no format.
16 | ///
17 | public static readonly DocumentCaseType None = new DocumentCaseType("None");
18 | ///
19 | /// Represents underscore_case or snake_case.
20 | ///
21 | public static readonly DocumentCaseType UnderscoreCase = new DocumentCaseType("UnderscoreCase");
22 | ///
23 | /// Represents kebab-case.
24 | ///
25 | public static readonly DocumentCaseType KebabCase = new DocumentCaseType("KebabCase");
26 |
27 | internal override string Convert(string str)
28 | {
29 | if (Equals(this, None))
30 | {
31 | return str.ToLowerInvariant();
32 | }
33 | if (Equals(this, UnderscoreCase))
34 | {
35 | return str.ToLowerInvariant().Underscore();
36 | }
37 | if (Equals(this, KebabCase))
38 | {
39 | return str.ToLowerInvariant().Kebaberize();
40 | }
41 | throw new NotSupportedException($"Value {Value} not supported.");
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Helpers/CouchContractResolver.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using CouchDB.Driver.Extensions;
3 | using CouchDB.Driver.Options;
4 | using Newtonsoft.Json;
5 | using Newtonsoft.Json.Serialization;
6 |
7 | namespace CouchDB.Driver.Helpers
8 | {
9 | public class CouchContractResolver : DefaultContractResolver
10 | {
11 | private readonly PropertyCaseType _propertyCaseType;
12 | private readonly string? _databaseSplitDiscriminator;
13 |
14 | internal CouchContractResolver(PropertyCaseType propertyCaseType, string? databaseSplitDiscriminator)
15 | {
16 | _propertyCaseType = propertyCaseType;
17 | _databaseSplitDiscriminator = databaseSplitDiscriminator;
18 | }
19 |
20 | protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
21 | {
22 | Check.NotNull(member, nameof(member));
23 |
24 | JsonProperty property = base.CreateProperty(member, memberSerialization);
25 | if (property is { Ignored: false })
26 | {
27 | if (member.DeclaringType!.Assembly != GetType().Assembly)
28 | {
29 | property.PropertyName = member.GetCouchPropertyName(_propertyCaseType);
30 | }
31 | }
32 |
33 | if (property.PropertyName == CouchClient.DefaultDatabaseSplitDiscriminator && !string.IsNullOrWhiteSpace(_databaseSplitDiscriminator))
34 | {
35 | property.PropertyName = _databaseSplitDiscriminator;
36 | }
37 | return property;
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/CouchDB.Driver.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | CouchDB.NET
6 | Matteo Bortolazzo
7 | A .NET Standard driver for CouchDB.
8 | https://github.com/matteobortolazzo/couchdb-net
9 | https://github.com/matteobortolazzo/couchdb-net
10 | couchdb,driver,nosql,netstandard,pouchdb,xamarin
11 |
12 | Library
13 |
14 | en
15 | latest
16 | enable
17 | icon.png
18 | LICENSE.txt
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | true
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Options/CouchDocumentBuilder`.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.Indexes;
2 | using CouchDB.Driver.Types;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace CouchDB.Driver.Options
7 | {
8 | public class CouchDocumentBuilder : CouchDocumentBuilder
9 | where TSource : CouchDocument
10 | {
11 | internal List> IndexDefinitions { get; }
12 |
13 | internal CouchDocumentBuilder()
14 | {
15 | IndexDefinitions = new List>();
16 | }
17 |
18 | public CouchDocumentBuilder ToDatabase(string database)
19 | {
20 | Database = database;
21 | return this;
22 | }
23 |
24 | public CouchDocumentBuilder WithShards(int shards)
25 | {
26 | Shards = shards;
27 | return this;
28 | }
29 |
30 | public CouchDocumentBuilder WithReplicas(int replicas)
31 | {
32 | Replicas = replicas;
33 | return this;
34 | }
35 |
36 | public CouchDocumentBuilder IsPartitioned()
37 | {
38 | Partitioned = true;
39 | return this;
40 | }
41 |
42 | public CouchDocumentBuilder HasIndex(string name, Action> indexBuilderAction,
43 | IndexOptions? options = null)
44 | {
45 | var indexDefinition = new IndexSetupDefinition(name, indexBuilderAction, options);
46 | IndexDefinitions.Add(indexDefinition);
47 | return this;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | for details on configuring this project to bundle and minify static web assets. */
3 |
4 | a.navbar-brand {
5 | white-space: normal;
6 | text-align: center;
7 | word-break: break-all;
8 | }
9 |
10 | /* Provide sufficient contrast against white background */
11 | a {
12 | color: #0366d6;
13 | }
14 |
15 | .btn-primary {
16 | color: #fff;
17 | background-color: #1b6ec2;
18 | border-color: #1861ac;
19 | }
20 |
21 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link {
22 | color: #fff;
23 | background-color: #1b6ec2;
24 | border-color: #1861ac;
25 | }
26 |
27 | /* Sticky footer styles
28 | -------------------------------------------------- */
29 | html {
30 | font-size: 14px;
31 | }
32 | @media (min-width: 768px) {
33 | html {
34 | font-size: 16px;
35 | }
36 | }
37 |
38 | .border-top {
39 | border-top: 1px solid #e5e5e5;
40 | }
41 | .border-bottom {
42 | border-bottom: 1px solid #e5e5e5;
43 | }
44 |
45 | .box-shadow {
46 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
47 | }
48 |
49 | button.accept-policy {
50 | font-size: 1rem;
51 | line-height: inherit;
52 | }
53 |
54 | /* Sticky footer styles
55 | -------------------------------------------------- */
56 | html {
57 | position: relative;
58 | min-height: 100%;
59 | }
60 |
61 | body {
62 | /* Margin bottom by footer height */
63 | margin-bottom: 60px;
64 | }
65 | .footer {
66 | position: absolute;
67 | bottom: 0;
68 | width: 100%;
69 | white-space: nowrap;
70 | line-height: 60px; /* Vertically center the text there */
71 | }
72 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/Feed/ChangesFeedOptions_Tests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using CouchDB.Driver.ChangesFeed;
4 | using CouchDB.Driver.Shared;
5 | using Xunit;
6 |
7 | namespace CouchDB.Driver.UnitTests.Feed
8 | {
9 | public class ChangesFeedOptions_Tests
10 | {
11 | [Fact]
12 | public void ToQueryParameters_WhenDefault_Return_NoProperties()
13 | {
14 | // Arrange
15 | var options = new ChangesFeedOptions();
16 |
17 | // Act
18 | var parameters = OptionsHelper.ToQueryParameters(options);
19 |
20 | // Assert
21 | Assert.Empty(parameters);
22 | }
23 |
24 | [Fact]
25 | public void ToQueryParameters_WhenAllPropertyNotDefault_Return_AllProperties()
26 | {
27 | // Arrange
28 | var options = new ChangesFeedOptions
29 | {
30 | Conflicts = true,
31 | Descending = true,
32 | Filter = Guid.NewGuid().ToString(),
33 | Heartbeat = 1,
34 | IncludeDocs = true,
35 | Attachments = true,
36 | AttachEncodingInfo = true,
37 | Limit = 1,
38 | Since = Guid.NewGuid().ToString(),
39 | Style = ChangesFeedStyle.AllDocs,
40 | Timeout = 1,
41 | View = Guid.NewGuid().ToString(),
42 | SeqInterval = 1
43 | };
44 |
45 | // Act
46 | var parameters = OptionsHelper.ToQueryParameters(options);
47 |
48 | // Assert
49 | Assert.Equal(13, parameters.Count());
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/QueryTranslator.cs:
--------------------------------------------------------------------------------
1 | using System.Linq.Expressions;
2 | using System.Text;
3 | using CouchDB.Driver.Options;
4 |
5 | namespace CouchDB.Driver.Query
6 | {
7 | internal partial class QueryTranslator : ExpressionVisitor, IQueryTranslator
8 | {
9 | private readonly CouchOptions _options;
10 | private readonly StringBuilder _sb;
11 | private bool _isSelectorSet;
12 | private readonly object _sbLock = new();
13 |
14 | internal QueryTranslator(CouchOptions options)
15 | {
16 | _sb = new StringBuilder();
17 | _options = options;
18 | }
19 |
20 | public string Translate(Expression e)
21 | {
22 | lock (_sbLock)
23 | {
24 | _isSelectorSet = false;
25 | _sb.Clear();
26 | _sb.Append('{');
27 | Visit(e);
28 |
29 | // If no Where() calls
30 | if (!_isSelectorSet)
31 | {
32 | // If no other methods calls - ToList()
33 | if (_sb.Length > 1)
34 | {
35 | _sb.Length--;
36 | _sb.Append(',');
37 | }
38 |
39 | _sb.Append("\"selector\":{}");
40 | }
41 | else
42 | {
43 | _sb.Length--;
44 | }
45 |
46 | _sb.Append('}');
47 | var body = _sb.ToString();
48 | return body;
49 | }
50 | }
51 |
52 | protected override Expression VisitLambda(Expression l)
53 | {
54 | Visit(l.Body);
55 | return l;
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/IndexInfo.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using CouchDB.Driver.DTOs;
5 | using Newtonsoft.Json;
6 |
7 | namespace CouchDB.Driver.Types
8 | {
9 | ///
10 | /// Represent info about the index.
11 | ///
12 | public class IndexInfo
13 | {
14 | public IndexInfo()
15 | {
16 | Fields = new Dictionary();
17 | }
18 |
19 | ///
20 | /// ID of the design document the index belongs to.
21 | ///
22 | [JsonProperty("ddoc")]
23 | public string DesignDocument { get; set; }
24 |
25 | ///
26 | /// The name of the index.
27 | ///
28 | [JsonProperty("name")]
29 | public string Name { get; set; }
30 |
31 | ///
32 | /// The fields used in the index
33 | ///
34 | [JsonIgnore]
35 | public Dictionary Fields { get; }
36 |
37 | [JsonProperty("def")]
38 | internal IndexDefinitionInfo Definition
39 | {
40 | set
41 | {
42 | Fields.Clear();
43 |
44 | foreach (Dictionary definitions in value.Fields)
45 | {
46 | var (name, direction) = definitions.First();
47 | IndexFieldDirection fieldDirection = direction == "asc"
48 | ? IndexFieldDirection.Ascending
49 | : IndexFieldDirection.Descending;
50 | Fields.Add(name, fieldDirection);
51 | }
52 | }
53 | }
54 | }
55 | }
56 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/Translators/UnaryExpressionTranslator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq.Expressions;
3 |
4 | #pragma warning disable IDE0058 // Expression value is never used
5 | namespace CouchDB.Driver.Query
6 | {
7 | internal partial class QueryTranslator
8 | {
9 | protected override Expression VisitUnary(UnaryExpression u)
10 | {
11 | switch (u.NodeType)
12 | {
13 | case ExpressionType.Not:
14 | switch (u.Operand)
15 | {
16 | case BinaryExpression b when (b.NodeType == ExpressionType.Or || b.NodeType == ExpressionType.OrElse):
17 | _sb.Append('{');
18 | VisitBinaryCombinationOperator(b, true);
19 | _sb.Append('}');
20 | break;
21 | case MethodCallExpression m when m.Method.Name == "In":
22 | VisitInMethod(m, true);
23 | break;
24 | default:
25 | _sb.Append('{');
26 | _sb.Append("\"$not\":");
27 | Visit(u.Operand);
28 | _sb.Append('}');
29 | break;
30 | }
31 | break;
32 | case ExpressionType.Convert:
33 | Visit(u.Operand);
34 | break;
35 | default:
36 | throw new NotSupportedException($"The unary operator '{u.NodeType}' is not supported");
37 | }
38 | return u;
39 | }
40 |
41 | }
42 | }
43 | #pragma warning restore IDE0058 // Expression value is never used
44 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/ExecutionStats.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace CouchDB.Driver.Types
4 | {
5 | ///
6 | /// Represents basic execution statistics for a specific request.
7 | ///
8 | public sealed class ExecutionStats
9 | {
10 | ///
11 | /// Number of index keys examined.
12 | ///
13 | [JsonProperty("total_keys_examined")]
14 | public int TotalKeysExamined { get; internal set; }
15 |
16 | ///
17 | /// Number of documents fetched from the database/index, equivalent to using include_docs=true in a view. These may then be filtered in-memory to further narrow down the result set based on the selector.
18 | ///
19 | [JsonProperty("total_docs_examined")]
20 | public int TotalDocsExamined { get; internal set; }
21 |
22 | ///
23 | /// Number of documents fetched from the database using an out-of-band document fetch. This is only non-zero when read quorum > 1 is specified in the query parameters.
24 | ///
25 | [JsonProperty("total_quorum_docs_examined")]
26 | public int TotalQuorumDocsExamined { get; internal set; }
27 |
28 | ///
29 | /// Number of results returned from the query. Ideally this should not be significantly lower than the total documents/keys examined.
30 | ///
31 | [JsonProperty("results_returned")]
32 | public int ResultsReturned { get; internal set; }
33 |
34 | ///
35 | /// Total execution time in milliseconds as measured by the database.
36 | ///
37 | [JsonProperty("execution_time_ms")]
38 | public float ExecutionTimeMs { get; internal set; }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/CouchUser.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Collections.Generic;
3 | using System.Runtime.Serialization;
4 | using CouchDB.Driver.Helpers;
5 |
6 | namespace CouchDB.Driver.Types
7 | {
8 | ///
9 | /// Represents a CouchDB user.
10 | ///
11 | [JsonObject("_users")]
12 | public class CouchUser : CouchDocument
13 | {
14 | internal const string Prefix = "org.couchdb.user:";
15 |
16 | public CouchUser(string name, string password, List? roles = null, string type = "user")
17 | {
18 | Check.NotNull(name, nameof(name));
19 | Check.NotNull(type, nameof(type));
20 |
21 | Id = Prefix + name;
22 | Name = name;
23 | Password = password;
24 | Roles = roles ?? new List();
25 | Type = type;
26 | }
27 |
28 | [DataMember]
29 | [JsonProperty("password")]
30 | internal string Password { get; set; }
31 |
32 | ///
33 | /// User’s name aka login. Immutable e.g. you cannot rename an existing user - you have to create new one.
34 | ///
35 | [DataMember]
36 | [JsonProperty("name")]
37 | public string Name { get; set; }
38 |
39 | ///
40 | /// List of user roles. CouchDB doesn’t provide any built-in roles, so you’re free to define your own depending on your needs.
41 | /// However, you cannot set system roles like _admin there.
42 | /// Also, only administrators may assign roles to users - by default all users have no roles
43 | ///
44 | [DataMember]
45 | [JsonProperty("roles")]
46 | public List Roles { get; set; }
47 |
48 | ///
49 | /// Document type. Constantly has the value user.
50 | ///
51 | [DataMember]
52 | [JsonProperty("type")]
53 | public string Type { get; set; }
54 | }
55 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/CouchQueryable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Linq.Expressions;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using CouchDB.Driver.Query;
9 | using CouchDB.Driver.Types;
10 |
11 | namespace CouchDB.Driver
12 | {
13 | internal class CouchQueryable : IOrderedQueryable
14 | {
15 | private readonly Expression _expression;
16 | private readonly IAsyncQueryProvider _queryProvider;
17 |
18 | public CouchQueryable(IAsyncQueryProvider queryProvider)
19 | {
20 | _queryProvider = queryProvider;
21 | _expression = Expression.Constant(this);
22 | }
23 |
24 | public CouchQueryable(IAsyncQueryProvider queryProvider, Expression expression)
25 | {
26 | _queryProvider = queryProvider;
27 | _expression = expression;
28 | }
29 |
30 | public override string ToString()
31 | {
32 | return _queryProvider.ToString(_expression);
33 | }
34 |
35 | Expression IQueryable.Expression
36 | {
37 | get { return _expression; }
38 | }
39 |
40 | Type IQueryable.ElementType
41 | {
42 | get { return typeof(TResult); }
43 | }
44 |
45 | IQueryProvider IQueryable.Provider
46 | {
47 | get { return _queryProvider; }
48 | }
49 |
50 | public IEnumerator GetEnumerator()
51 | => _queryProvider.Execute>(_expression).GetEnumerator();
52 |
53 | IEnumerator IEnumerable.GetEnumerator()
54 | => _queryProvider.Execute(_expression).GetEnumerator();
55 |
56 | public Task> ToCouchListAsync(CancellationToken cancellationToken = default)
57 | => _queryProvider.ExecuteAsync>>(_expression, cancellationToken);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/CouchQueryProvider.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.Extensions;
2 | using System.Linq;
3 | using System.Linq.Expressions;
4 | using System.Reflection;
5 | using System.Threading;
6 |
7 | namespace CouchDB.Driver.Query
8 | {
9 | internal class CouchQueryProvider : IAsyncQueryProvider
10 | {
11 | private static readonly MethodInfo GenericCreateQueryMethod
12 | = typeof(CouchQueryProvider).GetRuntimeMethods()
13 | .Single(m => (m.Name == "CreateQuery") && m.IsGenericMethod);
14 |
15 | private readonly MethodInfo _genericExecuteMethod;
16 |
17 | private readonly IQueryCompiler _queryCompiler;
18 |
19 | public CouchQueryProvider(IQueryCompiler queryCompiler)
20 | {
21 | _queryCompiler = queryCompiler;
22 | _genericExecuteMethod = queryCompiler.GetType()
23 | .GetRuntimeMethods()
24 | .Single(m => (m.Name == "Execute") && m.IsGenericMethod);
25 | }
26 |
27 | public IQueryable CreateQuery(Expression expression)
28 | => new CouchQueryable(this, expression);
29 |
30 | public IQueryable CreateQuery(Expression expression)
31 | => (IQueryable)GenericCreateQueryMethod
32 | .MakeGenericMethod(expression.Type.GetSequenceType())
33 | .Invoke(this, new object[] { expression });
34 |
35 | public TResult Execute(Expression expression)
36 | => _queryCompiler.Execute(expression);
37 |
38 | public object Execute(Expression expression)
39 | => _genericExecuteMethod.MakeGenericMethod(expression.Type)
40 | .Invoke(_queryCompiler, new object[] { expression });
41 |
42 | public TResult ExecuteAsync(Expression expression, CancellationToken cancellationToken = default)
43 | => _queryCompiler.ExecuteAsync(expression, cancellationToken);
44 |
45 | public string ToString(Expression expression)
46 | => _queryCompiler.ToString(expression);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Options/CouchOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net.Http;
4 | using System.Net.Security;
5 | using System.Security.Cryptography.X509Certificates;
6 | using System.Threading.Tasks;
7 | using Flurl.Http.Configuration;
8 | using Newtonsoft.Json;
9 |
10 | namespace CouchDB.Driver.Options
11 | {
12 | public abstract class CouchOptions
13 | {
14 | public abstract Type ContextType { get; }
15 |
16 | internal Uri? Endpoint { get; set; }
17 | internal bool CheckDatabaseExists { get; set; }
18 | internal bool OverrideExistingIndexes { get; set; }
19 |
20 | internal AuthenticationType AuthenticationType { get; set; }
21 | internal string? Username { get; set; }
22 | internal string? Password { get; set; }
23 | internal IReadOnlyCollection? Roles { get; set; }
24 | internal int CookiesDuration { get; set; }
25 | internal Func>? JwtTokenGenerator { get; set; }
26 |
27 | internal bool PluralizeEntities { get; set; }
28 | internal DocumentCaseType DocumentsCaseType { get; set; }
29 | internal PropertyCaseType PropertiesCase { get; set; }
30 |
31 | internal string? DatabaseSplitDiscriminator { get; set; }
32 | internal NullValueHandling? NullValueHandling { get; set; }
33 | internal bool LogOutOnDispose { get; set; }
34 |
35 | internal Func? ServerCertificateCustomValidationCallback { get; set; }
36 | internal Action? ClientFlurlHttpSettingsAction { get; set; }
37 |
38 | internal bool ThrowOnQueryWarning { get; set; }
39 |
40 | internal CouchOptions()
41 | {
42 | AuthenticationType = AuthenticationType.None;
43 | PluralizeEntities = true;
44 | DocumentsCaseType = DocumentCaseType.UnderscoreCase;
45 | PropertiesCase = PropertyCaseType.CamelCase;
46 | NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
47 | LogOutOnDispose = true;
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Startup.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.DependencyInjection;
2 | using Microsoft.AspNetCore.Builder;
3 | using Microsoft.AspNetCore.Hosting;
4 | using Microsoft.Extensions.Configuration;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using Microsoft.Extensions.Hosting;
7 |
8 | namespace CouchDB.Driver.Example
9 | {
10 | public class Startup
11 | {
12 | public Startup(IConfiguration configuration)
13 | {
14 | Configuration = configuration;
15 | }
16 |
17 | public IConfiguration Configuration { get; }
18 |
19 | // This method gets called by the runtime. Use this method to add services to the container.
20 | public void ConfigureServices(IServiceCollection services)
21 | {
22 | services.AddControllersWithViews();
23 |
24 | services.AddCouchContext(builder => builder
25 | .UseEndpoint("http://localhost:5984")
26 | .UseBasicAuthentication(username: "admin", password: "admin")
27 | .EnsureDatabaseExists());
28 | }
29 |
30 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
31 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
32 | {
33 | if (env.IsDevelopment())
34 | {
35 | app.UseDeveloperExceptionPage();
36 | }
37 | else
38 | {
39 | app.UseExceptionHandler("/Home/Error");
40 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
41 | app.UseHsts();
42 | }
43 | app.UseHttpsRedirection();
44 | app.UseStaticFiles();
45 |
46 | app.UseRouting();
47 |
48 | app.UseAuthorization();
49 |
50 | app.UseEndpoints(endpoints =>
51 | {
52 | endpoints.MapControllerRoute(
53 | name: "default",
54 | pattern: "{controller=Rebels}/{action=Index}/{id?}");
55 | });
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Options/PropertyCaseType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Humanizer;
3 |
4 | namespace CouchDB.Driver.Options
5 | {
6 | ///
7 | /// A helper class for specify a case format for properties.
8 | ///
9 | public class PropertyCaseType : CaseType
10 | {
11 | private PropertyCaseType(string value) : base(value) { }
12 |
13 | ///
14 | /// Represents no format.
15 | ///
16 | public static readonly PropertyCaseType None = new("None");
17 | ///
18 | /// Represents underscore_case.
19 | ///
20 | public static readonly PropertyCaseType UnderscoreCase = new("UnderscoreCase");
21 | ///
22 | /// Represents dash-case, allows uppercase characters.
23 | ///
24 | public static readonly PropertyCaseType DashCase = new("DashCase");
25 | ///
26 | /// Represents kebab-case.
27 | ///
28 | public static readonly PropertyCaseType KebabCase = new("KebabCase");
29 | ///
30 | /// Represents PascalCase.
31 | ///
32 | public static readonly PropertyCaseType PascalCase = new("PascalCase");
33 | ///
34 | /// Represents camelCase.
35 | ///
36 | public static readonly PropertyCaseType CamelCase = new("CamelCase");
37 |
38 | internal override string Convert(string str)
39 | {
40 | if (Equals(this, None))
41 | {
42 | return str;
43 | }
44 | if (Equals(this, UnderscoreCase))
45 | {
46 | return str.Underscore();
47 | }
48 | if (Equals(this, DashCase))
49 | {
50 | return str.Dasherize();
51 | }
52 | if (Equals(this, KebabCase))
53 | {
54 | return str.Kebaberize();
55 | }
56 | if (Equals(this, PascalCase))
57 | {
58 | return str.Pascalize();
59 | }
60 | if (Equals(this, CamelCase))
61 | {
62 | return str.Camelize();
63 | }
64 |
65 | throw new NotSupportedException($"Value {Value} not supported.");
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Shared/OptionsHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Reflection;
6 | using Newtonsoft.Json;
7 |
8 | namespace CouchDB.Driver.Shared
9 | {
10 | internal static class OptionsHelper
11 | {
12 | public static IEnumerable<(string Name, object? Value)> ToQueryParameters(object options)
13 | {
14 | static TAttribute? GetAttribute(ICustomAttributeProvider propertyInfo)
15 | {
16 | return propertyInfo
17 | .GetCustomAttributes(typeof(TAttribute), true)
18 | .Cast()
19 | .FirstOrDefault();
20 | }
21 |
22 | Type optionsType = options.GetType();
23 | foreach (PropertyInfo propertyInfo in optionsType.GetProperties())
24 | {
25 | JsonPropertyAttribute? jsonProperty = GetAttribute(propertyInfo);
26 | DefaultValueAttribute? defaultValue = GetAttribute(propertyInfo);
27 | if (jsonProperty == null || defaultValue == null)
28 | {
29 | continue;
30 | }
31 |
32 | var propertyName = jsonProperty.PropertyName
33 | ?? throw new ArgumentException($"JSON attribute not found for property {propertyInfo.Name}.");
34 | object propertyValue = propertyInfo.GetValue(options);
35 | object propertyDefaultValue = defaultValue.Value;
36 |
37 | var isDefault = Equals(propertyValue, propertyDefaultValue) ||
38 | string.Equals(propertyValue?.ToString(), propertyDefaultValue?.ToString(), StringComparison.InvariantCultureIgnoreCase);
39 | if (isDefault)
40 | {
41 | continue;
42 | }
43 |
44 | object? propertyStringValue = propertyValue?.ToString();
45 | if (propertyInfo.PropertyType == typeof(bool))
46 | {
47 | propertyStringValue = propertyValue?.ToString().ToLowerInvariant();
48 | }
49 |
50 | yield return (propertyName, propertyStringValue);
51 | }
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/CouchActiveTask.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using System;
3 | using CouchDB.Driver.Helpers;
4 | using Newtonsoft.Json;
5 |
6 | namespace CouchDB.Driver.Types
7 | {
8 | ///
9 | /// Represents an active task.
10 | ///
11 | public sealed class CouchActiveTask
12 | {
13 | ///
14 | /// Processes changes.
15 | ///
16 | [JsonProperty("changes-done")]
17 | public int ChangesDone { get; internal set; }
18 |
19 | ///
20 | /// Source database.
21 | ///
22 | [JsonProperty("database")]
23 | public string Database { get; internal set; }
24 |
25 | ///
26 | /// Process ID
27 | ///
28 | [JsonProperty("pid")]
29 | public string PID { get; internal set; }
30 |
31 | ///
32 | /// Current percentage progress.
33 | ///
34 | [JsonProperty("progress")]
35 | public int Progress { get; internal set; }
36 |
37 | ///
38 | /// Task start time.
39 | ///
40 | [JsonProperty("started_on")]
41 | [JsonConverter(typeof(MicrosecondEpochConverter))]
42 | public DateTime StartedOn { get; internal set; }
43 |
44 | ///
45 | /// Task status message.
46 | ///
47 | [JsonProperty("status")]
48 | public string Status { get; internal set; }
49 |
50 | ///
51 | /// Task name.
52 | ///
53 | [JsonProperty("task")]
54 | public string Task { get; internal set; }
55 |
56 | ///
57 | /// Total changes to process.
58 | ///
59 | [JsonProperty("total_changes-done")]
60 | public int TotalChanges { get; internal set; }
61 |
62 | ///
63 | /// Operation type.
64 | ///
65 | [JsonProperty("type")]
66 | public string Type { get; internal set; }
67 |
68 | ///
69 | /// Last operation update.
70 | ///
71 | [JsonProperty("updated_on")]
72 | [JsonConverter(typeof(MicrosecondEpochConverter))]
73 | public DateTime UpdatedOn { get; internal set; }
74 | }
75 | }
76 | #nullable restore
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/Find/Find_Sort.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.UnitTests.Models;
2 | using System;
3 | using Xunit;
4 | using System.Linq;
5 |
6 | namespace CouchDB.Driver.UnitTests.Find
7 | {
8 | public class Find_Sort
9 | {
10 | private readonly ICouchDatabase _rebels;
11 |
12 | public Find_Sort()
13 | {
14 | var client = new CouchClient("http://localhost");
15 | _rebels = client.GetDatabase();
16 | }
17 |
18 | [Fact]
19 | public void SortAsc()
20 | {
21 | var json = _rebels.OrderBy(c => c.Name).ToString();
22 | Assert.Equal(@"{""sort"":[""name""],""selector"":{}}", json);
23 | }
24 |
25 | [Fact]
26 | public void SortDesc()
27 | {
28 | var json = _rebels.OrderByDescending(c => c.Name).ToString();
29 | Assert.Equal(@"{""sort"":[{""name"":""desc""}],""selector"":{}}", json);
30 | }
31 |
32 | [Fact]
33 | public void SortAscMultiple()
34 | {
35 | var json = _rebels.OrderBy(c => c.Name).ThenBy(c => c.Age).ToString();
36 | Assert.Equal(@"{""sort"":[""name"",""age""],""selector"":{}}", json);
37 | }
38 |
39 | [Fact]
40 | public void SortDescMultiple()
41 | {
42 | var json = _rebels.OrderByDescending(c => c.Name).ThenByDescending(c => c.Age).ToString();
43 | Assert.Equal(@"{""sort"":[{""name"":""desc""},{""age"":""desc""}],""selector"":{}}", json);
44 | }
45 |
46 | [Fact]
47 | public void SortAscMultiple_DifferentDirections()
48 | {
49 | var exception = Record.Exception(() =>
50 | {
51 | _rebels.OrderBy(c => c.Name).ThenByDescending(c => c.Age).ToString();
52 | });
53 | Assert.NotNull(exception);
54 | Assert.IsType(exception);
55 | }
56 |
57 | [Fact]
58 | public void SortDescMultiple_DifferentDirections()
59 | {
60 | var exception = Record.Exception(() =>
61 | {
62 | _rebels.OrderByDescending(c => c.Name).ThenBy(c => c.Age).ToString();
63 | });
64 | Assert.NotNull(exception);
65 | Assert.IsType(exception);
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.Example/Views/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @ViewData["Title"] - CouchDB.Driver.Example
7 |
8 |
9 |
10 |
11 |
32 |
33 |
34 | @RenderBody()
35 |
36 |
37 |
38 |
43 |
44 |
45 |
46 | @RenderSection("Scripts", required: false)
47 |
48 |
49 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.E2ETests/MyDeathStarContext.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.E2ETests.Models;
2 | using CouchDB.Driver.Options;
3 |
4 | namespace CouchDB.Driver.E2ETests
5 | {
6 | public class MyDeathStarContext : CouchContext
7 | {
8 | public CouchDatabase Rebels { get; set; }
9 |
10 | protected override void OnConfiguring(CouchOptionsBuilder optionsBuilder)
11 | {
12 | optionsBuilder
13 | .UseEndpoint("http://localhost:5984/")
14 | .EnsureDatabaseExists()
15 | .UseBasicAuthentication(username: "admin", password: "admin");
16 | }
17 |
18 | protected override void OnDatabaseCreating(CouchDatabaseBuilder databaseBuilder)
19 | {
20 | databaseBuilder.Document()
21 | .HasIndex("surnames_index", builder => builder
22 | .IndexBy(r => r.Surname)
23 | .ThenBy(r => r.Name));
24 | }
25 | }
26 |
27 | ///
28 | /// Different indexes
29 | ///
30 | public class MyDeathStarContext2 : CouchContext
31 | {
32 | public CouchDatabase Rebels { get; set; }
33 |
34 | protected override void OnConfiguring(CouchOptionsBuilder optionsBuilder)
35 | {
36 | optionsBuilder
37 | .UseEndpoint("http://localhost:5984/")
38 | .EnsureDatabaseExists()
39 | .OverrideExistingIndexes()
40 | .UseBasicAuthentication(username: "admin", password: "admin");
41 | }
42 |
43 | protected override void OnDatabaseCreating(CouchDatabaseBuilder databaseBuilder)
44 | {
45 | databaseBuilder.Document()
46 | .HasIndex("surnames_index", builder => builder
47 | .IndexByDescending(r => r.Surname)
48 | .ThenByDescending(r => r.Name));
49 | }
50 | }
51 |
52 | public class MyDeathStarContextWithQueryWarning : CouchContext
53 | {
54 | public CouchDatabase Rebels { get; set; }
55 |
56 | protected override void OnConfiguring(CouchOptionsBuilder optionsBuilder)
57 | {
58 | optionsBuilder
59 | .UseEndpoint("http://localhost:5984/")
60 | .EnsureDatabaseExists()
61 | .UseBasicAuthentication(username: "admin", password: "admin")
62 | .ThrowOnQueryWarning();
63 | }
64 |
65 | protected override void OnDatabaseCreating(CouchDatabaseBuilder databaseBuilder)
66 | {
67 | databaseBuilder.Document()
68 | .HasIndex("surnames_index", builder => builder
69 | .IndexBy(r => r.Surname)
70 | .ThenBy(r => r.Name));
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Local/LocalDocumentsOptions.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using Newtonsoft.Json;
3 |
4 | namespace CouchDB.Driver.Local
5 | {
6 | public class LocalDocumentsOptions
7 | {
8 | ///
9 | /// Includes conflicts information in response. Ignored if IncludeDocs isn’t True.
10 | ///
11 | [JsonProperty("conflicts")]
12 | [DefaultValue(false)]
13 | public bool Conflicts { get; set; }
14 |
15 | ///
16 | /// Return the change results in descending sequence order (most recent change first).
17 | ///
18 | [JsonProperty("descending")]
19 | [DefaultValue(false)]
20 | public bool Descending { get; set; }
21 |
22 | ///
23 | /// Return the change results in descending sequence order (most recent change first).
24 | ///
25 | [JsonProperty("end_key")]
26 | [DefaultValue(null)]
27 | public string? EndKey { get; set; }
28 |
29 | ///
30 | /// Stop returning records when the specified local document ID is reached.
31 | ///
32 | [JsonProperty("end_key_doc_id")]
33 | [DefaultValue(null)]
34 | public string? EndKeyDocId { get; set; }
35 |
36 | ///
37 | /// Specifies whether the specified end key should be included in the result.
38 | ///
39 | [JsonProperty("include_docs")]
40 | [DefaultValue(true)]
41 | public bool InclusiveEnd { get; set; } = true;
42 |
43 | ///
44 | /// Return only local documents that match the specified key.
45 | ///
46 | [JsonProperty("key")]
47 | [DefaultValue(null)]
48 | public string? Key { get; set; }
49 |
50 | ///
51 | /// Limit the number of the returned local documents to the specified number.
52 | ///
53 | [JsonProperty("limit")]
54 | [DefaultValue(null)]
55 | public int? Limit { get; set; }
56 |
57 | ///
58 | /// Skip this number of records before starting to return the results.
59 | ///
60 | [JsonProperty("skip ")]
61 | [DefaultValue(0)]
62 | public int Skip { get; set; }
63 |
64 | ///
65 | /// Return records starting with the specified key.
66 | ///
67 | [JsonProperty("start_key")]
68 | [DefaultValue(null)]
69 | public string? StartKey { get; set; }
70 |
71 | ///
72 | /// Return records starting with the specified local document ID.
73 | ///
74 | [JsonProperty("start_key_doc_id")]
75 | [DefaultValue(null)]
76 | public string? StartKeyDocId { get; set; }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Extensions/MemberInfoExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using System.Reflection;
6 | using CouchDB.Driver.Options;
7 | using Newtonsoft.Json;
8 |
9 | namespace CouchDB.Driver.Extensions
10 | {
11 | internal static class MemberInfoExtensions
12 | {
13 | public static string GetCouchPropertyName(this MemberInfo memberInfo, PropertyCaseType propertyCaseType)
14 | {
15 | object[] jsonPropertyAttributes = memberInfo.GetCustomAttributes(typeof(JsonPropertyAttribute), true);
16 | JsonPropertyAttribute? jsonProperty = jsonPropertyAttributes.Length > 0
17 | ? jsonPropertyAttributes[0] as JsonPropertyAttribute
18 | : null;
19 |
20 | return jsonProperty != null
21 | ? jsonProperty.PropertyName!
22 | : propertyCaseType.Convert(memberInfo.Name);
23 | }
24 |
25 | public static MethodInfo GetMinOrMaxWithoutSelector(this List queryableMethods, string methodName)
26 | => queryableMethods.Single(
27 | mi => mi.Name == methodName
28 | && mi.GetParameters().Length == 1
29 | && mi.GetParameters()[0].ParameterType.GetGenericArguments()[0] == typeof(T));
30 |
31 | public static MethodInfo GetSumOrAverageWithoutSelector(this List queryableMethods, string methodName)
32 | => queryableMethods.Single(
33 | mi => mi.Name == methodName
34 | && mi.GetParameters().Length == 1
35 | && mi.GetParameters()[0].ParameterType.GetGenericArguments()[0] == typeof(T));
36 |
37 | public static MethodInfo GetSumOrAverageWithSelector(this List queryableMethods, string methodName)
38 | => queryableMethods.Single(
39 | mi => mi.Name == methodName
40 | && mi.GetParameters().Length == 2
41 | && IsSelector(mi.GetParameters()[1].ParameterType));
42 |
43 | public static bool IsExpressionOfFunc(this Type type, int funcGenericArgs = 2)
44 | => type.IsGenericType
45 | && type.GetGenericTypeDefinition() == typeof(Expression<>)
46 | && type.GetGenericArguments()[0].IsGenericType
47 | && type.GetGenericArguments()[0].GetGenericArguments().Length == funcGenericArgs;
48 |
49 | public static bool IsSelector(this Type type)
50 | => type.IsGenericType
51 | && type.GetGenericTypeDefinition() == typeof(Expression<>)
52 | && type.GetGenericArguments()[0].IsGenericType
53 | && type.GetGenericArguments()[0].GetGenericArguments().Length == 2
54 | && type.GetGenericArguments()[0].GetGenericArguments()[1] == typeof(T);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Indexes/IndexBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using CouchDB.Driver.Extensions;
6 | using CouchDB.Driver.Options;
7 | using CouchDB.Driver.Query;
8 | using CouchDB.Driver.Types;
9 |
10 | namespace CouchDB.Driver.Indexes
11 | {
12 | internal class IndexBuilder: IIndexBuilder, IOrderedIndexBuilder, IOrderedDescendingIndexBuilder
13 | where TSource : CouchDocument
14 | {
15 | private readonly CouchOptions _options;
16 | private readonly IAsyncQueryProvider _queryProvider;
17 |
18 | private bool _ascending = true;
19 | private readonly List _fields;
20 | private string? _partialSelector;
21 |
22 | public IndexBuilder(CouchOptions options, IAsyncQueryProvider queryProvider)
23 | {
24 | _options = options;
25 | _queryProvider = queryProvider;
26 | _fields = new List();
27 | }
28 |
29 | public IOrderedIndexBuilder IndexBy(Expression> selector)
30 | {
31 | AddField(selector);
32 | return this;
33 | }
34 |
35 | public IOrderedDescendingIndexBuilder IndexByDescending(Expression> selector)
36 | {
37 | _ascending = false;
38 | AddField(selector);
39 | return this;
40 | }
41 |
42 | public IOrderedIndexBuilder ThenBy(Expression> selector)
43 | {
44 | return IndexBy(selector);
45 | }
46 |
47 | public IOrderedDescendingIndexBuilder ThenByDescending(Expression> selector)
48 | {
49 | return IndexByDescending(selector);
50 | }
51 |
52 | public void Where(Expression> predicate)
53 | {
54 | MethodCallExpression whereExpression = predicate.WrapInWhereExpression();
55 | var jsonSelector = _queryProvider.ToString(whereExpression);
56 | _partialSelector = jsonSelector
57 | .Substring(1, jsonSelector.Length - 2)
58 | .Replace("selector", "partial_filter_selector", StringComparison.CurrentCultureIgnoreCase);
59 | }
60 |
61 | private void AddField(Expression> selector)
62 | {
63 | var memberExpression = selector.ToMemberExpression();
64 | _fields.Add(memberExpression.GetPropertyName(_options));
65 | }
66 |
67 | public IndexDefinition Build()
68 | {
69 | var fields = _fields.ToDictionary(
70 | field => field,
71 | _ => _ascending ? IndexFieldDirection.Ascending : IndexFieldDirection.Descending);
72 | return new IndexDefinition(fields, _partialSelector);
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/CouchDatabaseInfo.cs:
--------------------------------------------------------------------------------
1 | #nullable disable
2 | using Newtonsoft.Json;
3 |
4 | namespace CouchDB.Driver.Types
5 | {
6 | ///
7 | /// Represents information a specific database.
8 | ///
9 | public sealed class CouchDatabaseInfo
10 | {
11 | ///
12 | /// Cluster information.
13 | ///
14 | [JsonProperty("cluster")]
15 | public Cluster Cluster { get; internal set; }
16 |
17 | ///
18 | /// Set to true if the database compaction routine is operating on this database.
19 | ///
20 | [JsonProperty("compact_running")]
21 | public bool CompactRunning { get; internal set; }
22 |
23 | ///
24 | /// The name of the database.
25 | ///
26 | [JsonProperty("db_name")]
27 | public string DbName { get; internal set; }
28 |
29 | ///
30 | /// The version of the physical format used for the data when it is stored on disk.
31 | ///
32 | [JsonProperty("disk_format_version")]
33 | public int DiskFormatVersion { get; internal set; }
34 |
35 | ///
36 | /// A count of the documents in the specified database.
37 | ///
38 | [JsonProperty("doc_count")]
39 | public int DocCount { get; internal set; }
40 |
41 | ///
42 | /// Number of deleted documents.
43 | ///
44 | [JsonProperty("doc_del_count")]
45 | public int DocDelCount { get; internal set; }
46 |
47 | ///
48 | /// An opaque string that describes the purge state of the database. Do not rely on this string for counting the number of purge operations.
49 | ///
50 | [JsonProperty("purge_seq")]
51 | public string PurgeSeq { get; internal set; }
52 |
53 | ///
54 | /// Size information
55 | ///
56 | [JsonProperty("sizes")]
57 | public Sizes Sizes { get; internal set; }
58 |
59 | ///
60 | /// An opaque string that describes the state of the database. Do not rely on this string for counting the number of updates.
61 | ///
62 | [JsonProperty("update_seq")]
63 | public string UpdateSeq { get; internal set; }
64 |
65 | ///
66 | /// Indicates whether the database is partitioned or not.
67 | ///
68 | [JsonProperty("props")]
69 | public DatabaseProps Props { get; internal set; }
70 | }
71 |
72 | ///
73 | /// Represents database properties.
74 | ///
75 | public sealed class DatabaseProps
76 | {
77 | ///
78 | /// Indicates whether the database is partitioned.
79 | ///
80 | [JsonProperty("partitioned")]
81 | public bool Partitioned { get; internal set; }
82 | }
83 | }
84 | #nullable restore
--------------------------------------------------------------------------------
/src/CouchDB.Driver/DatabaseApiMethodOptions/FindOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace CouchDB.Driver.DatabaseApiMethodOptions
6 | {
7 | ///
8 | /// Options relevant to getting a document (supported by GET HTTP-method).
9 | /// Check https://docs.couchdb.org/en/stable/api/document/common.html#get--db-docid
10 | ///
11 | public class FindOptions
12 | {
13 | ///
14 | /// Includes attachments bodies in response. Default is False
15 | ///
16 | public bool Attachments { get; set; }
17 |
18 | ///
19 | /// Includes encoding information in attachment stubs if the particular attachment is compressed. Default is False
20 | ///
21 | public bool AttachmentsEncodingInfo { get; set; }
22 |
23 | ///
24 | /// Includes attachments only since specified revisions. Doesn’t includes attachments for specified revisions. Optional
25 | ///
26 | public IList? AttachmentsSince { get; set; }
27 |
28 | ///
29 | /// Includes information about conflicts in document. Default is False
30 | ///
31 | public bool Conflicts { get; set; }
32 |
33 | ///
34 | /// Includes information about deleted conflicted revisions. Default is False
35 | ///
36 | public bool DeleteConflicts { get; set; }
37 |
38 | ///
39 | /// Forces retrieving latest “leaf” revision, no matter what rev was requested. Default is False
40 | ///
41 | public bool Latest { get; set; }
42 |
43 | ///
44 | /// Includes last update sequence for the document. Default is <False
45 | ///
46 | public bool LocalSequence { get; set; }
47 |
48 | ///
49 | /// Acts same as specifying all , and query parameters. Default is False
50 | ///
51 | public bool Meta { get; set; }
52 |
53 | ///
54 | /// Retrieves documents of specified leaf revisions. Additionally, it accepts value as all to return all leaf revisions. Optional
55 | ///
56 | public IList? OpenRevisions { get; set; }
57 |
58 | ///
59 | /// Retrieves document of specified revision. Optional
60 | ///
61 | public string? Revision { get; set; }
62 |
63 | ///
64 | /// Includes list of all known document revisions. Default is False
65 | ///
66 | public bool Revisions { get; set; }
67 |
68 | ///
69 | /// Includes detailed information for all known document revisions. Default is False
70 | ///
71 | public bool RevisionsInfo { get; set; }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/Extensions/ObjectQueryExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using CouchDB.Driver.Helpers;
6 | using CouchDB.Driver.Types;
7 |
8 | namespace CouchDB.Driver.Query.Extensions
9 | {
10 | public static class ObjectQueryExtensions
11 | {
12 | ///
13 | /// Determines whether value is contained in the sequence provided.
14 | ///
15 | /// The type of the elements of source.
16 | /// The value to locate in the input.
17 | /// A sequence in which to locate the value.
18 | /// true if the input sequence contains an element that has the specified value; otherwise, false.
19 | public static bool In(this T value, IEnumerable input)
20 | {
21 | Check.NotNull(input, nameof(input));
22 |
23 | return input.Contains(value);
24 | }
25 |
26 | ///
27 | /// Determines the field exists in the database.
28 | ///
29 | /// The type of the elements of source.
30 | /// The value to check.
31 | /// The name of the field to check.
32 | /// true if the field exists; otherwise, false.
33 | public static bool FieldExists(this T source, string fieldName)
34 | {
35 | if (source == null)
36 | {
37 | throw new ArgumentNullException(nameof(source));
38 | }
39 |
40 | return source.GetType().GetProperties().Any(p => p.Name == fieldName);
41 | }
42 |
43 | ///
44 | /// Determines the field is of the specified type.
45 | ///
46 | /// The type of the elements of source.
47 | /// The value to check.
48 | /// Type couch type to compare.
49 | /// true if the field has the specified type; otherwise, false.
50 | public static bool IsCouchType(this T source, CouchType couchType)
51 | {
52 | if (couchType == CouchType.CNull && source == null)
53 | {
54 | return true;
55 | }
56 | if (couchType == CouchType.CBoolean && source is bool)
57 | {
58 | return true;
59 | }
60 | if (couchType == CouchType.CString && source is string)
61 | {
62 | return true;
63 | }
64 | if (couchType == CouchType.CNumber && typeof(T).IsPrimitive)
65 | {
66 | return true;
67 | }
68 | if (couchType == CouchType.CArray && source is IEnumerable)
69 | {
70 | return true;
71 | }
72 | return couchType == CouchType.CObject && typeof(T).IsClass;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/Translators/ConstantExpressionTranslator.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections;
4 | using System.Diagnostics;
5 | using System.Linq;
6 | using System.Linq.Expressions;
7 |
8 | #pragma warning disable IDE0058 // Expression value is never used
9 | namespace CouchDB.Driver.Query
10 | {
11 | internal partial class QueryTranslator
12 | {
13 | protected override Expression VisitConstant(ConstantExpression c)
14 | {
15 | HandleConstant(c.Value);
16 |
17 | return c;
18 | }
19 |
20 | private void HandleConstant(object? constant)
21 | {
22 | if (constant is IQueryable)
23 | {
24 | // assume constant nodes w/ IQueryables are table references
25 | // q.ElementType.Name
26 | }
27 | else if (constant == null)
28 | {
29 | _sb.Append("null");
30 | }
31 | else
32 | {
33 | switch (Type.GetTypeCode(constant.GetType()))
34 | {
35 | case TypeCode.Boolean:
36 | _sb.Append(((bool)constant) ? "true" : "false");
37 | break;
38 | case TypeCode.String:
39 | _sb.Append(JsonConvert.SerializeObject(constant));
40 | break;
41 | case TypeCode.DateTime:
42 | _sb.Append(JsonConvert.SerializeObject(constant));
43 | break;
44 | case TypeCode.Object:
45 | switch (constant)
46 | {
47 | case IEnumerable enumerable:
48 | VisitIEnumerable(enumerable);
49 | break;
50 | case Guid _:
51 | _sb.Append(JsonConvert.SerializeObject(constant));
52 | break;
53 | default:
54 | Debug.WriteLine($"The constant for '{constant}' not officially supported.");
55 | _sb.Append(JsonConvert.SerializeObject(constant));
56 | break;
57 | }
58 | break;
59 | case TypeCode.Int32:
60 | _sb.Append((int)constant);
61 | break;
62 | default:
63 | _sb.Append(constant);
64 | break;
65 | }
66 | }
67 |
68 | }
69 |
70 | private void VisitIEnumerable(IEnumerable list)
71 | {
72 | _sb.Append('[');
73 | var needsComma = false;
74 | foreach (var item in list)
75 | {
76 | if (needsComma)
77 | {
78 | _sb.Append(',');
79 | }
80 | HandleConstant(item);
81 | needsComma = true;
82 | }
83 | _sb.Append(']');
84 | }
85 | }
86 | }
87 | #pragma warning restore IDE0058 // Expression value is never used
--------------------------------------------------------------------------------
/src/CouchDB.Driver/ChangesFeed/StreamExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Buffers;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Runtime.CompilerServices;
6 | using System.Text;
7 | using System.Threading;
8 |
9 | namespace CouchDB.Driver.ChangesFeed
10 | {
11 | internal static class StreamExtensions
12 | {
13 | public static async IAsyncEnumerable ReadLinesAsync(this Stream stream,
14 | [EnumeratorCancellation] CancellationToken cancellationToken)
15 | {
16 | using IMemoryOwner owner = MemoryPool.Shared.Rent();
17 | using var decoder = new LinesDecoder(owner.Memory);
18 |
19 | while (!cancellationToken.IsCancellationRequested)
20 | {
21 | var readCharCount = await stream
22 | .ReadAsync(owner.Memory, cancellationToken)
23 | .ConfigureAwait(false);
24 |
25 | if (readCharCount == 0)
26 | {
27 | yield break;
28 | }
29 |
30 | foreach (var line in decoder.ReadLines(readCharCount))
31 | {
32 | yield return line;
33 | }
34 | }
35 | }
36 |
37 | private class LinesDecoder: IDisposable
38 | {
39 | private readonly Decoder _uniDecoder;
40 | private readonly Memory _streamMemory;
41 | private string _remainder = string.Empty;
42 | private readonly IMemoryOwner _decodingMemory;
43 |
44 | public LinesDecoder(Memory streamMemory)
45 | {
46 | _uniDecoder = Encoding.UTF8.GetDecoder();
47 | _streamMemory = streamMemory;
48 | _decodingMemory = MemoryPool.Shared.Rent(streamMemory.Length);
49 | }
50 |
51 | public IEnumerable ReadLines(int readCharCount)
52 | {
53 | Span readableStreamSpan = _streamMemory.Span[..readCharCount];
54 | var charCount = _uniDecoder.GetCharCount(readableStreamSpan, false);
55 | _ = _uniDecoder.GetChars(readableStreamSpan, _decodingMemory.Memory.Span, false);
56 |
57 | Span decodedSpan = _decodingMemory.Memory.Span[..charCount];
58 | var str = new string(decodedSpan);
59 | var lines = str.Split('\n');
60 |
61 | for (var i = 0; i < lines.Length; i++)
62 | {
63 | var line = lines[i];
64 | if (line.Length == 0)
65 | {
66 | continue;
67 | }
68 |
69 | if (_remainder.Length > 0)
70 | {
71 | line = _remainder + line;
72 | _remainder = string.Empty;
73 | }
74 |
75 | if (i == lines.Length - 1)
76 | {
77 | _remainder = line;
78 | continue;
79 | }
80 |
81 | yield return line;
82 | }
83 | }
84 |
85 | public void Dispose()
86 | {
87 | _decodingMemory.Dispose();
88 | }
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Query/QuerySender.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Reflection;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using CouchDB.Driver.DTOs;
7 | using CouchDB.Driver.Exceptions;
8 | using CouchDB.Driver.Helpers;
9 | using CouchDB.Driver.Types;
10 | using Flurl.Http;
11 |
12 | namespace CouchDB.Driver.Query
13 | {
14 | internal class QuerySender : IQuerySender
15 | {
16 | private readonly IFlurlClient _client;
17 | private readonly QueryContext _queryContext;
18 |
19 | private static readonly MethodInfo GenericToListMethod
20 | = typeof(QuerySender).GetRuntimeMethods()
21 | .Single(m => (m.Name == nameof(ToList)) && m.IsGenericMethod);
22 | private static readonly MethodInfo GenericToListAsyncMethod
23 | = typeof(QuerySender).GetRuntimeMethods()
24 | .Single(m => (m.Name == nameof(ToListAsync)) && m.IsGenericMethod);
25 |
26 | public QuerySender(IFlurlClient client, QueryContext queryContext)
27 | {
28 | _client = client;
29 | _queryContext = queryContext;
30 | }
31 |
32 | public TResult Send(string body, bool async, CancellationToken cancellationToken)
33 | {
34 | Type resultType = typeof(TResult);
35 | if (async)
36 | {
37 | resultType = resultType.GetGenericArguments()[0];
38 | }
39 |
40 | Type itemType = resultType.IsGenericType ? resultType.GetGenericArguments()[0] : typeof(object);
41 |
42 | MethodInfo toListMethodInfo = async ? GenericToListAsyncMethod : GenericToListMethod;
43 |
44 | return (TResult)toListMethodInfo
45 | .MakeGenericMethod(itemType)
46 | .Invoke(this, new object[] { body, cancellationToken });
47 | }
48 |
49 | private CouchList ToList(string body, CancellationToken cancellationToken)
50 | {
51 | FindResult result = SendAsync(body, cancellationToken).GetAwaiter().GetResult();
52 | return new CouchList(result.Docs.ToList(), result.Bookmark, result.ExecutionStats);
53 | }
54 |
55 | private async Task> ToListAsync(string body, CancellationToken cancellationToken)
56 | {
57 | FindResult result = await SendAsync(body, cancellationToken).ConfigureAwait(false);
58 | return new CouchList(result.Docs.ToList(), result.Bookmark, result.ExecutionStats);
59 | }
60 |
61 | private async Task> SendAsync(string body, CancellationToken cancellationToken)
62 | {
63 | var findResult = await _client
64 | .Request(_queryContext.Endpoint)
65 | .AppendPathSegments(_queryContext.DatabaseName, "_find")
66 | .WithHeader("Content-Type", "application/json")
67 | .PostStringAsync(body, cancellationToken)
68 | .ReceiveJson>()
69 | .SendRequestAsync();
70 |
71 | if (this._queryContext.ThrowOnQueryWarning && !String.IsNullOrEmpty(findResult.Warning))
72 | {
73 | throw new CouchDBQueryWarningException(findResult.Warning);
74 | }
75 |
76 | return findResult;
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/Find/Find_Optimized.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using CouchDB.UnitTests.Models;
5 | using Flurl.Http.Testing;
6 | using Xunit;
7 |
8 | namespace CouchDB.Driver.UnitTests.Find
9 | {
10 | public class Find_Optimized
11 | {
12 | private const string _databaseName = "allrebels";
13 | private readonly ICouchDatabase _rebels;
14 | private readonly object _response;
15 |
16 | public Find_Optimized()
17 | {
18 | var client = new CouchClient("http://localhost");
19 | _rebels = client.GetDatabase(_databaseName);
20 |
21 | var mainRebel = new Rebel
22 | {
23 | Id = Guid.NewGuid().ToString(),
24 | Name = "Luke",
25 | Age = 19,
26 | Skills = new List { "Force" }
27 | };
28 | var rebelsList = new List
29 | {
30 | mainRebel
31 | };
32 | _response = new
33 | {
34 | Docs = rebelsList
35 | };
36 | }
37 |
38 | [Fact]
39 | public void FirstOrDefault()
40 | {
41 | using var httpTest = new HttpTest();
42 | httpTest.RespondWithJson(_response);
43 | _rebels.FirstOrDefault();
44 | Assert.Equal(@"{""limit"":1,""selector"":{}}", httpTest.CallLog[0].RequestBody);
45 | }
46 |
47 | [Fact]
48 | public void LastOrDefault()
49 | {
50 | using var httpTest = new HttpTest();
51 | httpTest.RespondWithJson(_response);
52 | _rebels.LastOrDefault();
53 | Assert.Equal(@"{""selector"":{}}", httpTest.CallLog[0].RequestBody);
54 | }
55 |
56 | [Fact]
57 | public void FirstOrDefault_Predicate()
58 | {
59 | using var httpTest = new HttpTest();
60 | httpTest.RespondWithJson(_response);
61 | _rebels.FirstOrDefault(r => r.Age == 19);
62 | Assert.Equal(@"{""selector"":{""age"":19},""limit"":1}", httpTest.CallLog[0].RequestBody);
63 | }
64 |
65 | [Fact]
66 | public void LastOrDefault_Predicate()
67 | {
68 | using var httpTest = new HttpTest();
69 | httpTest.RespondWithJson(_response);
70 | _rebels.LastOrDefault(r => r.Age == 19);
71 | Assert.Equal(@"{""selector"":{""age"":19}}", httpTest.CallLog[0].RequestBody);
72 | }
73 |
74 | [Fact]
75 | public void FirstOrDefault_Predicate_Where()
76 | {
77 | using var httpTest = new HttpTest();
78 | httpTest.RespondWithJson(_response);
79 | _rebels.Where(c => c.Name == "Luke").FirstOrDefault(r => r.Age == 19);
80 | Assert.Equal(@"{""selector"":{""$and"":[{""name"":""Luke""},{""age"":19}]},""limit"":1}", httpTest.CallLog[0].RequestBody);
81 | }
82 |
83 | [Fact]
84 | public void LastOrDefault_Predicate_Where()
85 | {
86 | using var httpTest = new HttpTest();
87 | httpTest.RespondWithJson(_response);
88 | _rebels.Where(c => c.Name == "Luke").LastOrDefault(r => r.Age == 19);
89 | Assert.Equal(@"{""selector"":{""$and"":[{""name"":""Luke""},{""age"":19}]}}", httpTest.CallLog[0].RequestBody);
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/ChangesFeed/ChangesFeedFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq.Expressions;
4 | using CouchDB.Driver.ChangesFeed.Filters;
5 | using CouchDB.Driver.Types;
6 |
7 | namespace CouchDB.Driver.ChangesFeed
8 | {
9 | ///
10 | /// Represent a filter for the changes feed.
11 | ///
12 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1052:Static holder types should be Static or NotInheritable", Justification = "")]
13 | public class ChangesFeedFilter
14 | {
15 | ///
16 | /// Create a filter for document IDs.
17 | ///
18 | /// The document IDs to use as filters.
19 | ///
20 | public static ChangesFeedFilter DocumentIds(IList documentIds)
21 | => new DocumentIdsChangesFeedFilter(documentIds);
22 |
23 | ///
24 | /// Create a filter using the same syntax used to query.
25 | ///
26 | ///
27 | /// This is significantly more efficient than using a JavaScript filter function and is the recommended option if filtering on document attributes only.
28 | ///
29 | /// The type of database documents.
30 | /// The function used to filter.
31 | ///
32 | public static ChangesFeedFilter Selector(Expression> selector) where TSource : CouchDocument
33 | => new SelectorChangesFeedFilter(selector);
34 |
35 | ///
36 | /// Create a filter that accepts only changes for any design document within the requested database.
37 | ///
38 | ///
39 | public static ChangesFeedFilter Design()
40 | => new DesignChangesFeedFilter();
41 |
42 | ///
43 | /// Create a filter that uses an existing map function to the filter.
44 | ///
45 | ///
46 | /// If the map function emits anything for the processed document it counts as accepted and the changes event emits to the feed.
47 | ///
48 | /// The view.
49 | ///
50 | public static ChangesFeedFilter View(string view)
51 | => new ViewChangesFeedFilter(view);
52 |
53 | ///
54 | /// Create a filter using a design document filter function with optional query parameters.
55 | ///
56 | ///
57 | /// The filter function in the design document can access query parameters via req.query.
58 | /// This is useful for passing partition keys or other custom filtering parameters.
59 | ///
60 | /// The filter name in format "designdoc/filtername" (e.g., "replication/by_partition").
61 | /// Optional query parameters to pass to the filter function.
62 | ///
63 | public static ChangesFeedFilter DesignDocument(string filterName, Dictionary? queryParameters = null)
64 | => new DesignDocumentChangesFeedFilter(filterName, queryParameters);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/.github/workflows/build-and-release.yml:
--------------------------------------------------------------------------------
1 | name: Build and Release
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | paths-ignore:
8 | - 'README.md'
9 | - 'CHANGELOG.md'
10 | - 'LATEST_CHANGE.md'
11 | pull_request:
12 | paths-ignore:
13 | - 'README.md'
14 | - 'CHANGELOG.md'
15 | - 'LATEST_CHANGE.md'
16 |
17 | env:
18 | BuildConfiguration: Release
19 | PackageVersion: '3.7.0'
20 |
21 | jobs:
22 | build:
23 | name: Build Package
24 | runs-on: ubuntu-latest
25 |
26 | steps:
27 | - name: Checkout code
28 | uses: actions/checkout@v4
29 |
30 | - name: Setup .NET
31 | uses: actions/setup-dotnet@v4
32 | with:
33 | dotnet-version: 10
34 |
35 | - name: Restore NuGet packages
36 | run: dotnet restore **/*.sln
37 |
38 | - name: Build solution
39 | run: dotnet build **/*.sln --configuration ${{ env.BuildConfiguration }} --no-restore
40 |
41 | - name: Run unit tests
42 | run: dotnet test **/**/*UnitTests*.csproj --configuration ${{ env.BuildConfiguration }} --no-build
43 |
44 | - name: Create NuGet packages
45 | if: github.event_name != 'pull_request'
46 | run: |
47 | for project in src/**/*.csproj; do
48 | dotnet pack "$project" \
49 | --configuration ${{ env.BuildConfiguration }} \
50 | --no-build \
51 | --output ./artifacts \
52 | -p:PackageVersion=${{ env.PackageVersion }} \
53 | --include-symbols
54 | done
55 | shell: bash
56 |
57 | - name: Copy release notes
58 | if: github.event_name != 'pull_request'
59 | run: |
60 | if [ -f "LATEST_CHANGE.md" ]; then
61 | cp LATEST_CHANGE.md ./artifacts/
62 | fi
63 | shell: bash
64 |
65 | - name: Upload artifacts
66 | if: github.event_name != 'pull_request'
67 | uses: actions/upload-artifact@v4
68 | with:
69 | name: packages
70 | path: ./artifacts/
71 |
72 | release:
73 | name: Release Package
74 | needs: build
75 | if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master'
76 | runs-on: ubuntu-latest
77 | environment: NuGet
78 |
79 | steps:
80 | - name: Download artifacts
81 | uses: actions/download-artifact@v4
82 | with:
83 | name: packages
84 | path: ./artifacts
85 |
86 | - name: Push to NuGet
87 | run: |
88 | for package in ./artifacts/*.nupkg; do
89 | if [[ ! "$package" =~ \.symbols\.nupkg$ ]]; then
90 | dotnet nuget push "$package" \
91 | --api-key ${{ secrets.NUGET_API_KEY }} \
92 | --source https://api.nuget.org/v3/index.json \
93 | --skip-duplicate
94 | fi
95 | done
96 | shell: bash
97 |
98 | - name: Create GitHub Release
99 | uses: softprops/action-gh-release@v1
100 | with:
101 | tag_name: v${{ env.PackageVersion }}
102 | name: v${{ env.PackageVersion }}
103 | body_path: ./artifacts/LATEST_CHANGE.md
104 | files: ./artifacts/*.nupkg
105 | generate_release_notes: true
106 | env:
107 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
108 |
109 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/Index_Tests.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http;
2 | using System.Threading.Tasks;
3 | using CouchDB.Driver.Indexes;
4 | using CouchDB.UnitTests.Models;
5 | using Flurl.Http.Testing;
6 | using Xunit;
7 |
8 | namespace CouchDB.Driver.UnitTests
9 | {
10 | public class Index_Tests
11 | {
12 | private readonly ICouchClient _client;
13 | private readonly ICouchDatabase _rebels;
14 |
15 | public Index_Tests()
16 | {
17 | _client = new CouchClient("http://localhost");
18 | _rebels = _client.GetDatabase();
19 | }
20 |
21 | [Fact]
22 | public async Task CreateIndex()
23 | {
24 | using var httpTest = new HttpTest();
25 | httpTest.RespondWithJson(new
26 | {
27 | result = "created"
28 | });
29 |
30 | await _rebels.CreateIndexAsync("skywalkers", b => b
31 | .IndexBy(r => r.Surname));
32 |
33 |
34 | var expectedBody =
35 | "{\"index\":{\"fields\":[\"surname\"]},\"name\":\"skywalkers\",\"type\":\"json\"}";
36 | httpTest
37 | .ShouldHaveCalled("http://localhost/rebels/_index")
38 | .WithRequestBody(expectedBody)
39 | .WithVerb(HttpMethod.Post);
40 | }
41 |
42 | [Fact]
43 | public async Task CreateIndex_WithOptions()
44 | {
45 | using var httpTest = new HttpTest();
46 | httpTest.RespondWithJson(new
47 | {
48 | result = "created"
49 | });
50 |
51 | await _rebels.CreateIndexAsync("skywalkers", b => b
52 | .IndexByDescending(r => r.Surname)
53 | .ThenByDescending(r => r.Name),
54 | new IndexOptions()
55 | {
56 | DesignDocument = "skywalkers_ddoc",
57 | Partitioned = true
58 | });
59 |
60 |
61 | var expectedBody =
62 | "{\"index\":{\"fields\":[{\"surname\":\"desc\"},{\"name\":\"desc\"}]},\"name\":\"skywalkers\",\"type\":\"json\",\"ddoc\":\"skywalkers_ddoc\",\"partitioned\":true}";
63 | httpTest
64 | .ShouldHaveCalled("http://localhost/rebels/_index")
65 | .WithRequestBody(expectedBody)
66 | .WithVerb(HttpMethod.Post);
67 | }
68 |
69 | [Fact]
70 | public async Task CreateIndex_Partial()
71 | {
72 | using var httpTest = new HttpTest();
73 | httpTest.RespondWithJson(new
74 | {
75 | result = "created"
76 | });
77 |
78 | await _rebels.CreateIndexAsync("skywalkers", b => b
79 | .IndexBy(r => r.Surname)
80 | .Where(r => r.Surname == "Skywalker"),
81 | new IndexOptions()
82 | {
83 | DesignDocument = "skywalkers_ddoc",
84 | Partitioned = true
85 | });
86 |
87 |
88 | var expectedBody =
89 | "{\"index\":{\"partial_filter_selector\":{\"surname\":\"Skywalker\"},\"fields\":[\"surname\"]},\"name\":\"skywalkers\",\"type\":\"json\",\"ddoc\":\"skywalkers_ddoc\",\"partitioned\":true}";
90 | httpTest
91 | .ShouldHaveCalled("http://localhost/rebels/_index")
92 | .WithRequestBody(expectedBody)
93 | .WithVerb(HttpMethod.Post);
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/CouchDB.Driver/Types/CouchAttachmentsCollection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using CouchDB.Driver.Helpers;
7 |
8 | namespace CouchDB.Driver.Types
9 | {
10 | public sealed class CouchAttachmentsCollection : IEnumerable
11 | {
12 | private readonly Dictionary _attachments;
13 |
14 | internal CouchAttachmentsCollection()
15 | {
16 | _attachments = new Dictionary();
17 | }
18 |
19 | internal CouchAttachmentsCollection(Dictionary attachments)
20 | {
21 | _attachments = attachments;
22 | foreach (KeyValuePair item in _attachments)
23 | {
24 | item.Value.Name = item.Key;
25 | }
26 | }
27 |
28 | public void AddOrUpdate(string path, string contentType)
29 | {
30 | FileInfo info = GetFileInfo(path);
31 | AddOrUpdate(info.Name, path, contentType);
32 | }
33 |
34 | public void AddOrUpdate(string attachmentName, string path, string contentType)
35 | {
36 | FileInfo info = GetFileInfo(path);
37 |
38 | if (!_attachments.ContainsKey(attachmentName))
39 | {
40 | _attachments.Add(attachmentName, new CouchAttachment());
41 | }
42 |
43 | CouchAttachment attachment = _attachments[attachmentName];
44 | attachment.Name = attachmentName;
45 | attachment.FileInfo = info;
46 | attachment.ContentType = contentType;
47 | }
48 |
49 | public void Delete(string attachmentName)
50 | {
51 | CouchAttachment attachment = _attachments[attachmentName];
52 | attachment.Deleted = true;
53 | }
54 |
55 | public CouchAttachment this[string key]
56 | {
57 | get => _attachments[key];
58 | }
59 |
60 | public IEnumerator GetEnumerator()
61 | {
62 | return _attachments
63 | .Select(kv => kv.Value)
64 | .Where(at => !at.Deleted)
65 | .GetEnumerator();
66 | }
67 |
68 | IEnumerator IEnumerable.GetEnumerator()
69 | {
70 | return GetEnumerator();
71 | }
72 |
73 | internal CouchAttachment[] GetAddedAttachments()
74 | {
75 | return _attachments
76 | .Where(kv => kv.Value.FileInfo != null)
77 | .Select(kv => kv.Value)
78 | .ToArray();
79 | }
80 |
81 | internal CouchAttachment[] GetDeletedAttachments()
82 | {
83 | return _attachments
84 | .Where(kv => kv.Value.Deleted)
85 | .Select(kv => kv.Value)
86 | .ToArray();
87 | }
88 |
89 | internal void RemoveAttachment(CouchAttachment attachment)
90 | {
91 | _ = _attachments.Remove(attachment.Name);
92 | }
93 |
94 | private static FileInfo GetFileInfo(string path)
95 | {
96 | Check.NotNull(path, nameof(path));
97 |
98 | if (!File.Exists(path))
99 | {
100 | throw new InvalidOperationException($"File does not exists: {path}");
101 | }
102 |
103 | return new FileInfo(path);
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/tests/CouchDB.Driver.UnitTests/ChangesFeed_DesignDocumentFilter_Tests.cs:
--------------------------------------------------------------------------------
1 | using CouchDB.Driver.ChangesFeed;
2 | using CouchDB.UnitTests.Models;
3 | using Flurl.Http.Testing;
4 | using System.Collections.Generic;
5 | using System.Net.Http;
6 | using System.Threading.Tasks;
7 | using Xunit;
8 |
9 | namespace CouchDB.Driver.UnitTests
10 | {
11 | public class ChangesFeed_DesignDocumentFilter_Tests
12 | {
13 | private readonly ICouchClient _client;
14 | private readonly ICouchDatabase