Skip to content

Commit

Permalink
refactor: split code by using SurrealDbNamespaceResource
Browse files Browse the repository at this point in the history
  • Loading branch information
Odonno committed Sep 23, 2024
1 parent c6b29ff commit ae54aed
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 76 deletions.
16 changes: 11 additions & 5 deletions src/Aspire.Hosting.SurrealDb/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@
Aspire.Hosting.ApplicationModel.SurrealDbDatabaseResource
Aspire.Hosting.ApplicationModel.SurrealDbDatabaseResource.ConnectionStringExpression.get -> Aspire.Hosting.ApplicationModel.ReferenceExpression!
Aspire.Hosting.ApplicationModel.SurrealDbDatabaseResource.DatabaseName.get -> string!
Aspire.Hosting.ApplicationModel.SurrealDbDatabaseResource.NamespaceName.get -> string!
Aspire.Hosting.ApplicationModel.SurrealDbDatabaseResource.Parent.get -> Aspire.Hosting.ApplicationModel.SurrealDbServerResource!
Aspire.Hosting.ApplicationModel.SurrealDbDatabaseResource.SurrealDbDatabaseResource(string! name, string! namespaceName, string! databaseName, Aspire.Hosting.ApplicationModel.SurrealDbServerResource! parent) -> void
Aspire.Hosting.ApplicationModel.SurrealDbDatabaseResource.Parent.get -> Aspire.Hosting.ApplicationModel.SurrealDbNamespaceResource!
Aspire.Hosting.ApplicationModel.SurrealDbDatabaseResource.SurrealDbDatabaseResource(string! name, string! databaseName, Aspire.Hosting.ApplicationModel.SurrealDbNamespaceResource! parent) -> void
Aspire.Hosting.ApplicationModel.SurrealDbNamespaceResource
Aspire.Hosting.ApplicationModel.SurrealDbNamespaceResource.ConnectionStringExpression.get -> Aspire.Hosting.ApplicationModel.ReferenceExpression!
Aspire.Hosting.ApplicationModel.SurrealDbNamespaceResource.Databases.get -> System.Collections.Generic.IReadOnlyDictionary<string!, string!>!
Aspire.Hosting.ApplicationModel.SurrealDbNamespaceResource.NamespaceName.get -> string!
Aspire.Hosting.ApplicationModel.SurrealDbNamespaceResource.Parent.get -> Aspire.Hosting.ApplicationModel.SurrealDbServerResource!
Aspire.Hosting.ApplicationModel.SurrealDbNamespaceResource.SurrealDbNamespaceResource(string! name, string! namespaceName, Aspire.Hosting.ApplicationModel.SurrealDbServerResource! parent) -> void
Aspire.Hosting.ApplicationModel.SurrealDbServerResource
Aspire.Hosting.ApplicationModel.SurrealDbServerResource.ConnectionStringExpression.get -> Aspire.Hosting.ApplicationModel.ReferenceExpression!
Aspire.Hosting.ApplicationModel.SurrealDbServerResource.Databases.get -> System.Collections.Generic.IReadOnlyDictionary<string!, (string!, string!)>!
Aspire.Hosting.ApplicationModel.SurrealDbServerResource.GetConnectionStringAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<string?>
Aspire.Hosting.ApplicationModel.SurrealDbServerResource.Namespaces.get -> System.Collections.Generic.IReadOnlyDictionary<string!, string!>!
Aspire.Hosting.ApplicationModel.SurrealDbServerResource.PasswordParameter.get -> Aspire.Hosting.ApplicationModel.ParameterResource!
Aspire.Hosting.ApplicationModel.SurrealDbServerResource.PrimaryEndpoint.get -> Aspire.Hosting.ApplicationModel.EndpointReference!
Aspire.Hosting.ApplicationModel.SurrealDbServerResource.SurrealDbServerResource(string! name, Aspire.Hosting.ApplicationModel.ParameterResource? userName, Aspire.Hosting.ApplicationModel.ParameterResource! password) -> void
Aspire.Hosting.ApplicationModel.SurrealDbServerResource.UserNameParameter.get -> Aspire.Hosting.ApplicationModel.ParameterResource?
Aspire.Hosting.SurrealDbBuilderExtensions
static Aspire.Hosting.SurrealDbBuilderExtensions.AddDatabase(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.SurrealDbServerResource!>! builder, string! name, string! namespaceName = "test", string! databaseName = "test") -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.SurrealDbDatabaseResource!>!
static Aspire.Hosting.SurrealDbBuilderExtensions.AddDatabase(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.SurrealDbNamespaceResource!>! builder, string! name, string? databaseName = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.SurrealDbDatabaseResource!>!
static Aspire.Hosting.SurrealDbBuilderExtensions.AddNamespace(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.SurrealDbServerResource!>! builder, string! name, string? namespaceName = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.SurrealDbNamespaceResource!>!
static Aspire.Hosting.SurrealDbBuilderExtensions.AddSurrealServer(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.ParameterResource!>? userName = null, Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.ParameterResource!>? password = null, int? port = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.SurrealDbServerResource!>!
static Aspire.Hosting.SurrealDbBuilderExtensions.WithDataBindMount(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.SurrealDbServerResource!>! builder, string! source, bool isReadOnly = false) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.SurrealDbServerResource!>!
static Aspire.Hosting.SurrealDbBuilderExtensions.WithDataVolume(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.SurrealDbServerResource!>! builder, string? name = null, bool isReadOnly = false) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.SurrealDbServerResource!>!
5 changes: 4 additions & 1 deletion src/Aspire.Hosting.SurrealDb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@ dotnet add package Aspire.Hosting.SurrealDb
Then, in the _Program.cs_ file of `AppHost`, add a SurrealDB resource and consume the connection using the following methods:

```csharp
var db = builder.AddSurrealServer("surreal").AddDatabase("db");
var db = builder.AddSurrealServer("surreal")
.AddNamespace("ns")
.AddDatabase("db");

var myService = builder.AddProject<Projects.MyService>()
.WithReference(db);
```

## Additional documentation

https://learn.microsoft.com/dotnet/aspire/database/surrealdb-component

## Feedback & contributing
Expand Down
51 changes: 44 additions & 7 deletions src/Aspire.Hosting.SurrealDb/SurrealDbBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,61 @@ public static IResourceBuilder<SurrealDbServerResource> AddSurrealServer(
context.EnvironmentVariables[PasswordEnvVarName] = surrealServer.PasswordParameter;
})
.WithEntrypoint("/surreal")
.WithArgs("start", "--auth");
.WithArgs("start");
}

/// <summary>
/// Adds a SurrealDB database to the application model. This is a child resource of a <see cref="SurrealDbServerResource"/>.
/// Adds a SurrealDB namespace to the application model. This is a child resource of a <see cref="SurrealDbServerResource"/>.
/// </summary>
/// <param name="builder">The SurrealDB resource builders.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="namespaceName">The name of the namespace. If not provided, this defaults to "test".</param>
/// <param name="databaseName">The name of the database. If not provided, this defaults to "test".</param>
/// <param name="namespaceName">The name of the namespace. If not provided, this defaults to the same value as <paramref name="name"/>.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<SurrealDbDatabaseResource> AddDatabase(this IResourceBuilder<SurrealDbServerResource> builder, string name, string namespaceName = "test", string databaseName = "test")
public static IResourceBuilder<SurrealDbNamespaceResource> AddNamespace(this IResourceBuilder<SurrealDbServerResource> builder, string name, string? namespaceName = null)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentException.ThrowIfNullOrEmpty(name);

builder.Resource.AddDatabase(name, namespaceName, databaseName);
var surrealServerDatabase = new SurrealDbDatabaseResource(name, namespaceName, databaseName, builder.Resource);
// Use the resource name as the namespace name if it's not provided
namespaceName ??= name;

builder.Resource.AddNamespace(name, namespaceName);
var surrealServerNamespace = new SurrealDbNamespaceResource(name, namespaceName, builder.Resource);
return builder.ApplicationBuilder.AddResource(surrealServerNamespace);
}

