Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ exclude = [
resolver = "2"

[workspace.package]
version = "2.8.0"
version = "2.9.0"
edition = "2021"
authors = ["Steven Hildreth"]
license = "Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.8.0
2.9.0
4 changes: 2 additions & 2 deletions benchmarks/rust-baseline/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion bindings/dart/dart/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: decentdb
description: Dart FFI bindings for the Rust DecentDB C ABI.
version: 2.8.0
version: 2.9.0
repository: https://github.com/sphildreth/decentdb
homepage: https://github.com/sphildreth/decentdb/tree/main/bindings/dart

Expand Down
2 changes: 1 addition & 1 deletion bindings/dart/examples/console/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ packages:
path: "../../dart"
relative: true
source: path
version: "2.8.0"
version: "2.9.0"
ffi:
dependency: transitive
description:
Expand Down
2 changes: 1 addition & 1 deletion bindings/dart/examples/console_complex/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ packages:
path: "../../dart"
relative: true
source: path
version: "2.8.0"
version: "2.9.0"
ffi:
dependency: transitive
description:
Expand Down
2 changes: 1 addition & 1 deletion bindings/dart/examples/flutter_desktop/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ packages:
path: "../../dart"
relative: true
source: path
version: "2.8.0"
version: "2.9.0"
ffi:
dependency: transitive
description:
Expand Down
2 changes: 1 addition & 1 deletion bindings/dart/flutter/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
}

group = 'dev.decentdb.decentdb_flutter'
version = '2.8.0'
version = '2.9.0'

android {
namespace 'dev.decentdb.decentdb_flutter'
Expand Down
4 changes: 2 additions & 2 deletions bindings/dart/flutter/example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ packages:
path: "../../dart"
relative: true
source: path
version: "2.8.0"
version: "2.9.0"
decentdb_flutter:
dependency: "direct main"
description:
path: ".."
relative: true
source: path
version: "2.8.0"
version: "2.9.0"
fake_async:
dependency: transitive
description:
Expand Down
2 changes: 1 addition & 1 deletion bindings/dart/flutter/example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: decentdb_flutter_example
description: Reference Flutter mobile app for DecentDB.
publish_to: none
version: 2.8.0
version: 2.9.0

environment:
sdk: ^3.0.0
Expand Down
2 changes: 1 addition & 1 deletion bindings/dart/flutter/ios/decentdb_flutter.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'decentdb_flutter'
s.version = '2.8.0'
s.version = '2.9.0'
s.summary = 'Flutter mobile integration helpers for DecentDB.'
s.description = 'Provides Flutter registration and native artifact wiring for the DecentDB Dart FFI package.'
s.homepage = 'https://github.com/sphildreth/decentdb'
Expand Down
2 changes: 1 addition & 1 deletion bindings/dart/flutter/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ packages:
path: "../dart"
relative: true
source: path
version: "2.8.0"
version: "2.9.0"
fake_async:
dependency: transitive
description:
Expand Down
2 changes: 1 addition & 1 deletion bindings/dart/flutter/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: decentdb_flutter
description: Flutter mobile integration helpers for the DecentDB Dart FFI package.
version: 2.8.0
version: 2.9.0
publish_to: none
repository: https://github.com/sphildreth/decentdb
homepage: https://github.com/sphildreth/decentdb/tree/main/bindings/dart/flutter
Expand Down
13 changes: 13 additions & 0 deletions bindings/dotnet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ This directory contains the official .NET bindings for DecentDB:
| Connection pooling | ❌ (MicroOrm interprets `Pooling`) | ✅ | ❌ |
| View querying (keyless DTO) | ✅ | ✅ (`QueryRawAsync<T>`) | ✅ (`DbQuery` / keyless entity) |
| Diagnostic events (`SqlExecuting`/`SqlExecuted`) | ✅ | ❌ | ✅ (EF Core logging) |
| Query plan helper (`ExplainQuery`) | ✅ | ❌ | ✅ (`ToQueryString` + ADO.NET helper) |
| `GetSchema("Indexes")` with `IS_PRIMARY_KEY` | ✅ | N/A | N/A |
| `DeleteDatabaseFiles` helper | ✅ | N/A | N/A |
| File maintenance (`GetWalStatus`, `CheckpointAsync`, `CompactAsync`, `VacuumAsync`) | ✅ | N/A | N/A |
| Model pre-building cache | N/A | N/A | ✅ (`DecentDBModelBuilder`) |
| Compiled query support | N/A | N/A | ✅ (`EF.CompileQuery`) |
| Correlated aggregate rewrite | N/A | N/A | ✅ (infrastructure; rewrite deferred) |
Expand Down Expand Up @@ -69,6 +71,17 @@ Supported keys:

The `DecentDBConnection.DeleteDatabaseFiles(path)` helper deletes the database file and all sidecar files (`.wal`, `-wal`, `-shm`, `.coord`) safely.

The `DecentDBMaintenance` helper exposes binding-native maintenance operations:
`GetWalStatus(path)`, `CheckpointAsync(path)`, `CompactAsync(source, target)`,
and `VacuumAsync(path, createBackup: true)`. These helpers use the .NET binding
directly. The older `VacuumAtomicAsync(path, cliPath, ...)` remains available
for legacy executable-backed vacuum workflows.

For query-plan diagnostics, call `connection.ExplainQuery(sql)` or
`connection.ExplainQuery(sql, analyze: true)` on an open ADO.NET connection.
The returned plan includes the generated `EXPLAIN` SQL, plan lines, joined text,
and elapsed diagnostic duration.

`DecentDB.Native.DecentDB.ExecuteQueued(sql)` exposes the native queued path for
self-contained SQL, and `WriteQueueMetrics()` returns queue counters. ADO.NET
commands keep prepared-statement execution on the direct path until the C ABI
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -712,14 +712,14 @@ private static async Task DemonstrateOperationalBehaviors(ShowcaseScenarioContex
inMemory.SaveAs(maintenanceDbPath);
}

var vacuumed = await DecentDBMaintenance.VacuumAtomicAsync(maintenanceDbPath);
var vacuumResult = await DecentDBMaintenance.VacuumAsync(maintenanceDbPath);
using var verify = scenario.CreateOpenConnection(maintenanceDbPath);
using var verifyCommand = verify.CreateCommand();
verifyCommand.CommandText = "SELECT COUNT(*) FROM maintenance_demo";
var copiedRows = Convert.ToInt64(verifyCommand.ExecuteScalar());

scenario.WriteLine($" SaveAs copied rows: {copiedRows}");
scenario.WriteLine($" VacuumAtomicAsync: {vacuumed}");
scenario.WriteLine($" VacuumAsync replaced database: {vacuumResult.DatabaseExisted}");
scenario.WriteLine();
}
private static async Task DemonstrateConcurrencyControl(ShowcaseScenarioContext scenario)
Expand Down
2 changes: 1 addition & 1 deletion bindings/dotnet/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ connection.GetSchema("Indexes") // Index information
### Database Maintenance
- **Checkpoint** - Flush WAL to main database file
- **SaveAs** - Export database to new file
- **VacuumAtomicAsync** - Compact a file-backed database with the maintenance helper
- **VacuumAsync** - Compact a file-backed database with the maintenance helper

