All Projects → coronabytes → dotnet-arangodb

coronabytes / dotnet-arangodb

Licence: Apache-2.0 license
.NET Driver for ArangoDB

Programming Languages

C#
18002 projects
shell
77523 projects

Projects that are alternatives of or similar to dotnet-arangodb

Couchdb Net
EF Core-like CouchDB experience for .NET!
Stars: ✭ 50 (-3.85%)
Mutual labels:  driver, netcore
fuerte
Low Level C++ Driver for ArangoDB
Stars: ✭ 41 (-21.15%)
Mutual labels:  driver, arangodb
Adonetcore.aseclient
AdoNetCore.AseClient - a .NET Core DB Provider for SAP ASE
Stars: ✭ 72 (+38.46%)
Mutual labels:  driver, netcore
BioBalanceDetector
Bio Balance Detector's products aim to show the weak electromagnetic fields around every living being (including plants, animals and humans) and display it in a heat-map like hyper-spectral image.
Stars: ✭ 18 (-65.38%)
Mutual labels:  driver, netcore
arangors
Easy to use rust driver for arangoDB
Stars: ✭ 120 (+130.77%)
Mutual labels:  arangodb, arangodb-client
Arangojs
The official ArangoDB JavaScript driver.
Stars: ✭ 503 (+867.31%)
Mutual labels:  driver, arangodb
Arangodb Java Driver
The official ArangoDB Java driver.
Stars: ✭ 174 (+234.62%)
Mutual labels:  driver, arangodb
arangodb-java-driver-async
ArangoDB Asynchronous Java driver
Stars: ✭ 45 (-13.46%)
Mutual labels:  driver, arangodb
Arangoclient.net
ArangoDB .NET Client with LINQ support
Stars: ✭ 94 (+80.77%)
Mutual labels:  linq, arangodb
ormdb
ORM tool for .Net / .Net.Core
Stars: ✭ 14 (-73.08%)
Mutual labels:  linq, netcore
Arango
Golang driver for ArangoDB
Stars: ✭ 125 (+140.38%)
Mutual labels:  driver, arangodb
EFSqlTranslator
A standalone linq to sql translator that can be used with EF and Dapper.
Stars: ✭ 51 (-1.92%)
Mutual labels:  linq, netcore
Arangodb Php
PHP ODM for ArangoDB
Stars: ✭ 178 (+242.31%)
Mutual labels:  driver, arangodb
Kendo.DynamicLinqCore
KendoNET.DynamicLinq implements server paging, filtering, sorting, grouping, and aggregating to Kendo UI via Dynamic Linq for .Net Core App(1.x ~ 3.x).
Stars: ✭ 36 (-30.77%)
Mutual labels:  linq, netcore
python-arango
Python Driver for ArangoDB
Stars: ✭ 407 (+682.69%)
Mutual labels:  arangodb, arangodb-client
loopback-connector-arangodb
LoopBack connector for ArangoDB
Stars: ✭ 20 (-61.54%)
Mutual labels:  arangodb
Tomlet
Zero-Dependency, model-based TOML De/Serializer for .NET
Stars: ✭ 56 (+7.69%)
Mutual labels:  netcore
ErpNet.FP
ErpNet.FP is a light-weight cross-platform Http server facilitating printing to fiscal printers through simple JSON Api.
Stars: ✭ 75 (+44.23%)
Mutual labels:  driver
pyderman
Install Selenium-compatible Chrome/Firefox/Opera/PhantomJS/Edge webdrivers automatically.
Stars: ✭ 24 (-53.85%)
Mutual labels:  driver
hid-tmff2
Linux kernel module for Thrustmaster T300RS and T248
Stars: ✭ 83 (+59.62%)
Mutual labels:  driver

Build Nuget Nuget

dotnet add package Core.Arango

.NET driver for ArangoDB

  • .NET Standard 2.0, 2.1, .NET 5.0 and .NET 6.0 driver for ArangoDB 3.8+
  • LINQ support (WIP)
  • Newtonsoft and System.Text.Json serialization support with PascalCase and camelCase options
  • Updates from anonymous types supported as (Id, Key, Revision, From, To) properties are translated to (_id, _key, _rev, _from, _to)
    • This means these property names are reserved and cannot be used for something else (e.g. "To" property in email collection)

Extensions

This driver has various extensions available.

Extension Nuget Command
Core.Arango.Migration Nuget Nuget dotnet add package Core.Arango.Migration
Core.Arango.DataProtection Nuget Nuget dotnet add package Core.Arango.DataProtection
Core.Arango.DevExtreme Nuget Nuget dotnet add package Core.Arango.DevExtreme
Core.Arango.Serilog Nuget Nuget dotnet add package Core.Arango.Serilog