/// <summary>
/// Adds a SurrealDB database to the application model. This is a child resource of a <see cref="SurrealDbNamespaceResource"/>.
/// </summary>
/// <param name="builder">The SurrealDB resource builders.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="databaseName">The name of the database. If not provided, this defaults to the same value as <paramref name="name"/>.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<SurrealDbDatabaseResource> AddDatabase(this IResourceBuilder<SurrealDbNamespaceResource> builder, string name, string? databaseName = null)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentException.ThrowIfNullOrEmpty(name);

// Use the resource name as the database name if it's not provided
databaseName ??= name;

builder.Resource.AddDatabase(name, databaseName);
var surrealServerDatabase = new SurrealDbDatabaseResource(name, databaseName, builder.Resource);

string? connectionString = null;

builder.ApplicationBuilder.Eventing.Subscribe<ConnectionStringAvailableEvent>(surrealServerDatabase, async (@event, ct) =>
{
connectionString = await surrealServerDatabase.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false);
if (connectionString == null)
{
throw new DistributedApplicationException($"ConnectionStringAvailableEvent was published for the '{surrealServerDatabase}' resource but the connection string was null.");
}
});

// TODO : Add HealthChecks, waiting for https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks/pull/2047

return builder.ApplicationBuilder.AddResource(surrealServerDatabase);
}