### Provider Ergonomics
- `DecentDBConnectionStringBuilder` can be passed directly to `UseDecentDB(...)`
Expand Down
16 changes: 15 additions & 1 deletion bindings/dotnet/src/DecentDB.AdoNet/DecentDBConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,24 @@ public override void Open()
catch (Exception ex)
{
_state = ConnectionState.Closed;
throw new InvalidOperationException($"Failed to open database: {ex.Message}", ex);
throw new InvalidOperationException(CreateOpenFailureMessage(path, ex), ex);
}
}

private static string CreateOpenFailureMessage(string path, Exception exception)
{
var message = exception.Message;
if (message.Contains("unsupported database format version", StringComparison.OrdinalIgnoreCase))
{
return "Failed to open database: unsupported DecentDB file format. " +
"Use a compatible DecentDB engine, run decentdb-migrate when a migration path is available, " +
"or rebuild/export the database with the current engine. " +
$"Path: {path}. Native error: {message}";
}

return $"Failed to open database: {message}";
}

public override Task OpenAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;

namespace DecentDB.AdoNet;

Expand All @@ -9,4 +12,44 @@ public static void Checkpoint(this DecentDBConnection connection)
if (connection == null) throw new ArgumentNullException(nameof(connection));
connection.Checkpoint();
}

/// <summary>
/// Executes EXPLAIN or EXPLAIN ANALYZE for a SQL statement and returns the plan text.
/// </summary>
/// <param name="connection">An open DecentDB connection.</param>
/// <param name="sql">The SQL statement to inspect.</param>
/// <param name="analyze">When true, executes EXPLAIN ANALYZE and includes actual metrics.</param>
public static DecentDBQueryPlan ExplainQuery(
this DecentDBConnection connection,
string sql,
bool analyze = false)
{
if (connection == null) throw new ArgumentNullException(nameof(connection));
if (string.IsNullOrWhiteSpace(sql))
throw new ArgumentException("SQL cannot be null or empty.", nameof(sql));
if (connection.State != ConnectionState.Open)
throw new InvalidOperationException("Connection is not open.");

var explainSql = analyze ? $"EXPLAIN ANALYZE {sql}" : $"EXPLAIN {sql}";
var stopwatch = Stopwatch.StartNew();
var lines = new List<string>();

using (var command = connection.CreateCommand())
{
command.CommandText = explainSql;
using var reader = command.ExecuteReader();
while (reader.Read())
{
lines.Add(Convert.ToString(reader.GetValue(0)) ?? string.Empty);
}
}

stopwatch.Stop();
return new DecentDBQueryPlan(
sql,
explainSql,
analyze,
lines,
stopwatch.Elapsed);
}
}
Loading
Loading