55using  CommunityToolkit . Aspire . SurrealDb ; 
66using  Microsoft . Extensions . DependencyInjection ; 
77using  Microsoft . Extensions . Diagnostics . HealthChecks ; 
8+ using  Microsoft . Extensions . Logging ; 
89using  SurrealDb . Net ; 
10+ using  SurrealDb . Net . Models . Response ; 
911using  System . Text ; 
1012using  System . Text . Json ; 
1113
@@ -80,6 +82,59 @@ public static IResourceBuilder<SurrealDbServerResource> AddSurrealServer(
8082            :  SurrealDbContainerImageTags . Tag ; 
8183
8284        var  surrealServer  =  new  SurrealDbServerResource ( name ,  userName ? . Resource ,  passwordParameter ) ; 
85+         
86+         string ?  connectionString  =  null ; 
87+ 
88+         builder . Eventing . Subscribe < ConnectionStringAvailableEvent > ( surrealServer ,  async  ( _ ,  ct )  => 
89+         { 
90+             connectionString  =  await  surrealServer . GetConnectionStringAsync ( ct ) . ConfigureAwait ( false ) ; 
91+ 
92+             if  ( connectionString  ==  null ) 
93+             { 
94+                 throw  new  DistributedApplicationException ( $ "ConnectionStringAvailableEvent was published for the '{ surrealServer . Name } ' resource but the connection string was null.") ; 
95+             } 
96+         } ) ; 
97+ 
98+         builder . Eventing . Subscribe < ResourceReadyEvent > ( surrealServer ,  async  ( @event ,  ct )  => 
99+         { 
100+             if  ( connectionString  is  null ) 
101+             { 
102+                 throw  new  DistributedApplicationException ( $ "ResourceReadyEvent was published for the '{ surrealServer . Name } ' resource but the connection string was null.") ; 
103+             } 
104+ 
105+             if  ( ! strictMode ) 
106+             { 
107+                 return ; 
108+             } 
109+ 
110+             var  options  =  new  SurrealDbOptionsBuilder ( ) . FromConnectionString ( connectionString ) . Build ( ) ; 
111+             await  using  var  surrealClient  =  new  SurrealDbClient ( options ) ; 
112+ 
113+             foreach  ( var  nsResourceName  in  surrealServer . Namespaces . Keys ) 
114+             { 
115+                 if  ( builder . Resources . FirstOrDefault ( n => 
116+                         string . Equals ( n . Name ,  nsResourceName ,  StringComparison . OrdinalIgnoreCase ) )  is 
117+                     SurrealDbNamespaceResource  surrealDbNamespace ) 
118+                 { 
119+                     await  CreateNamespaceAsync ( surrealClient ,  surrealDbNamespace ,  @event . Services ,  ct ) 
120+                         . ConfigureAwait ( false ) ; 
121+                 
122+                     await  surrealClient . Use ( surrealDbNamespace . NamespaceName ,  null ! ,  ct ) . ConfigureAwait ( false ) ; 
123+ 
124+                     foreach  ( var  dbResourceName  in  surrealDbNamespace . Databases . Keys ) 
125+                     { 
126+                         if  ( builder . Resources . FirstOrDefault ( n => 
127+                                 string . Equals ( n . Name ,  dbResourceName ,  StringComparison . OrdinalIgnoreCase ) )  is 
128+                             SurrealDbDatabaseResource  surrealDbDatabase ) 
129+                         { 
130+                             await  CreateDatabaseAsync ( surrealClient ,  surrealDbDatabase ,  @event . Services ,  ct ) 
131+                                 . ConfigureAwait ( false ) ; 
132+                         } 
133+                     } 
134+                 } 
135+             } 
136+         } ) ; 
137+         
83138        return  builder . AddResource ( surrealServer ) 
84139                      . WithEndpoint ( port :  port ,  targetPort :  SurrealDbPort ,  name :  SurrealDbServerResource . PrimaryEndpointName ) 
85140                      . WithImage ( SurrealDbContainerImageTags . Image ,  imageTag ) 
@@ -132,6 +187,25 @@ public static IResourceBuilder<SurrealDbNamespaceResource> AddNamespace(
132187        var  surrealServerNamespace  =  new  SurrealDbNamespaceResource ( name ,  namespaceName ,  builder . Resource ) ; 
133188        return  builder . ApplicationBuilder . AddResource ( surrealServerNamespace ) ; 
134189    } 
190+     
191+     /// <summary> 
192+     /// Defines the SQL script used to create the namespace. 
193+     /// </summary> 
194+     /// <param name="builder">The builder for the <see cref="SurrealDbNamespaceResource"/>.</param> 
195+     /// <param name="script">The SQL script used to create the namespace.</param> 
196+     /// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns> 
197+     /// <remarks> 
198+     /// <value>Default script is <code>DEFINE NAMESPACE IF NOT EXISTS `QUOTED_NAMESPACE_NAME`;</code></value> 
199+     /// </remarks> 
200+     public  static IResourceBuilder < SurrealDbNamespaceResource >  WithCreationScript ( this  IResourceBuilder < SurrealDbNamespaceResource >  builder ,  string  script ) 
201+     { 
202+         ArgumentNullException . ThrowIfNull ( builder ) ; 
203+         ArgumentNullException . ThrowIfNull ( script ) ; 
204+ 
205+         builder . WithAnnotation ( new  SurrealDbCreateNamespaceScriptAnnotation ( script ) ) ; 
206+ 
207+         return  builder ; 
208+     } 
135209
136210    /// <summary> 
137211    /// Adds a SurrealDB database to the application model. This is a child resource of a <see cref="SurrealDbNamespaceResource"/>. 
@@ -202,6 +276,25 @@ public static IResourceBuilder<SurrealDbDatabaseResource> AddDatabase(
202276        return  builder . ApplicationBuilder . AddResource ( surrealServerDatabase ) 
203277            . WithHealthCheck ( healthCheckKey ) ; 
204278    } 
279+     
280+     /// <summary> 
281+     /// Defines the SQL script used to create the database. 
282+     /// </summary> 
283+     /// <param name="builder">The builder for the <see cref="SurrealDbDatabaseResource"/>.</param> 
284+     /// <param name="script">The SQL script used to create the database.</param> 
285+     /// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns> 
286+     /// <remarks> 
287+     /// <value>Default script is <code>DEFINE DATABASE IF NOT EXISTS `QUOTED_DATABASE_NAME`;</code></value> 
288+     /// </remarks> 
289+     public  static IResourceBuilder < SurrealDbDatabaseResource >  WithCreationScript ( this  IResourceBuilder < SurrealDbDatabaseResource >  builder ,  string  script ) 
290+     { 
291+         ArgumentNullException . ThrowIfNull ( builder ) ; 
292+         ArgumentNullException . ThrowIfNull ( script ) ; 
293+ 
294+         builder . WithAnnotation ( new  SurrealDbCreateDatabaseScriptAnnotation ( script ) ) ; 
295+ 
296+         return  builder ; 
297+     } 
205298
206299    /// <summary> 
207300    /// Adds a named volume for the data folder to a SurrealDB resource. 
@@ -447,4 +540,62 @@ CancellationToken cancellationToken
447540
448541        return  Encoding . UTF8 . GetString ( stream . ToArray ( ) ) ; 
449542    } 
543+     
544+     private  static async  Task  CreateNamespaceAsync ( 
545+         SurrealDbClient  surrealClient ,  
546+         SurrealDbNamespaceResource  namespaceResource ,  
547+         IServiceProvider  serviceProvider ,  
548+         CancellationToken  cancellationToken 
549+     ) 
550+     { 
551+         var  scriptAnnotation  =  namespaceResource . Annotations . OfType < SurrealDbCreateNamespaceScriptAnnotation > ( ) . LastOrDefault ( ) ; 
552+ 
553+         var  logger  =  serviceProvider . GetRequiredService < ResourceLoggerService > ( ) . GetLogger ( namespaceResource . Parent ) ; 
554+         logger . LogDebug ( "Creating namespace '{NamespaceName}'" ,  namespaceResource . NamespaceName ) ; 
555+ 
556+         try 
557+         { 
558+             var  response  =  await  surrealClient . RawQuery ( 
559+                 scriptAnnotation ? . Script  ??  $ "DEFINE NAMESPACE IF NOT EXISTS `{ namespaceResource . NamespaceName } `;",  
560+                 cancellationToken :  cancellationToken 
561+             ) . ConfigureAwait ( false ) ; 
562+ 
563+             response . EnsureAllOks ( ) ; 
564+ 
565+             logger . LogDebug ( "Namespace '{NamespaceName}' created successfully" ,  namespaceResource . NamespaceName ) ; 
566+         } 
567+         catch  ( Exception  e ) 
568+         { 
569+             logger . LogError ( e ,  "Failed to create namespace '{NamespaceName}'" ,  namespaceResource . NamespaceName ) ; 
570+         } 
571+     } 
572+     
573+     private  static async  Task  CreateDatabaseAsync ( 
574+         SurrealDbClient  surrealClient ,  
575+         SurrealDbDatabaseResource  databaseResource ,  
576+         IServiceProvider  serviceProvider ,  
577+         CancellationToken  cancellationToken 
578+     ) 
579+     { 
580+         var  scriptAnnotation  =  databaseResource . Annotations . OfType < SurrealDbCreateDatabaseScriptAnnotation > ( ) . LastOrDefault ( ) ; 
581+ 
582+         var  logger  =  serviceProvider . GetRequiredService < ResourceLoggerService > ( ) . GetLogger ( databaseResource . Parent . Parent ) ; 
583+         logger . LogDebug ( "Creating database '{DatabaseName}'" ,  databaseResource . DatabaseName ) ; 
584+ 
585+         try 
586+         { 
587+             var  response  =  await  surrealClient . RawQuery ( 
588+                 scriptAnnotation ? . Script  ??  $ "DEFINE DATABASE IF NOT EXISTS `{ databaseResource . DatabaseName } `;",  
589+                 cancellationToken :  cancellationToken 
590+             ) . ConfigureAwait ( false ) ; 
591+ 
592+             response . EnsureAllOks ( ) ; 
593+ 
594+             logger . LogDebug ( "Database '{DatabaseName}' created successfully" ,  databaseResource . DatabaseName ) ; 
595+         } 
596+         catch  ( Exception  e ) 
597+         { 
598+             logger . LogError ( e ,  "Failed to create database '{DatabaseName}'" ,  databaseResource . DatabaseName ) ; 
599+         } 
600+     } 
450601} 
0 commit comments