All Projects β†’ matteobortolazzo β†’ Couchdb Net

matteobortolazzo / Couchdb Net

Licence: mit
EF Core-like CouchDB experience for .NET!

Projects that are alternatives of or similar to Couchdb Net

Dbreeze
C# .NET MONO NOSQL ( key value store embedded ) ACID multi-paradigm database management system.
Stars: ✭ 383 (+666%)
Mutual labels:  database, nosql, netstandard, xamarin, netcore
Rxdb
πŸ”„ A client side, offline-first, reactive database for JavaScript Applications
Stars: ✭ 16,670 (+33240%)
Mutual labels:  database, nosql, couchdb, pouchdb
Cosmos.Identity
A Cosmos storage provider for ASP.NET Core Identity.
Stars: ✭ 26 (-48%)
Mutual labels:  nosql, aspnetcore, netcore, netstandard
Kivik
Kivik provides a common interface to CouchDB or CouchDB-like databases for Go and GopherJS.
Stars: ✭ 200 (+300%)
Mutual labels:  database, nosql, couchdb, pouchdb
Pouchdb
🐨 - PouchDB is a pocket-sized database.
Stars: ✭ 14,625 (+29150%)
Mutual labels:  database, couchdb, pouchdb
Arangodb Php
PHP ODM for ArangoDB
Stars: ✭ 178 (+256%)
Mutual labels:  database, nosql, driver
Mongo Cxx Driver
C++ Driver for MongoDB
Stars: ✭ 792 (+1484%)
Mutual labels:  database, nosql, driver
grandnode2
Free, Open source, Fast, Headless, Multi-tenant eCommerce platform built with .NET Core, MongoDB, AWS DocumentDB, Azure CosmosDB, LiteDB, Vue.js.
Stars: ✭ 626 (+1152%)
Mutual labels:  nosql, aspnetcore, netcore
Portable-WebDAV-Library
Moved to codeberg.org - https://codeberg.org/DecaTec/Portable-WebDAV-Library - The Portable WebDAV Library is a strongly typed, async WebDAV client library which is fully compliant to RFC 4918, RFC 4331 and "Additional WebDAV Collection Properties". It is implemented as .NETStandard 1.1 library in oder to be used on any platform supporting .NETS…
Stars: ✭ 45 (-10%)
Mutual labels:  xamarin, netcore, netstandard
Csla
A home for your business logic in any .NET application.
Stars: ✭ 865 (+1630%)
Mutual labels:  aspnetcore, netstandard, xamarin
Csharp Driver
DataStax C# Driver for Apache Cassandra
Stars: ✭ 477 (+854%)
Mutual labels:  database, nosql, driver
Gocql
Package gocql implements a fast and robust Cassandra client for the Go programming language.
Stars: ✭ 2,182 (+4264%)
Mutual labels:  database, nosql, driver
Arangodb Java Driver
The official ArangoDB Java driver.
Stars: ✭ 174 (+248%)
Mutual labels:  database, nosql, driver
Vue Pouch Db
Vue Pouch DB is a VueJS Plugin that binds PouchDB with Vue and keeps a synchronised state with the database. Has support for Mango queries which are processed locally within the VuePouchDB state.
Stars: ✭ 127 (+154%)
Mutual labels:  database, couchdb, pouchdb
Dryioc
DryIoc is fast, small, full-featured IoC Container for .NET
Stars: ✭ 555 (+1010%)
Mutual labels:  netstandard, xamarin, netcore
Nodbi
Document DBI connector for R
Stars: ✭ 56 (+12%)
Mutual labels:  database, nosql, couchdb
Avancedb
An in-memory database based on the CouchDB REST API and containing the CouchDB Futon and Fauxton web sites
Stars: ✭ 161 (+222%)
Mutual labels:  nosql, couchdb, pouchdb
Nodejs Driver
DataStax Node.js Driver for Apache Cassandra
Stars: ✭ 1,074 (+2048%)
Mutual labels:  database, nosql, driver
framework
Solu Framework is a full featured, ORM-backed, isomorphic framework using RPython, Pouch/CouchDB and React.
Stars: ✭ 20 (-60%)
Mutual labels:  couchdb, nosql, pouchdb
Arangojs
The official ArangoDB JavaScript driver.
Stars: ✭ 503 (+906%)
Mutual labels:  database, nosql, driver

