diff --git a/Directory.Packages.props b/Directory.Packages.props
index 8c2d31084..c1ea4fa17 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -90,8 +90,8 @@
-
-
+
+
diff --git a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/Todo.cs b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/Todo.cs
index c4981aa71..ac82b7946 100644
--- a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/Todo.cs
+++ b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/Todo.cs
@@ -1,12 +1,19 @@
using SurrealDb.Net.Models;
+using System.ComponentModel.DataAnnotations.Schema;
namespace CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService.Models;
+[Table(Table)]
public class Todo : Record
{
internal const string Table = "todo";
+ [Column("title")]
public string? Title { get; set; }
+
+ [Column("due_by")]
public DateOnly? DueBy { get; set; } = null;
+
+ [Column("is_complete")]
public bool IsComplete { get; set; } = false;
}
\ No newline at end of file
diff --git a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/TodoFaker.cs b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/TodoFaker.cs
new file mode 100644
index 000000000..fda23c38a
--- /dev/null
+++ b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/TodoFaker.cs
@@ -0,0 +1,16 @@
+using Bogus;
+
+namespace CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService.Models;
+
+///
+/// Faker test class to generate fake objects.
+///
+public class TodoFaker : Faker
+{
+ public TodoFaker()
+ {
+ RuleFor(o => o.Title, f => f.Lorem.Sentence());
+ RuleFor(o => o.DueBy, f => f.Date.FutureDateOnly());
+ RuleFor(o => o.IsComplete, f => f.Random.Bool());
+ }
+}
\ No newline at end of file
diff --git a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/WeatherForecast.cs b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/WeatherForecast.cs
index a90521be4..20d238b90 100644
--- a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/WeatherForecast.cs
+++ b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/WeatherForecast.cs
@@ -1,10 +1,12 @@
using SurrealDb.Net.Models;
+using System.ComponentModel.DataAnnotations.Schema;
namespace CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService.Models;
///
/// Weather forecast model.
///
+[Table(Table)]
public class WeatherForecast : Record
{
internal const string Table = "weatherForecast";
@@ -12,25 +14,30 @@ public class WeatherForecast : Record
///
/// Date of the weather forecast.
///
+ [Column("date")]
public DateTime Date { get; set; }
///
/// Country of the weather forecast.
///
+ [Column("country")]
public string? Country { get; set; }
///
/// Temperature in Celsius.
///
+ [Column("temperature_c")]
public int TemperatureC { get; set; }
///
/// Temperature in Fahrenheit.
///
+ [Column("temperature_f")]
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
///
/// Summary of the weather forecast.
///
+ [Column("summary")]
public string? Summary { get; set; }
}
\ No newline at end of file
diff --git a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/WeatherForecastFaker.cs b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/WeatherForecastFaker.cs
index 027fbe81e..3aa6fb8f3 100644
--- a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/WeatherForecastFaker.cs
+++ b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Models/WeatherForecastFaker.cs
@@ -3,7 +3,7 @@
namespace CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService.Models;
///
-/// Faker test class to generate fake WeatherForecast objects.
+/// Faker test class to generate fake objects.
///
public class WeatherForecastFaker : Faker
{
@@ -21,9 +21,6 @@ public class WeatherForecastFaker : Faker
"Scorching"
};
- ///
- /// Constructor
- ///
public WeatherForecastFaker()
{
RuleFor(o => o.Date, f => f.Date.Recent());
diff --git a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Program.cs b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Program.cs
index 0f13ace2e..80517fdf7 100644
--- a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Program.cs
+++ b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.ApiService/Program.cs
@@ -2,37 +2,51 @@
using SurrealDb.Net;
var builder = WebApplication.CreateBuilder(args);
+var configuration = builder.Configuration;
builder.AddServiceDefaults();
-builder.AddSurrealClient("db", settings =>
-{
- settings.Options!.NamingPolicy = "CamelCase";
-});
+builder.AddSurrealClient("db");
var app = builder.Build();
app.MapDefaultEndpoints();
app.MapGroup("/api")
- .MapSurrealEndpoints(
+ .MapSurrealEndpoints(
"/weatherForecast",
new() { EnableMutations = false }
)
- .MapSurrealEndpoints("/todo");
+ .MapSurrealEndpoints("/todo");
app.MapPost("/init", InitializeDbAsync);
app.Run();
-Task InitializeDbAsync(ISurrealDbClient surrealDbClient)
+async Task InitializeDbAsync()
{
const int initialCount = 5;
var weatherForecasts = new WeatherForecastFaker().Generate(initialCount);
-
- var tasks = weatherForecasts.Select(weatherForecast =>
- surrealDbClient.Create(WeatherForecast.Table, weatherForecast)
+ var todos = new TodoFaker().Generate(initialCount);
+
+ var surrealDbClient = new SurrealDbClient(
+ SurrealDbOptions
+ .Create()
+ .FromConnectionString(configuration.GetConnectionString("db")!)
+ .Build()
);
- return Task.WhenAll(tasks);
+ var weatherForecastTasks = weatherForecasts.Select(async weatherForecast => {
+ await surrealDbClient.Create(WeatherForecast.Table, weatherForecast);
+ return Task.CompletedTask;
+ });
+
+ var todoTasks = todos.Select(async todo => {
+ await surrealDbClient.Create(Todo.Table, todo);
+ return Task.CompletedTask;
+ });
+
+ await Task.WhenAll(weatherForecastTasks.Concat(todoTasks));
+
+ await surrealDbClient.DisposeAsync();
}
\ No newline at end of file
diff --git a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.TypeScript/apphost.mts b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.TypeScript/apphost.mts
index 0e1d7d777..b50a81e69 100644
--- a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.TypeScript/apphost.mts
+++ b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.TypeScript/apphost.mts
@@ -3,9 +3,8 @@ import { createBuilder } from "./.aspire/modules/aspire.mjs";
const builder = await createBuilder();
let primary = await builder.addSurrealServer("primary", {
- port: 18000,
- path: "memory",
- strictMode: true,
+ port: 18000,
+ path: "memory",
});
primary = await primary.withDataVolume({ name: "surreal-primary-data" });
@@ -14,22 +13,22 @@ primary = await primary.withSurrealist({ containerName: "surrealist-primary" });
primary = await primary.withSurrealDbOtlpExporter();
let appNamespace = await primary.addNamespace("appns", {
- namespaceName: "polyglotNs",
+ namespaceName: "polyglotNs",
});
appNamespace = await appNamespace.withCreationScript(
- "DEFINE NAMESPACE IF NOT EXISTS `polyglotNs`;",
+ "DEFINE NAMESPACE IF NOT EXISTS `polyglotNs`;",
);
let appDatabase = await appNamespace.addDatabase("appdb", {
- databaseName: "polyglotDb",
+ databaseName: "polyglotDb",
});
appDatabase = await appDatabase.withCreationScript(
- "DEFINE DATABASE IF NOT EXISTS `polyglotDb`;",
+ "DEFINE DATABASE IF NOT EXISTS `polyglotDb`;",
);
let mounted = await builder.addSurrealServer("mounted", {
- port: 18001,
- path: "memory",
+ port: 18001,
+ path: "memory",
});
mounted = await mounted.withDataBindMount("./data");
mounted = await mounted.withInitFiles("./seed.surql");
@@ -43,13 +42,13 @@ const _primaryConnectionString = await primary.connectionStringExpression();
const _namespaceParent = await appNamespace.parent();
const _namespaceConnectionString =
- await appNamespace.connectionStringExpression();
+ await appNamespace.connectionStringExpression();
const _namespaceName = await appNamespace.namespaceName();
const _namespaceParentName = await _namespaceParent.name();
const _databaseParent = await appDatabase.parent();
const _databaseConnectionString =
- await appDatabase.connectionStringExpression();
+ await appDatabase.connectionStringExpression();
const _databaseName = await appDatabase.databaseName();
const _databaseParentName = await _databaseParent.name();
const _databaseServerName = await (await _databaseParent.parent()).name();
@@ -61,4 +60,3 @@ const _mountedUri = await mounted.uriExpression();
const _mountedConnectionString = await mounted.connectionStringExpression();
await builder.build().run();
-
diff --git a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.csproj b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.csproj
index 13953b7f9..9875cb3e7 100644
--- a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.csproj
+++ b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.csproj
@@ -1,4 +1,4 @@
-
+
Exe
diff --git a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost/Program.cs b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost/Program.cs
index 949076eef..517d3b0a6 100644
--- a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost/Program.cs
+++ b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost/Program.cs
@@ -4,33 +4,33 @@
bool strictMode = false;
-var db = builder.AddSurrealServer("surreal", strictMode: strictMode)
+var db = builder.AddSurrealServer("surreal")
.WithSurrealist()
.AddNamespace("ns")
.AddDatabase("db");
-if (strictMode)
-{
#pragma warning disable CTASPIRE002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
- db.WithCreationScript(
- $"""
- DEFINE DATABASE IF NOT EXISTS {nameof(db)};
- USE DATABASE {nameof(db)};
-
- DEFINE TABLE todo;
- DEFINE FIELD title ON todo TYPE string;
- DEFINE FIELD dueBy ON todo TYPE datetime;
- DEFINE FIELD isComplete ON todo TYPE bool;
-
- DEFINE TABLE weatherForecast;
- DEFINE FIELD date ON weatherForecast TYPE datetime;
- DEFINE FIELD country ON weatherForecast TYPE string;
- DEFINE FIELD temperatureC ON weatherForecast TYPE number;
- DEFINE FIELD summary ON weatherForecast TYPE string;
- """
- );
+string strictSuffix = strictMode ? " STRICT" : string.Empty;
+db.WithCreationScript(
+ $"""
+ DEFINE DATABASE IF NOT EXISTS {nameof(db)}{strictSuffix};
+ USE DATABASE {nameof(db)};
+
+ DEFINE TABLE todo;
+ DEFINE FIELD title ON todo TYPE string;
+ DEFINE FIELD due_by ON todo TYPE datetime;
+ DEFINE FIELD is_complete ON todo TYPE bool;
+
+ DEFINE TABLE weatherForecast;
+ DEFINE FIELD date ON weatherForecast TYPE datetime;
+ DEFINE FIELD country ON weatherForecast TYPE string;
+ DEFINE FIELD temperature_c ON weatherForecast TYPE number;
+ DEFINE FIELD temperature_f ON weatherForecast TYPE number;
+ DEFINE FIELD summary ON weatherForecast TYPE string;
+ """
+);
#pragma warning restore CTASPIRE002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
-}
+
builder.AddProject("apiservice")
.WithReference(db)
diff --git a/src/CommunityToolkit.Aspire.Hosting.SurrealDb/SurrealDbBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.SurrealDb/SurrealDbBuilderExtensions.cs
index 6957b5a53..91cc6d23d 100644
--- a/src/CommunityToolkit.Aspire.Hosting.SurrealDb/SurrealDbBuilderExtensions.cs
+++ b/src/CommunityToolkit.Aspire.Hosting.SurrealDb/SurrealDbBuilderExtensions.cs
@@ -33,7 +33,6 @@ public static class SurrealDbBuilderExtensions
/// The parameter used to provide the administrator password for the SurrealDB resource. If a random password will be generated.
/// The host port for the SurrealDB instance.
/// Sets the path for storing data. If no argument is given, the default of memory for non-persistent storage in memory is assumed.
- /// Whether strict mode is enabled on the server.
/// A reference to the .
///
///
@@ -58,8 +57,7 @@ public static IResourceBuilder AddSurrealServer(
IResourceBuilder? userName = null,
IResourceBuilder? password = null,
int? port = null,
- string path = "memory",
- bool strictMode = false
+ string path = "memory"
)
{
ArgumentNullException.ThrowIfNull(builder);
@@ -70,10 +68,6 @@ public static IResourceBuilder AddSurrealServer(
"start",
path
};
- if (strictMode)
- {
- args.Add("--strict");
- }
// The password must be at least 8 characters long and contain characters from three of the following four sets: Uppercase letters, Lowercase letters, Base 10 digits, and Symbols
var passwordParameter = password?.Resource ?? ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(builder, $"{name}-password", minLower: 1, minUpper: 1, minNumeric: 1);
@@ -97,11 +91,6 @@ public static IResourceBuilder AddSurrealServer(
.WithArgs([.. args])
.OnResourceReady(async (_, @event, ct) =>
{
- if (!strictMode)
- {
- return;
- }
-
var connectionString = await surrealServer.GetConnectionStringAsync(ct).ConfigureAwait(false);
if (connectionString is null)
{
diff --git a/src/CommunityToolkit.Aspire.Hosting.SurrealDb/SurrealDbContainerImageTags.cs b/src/CommunityToolkit.Aspire.Hosting.SurrealDb/SurrealDbContainerImageTags.cs
index b2ec7e980..bcad99984 100644
--- a/src/CommunityToolkit.Aspire.Hosting.SurrealDb/SurrealDbContainerImageTags.cs
+++ b/src/CommunityToolkit.Aspire.Hosting.SurrealDb/SurrealDbContainerImageTags.cs
@@ -9,13 +9,13 @@ internal sealed class SurrealDbContainerImageTags
public const string Registry = "docker.io";
/// surrealdb/surrealdb
public const string Image = "surrealdb/surrealdb";
- /// v2.4
- public const string Tag = "v2.4";
+ /// v3.1
+ public const string Tag = "v3.1";
/// docker.io
public const string SurrealistRegistry = "docker.io";
/// surrealdb/surrealist
public const string SurrealistImage = "surrealdb/surrealist";
- /// 3.6.9
- public const string SurrealistTag = "3.6.9";
+ /// 3.8.3
+ public const string SurrealistTag = "3.8.3";
}
\ No newline at end of file
diff --git a/src/CommunityToolkit.Aspire.SurrealDb/SurrealDbClientSettings.cs b/src/CommunityToolkit.Aspire.SurrealDb/SurrealDbClientSettings.cs
index 02c077197..72127a9d1 100644
--- a/src/CommunityToolkit.Aspire.SurrealDb/SurrealDbClientSettings.cs
+++ b/src/CommunityToolkit.Aspire.SurrealDb/SurrealDbClientSettings.cs
@@ -20,9 +20,9 @@ public sealed class SurrealDbClientSettings
/// Gets or sets the Service lifetime to register services under.
///
///
- /// The default value is .
+ /// The default value is .
///
- public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Singleton;
+ public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Scoped;
///
/// Gets or sets a boolean value that indicates whether the SurrealDB health check is disabled or not.
diff --git a/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/AppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/AppHostTests.cs
index 29d1dc54d..e8c4308cc 100644
--- a/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/AppHostTests.cs
+++ b/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/AppHostTests.cs
@@ -42,11 +42,11 @@ public async Task ApiServiceStartsAndRespondsOk()
await fixture.ResourceNotificationService.WaitForResourceHealthyAsync(resourceName).WaitAsync(TimeSpan.FromMinutes(1));
var httpClient = fixture.CreateHttpClient(resourceName);
- var todoResponse = await httpClient.GetAsync("/api/todo");
- Assert.Equal(HttpStatusCode.OK, todoResponse.StatusCode);
-
var initResponse = await httpClient.PostAsync("/init", null);
Assert.Equal(HttpStatusCode.OK, initResponse.StatusCode);
+
+ var todoResponse = await httpClient.GetAsync("/api/todo");
+ Assert.Equal(HttpStatusCode.OK, todoResponse.StatusCode);
var weatherForecastResponse = await httpClient.GetAsync("/api/weatherForecast");
Assert.Equal(HttpStatusCode.OK, weatherForecastResponse.StatusCode);
diff --git a/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/SurrealDbFunctionalTests.cs b/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/SurrealDbFunctionalTests.cs
index 4f92c4573..6dc0f884e 100644
--- a/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/SurrealDbFunctionalTests.cs
+++ b/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/SurrealDbFunctionalTests.cs
@@ -1,7 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using Aspire.Components.Common.Tests;
using Aspire.Hosting;
using Aspire.Hosting.Utils;
using Bogus;
@@ -12,7 +11,7 @@
using Polly;
using SurrealDb.Net;
using SurrealDb.Net.Exceptions;
-using System.Data;
+using System.ComponentModel.DataAnnotations.Schema;
using SurrealRecord = SurrealDb.Net.Models.Record;
namespace CommunityToolkit.Aspire.Hosting.SurrealDb.Tests;
@@ -39,7 +38,7 @@ public async Task VerifySurrealDbResource()
{
using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
var ct = cts.Token;
- using var builder = TestDistributedApplicationBuilder.Create(testOutputHelper);
+ await using var builder = TestDistributedApplicationBuilder.Create(testOutputHelper);
var surrealServer = builder.AddSurrealServer("surreal");
@@ -47,15 +46,15 @@ public async Task VerifySurrealDbResource()
.AddNamespace("ns")
.AddDatabase("db");
- using var app = builder.Build();
+ await using var app = builder.Build();
- await app.StartAsync();
+ await app.StartAsync(ct);
await app.ResourceNotifications.WaitForResourceHealthyAsync(db.Resource.Name, ct);
var hb = Host.CreateApplicationBuilder();
- hb.Configuration[$"ConnectionStrings:{db.Resource.Name}"] = await db.Resource.ConnectionStringExpression.GetValueAsync(default);
+ hb.Configuration[$"ConnectionStrings:{db.Resource.Name}"] = await db.Resource.ConnectionStringExpression.GetValueAsync(ct);
hb.AddSurrealClient(db.Resource.Name);
@@ -63,10 +62,11 @@ public async Task VerifySurrealDbResource()
await host.StartAsync(ct);
- var surrealDbClient = host.Services.GetRequiredService();
+ await using var scope = host.Services.CreateAsyncScope();
+ await using var client = scope.ServiceProvider.GetRequiredService();
- await CreateTestData(surrealDbClient, ct);
- await AssertTestData(surrealDbClient, ct);
+ await CreateTestData(client, ct);
+ await AssertTestData(client, ct);
}
[Theory]
@@ -80,14 +80,17 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
string? volumeName = null;
string? bindMountPath = null;
+ const string databasePath = "surrealkv://data/db.db";
+
try
{
using var builder1 = TestDistributedApplicationBuilder.Create(testOutputHelper);
-
+
var password1 = builder1.AddParameter("surreal-password", secret: true);
password1.Resource.Default = new PasswordConstantDefault();
-
- var surrealServer1 = builder1.AddSurrealServer("surreal", path: "rocksdb://data/db.db", password: password1);
+
+ var surrealServer1 =
+ builder1.AddSurrealServer("surreal", path: databasePath, password: password1);
var db1 = surrealServer1
.AddNamespace("ns")
@@ -96,7 +99,8 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
if (useVolume)
{
// Use a deterministic volume name to prevent them from exhausting the machines if deletion fails
- volumeName = VolumeNameGenerator.Generate(surrealServer1, nameof(WithDataShouldPersistStateBetweenUsages));
+ volumeName = VolumeNameGenerator.Generate(surrealServer1,
+ nameof(WithDataShouldPersistStateBetweenUsages));
// if the volume already exists (because of a crashing previous run), delete it
DockerUtils.AttemptDeleteDockerVolume(volumeName, throwOnFailure: true);
@@ -109,7 +113,9 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
if (!OperatingSystem.IsWindows())
{
- File.SetUnixFileMode(bindMountPath, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute | UnixFileMode.OtherRead | UnixFileMode.OtherWrite | UnixFileMode.OtherExecute);
+ File.SetUnixFileMode(bindMountPath,
+ UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute |
+ UnixFileMode.OtherRead | UnixFileMode.OtherWrite | UnixFileMode.OtherExecute);
}
}
@@ -124,16 +130,18 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
{
var hb = Host.CreateApplicationBuilder();
- hb.Configuration[$"ConnectionStrings:{db1.Resource.Name}"] = await db1.Resource.ConnectionStringExpression.GetValueAsync(ct);
+ hb.Configuration[$"ConnectionStrings:{db1.Resource.Name}"] =
+ await db1.Resource.ConnectionStringExpression.GetValueAsync(ct);
hb.AddSurrealClient(db1.Resource.Name);
using var host = hb.Build();
await host.StartAsync(ct);
- await using var surrealDbClient = host.Services.GetRequiredService();
- await CreateTestData(surrealDbClient, ct);
- await AssertTestData(surrealDbClient, ct);
+ await using var scope1 = host.Services.CreateAsyncScope();
+ await using var client = scope1.ServiceProvider.GetRequiredService();
+ await CreateTestData(client, ct);
+ await AssertTestData(client, ct);
}
finally
{
@@ -143,11 +151,12 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
}
using var builder2 = TestDistributedApplicationBuilder.Create(testOutputHelper);
-
+
var password2 = builder2.AddParameter("surreal-password", secret: true);
password2.Resource.Default = new PasswordConstantDefault();
-
- var surrealServer2 = builder2.AddSurrealServer("surreal", path: "rocksdb://data/db.db", password: password2);
+
+ var surrealServer2 =
+ builder2.AddSurrealServer("surreal", path: databasePath, password: password2);
var db2 = surrealServer2
.AddNamespace("ns")
@@ -173,14 +182,16 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
{
var hb = Host.CreateApplicationBuilder();
- hb.Configuration[$"ConnectionStrings:{db2.Resource.Name}"] = await db2.Resource.ConnectionStringExpression.GetValueAsync(ct);
+ hb.Configuration[$"ConnectionStrings:{db2.Resource.Name}"] =
+ await db2.Resource.ConnectionStringExpression.GetValueAsync(ct);
hb.AddSurrealClient(db2.Resource.Name);
using var host = hb.Build();
await host.StartAsync(ct);
- await using var surrealDbClient = host.Services.GetRequiredService();
- await AssertTestData(surrealDbClient, ct);
+ await using var scope2 = host.Services.CreateAsyncScope();
+ await using var client = scope2.ServiceProvider.GetRequiredService();
+ await AssertTestData(client, ct);
}
finally
{
@@ -188,7 +199,6 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
await app.StopAsync(ct);
}
}
-
}
finally
{
@@ -215,7 +225,7 @@ public async Task WithDataShouldPersistStateBetweenUsages(bool useVolume)
public async Task VerifyWaitForOnSurrealDbBlocksDependentResources()
{
using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(10));
- using var builder = TestDistributedApplicationBuilder.Create(testOutputHelper);
+ await using var builder = TestDistributedApplicationBuilder.Create(testOutputHelper);
var healthCheckTcs = new TaskCompletionSource();
builder.Services.AddHealthChecks().AddAsyncCheck("blocking_check", () => healthCheckTcs.Task);
@@ -226,7 +236,7 @@ public async Task VerifyWaitForOnSurrealDbBlocksDependentResources()
var dependentResource = builder.AddSurrealServer("dependentresource")
.WaitFor(resource);
- using var app = builder.Build();
+ await using var app = builder.Build();
var pendingStart = app.StartAsync(cts.Token);
@@ -244,7 +254,7 @@ public async Task VerifyWaitForOnSurrealDbBlocksDependentResources()
await pendingStart;
- await app.StopAsync();
+ await app.StopAsync(cts.Token);
}
[Fact(Skip = "Feature is unstable and blocking the release")]
@@ -278,8 +288,8 @@ await File.WriteAllTextAsync(
""",
cts.Token
);
-
- using var builder = TestDistributedApplicationBuilder.Create(testOutputHelper);
+
+ await using var builder = TestDistributedApplicationBuilder.Create(testOutputHelper);
#pragma warning disable CTASPIRE002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var surrealServer = builder
@@ -289,8 +299,8 @@ await File.WriteAllTextAsync(
var ns = surrealServer.AddNamespace(surrealNsName);
var db = ns.AddDatabase(surrealDbName);
-
- using var app = builder.Build();
+
+ await using var app = builder.Build();
await app.StartAsync(cts.Token);
@@ -316,7 +326,7 @@ await File.WriteAllTextAsync(
await pipeline.ExecuteAsync(async token =>
{
- var client = host.Services.GetRequiredService();
+ await using var client = host.Services.GetRequiredService();
var cars = (await client.Select(Car.Table, token)).ToList();
var car = Assert.Single(cars);
@@ -346,7 +356,7 @@ public async Task AddDatabaseCreatesDatabaseWithCustomScript()
var surrealNsName = "ns1";
var surrealDbName = "db1";
- var surreal = builder.AddSurrealServer("surreal", strictMode: true);
+ var surreal = builder.AddSurrealServer("surreal");
#pragma warning disable CTASPIRE002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var db = surreal
@@ -358,9 +368,9 @@ public async Task AddDatabaseCreatesDatabaseWithCustomScript()
USE DATABASE {surrealDbName};
DEFINE TABLE todo;
- DEFINE FIELD Title ON todo TYPE string;
- DEFINE FIELD DueBy ON todo TYPE datetime;
- DEFINE FIELD IsComplete ON todo TYPE bool;
+ DEFINE FIELD title ON todo TYPE string;
+ DEFINE FIELD due_by ON todo TYPE datetime;
+ DEFINE FIELD is_complete ON todo TYPE bool;
"""
);
#pragma warning restore CTASPIRE002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
@@ -381,23 +391,24 @@ public async Task AddDatabaseCreatesDatabaseWithCustomScript()
await app.ResourceNotifications.WaitForResourceHealthyAsync(db.Resource.Name, cts.Token);
- await using var client = host.Services.GetRequiredService();
+ await using var scope = host.Services.CreateAsyncScope();
+ await using var client = scope.ServiceProvider.GetRequiredService();
await CreateTestData(client, cts.Token);
await AssertTestData(client, cts.Token);
}
- private static async Task CreateTestData(SurrealDbClient surrealDbClient, CancellationToken ct)
+ private static async Task CreateTestData(SurrealDbSession client, CancellationToken ct)
{
- await surrealDbClient.Insert(Todo.Table, _todoList, ct);
+ await client.Insert(Todo.Table, _todoList, ct);
}
- private static async Task AssertTestData(SurrealDbClient surrealDbClient, CancellationToken ct)
+ private static async Task AssertTestData(SurrealDbSession client, CancellationToken ct)
{
- var records = await surrealDbClient.Select(Todo.Table, ct);
+ var records = await client.Select(Todo.Table, ct);
Assert.Equal(_generatedTodoCount, records.Count());
- var firstRecord = await surrealDbClient.Select((Todo.Table, "1"), ct);
+ var firstRecord = await client.Select((Todo.Table, "1"), ct);
Assert.NotNull(firstRecord);
Assert.Equivalent(firstRecord, _todoList[0]);
}
@@ -406,8 +417,13 @@ private sealed class Todo : SurrealRecord
{
internal const string Table = "todo";
+ [Column("title")]
public string? Title { get; set; }
+
+ [Column("due_by")]
public DateOnly? DueBy { get; set; } = null;
+
+ [Column("is_complete")]
public bool IsComplete { get; set; } = false;
}
@@ -425,6 +441,7 @@ private sealed class Car : SurrealRecord
{
internal const string Table = "car";
+ [Column("brand")]
public string Brand { get; set; } = string.Empty;
}
}
\ No newline at end of file
diff --git a/tests/CommunityToolkit.Aspire.SurrealDb.Tests/AspireSurrealClientExtensionsTest.cs b/tests/CommunityToolkit.Aspire.SurrealDb.Tests/AspireSurrealClientExtensionsTest.cs
index bbb8c6e2c..eb8548ba1 100644
--- a/tests/CommunityToolkit.Aspire.SurrealDb.Tests/AspireSurrealClientExtensionsTest.cs
+++ b/tests/CommunityToolkit.Aspire.SurrealDb.Tests/AspireSurrealClientExtensionsTest.cs
@@ -97,15 +97,25 @@ public void CanAddMultipleKeyedServices()
builder.AddKeyedSurrealClient("surreal2");
builder.AddKeyedSurrealClient("surreal3");
- using var host = builder.Build();
+ var host = builder.Build();
- var client1 = host.Services.GetRequiredService();
- var client2 = host.Services.GetRequiredKeyedService("surreal2");
- var client3 = host.Services.GetRequiredKeyedService("surreal3");
+ var client1 = host.Services.GetRequiredService();
+ var client2 = host.Services.GetRequiredKeyedService("surreal2");
+ var client3 = host.Services.GetRequiredKeyedService("surreal3");
Assert.NotSame(client1, client2);
Assert.NotSame(client1, client3);
Assert.NotSame(client2, client3);
+
+ try
+ {
+ host.Dispose();
+ }
+ catch
+ {
+ // ignored
+ // Failed to be disposed on unknown server
+ }
}
[Fact]
@@ -121,12 +131,22 @@ public void CanAddClientFromEncodedConnectionString()
builder.AddSurrealClient("surreal1");
builder.AddKeyedSurrealClient("surreal2");
- using var host = builder.Build();
+ var host = builder.Build();
- var client1 = host.Services.GetRequiredService();
- var client2 = host.Services.GetRequiredKeyedService("surreal2");
+ var client1 = host.Services.GetRequiredService();
+ var client2 = host.Services.GetRequiredKeyedService("surreal2");
Assert.NotSame(client1, client2);
+
+ try
+ {
+ host.Dispose();
+ }
+ catch
+ {
+ // ignored
+ // Failed to be disposed on unknown server
+ }
}
private static HostApplicationBuilder CreateBuilder(string connectionString)
diff --git a/tests/CommunityToolkit.Aspire.SurrealDb.Tests/ConfigurationTests.cs b/tests/CommunityToolkit.Aspire.SurrealDb.Tests/ConfigurationTests.cs
index 162d09f97..97cd6f042 100644
--- a/tests/CommunityToolkit.Aspire.SurrealDb.Tests/ConfigurationTests.cs
+++ b/tests/CommunityToolkit.Aspire.SurrealDb.Tests/ConfigurationTests.cs
@@ -14,6 +14,6 @@ public void OptionsAreNullByDefault() =>
Assert.Null(new SurrealDbClientSettings().Options);
[Fact]
- public void LifetimeIsSingletonByDefault() =>
- Assert.Equal(ServiceLifetime.Singleton, new SurrealDbClientSettings().Lifetime);
+ public void LifetimeIsScopedByDefault() =>
+ Assert.Equal(ServiceLifetime.Scoped, new SurrealDbClientSettings().Lifetime);
}
diff --git a/tests/CommunityToolkit.Aspire.SurrealDb.Tests/ConformanceTests.cs b/tests/CommunityToolkit.Aspire.SurrealDb.Tests/ConformanceTests.cs
index 1d170ce32..110103e7e 100644
--- a/tests/CommunityToolkit.Aspire.SurrealDb.Tests/ConformanceTests.cs
+++ b/tests/CommunityToolkit.Aspire.SurrealDb.Tests/ConformanceTests.cs
@@ -15,12 +15,12 @@ public class ConformanceCollection;
[Collection("Conformance")]
public class ConformanceTests :
- ConformanceTests,
+ ConformanceTests,
IClassFixture
{
private readonly SurrealDbContainerFixture _containerFixture;
- protected override ServiceLifetime ServiceLifetime => ServiceLifetime.Singleton;
+ protected override ServiceLifetime ServiceLifetime => ServiceLifetime.Scoped;
protected override string ActivitySourceName => string.Empty;
@@ -104,7 +104,7 @@ protected override void SetTracing(SurrealDbClientSettings options, bool enabled
throw new NotImplementedException();
}
- protected override void TriggerActivity(SurrealDbClient service)
+ protected override void TriggerActivity(SurrealDbSession service)
{
using var source = new CancellationTokenSource(100);
diff --git a/tests/CommunityToolkit.Aspire.Testing/CommunityToolkit.Aspire.Testing.csproj b/tests/CommunityToolkit.Aspire.Testing/CommunityToolkit.Aspire.Testing.csproj
index b0251f810..f48b2b9af 100644
--- a/tests/CommunityToolkit.Aspire.Testing/CommunityToolkit.Aspire.Testing.csproj
+++ b/tests/CommunityToolkit.Aspire.Testing/CommunityToolkit.Aspire.Testing.csproj
@@ -1,4 +1,4 @@
-
+
false
diff --git a/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs b/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs
index 13e8441a8..bd4446459 100644
--- a/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs
+++ b/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs
@@ -176,7 +176,7 @@ public void MetricsRegistersMeterProvider(bool enabled)
[Theory]
[InlineData(true)]
[InlineData(false)]
- public void ServiceLifetimeIsAsExpected(bool useKey)
+ public async Task ServiceLifetimeIsAsExpected(bool useKey)
{
SkipIfRequiredServerConnectionCanNotBeEstablished();
SkipIfKeyedRegistrationIsNotSupported(useKey);
@@ -186,18 +186,31 @@ public void ServiceLifetimeIsAsExpected(bool useKey)
using IHost host = CreateHostWithComponent(key: key);
- using (IServiceScope scope1 = host.Services.CreateScope())
+ if (typeof(IAsyncDisposable).IsAssignableFrom(typeof(TService)))
{
- serviceFromFirstScope = Resolve(scope1.ServiceProvider, key);
+ await using (AsyncServiceScope scope1 = host.Services.CreateAsyncScope())
+ {
+ serviceFromFirstScope = Resolve(scope1.ServiceProvider, key);
+ }
+ await using (AsyncServiceScope scope2 = host.Services.CreateAsyncScope())
+ {
+ serviceFromSecondScope = Resolve(scope2.ServiceProvider, key);
+ secondServiceFromSecondScope = Resolve(scope2.ServiceProvider, key);
+ }
}
-
- using (IServiceScope scope2 = host.Services.CreateScope())
+ else
{
- serviceFromSecondScope = Resolve(scope2.ServiceProvider, key);
-
- secondServiceFromSecondScope = Resolve(scope2.ServiceProvider, key);
+ using (IServiceScope scope1 = host.Services.CreateScope())
+ {
+ serviceFromFirstScope = Resolve(scope1.ServiceProvider, key);
+ }
+ using (IServiceScope scope2 = host.Services.CreateScope())
+ {
+ serviceFromSecondScope = Resolve(scope2.ServiceProvider, key);
+ secondServiceFromSecondScope = Resolve(scope2.ServiceProvider, key);
+ }
}
-
+
Assert.NotNull(serviceFromFirstScope);
Assert.NotNull(serviceFromSecondScope);
Assert.NotNull(secondServiceFromSecondScope);
@@ -285,7 +298,7 @@ public void LoggerFactoryIsUsedByRegisteredClient(bool registerAfterLoggerFactor
builder.Services.AddSingleton();
}
- using IHost host = builder.Build();
+ IHost host = builder.Build();
TService service = key is null
? host.Services.GetRequiredService()
@@ -307,6 +320,15 @@ public void LoggerFactoryIsUsedByRegisteredClient(bool registerAfterLoggerFactor
{
Assert.DoesNotContain(logCategory, loggerFactory.Categories);
}
+
+ try
+ {
+ host.Dispose();
+ }
+ catch
+ {
+ // ignored
+ }
}
[Theory]