See dotnet-arangodb
Extension | Nuget | Command |
---|---|---|
Core.Arango.Migration | dotnet add package Core.Arango.Migration | |
Core.Arango.DataProtection | dotnet add package Core.Arango.DataProtection | |
Core.Arango.DevExtreme | dotnet add package Core.Arango.DevExtreme | |
Core.Arango.Serilog | dotnet add package Core.Arango.Serilog |
- Ensures the Arango structure / model is up-to-date
- Synchronises collection, index, graph, analyzer, views and custom functions from code model to arango db
- objects are compared and if they differ they will be dropped and recreated
- objects cannot be renamed with this method as they are matched by name and not by id
- collections cannot be updated (data-loss) with this method, only new ones can be created and old ones dropped
- Database export and import support with zip-archives
- Full and partial updates
- Optional history collection for advanced migration scenarios, like running transformation queries
- Still under heavy development, might toss some functions around
var migrationService = new ArangoMigrator(Arango);
var structure = await migrationService.GetStructureAsync("source-database");
var migrationService = new ArangoMigrator(Arango);
await migrationService.ApplyStructureAsync("target-database", structure, new ArangoMigrationOptions
{
DryRun = true,
Notify = n =>
{
if (n.State != ArangoMigrationState.Identical)
_output.WriteLine($"{n.State} {n.Object} {n.Name}");
}
});
var migrationService = new ArangoMigrator(Arango);
await migrationService.ApplyStructureAsync("target-database", new ArangoStructure
{
Collections = new List<ArangoCollectionIndices>
{
new ()
{
Collection = new ArangoCollection
{
Name = "Project",
Type = ArangoCollectionType.Document
},
Indices = new List<ArangoIndex>
{
new ()
{
Name = "IDX_ParentKey",
Fields = new List<string> {"ParentKey"},
Type = ArangoIndexType.Hash
}
}
},
new ()
{
Collection = new ArangoCollection
{
Name = "Activity",
Type = ArangoCollectionType.Document
},
Indices = new List<ArangoIndex>
{
new ()
{
Name = "IDX_ProjectKey",
Fields = new List<string> {"ProjectKey"},
Type = ArangoIndexType.Hash
}
}
}
}
});
var migrationService = new ArangoMigrator(Arango);
await using var fs = File.Create("export.zip", 1024 * 1024);
await migrationService.ExportAsync("source-database", fs, ArangoMigrationScope.Data | ArangoMigrationScope.Structure);
var migrationService = new ArangoMigrator(Arango);
await using var fs = File.OpenRead("export.zip");
await migrationService.ImportAsync("target-database", fs, ArangoMigrationScope.Data | ArangoMigrationScope.Structure);
var migrator = new ArangoMigrator(Arango);
migrator.HistoryCollection = "MigrationHistory";
// load all migrations from assembly
migrator.AddMigrations(typeof(Program).Assembly);
// apply all migrations up to latest
await migrator.UpgradeAsync("target-database");
// sample migration / downgrades not yet supported
public class M20210401_001 : IArangoMigration
{
public long Id => 20210401_001; // sortable unique id
public string Name => "Initial";
public async Task Up(IArangoMigrator migrator, ArangoHandle handle)
{
await migrator.ApplyStructureAsync(...);
await migrator.Context.Query.ExecuteAsync(...);
}
public Task Down(IArangoMigrator migrator, ArangoHandle handle)
{
throw new NotImplementedException();
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(new ArangoContext(Configuration.GetConnectionString("Arango")));
var dataProtection = services.AddDataProtection()
.SetApplicationName("App")
.SetDefaultKeyLifetime(TimeSpan.FromDays(30));
dataProtection.PersistKeysToArangoDB(database: "dataprotection", collection: "keys");
}
- Translates DevExtreme queries to AQL with filtering, sorting, grouping and summaries on a 'best effort basis'
- Parameters are escaped with bindvars
- Property names
- need to match ^[A-Za-z_][A-Za-z0-9\.]*$
- need to be within 128 characters
- can be customized with ValidPropertyName() and PropertyTransform()
- Developer retains full control over the projection - full document by default
- Check safety limits in settings if your query fails
- Support for ArangoSearch is coming soon
- Not so soon...
- Groupings by foreign key can be enriched with displayValue using GroupLookups()
private static readonly ArangoTransformSettings Transform = new ArangoTransformSettings
{
IteratorVar = "x",
Key = "key",
Filter = "x.Active == true",
RestrictGroups = new HashSet<string>
{
"ProjectKey", "UserKey"
}, // null allows all groupings (not recommended) / empty hashset disables grouping
GroupLookups = new Dictionary<string, string>
{
["ProjectKey"] = "DOCUMENT(AProject, ProjectKey).Name",
["UserKey"] = "DOCUMENT(AUser, UserKey).Name"
}
};
[HttpGet("dx-query")]
public async Task<ActionResult<DxLoadResult>> DxQuery([FromQuery] DataSourceLoadOptions loadOptions)
{
var arangoTransform = new ArangoTransform(loadOptions, Transform);
if (!arangoTransform.Transform(out var error))
return BadRequest(error);
return await arangoTransform.ExecuteAsync<SomeEntity>(arango, "database", "collection");
}
builder.Host.UseSerilog(
(c, log) =>
{
var arango = builder.Configuration.GetConnectionString("Arango");
log.Enrich.FromLogContext();
log.WriteTo.Console(theme: AnsiConsoleTheme.Code);
log.WriteTo.Sink(new PeriodicBatchingSink(new ArangoSerilogSink(new ArangoContext(arango)), new PeriodicBatchingSinkOptions
{
BatchSizeLimit = 1000,
QueueLimit = 100000,
Period = TimeSpan.FromSeconds(2),
EagerlyEmitFirstEvent = true
}));
});