Downloads

CouchDB.NET

EF Core-like CouchDB experience for .NET!

LINQ queries

C# query example:

// Setup
public class MyDeathStarContext : CouchContext
{
    public CouchDatabase<Rebel> Rebels { get; set; }
    public CouchDatabase<Clone> Clones { get; set; }

    protected override void OnConfiguring(CouchOptionsBuilder optionsBuilder)
    {
      optionsBuilder
        .UseEndpoint("http://localhost:5984/")
        .EnsureDatabaseExists()
        .UseBasicAuthentication(username: "anakin", password: "empirerule");
    }
}

// Usage
await using var context = new MyDeathStarContext();
var skywalkers = await context.Rebels
    .Where(r => 
        r.Surname == "Skywalker" && 
        (
            r.Battles.All(b => b.Planet == "Naboo") ||
            r.Battles.Any(b => b.Planet == "Death Star")
        )
    )
    .OrderByDescending(r => r.Name)
    .ThenByDescending(r => r.Age)
    .Take(2)
    .Select(
        r => r.Name,
        r => r.Age
    })
    .ToListAsync();

The produced Mango JSON:

{
  "selector": {
    "$and": [
      {
        "surname": "Skywalker"
      },
      {
        "$or": [
          {
            "battles": {
              "$allMatch": {
                "planet": "Naboo"
              }
            }
          },
          {
            "battles": {
              "$elemMatch": {
                "planet": "Death Star"
              }
            }
          }
        ]
      }
    ]
  },
  "sort": [
    { "name": "desc" },
    { "age": "desc" }
  ],
  "limit": 2,
  "fields": [
    "name",
    "age"
  ]
}

Index

Getting started

  • Install it from NuGet: https://www.nuget.org/packages/CouchDB.NET
  • Create a context or a client, where localhost will be the IP address and 5984 is CouchDB standard tcp port:
    await using var context = new MyDeathStarContext(builder => {});
    // or
    await using(var client = new CouchClient("http://localhost:5984", builder => {})) { }
    
  • Create a document class:
    public class Rebel : CouchDocument
    
  • Get a database reference:
    var rebels = context.Rebels;
    // or
    var rebels = client.GetDatabase<Rebel>();
    
  • Query the database
    var skywalkers = await rebels.Where(r => r.Surname == "Skywalker").ToListAsync();
    

Queries

The database class exposes all the implemented LINQ methods like Where and OrderBy, those methods returns an IQueryable.

LINQ are supported natively to the following is possible:

var skywalkers =
    from r in context.Rebels
    where r.Surname == "Skywalker"
    select r;

Selector

The selector is created when the method Where (IQueryable) is called. If the Where method is not called in the expression, it will at an empty selector.

Combinations

Mango C#
$and &&
$or ||
$not !
$nor !( || )
$all a.Contains(x)
$all a.Contains(list)
$elemMatch a.Any(condition)
$allMatch a.All(condition)

Conditions

Mango C#
$lt <
$lte <=
$eq (implicit) ==
$ne !=
$gte >=
$gt >
$exists o.FieldExists(s)
$type o.IsCouchType(...)
$in o.In(list)
$nin !o.In(list)
$size a.Count == x
$mod n % x = y
$regex s.IsMatch(rx)

Native methods

Mango C#
limit Take(n)
skip Skip(n)
sort OrderBy(..)
sort OrderBy(..).ThenBy()
sort OrderByDescending(..)
sort OrderByDescending(..).ThenByDescending()
fields Select(x => x.Prop1, x => x.Prop2)
fields Convert<SourceType, SimplerType>()
use_index UseIndex("design_document")
use_index UseIndex(new [] { "design_document", "index_name" })
r WithReadQuorum(n)
bookmark UseBookmark(s)
update WithoutIndexUpdate()
stable FromStable()
execution_stats IncludeExecutionStats()
conflicts IncludeConflicts()

Composite methods

Some methods that are not directly supported by CouchDB are converted to a composition of supported ones!