Expand Down
22 changes: 7 additions & 15 deletions src/Aspire.Hosting.SurrealDb/SurrealDbDatabaseResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,20 @@
namespace Aspire.Hosting.ApplicationModel;

/// <summary>
/// A resource that represents a SurrealDB database that is a child of a SurrealDB container resource.
/// A resource that represents a SurrealDB database that is a child of a SurrealDB namespace resource.
/// </summary>
public class SurrealDbDatabaseResource : Resource, IResourceWithParent<SurrealDbServerResource>, IResourceWithConnectionString
public class SurrealDbDatabaseResource : Resource, IResourceWithParent<SurrealDbNamespaceResource>, IResourceWithConnectionString
{
/// <summary>
/// Gets the parent SurrealDB container resource.
/// Gets the parent SurrealDB namespace resource.
/// </summary>
public SurrealDbServerResource Parent { get; }
public SurrealDbNamespaceResource Parent { get; }

/// <summary>
/// Gets the connection string expression for the SurrealDB database.
/// </summary>
public ReferenceExpression ConnectionStringExpression =>
ReferenceExpression.Create($"{Parent};Namespace={NamespaceName};Database={DatabaseName}");

/// <summary>
/// Gets the namespace name.
/// </summary>
public string NamespaceName { get; }
ReferenceExpression.Create($"{Parent};Database={DatabaseName}");

/// <summary>
/// Gets the database name.
Expand All @@ -33,16 +28,13 @@ public class SurrealDbDatabaseResource : Resource, IResourceWithParent<SurrealDb
/// Initializes a new instance of the <see cref="SurrealDbDatabaseResource"/> class.
/// </summary>
/// <param name="name">The name of the resource.</param>
/// <param name="namespaceName">The namespace name.</param>
/// <param name="databaseName">The database name.</param>
/// <param name="parent">The parent SQL Server server resource.</param>
public SurrealDbDatabaseResource(string name, string namespaceName, string databaseName, SurrealDbServerResource parent) : base(name)
/// <param name="parent">The parent SurrealDB namespace resource.</param>
public SurrealDbDatabaseResource(string name, string databaseName, SurrealDbNamespaceResource parent) : base(name)
{
ArgumentException.ThrowIfNullOrEmpty(namespaceName);
ArgumentException.ThrowIfNullOrEmpty(databaseName);
ArgumentNullException.ThrowIfNull(parent);

NamespaceName = namespaceName;
DatabaseName = databaseName;
Parent = parent;
}
Expand Down
53 changes: 53 additions & 0 deletions src/Aspire.Hosting.SurrealDb/SurrealDbNamespaceResource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Aspire.Hosting.ApplicationModel;

/// <summary>
/// A resource that represents a SurrealDB namespace that is a child of a SurrealDB container resource.
/// </summary>
public class SurrealDbNamespaceResource : Resource, IResourceWithParent<SurrealDbServerResource>, IResourceWithConnectionString
{
/// <summary>
/// Gets the parent SurrealDB container resource.
/// </summary>
public SurrealDbServerResource Parent { get; }

/// <summary>
/// Gets the connection string expression for the SurrealDB database.
/// </summary>
public ReferenceExpression ConnectionStringExpression =>
ReferenceExpression.Create($"{Parent};Namespace={NamespaceName}");

/// <summary>
/// Gets the namespace name.
/// </summary>
public string NamespaceName { get; }

/// <summary>
/// Initializes a new instance of the <see cref="SurrealDbNamespaceResource"/> class.
/// </summary>
/// <param name="name">The name of the resource.</param>
/// <param name="namespaceName">The namespace name.</param>
/// <param name="parent">The parent SurrealDB server resource.</param>
public SurrealDbNamespaceResource(string name, string namespaceName, SurrealDbServerResource parent) : base(name)
{
ArgumentException.ThrowIfNullOrEmpty(namespaceName);
ArgumentNullException.ThrowIfNull(parent);

NamespaceName = namespaceName;
Parent = parent;
}

private readonly Dictionary<string, string> _databases = new(StringComparer.Ordinal);

/// <summary>
/// A dictionary where the key is the resource name and the value is the database name.
/// </summary>
public IReadOnlyDictionary<string, string> Databases => _databases;

internal void AddDatabase(string name, string databaseName)
{
_databases.TryAdd(name, databaseName);
}
}
10 changes: 5 additions & 5 deletions src/Aspire.Hosting.SurrealDb/SurrealDbServerResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,15 @@ public ReferenceExpression ConnectionStringExpression
return ConnectionString.GetValueAsync(cancellationToken);
}