Common Snippets

Initialize context

  • Realm optionally prefixes all further database handles (e.g. "myproject-database")
  • Context is completely thread-safe and can be shared for your whole application
// from connection string
var arango = new ArangoContext("Server=http://localhost:8529;Realm=myproject;User=root;Password=;");

// from connection string - NO_AUTH
var arango = new ArangoContext("Server=http://localhost:8529;");

// from connection string with camelCase serialization
var arango = new ArangoContext("Server=http://localhost:8529;Realm=myproject;User=root;Password=;",
new ArangoConfiguration
{
    Serializer = new ArangoNewtonsoftSerializer(new ArangoNewtonsoftCamelCaseContractResolver())
});
  • For AspNetCore DI extension is available:
public void ConfigureServices(IServiceCollection services)
{
    // add with connection string
    services.AddArango(Configuration.GetConnectionString("Arango"));
    
    // or add with configuration set to System.Json.Text serialization
    services.AddArango((sp, config) =>
    {
        config.ConnectionString = Configuration.GetConnectionString("Arango");
        config.Serializer = new ArangoJsonSerializer(new ArangoJsonDefaultPolicy());
        
        var logger = sp.GetRequiredService<ILogger<Startup>>();
 
        config.QueryProfile = (query, bindVars, stats) =>
        {
            var boundQuery = query;

            // replace parameters with bound values
            foreach (var p in bindVars.OrderByDescending(x => x.Key.Length))
                boundQuery = boundQuery.Replace("@" + p.Key, JsonConvert.SerializeObject(p.Value));

            logger.LogInformation(boundQuery);
        }
    });
}
[ApiController]
[Route("api/demo")]
public class DemoController : Controller 
{
    private readonly IArangoContext _arango;

    public DemoController(IArangoContext arango)
    {
        _arango = arango;
    }
}

Create database

await arango.Database.CreateAsync("database");

Create collection

await arango.Collection.CreateAsync("database", "collection", ArangoCollectionType.Document);
  • collection with keys in ascending lexicographical sort order (ideal for log/audit collections)
await arango.Collection.CreateAsync("database", new ArangoCollection
{
    Name = "paddedcollection",
    Type = ArangoCollectionType.Document,
    KeyOptions = new ArangoKeyOptions
    {
        Type = ArangoKeyType.Padded,
        AllowUserKeys = false
    }
});

Create document

await arango.Document.CreateAsync("database", "collection", new
{
    Key = Guid.NewGuid(),
    SomeValue = 1
});

Update document

await arango.Document.UpdateAsync("database", "collection", new
{
    Key = Guid.Parse("some-guid"),
    SomeValue = 2
});

Update ignore some properties

// depending on serializer
using System.Text.Json.Serialization;
// or
using Newtonsoft.Json;

class ComplexEntity
{
    public string Key { get; set; }
    public string Name { get; set; }
    
    // Will never be read or written from or to arangodb
    [JsonIgnore]
    public object Data { get; set; }
    
    // Newtonsoft only
    // Will only be read from query, on write will be ignored
    [ArangoIgnore]
    public object CalculatedProperty { get; set; }
}

await arango.Document.UpdateAsync("database", "collection", new ComplexEntity {
    Key = "123",
    Name = "SomeName"
});

Query with bind vars through string interpolation

var col = "collection";
var list = new List<int> {1, 2, 3};

var result = await arango.Query.ExecuteAsync<JObject>("database",
  $"FOR c IN {col:@} FILTER c.SomeValue IN {list} RETURN c");

results in AQL injection save syntax:

'FOR c IN @@C1 FILTER c.SomeValue IN @P2 RETURN c'

{
  "@C1": "collection",
  "P2": [1, 2, 3]
}

for collections parameters, formats '@', 'C' and 'c' are supported. They all mean the same format.

  • Complex queries can be built from parts:
var collectionName = "collection";
var list = new List<int> {1, 2, 3};

FormattableString forPart = $"FOR c IN {collectionName:@}";
FormattableString filterPart = $"FILTER c.SomeValue IN {list}";
FormattableString returnPart = $"RETURN c";

var result = await arango.Query.ExecuteAsync<JObject>("database",
  $"{forPart} {filterPart} {returnPart}");

Query with async enumerator

// insert 100.000 entities 
await Arango.Document.CreateManyAsync("database", "collection", Enumerable.Range(1, 100000).Select(x => new Entity { Value = x }));

// iterate in batches over 100.000 entity ids
await foreach (var x in Arango.Query.ExecuteStreamAsync<string>("database", $"FOR c IN collection RETURN c._id"))
{
    Process(x)
}