Input Output
Min(d => d.Property) OrderBy(d => d.Property).Take(1).Select(d => d.Property).Min()
Max(d => d.Property) OrderByDescending(d => d.Property).Take(1).Select(d => d.Property).Max()
Sum(d => d.Property) Select(d => d.Property).Sum()
Average(d => d.Property) Select(d => d.Property).Average()
Any() Take(1).Any()
Any(d => condition) Where(d => condition).Take(1).Any()
All(d => condition) Where(d => !condition).Take(1).Any()
Single() Take(2).Single()
SingleOrDefault() Take(2).SingleOrDefault()
Single(d => condition) Where(d => condition).Take(2).Single()
SingleOrDefault(d => condition) Where(d => condition).Take(2).SingleOrDefault()
First() Take(1).First()
FirstOrDefault() Take(1).FirstOrDefault()
First(d => condition) Where(d => condition).Take(1).First()
FirstOrDefault(d => condition) Where(d => condition).Take(1).FirstOrDefault()
Last() Where(d => Last()
LastOrDefault() LastOrDefault()
Last(d => condition) Where(d => condition).Last()
LastOrDefault(d => condition) Where(d => condition).LastOrDefault()

INFO: Also Select(d => d.Property), Min and Max are supported.

WARN: Since Max and Min use sort, an index must be created.

All other IQueryables methods

Since v2.0 IQueryable methods that are not natively supported will throw an exception.

Client operations

// CRUD from class name (rebels)
var rebels = client.GetDatabase<Rebel>();
var rebels = await client.GetOrCreateDatabaseAsync<Rebel>();
var rebels = await client.CreateDatabaseAsync<Rebel>();
await client.DeleteDatabaseAsync<Rebel>();
// CRUD specific name
var rebels = client.GetDatabase<Rebel>("naboo_rebels");
var rebels = client.GetOrCreateDatabaseAsync<Rebel>("naboo_rebels");
var rebels = await client.CreateDatabaseAsync<Rebel>("naboo_rebels");
await client.DeleteDatabaseAsync("naboo_rebels");
// Utils
var isRunning = await client.IsUpAsync();
var databases = await client.GetDatabasesNamesAsync();
var tasks = await client.GetActiveTasksAsync();

Database operations

// CRUD
await rebels.AddAsync(rebel);
await rebels.AddOrUpdateAsync(rebel);
await rebels.RemoveAsync(rebel);
var rebel = await rebels.FindAsync(id);
var rebel = await rebels.FindAsync(id, withConflicts: true);
var list = await rebels.FindManyAsync(ids);
var list = await rebels.QueryAsync(someMangoJson);
var list = await rebels.QueryAsync(someMangoObject);
// Bulk
await rebels.AddOrUpdateRangeAsync(moreRebels);
// Utils
await rebels.CompactAsync();
var info = await rebels.GetInfoAsync();
// Security
await rebels.Security.SetInfoAsync(securityInfo);
var securityInfo = await rebels.Security.GetInfoAsync();

Authentication

// Basic
.UseBasicAuthentication("root", "relax")

// Cookie
.UseCookieAuthentication("root", "relax")
.UseCookieAuthentication("root", "relax", cookieDuration)

// Proxy
.UseProxyAuthentication("root", new[] { "role1", "role2" })

// JTW
.UseJwtAuthentication("token")
.UseJwtAuthentication(async () => await NewTokenAsync())

Options

The second parameter of the client constructor is a function to configure CouchSettings fluently.

public class MyDeathStarContext : CouchContext
{
  /* ... */

    protected override void OnConfiguring(CouchOptionsBuilder optionsBuilder)
    {
      optionsBuilder
        .UseBasicAuthentication("root", "relax")
        .DisableEntitisPluralization()
        ...
    }
}

// or

var client = new CouchClient("http://localhost:5984", builder => builder
    .UseBasicAuthentication("root", "relax")
    .DisableEntitisPluralization()
    ...
)
Method Description
UseBasicAuthentication Enables basic authentication.
UseCookieAuthentication Enables cookie authentication.
IgnoreCertificateValidation Removes any SSL certificate validation.
ConfigureCertificateValidation Sets a custom SSL validation rule.
DisableDocumentPluralization Disables documents pluralization in requests.
SetDocumentCase Sets the format case for documents.
SetPropertyCase Sets the format case for properties.
SetNullValueHandling Sets how to handle null values.
DisableLogOutOnDispose Disables log out on client dispose.
  • DocumentCaseTypes: None, UnderscoreCase (default), DashCase, KebabCase.
  • PropertyCaseTypes: None, CamelCase (default), PascalCase, UnderscoreCase, DashCase, KebabCase.

Custom JSON values

If you need custom values for documents and properties, it's possible to use JsonObject and JsonProperty attributes.

[JsonObject("custom-rebels")]
public class OtherRebel : Rebel

[JsonProperty("rebel_bith_date")]
public DateTime BirthDate { get; set; }

Attachments

The driver fully support attachments, you can list, create, delete and download them.

// Get a document
var luke = new Rebel { Name = "Luke", Age = 19 };

// Add in memory
var pathToDocument = @".\luke.txt"
luke.Attachments.AddOrUpdate(pathToDocument, MediaTypeNames.Text.Plain);

// Delete in memory
luke.Attachments.Delete("yoda.txt");

// Save
luke = await rebels.CreateOrUpdateAsync(luke);

// Get
CouchAttachment lukeTxt = luke.Attachments["luke.txt"];

// Iterate
foreach (CouchAttachment attachment in luke.Attachments)
{ 
  ...
}

// Download
string downloadFilePath = await rebels.DownloadAttachment(attachment, downloadFolderPath, "luke-downloaded.txt");

DB Changes Feed

The following feed modes are supported: normal, longpool and continuous. Also all options and filter types are supported.

Continuous mode is probably the most useful and it's implemented with the new IAsyncEnumerable.

var tokenSource = new CancellationTokenSource();
await foreach (var change in _rebels.GetContinuousChangesAsync(options: null, filter: null, tokenSource.Token))
{
    if (/* ... */) {
      tokenSource.Cancel();
    }
}

Feed Options

// Example
var options = new ChangesFeedOptions
{
  Descending = true,
  Limit = 10,
  Since = "now",
  IncludeDocs = true
};
ChangesFeedResponse<Rebel> changes = await GetChangesAsync(options);

Feed Filter

// _doc_ids
var filter = ChangesFeedFilter.DocumentIds(new[] { "luke", "leia" });
// _selector
var filter = ChangesFeedFilter.Selector<Rebel>(rebel => rebel.Age == 19);
// _design
var filter = ChangesFeedFilter.Design();
// _view
var filter = ChangesFeedFilter.View(view);

// Use
ChangesFeedResponse<Rebel> changes = await GetChangesAsync(options: null, filter);

Indexing

It is possible to create indexes to use when querying.

// Basic index creation
await _rebels.CreateIndexAsync("rebels_index", b => b
    .IndexBy(r => r.Surname))
    .ThenBy(r => r.Name));