private readonly Dictionary<string, (string, string)> _databases = new(StringComparer.Ordinal);
private readonly Dictionary<string, string> _namespaces = new(StringComparer.Ordinal);

/// <summary>
/// A dictionary where the key is the resource name and the value is the pair (namespace name, database name).
/// A dictionary where the key is the resource name and the value is the namespace name.
/// </summary>
public IReadOnlyDictionary<string, (string, string)> Databases => _databases;
public IReadOnlyDictionary<string, string> Namespaces => _namespaces;

internal void AddDatabase(string name, string namespaceName, string databaseName)
internal void AddNamespace(string name, string namespaceName)
{
_databases.TryAdd(name, (namespaceName, databaseName));
_namespaces.TryAdd(name, namespaceName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,12 @@ public void CtorSqlServerDatabaseResourceShouldThrowWhenDatabaseNameIsEmpty()
var distributedApplicationBuilder = DistributedApplication.CreateBuilder([]);

string name = "sqlserver";
string databaseName = null!;
string databaseName = "";
var password = ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(distributedApplicationBuilder, "password", special: false);
var parent = new SqlServerServerResource("sqlserver", password);
var action = () => new SqlServerDatabaseResource(name, databaseName, parent);

var exception = Assert.Throws<ArgumentNullException>(action);
var exception = Assert.Throws<ArgumentException>(action);
Assert.Equal(nameof(databaseName), exception.ParamName);
}

Expand Down
Loading

0 comments on commit ae54aed

Please sign in to comment.