Get documents

Get (many) documents by providing a list of keys or objects with "Key" and optional "Revision" property

var list1 = await Arango.Document.GetManyAsync<Entity>("database", "collection", new List<string> {
  "1", "2"
});

var list2 = await Arango.Document.GetManyAsync<Entity>("database", "collection", new List<object>
{
  new
  {
    Key = "1"
  },
  new
  {
    Key = "2"
  }
});

Linq

  • LINQ support has been adapted from https://github.com/ra0o0f/arangoclient.net
    • Internalized re-motion relinq since their nuget is quite outdated
  • Work in progress as some things are deprecated or need to be modernized
    • Basic queries generally work
    • Some more complex queries (chaining multiple operators, complex subqueries, etc.) are not supported yet
    • All these issues are solvable and pull requests are accepted
    • NOTE : Some queries will blow up at run time and you will get an exception, but some queries will actually generate valid AQL with the wrong semantics.
    • Combining multiple result operators is not recommended with the current implementation (e.g. .Intersect(list).Count() will generate valid AQL but will apply the operators in the wrong order)
    • The following operators are not yet supported:
      • .Average
      • .Cast
      • .Distinct
      • .GroupJoin
      • .Intersect
      • .Join
      • .Last
      • .Reverse
  • All other operators should be supported. If you find any queries that fail or generate incorrect AQL, open an issue so we can at least document it. A PR with a (failing) unit test would be even better!
  • There is also development done on a driver without relinq and aggregate support
  • Configurable property / collection / group naming for camelCase support

Simple query with DOCUMENT() lookup

var q = Arango.Query<Project>("test")
.Where(x => x.Name == "Project A")
.Select(x => new
{
    x.Key,
    x.Name,
    ClientName = Aql.Document<Client>("Client", x.ClientKey).Name
});

// Execute
await q.ToListAsync();

// Debug
var (aql, bindVars) = q.ToAql();

Let clauses for subqueries

  • Note: database/transaction is only specified on the root expression, not on the inner one
var q = from p in Arango.Query<Project>("test")
let clients = (from c in Arango.Query<Client>() select c.Key)
select new {p.Name, Clients = Aql.As<string[]>(clients) };

await q.ToListAsync();

Update

var q = Arango.Query<Project>("test")
  .Where(x => x.Name == "Project A")
  .Update(x => new
  {
    Name = Aql.Concat(x.Name, "2")
  }, x => x.Key);
		
await q.ToListAsync();

Parital Update

  • Note: To push an object to inner collection.
var q = Arango.Query<Project>("test")
  .PartialUpdate(p=>p.hobbies, x => new
  {
    "val1"=1,"val2"=2
  }, x => x.Key);
		
await q.ToListAsync();

will be converted to:

FOR doc IN Project
UPDATE doc WITH {
  hobbies: PUSH(doc.hobbies, {"val1": 1, "val2":2})
} IN users

Remove

await Arango.Query<Project>("test")
.Where(x => x.Name == "Project A")
.Remove().In<Project>().Select(x => x.Key).ToListAsync();

OPTIONS

"Option" is the query option that exists in ArangoDb. Some operations like FOR / Graph Traversal / SEARCH / COLLECT / INSERT / UPDATE / REPLACE / UPSERT / REMOVE would support "Options".

await Arango.Query<Project>("test")
.Where(x => x.Name == "Project A")
.Options(() => new { indexHint = "byName" }).ToListAsync();

Snippets for Advanced Use Cases

Create index

await arango.Index.CreateAsync("database", "collection", new ArangoIndex
{
    Fields = new List<string> {"SomeValue"},
    Type = ArangoIndexType.Hash
});

Create analyzer

await arango.Analyzer.CreateAsync("database", new ArangoAnalyzer
{
    Name = "text_de_nostem",
    Type = "text",
    Properties = new ArangoAnalyzerProperties
    {
        Locale = "de.utf-8",
        Case = ArangoAnalyzerCase.Lower,
        Accent = false,
        Stopwords = new List<string>(),
        Stemming = false
    },
    Features = new List<string> { "position", "norm", "frequency" }
});

Create view

await arango.View.CreateAsync("database", new ArangoView
{
    Name = "SomeView",
    Links = new Dictionary<string, ArangoLinkProperty>
    {
        ["collection"] = new ArangoLinkProperty
        {
            Fields = new Dictionary<string, ArangoLinkProperty>
            {
                ["SomeProperty"] = new ArangoLinkProperty
                {
                    Analyzers = new List<string>
                    {
                        "text_en"
                    }
                }
            }
        }
    },
    PrimarySort = new List<ArangoSort>
    {
        new ArangoSort
        {
            Field = "SomeProperty",
            Direction = ArangoSortDirection.Asc
        }
    }
});