// Descending index creation
await _rebels.CreateIndexAsync("rebels_index", b => b
    .IndexByDescending(r => r.Surname))
    .ThenByDescending(r => r.Name));

Index Options

// Specifies the design document and/or whether a JSON index is partitioned or global
await _rebels.CreateIndexAsync("rebels_index", b => b
    .IndexBy(r => r.Surname),
    new IndexOptions()
    {
        DesignDocument = "surnames_ddoc",
        Partitioned = true
    });

Partial Indexes

// Create an index which excludes documents at index time
await _rebels.CreateIndexAsync("skywalkers_index", b => b
    .IndexBy(r => r.Name)
    .Where(r => r.Surname == "Skywalker");

Indexes operations

// Get the list of indexes
var indexes = await _rebels.GetIndexesAsync();

// Delete an indexes
await _rebels.DeleteIndexAsync(indexes[0]);
// or
await _rebels.DeleteIndexAsync("surnames_ddoc", name: "surnames");

CouchContext Index Configuration

Finally it's possible to configure indexes on the CouchContext.

public class MyDeathStarContext : CouchContext
{
    public CouchDatabase<Rebel> Rebels { get; set; }

    // OnConfiguring(CouchOptionsBuilder optionsBuilder) { ... }

    protected override void OnDatabaseCreating(CouchDatabaseBuilder databaseBuilder)
    {
        databaseBuilder.Document<Rebel>()
            .HasIndex("rebel_surnames_index", b => b.IndexBy(b => b.Surname));
    }
}

Database Splitting

It is possible to use the same database for multiple types:

public class MyDeathStarContext : CouchContext
{
    public CouchDatabase<Rebel> Rebels { get; set; }
    public CouchDatabase<Vehicle> Vehicles { get; set; }

    // OnConfiguring(CouchOptionsBuilder optionsBuilder) { ... }

    protected override void OnDatabaseCreating(CouchDatabaseBuilder databaseBuilder)
    {
        databaseBuilder.Document<Rebel>().ToDatabase("troups");
        databaseBuilder.Document<Vehicle>().ToDatabase("troups");
    }
}

When multiple CouchDatabase point to the same database, a _discriminator field is added on documents creation.

When querying, a filter by discriminator is added automatically.

If you are not using CouchContext, you can still use the database slit feature:

var rebels = client.GetDatabase<Rebel>("troups", nameof(Rebel));
var vehicles = client.GetDatabase<Vehicle>("troups", nameof(Vehicle));

Views

It's possible to query a view with the following:

var options = new CouchViewOptions<string[]>
{
    StartKey = new[] {"Luke", "Skywalker"},
    IncludeDocs = true
};
var viewRows = await _rebels.GetViewAsync<string[], RebelView>("jedi", "by_name", options);
// OR
var details = await _rebels.GetDetailedViewAsync<int, BattleView>("battle", "by_name", options);

Local (non-replicating) Documents

The Local (non-replicating) document interface allows you to create local documents that are not replicated to other databases.

var docId = "settings";
var settings = new RebelSettings
{
    Id = docId,
    IsActive = true
};

// Create
await _rebels.LocalDocuments.CreateOrUpdateAsync(settings);

// Get by ID
settings = await _rebels.LocalDocuments.GetAsync<RebelSettings>(docId);

// Get all
var docs = await local.GetAsync();

// Search
var searchOpt = new LocalDocumentsOptions
{
    Descending = true,
    Limit = 10,
    Conflicts = true
};
var docs = await local.GetAsync(searchOpt);

Bookmark and Execution stats

If bookmark and execution stats must be retrived, call ToCouchList or ToCouchListAsync.

var allRebels = await rebels.ToCouchListAsync();

foreach(var r in allRebels) 
{
    ...
}
var b = allRebels.Bookmark;
var ex = allRebels.ExecutionStats; // .IncludeExecutionStats() must be called

Users

The driver natively support the _users database.

var users = client.GetUsersDatabase();
var luke = await users.CreateAsync(new CouchUser(name: "luke", password: "lasersword"));

It's possible to extend CouchUser for store custom info.

var users = client.GetUsersDatabase<CustomUser>();
var luke = await users.CreateAsync(new CustomUser(name: "luke", password: "lasersword"));

To change password:

luke = await users.ChangeUserPassword(luke, "r2d2");

Dependency Injection

public class MyDeathStarContext : CouchContext
{
    public CouchDatabase<Rebel> Rebels { get; set; }

    public MyDeathStarContext(CouchOptions<MyDeathStarContext> options)
        : base(options) { }
}
  • In the Startup class register the context:
// ConfigureServices
services.AddCouchContext<MyDeathStarContext>(builder => builder
    .UseEndpoint("http://localhost:5984")
    .UseBasicAuthentication(username: "admin", password: "admin"));
  • Inject the context:
// RebelsController
public class RebelsController : Controller
{
    private readonly MyDeathStarContext _context;

    public RebelsController(MyDeathStarContext context)
    {
        _context = context;
    }
}

Info: The context is registered as a singleton.

Advanced

If requests have to be modified before each call, it's possible to override OnBeforeCallAsync.

protected virtual Task OnBeforeCallAsync(HttpCall call)

Also, the configurator has ConfigureFlurlClient to set custom HTTP client options.

Contributors

Thanks to Ben Origas for features, ideas and tests like SSL custom validation, multi queryable, async deadlock, cookie authenication and many others.

Thanks to n9 for proxy authentication, some bug fixes, suggestions and the great feedback on the changes feed feature!

Thanks to Marc for NullValueHandling, bug fixes and suggestions!

Thanks to Panos for the help with Views and Table splitting.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].