5
5
using CommunityToolkit . Aspire . SurrealDb ;
6
6
using Microsoft . Extensions . DependencyInjection ;
7
7
using Microsoft . Extensions . Diagnostics . HealthChecks ;
8
+ using Microsoft . Extensions . Logging ;
8
9
using SurrealDb . Net ;
9
10
using System . Text ;
10
11
using System . Text . Json ;
@@ -80,6 +81,7 @@ public static IResourceBuilder<SurrealDbServerResource> AddSurrealServer(
80
81
: SurrealDbContainerImageTags . Tag ;
81
82
82
83
var surrealServer = new SurrealDbServerResource ( name , userName ? . Resource , passwordParameter ) ;
84
+
83
85
return builder . AddResource ( surrealServer )
84
86
. WithEndpoint ( port : port , targetPort : SurrealDbPort , name : SurrealDbServerResource . PrimaryEndpointName )
85
87
. WithImage ( SurrealDbContainerImageTags . Image , imageTag )
@@ -90,7 +92,47 @@ public static IResourceBuilder<SurrealDbServerResource> AddSurrealServer(
90
92
context . EnvironmentVariables [ PasswordEnvVarName ] = surrealServer . PasswordParameter ;
91
93
} )
92
94
. WithEntrypoint ( "/surreal" )
93
- . WithArgs ( [ .. args ] ) ;
95
+ . WithArgs ( [ .. args ] )
96
+ . OnResourceReady ( async ( _ , @event , ct ) =>
97
+ {
98
+ if ( ! strictMode )
99
+ {
100
+ return ;
101
+ }
102
+
103
+ var connectionString = await surrealServer . GetConnectionStringAsync ( ct ) . ConfigureAwait ( false ) ;
104
+ if ( connectionString is null )
105
+ {
106
+ throw new DistributedApplicationException ( $ "ResourceReadyEvent was published for the '{ surrealServer . Name } ' resource but the connection string was null.") ;
107
+ }
108
+
109
+ var options = new SurrealDbOptionsBuilder ( ) . FromConnectionString ( connectionString ) . Build ( ) ;
110
+ await using var surrealClient = new SurrealDbClient ( options ) ;
111
+
112
+ foreach ( var nsResourceName in surrealServer . Namespaces . Keys )
113
+ {
114
+ if ( builder . Resources . FirstOrDefault ( n =>
115
+ string . Equals ( n . Name , nsResourceName , StringComparison . OrdinalIgnoreCase ) ) is
116
+ SurrealDbNamespaceResource surrealDbNamespace )
117
+ {
118
+ await CreateNamespaceAsync ( surrealClient , surrealDbNamespace , @event . Services , ct )
119
+ . ConfigureAwait ( false ) ;
120
+
121
+ await surrealClient . Use ( surrealDbNamespace . NamespaceName , null ! , ct ) . ConfigureAwait ( false ) ;
122
+
123
+ foreach ( var dbResourceName in surrealDbNamespace . Databases . Keys )
124
+ {
125
+ if ( builder . Resources . FirstOrDefault ( n =>
126
+ string . Equals ( n . Name , dbResourceName , StringComparison . OrdinalIgnoreCase ) ) is
127
+ SurrealDbDatabaseResource surrealDbDatabase )
128
+ {
129
+ await CreateDatabaseAsync ( surrealClient , surrealDbDatabase , @event . Services , ct )
130
+ . ConfigureAwait ( false ) ;
131
+ }
132
+ }
133
+ }
134
+ }
135
+ } ) ;
94
136
}
95
137
96
138
/// <summary>
@@ -132,6 +174,25 @@ public static IResourceBuilder<SurrealDbNamespaceResource> AddNamespace(
132
174
var surrealServerNamespace = new SurrealDbNamespaceResource ( name , namespaceName , builder . Resource ) ;
133
175
return builder . ApplicationBuilder . AddResource ( surrealServerNamespace ) ;
134
176
}
177
+
178
+ /// <summary>
179
+ /// Defines the SQL script used to create the namespace.
180
+ /// </summary>
181
+ /// <param name="builder">The builder for the <see cref="SurrealDbNamespaceResource"/>.</param>
182
+ /// <param name="script">The SQL script used to create the namespace.</param>
183
+ /// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
184
+ /// <remarks>
185
+ /// <value>Default script is <code>DEFINE NAMESPACE IF NOT EXISTS `QUOTED_NAMESPACE_NAME`;</code></value>
186
+ /// </remarks>
187
+ public static IResourceBuilder < SurrealDbNamespaceResource > WithCreationScript ( this IResourceBuilder < SurrealDbNamespaceResource > builder , string script )
188
+ {
189
+ ArgumentNullException . ThrowIfNull ( builder ) ;
190
+ ArgumentNullException . ThrowIfNull ( script ) ;
191
+
192
+ builder . WithAnnotation ( new SurrealDbCreateNamespaceScriptAnnotation ( script ) ) ;
193
+
194
+ return builder ;
195
+ }
135
196
136
197
/// <summary>
137
198
/// Adds a SurrealDB database to the application model. This is a child resource of a <see cref="SurrealDbNamespaceResource"/>.
@@ -202,6 +263,25 @@ public static IResourceBuilder<SurrealDbDatabaseResource> AddDatabase(
202
263
return builder . ApplicationBuilder . AddResource ( surrealServerDatabase )
203
264
. WithHealthCheck ( healthCheckKey ) ;
204
265
}
266
+
267
+ /// <summary>
268
+ /// Defines the SQL script used to create the database.
269
+ /// </summary>
270
+ /// <param name="builder">The builder for the <see cref="SurrealDbDatabaseResource"/>.</param>
271
+ /// <param name="script">The SQL script used to create the database.</param>
272
+ /// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
273
+ /// <remarks>
274
+ /// <value>Default script is <code>DEFINE DATABASE IF NOT EXISTS `QUOTED_DATABASE_NAME`;</code></value>
275
+ /// </remarks>
276
+ public static IResourceBuilder < SurrealDbDatabaseResource > WithCreationScript ( this IResourceBuilder < SurrealDbDatabaseResource > builder , string script )
277
+ {
278
+ ArgumentNullException . ThrowIfNull ( builder ) ;
279
+ ArgumentNullException . ThrowIfNull ( script ) ;
280
+
281
+ builder . WithAnnotation ( new SurrealDbCreateDatabaseScriptAnnotation ( script ) ) ;
282
+
283
+ return builder ;
284
+ }
205
285
206
286
/// <summary>
207
287
/// Adds a named volume for the data folder to a SurrealDB resource.
@@ -447,4 +527,62 @@ CancellationToken cancellationToken
447
527
448
528
return Encoding . UTF8 . GetString ( stream . ToArray ( ) ) ;
449
529
}
530
+
531
+ private static async Task CreateNamespaceAsync (
532
+ SurrealDbClient surrealClient ,
533
+ SurrealDbNamespaceResource namespaceResource ,
534
+ IServiceProvider serviceProvider ,
535
+ CancellationToken cancellationToken
536
+ )
537
+ {
538
+ var scriptAnnotation = namespaceResource . Annotations . OfType < SurrealDbCreateNamespaceScriptAnnotation > ( ) . LastOrDefault ( ) ;
539
+
540
+ var logger = serviceProvider . GetRequiredService < ResourceLoggerService > ( ) . GetLogger ( namespaceResource . Parent ) ;
541
+ logger . LogDebug ( "Creating namespace '{NamespaceName}'" , namespaceResource . NamespaceName ) ;
542
+
543
+ try
544
+ {
545
+ var response = await surrealClient . RawQuery (
546
+ scriptAnnotation ? . Script ?? $ "DEFINE NAMESPACE IF NOT EXISTS `{ namespaceResource . NamespaceName } `;",
547
+ cancellationToken : cancellationToken
548
+ ) . ConfigureAwait ( false ) ;
549
+
550
+ response . EnsureAllOks ( ) ;
551
+
552
+ logger . LogDebug ( "Namespace '{NamespaceName}' created successfully" , namespaceResource . NamespaceName ) ;
553
+ }
554
+ catch ( Exception e )
555
+ {
556
+ logger . LogError ( e , "Failed to create namespace '{NamespaceName}'" , namespaceResource . NamespaceName ) ;
557
+ }
558
+ }
559
+
560
+ private static async Task CreateDatabaseAsync (
561
+ SurrealDbClient surrealClient ,
562
+ SurrealDbDatabaseResource databaseResource ,
563
+ IServiceProvider serviceProvider ,
564
+ CancellationToken cancellationToken
565
+ )
566
+ {
567
+ var scriptAnnotation = databaseResource . Annotations . OfType < SurrealDbCreateDatabaseScriptAnnotation > ( ) . LastOrDefault ( ) ;
568
+
569
+ var logger = serviceProvider . GetRequiredService < ResourceLoggerService > ( ) . GetLogger ( databaseResource . Parent . Parent ) ;
570
+ logger . LogDebug ( "Creating database '{DatabaseName}'" , databaseResource . DatabaseName ) ;
571
+
572
+ try
573
+ {
574
+ var response = await surrealClient . RawQuery (
575
+ scriptAnnotation ? . Script ?? $ "DEFINE DATABASE IF NOT EXISTS `{ databaseResource . DatabaseName } `;",
576
+ cancellationToken : cancellationToken
577
+ ) . ConfigureAwait ( false ) ;
578
+
579
+ response . EnsureAllOks ( ) ;
580
+
581
+ logger . LogDebug ( "Database '{DatabaseName}' created successfully" , databaseResource . DatabaseName ) ;
582
+ }
583
+ catch ( Exception e )
584
+ {
585
+ logger . LogError ( e , "Failed to create database '{DatabaseName}'" , databaseResource . DatabaseName ) ;
586
+ }
587
+ }
450
588
}
0 commit comments