Create graph

await arango.Collection.CreateAsync("database", "vertices", ArangoCollectionType.Document);
await Arango.Collection.CreateAsync("database", "edges", ArangoCollectionType.Edge);

await Arango.Graph.CreateAsync("database", new ArangoGraph
{
    Name = "graph",
    EdgeDefinitions = new List<ArangoEdgeDefinition>
    {
        new()
        {
          Collection = "edges",
          From = new List<string> {"vertices"},
          To = new List<string> {"vertices"}
        }
    }
});

Graph manipulation

await arango.Graph.Vertex.CreateAsync("database", "graph", "vertices", new
{
    Key = "alice",
    Name = "Alice"
});

await arango.Graph.Vertex.CreateAsync("database", "graph", "vertices", new
{
    Key = "bob",
    Name = "Bob"
});

await arango.Graph.Edge.CreateAsync("database", "graph", "edges", new
{
    Key = "ab",
    From = "vertices/alice",
    To = "vertices/bob",
    Label = "friend"
});

await arango.Graph.Edge.UpdateAsync("database", "graph", "edges", "ab", new
{
    Label = "foe"
});

await arango.Graph.Vertex.RemoveAsync("database", "graph", "vertices", "bob");

Create custom function

await arango.Function.CreateAsync("database", new ArangoFunctionDefinition
{
  Name = "CUSTOM::TIMES10",
  Code = "function (a) { return a * 10; }",
  IsDeterministic = true
});

Stream transactions

var transaction = await arango.Transaction.BeginAsync("database", new ArangoTransaction
{
    Collections = new ArangoTransactionScope
    {
        Write = new List<string> { "collection" }
    }
});

await arango.Document.CreateAsync(transaction, "collection", new
{
    Key = Guid.NewGuid(),
    SomeValue = 1
});

await arango.Document.CreateAsync(transaction, "collection", new
{
    Key = Guid.NewGuid(),
    SomeValue = 2
});

await arango.Transaction.CommitAsync(transaction);

Foxx services

// Build Foxx service zip archive
await using var ms = new MemoryStream();
using (var zip = new ZipArchive(ms, ZipArchiveMode.Create, true, Encoding.UTF8))
{
    await using (var manifest = zip.CreateEntry("manifest.json").Open())
    {
        await manifest.WriteAsync(Encoding.UTF8.GetBytes(@"
{
  ""$schema"": ""http://json.schemastore.org/foxx-manifest"",
  ""name"": ""SampleService"",
  ""description"": ""test"",
  ""version"": ""1.0.0"",
  ""license"": ""MIT"",
  ""engines"": {
    ""arangodb"": ""^3.0.0""
  },
  ""main"": ""index.js"",
  ""configuration"": {
    ""currency"": {
      ""description"": ""Currency symbol to use for prices in the shop."",
      ""default"": ""$"",
      ""type"": ""string""
    },
      ""secretKey"": {
      ""description"": ""Secret key to use for signing session tokens."",
      ""type"": ""password""
    }
  }
}
"));
    }

    await using (var readme = zip.CreateEntry("README").Open())
    {
        await readme.WriteAsync(Encoding.UTF8.GetBytes(@"
README!
"));
    }

    await using (var index = zip.CreateEntry("index.js").Open())
    {
        await index.WriteAsync(Encoding.UTF8.GetBytes(@"
'use strict';
const createRouter = require('@arangodb/foxx/router');
const router = createRouter();

module.context.use(router);
router.get('/hello-world', function (req, res) {{
  res.send({{ hello: 'world' }});
}})
.response(['application/json'], 'A generic greeting.')
.summary('Generic greeting')
.description('Prints a generic greeting.');
"));
    }
}

ms.Position = 0;

// install service
await Arango.Foxx.InstallServiceAsync("database", "/sample/service", ArangoFoxxSource.FromZip(ms));

// list services excluding system services
var services = await Arango.Foxx.ListServicesAsync("database", true);

// call service
var res = await Arango.Foxx.GetAsync<Dictionary<string, string>>("database", "/sample/service/hello-world");
Assert.Equal("world", res["hello"]);

Hot Backup (Enterprise Edition only)

var backup = await Arango.Backup.CreateAsync(new ArangoBackupRequest
{
	AllowInconsistent = false,
	Force = true,
	Label = "test",
	Timeout = 30
});

var backups = await Arango.Backup.ListAsync();

await Arango.Backup.RestoreAsync(backup.Id);

await Arango.Backup.DeleteAsync(backup.Id);
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].