@@ -4,6 +4,7 @@ use super::{
44 EnvironmentValue , KvNamespace , StorageConfig , UpdateEnvironmentInput , UpdateWorkerInput ,
55 UploadResult , UploadWorkerInfo , UploadedCounts , Worker ,
66} ;
7+ use crate :: config:: PlatformStorageConfig ;
78use crate :: s3:: { S3Client , S3Config , get_mime_type} ;
89use sha2:: { Digest , Sha256 } ;
910use sqlx:: { PgPool , Row } ;
@@ -13,23 +14,38 @@ use zip::ZipArchive;
1314pub struct DbBackend {
1415 pool : PgPool ,
1516 user_id : uuid:: Uuid ,
17+ platform_storage : Option < PlatformStorageConfig > ,
1618}
1719
1820impl DbBackend {
19- pub async fn new ( pool : PgPool ) -> Result < Self , BackendError > {
20- // Get or create admin user on initialization
21- let user_id: uuid:: Uuid = sqlx:: query_scalar (
22- r#"
23- INSERT INTO users (id, username, created_at, updated_at)
24- VALUES (gen_random_uuid(), 'cli-admin', now(), now())
25- ON CONFLICT (username) DO UPDATE SET username = users.username
26- RETURNING id
27- "# ,
28- )
29- . fetch_one ( & pool)
30- . await ?;
21+ pub async fn new (
22+ pool : PgPool ,
23+ username : Option < String > ,
24+ platform_storage : Option < PlatformStorageConfig > ,
25+ ) -> Result < Self , BackendError > {
26+ let username = username. ok_or_else ( || {
27+ BackendError :: Api (
28+ "No user configured for this DB alias. Use 'ow alias set <name> --db <url> --user <username>' to set a user." . to_string ( ) ,
29+ )
30+ } ) ?;
3131
32- Ok ( Self { pool, user_id } )
32+ // Look up user by username
33+ let user_id: uuid:: Uuid = sqlx:: query_scalar ( "SELECT id FROM users WHERE username = $1" )
34+ . bind ( & username)
35+ . fetch_optional ( & pool)
36+ . await ?
37+ . ok_or_else ( || {
38+ BackendError :: NotFound ( format ! (
39+ "User '{}' not found. Create an account first via the dashboard." ,
40+ username
41+ ) )
42+ } ) ?;
43+
44+ Ok ( Self {
45+ pool,
46+ user_id,
47+ platform_storage,
48+ } )
3349 }
3450
3551 async fn get_environment_values (
@@ -66,10 +82,12 @@ impl Backend for DbBackend {
6682 async fn list_workers ( & self ) -> Result < Vec < Worker > , BackendError > {
6783 let rows = sqlx:: query (
6884 r#"
69- SELECT id, name, "desc", current_version, created_at, updated_at
70- FROM workers
71- WHERE user_id = $1
72- ORDER BY name
85+ SELECT w.id, w.name, w."desc", w.current_version, w.created_at, w.updated_at,
86+ e.id as env_id, e.name as env_name
87+ FROM workers w
88+ LEFT JOIN environments e ON e.id = w.environment_id
89+ WHERE w.user_id = $1
90+ ORDER BY w.name
7391 "# ,
7492 )
7593 . bind ( self . user_id )
@@ -78,13 +96,26 @@ impl Backend for DbBackend {
7896
7997 let workers = rows
8098 . iter ( )
81- . map ( |row| Worker {
82- id : row. get :: < uuid:: Uuid , _ > ( "id" ) . to_string ( ) ,
83- name : row. get ( "name" ) ,
84- description : row. get ( "desc" ) ,
85- current_version : row. get ( "current_version" ) ,
86- created_at : row. get ( "created_at" ) ,
87- updated_at : row. get ( "updated_at" ) ,
99+ . map ( |row| {
100+ let env_id: Option < uuid:: Uuid > = row. get ( "env_id" ) ;
101+ let env_name: Option < String > = row. get ( "env_name" ) ;
102+ let environment =
103+ env_id
104+ . zip ( env_name)
105+ . map ( |( id, name) | super :: WorkerEnvironmentRef {
106+ id : id. to_string ( ) ,
107+ name,
108+ } ) ;
109+
110+ Worker {
111+ id : row. get :: < uuid:: Uuid , _ > ( "id" ) . to_string ( ) ,
112+ name : row. get ( "name" ) ,
113+ description : row. get ( "desc" ) ,
114+ current_version : row. get ( "current_version" ) ,
115+ environment,
116+ created_at : row. get ( "created_at" ) ,
117+ updated_at : row. get ( "updated_at" ) ,
118+ }
88119 } )
89120 . collect ( ) ;
90121
@@ -94,9 +125,11 @@ impl Backend for DbBackend {
94125 async fn get_worker ( & self , name : & str ) -> Result < Worker , BackendError > {
95126 let row = sqlx:: query (
96127 r#"
97- SELECT id, name, "desc", current_version, created_at, updated_at
98- FROM workers
99- WHERE name = $1 AND user_id = $2
128+ SELECT w.id, w.name, w."desc", w.current_version, w.created_at, w.updated_at,
129+ e.id as env_id, e.name as env_name
130+ FROM workers w
131+ LEFT JOIN environments e ON e.id = w.environment_id
132+ WHERE w.name = $1 AND w.user_id = $2
100133 "# ,
101134 )
102135 . bind ( name)
@@ -105,11 +138,21 @@ impl Backend for DbBackend {
105138 . await ?
106139 . ok_or_else ( || BackendError :: NotFound ( format ! ( "Worker '{}' not found" , name) ) ) ?;
107140
141+ let env_id: Option < uuid:: Uuid > = row. get ( "env_id" ) ;
142+ let env_name: Option < String > = row. get ( "env_name" ) ;
143+ let environment = env_id
144+ . zip ( env_name)
145+ . map ( |( id, name) | super :: WorkerEnvironmentRef {
146+ id : id. to_string ( ) ,
147+ name,
148+ } ) ;
149+
108150 Ok ( Worker {
109151 id : row. get :: < uuid:: Uuid , _ > ( "id" ) . to_string ( ) ,
110152 name : row. get ( "name" ) ,
111153 description : row. get ( "desc" ) ,
112154 current_version : row. get ( "current_version" ) ,
155+ environment,
113156 created_at : row. get ( "created_at" ) ,
114157 updated_at : row. get ( "updated_at" ) ,
115158 } )
@@ -136,6 +179,7 @@ impl Backend for DbBackend {
136179 name : row. get ( "name" ) ,
137180 description : row. get ( "desc" ) ,
138181 current_version : row. get ( "current_version" ) ,
182+ environment : None ,
139183 created_at : row. get ( "created_at" ) ,
140184 updated_at : row. get ( "updated_at" ) ,
141185 } )
@@ -186,30 +230,30 @@ impl Backend for DbBackend {
186230 None
187231 } ;
188232
189- let row = sqlx:: query (
233+ let result = sqlx:: query (
190234 r#"
191235 UPDATE workers
192236 SET environment_id = COALESCE($2, environment_id),
193237 updated_at = now()
194238 WHERE name = $1 AND user_id = $3
195- RETURNING id, name, "desc", current_version, created_at, updated_at
239+ RETURNING id
196240 "# ,
197241 )
198242 . bind ( name)
199243 . bind ( env_id)
200244 . bind ( self . user_id )
201245 . fetch_optional ( & self . pool )
202- . await ?
203- . ok_or_else ( || BackendError :: NotFound ( format ! ( "Worker '{}' not found" , name) ) ) ?;
246+ . await ?;
204247
205- Ok ( Worker {
206- id : row. get :: < uuid:: Uuid , _ > ( "id" ) . to_string ( ) ,
207- name : row. get ( "name" ) ,
208- description : row. get ( "desc" ) ,
209- current_version : row. get ( "current_version" ) ,
210- created_at : row. get ( "created_at" ) ,
211- updated_at : row. get ( "updated_at" ) ,
212- } )
248+ if result. is_none ( ) {
249+ return Err ( BackendError :: NotFound ( format ! (
250+ "Worker '{}' not found" ,
251+ name
252+ ) ) ) ;
253+ }
254+
255+ // Fetch updated worker with environment info
256+ self . get_worker ( name) . await
213257 }
214258
215259 async fn deploy_worker (
@@ -284,11 +328,10 @@ impl Backend for DbBackend {
284328 . parse ( )
285329 . map_err ( |_| BackendError :: Api ( format ! ( "Invalid worker ID: {}" , worker. id) ) ) ?;
286330
287- // 2. Get ASSETS binding for this worker
331+ // 2. Check for ASSETS binding (like API does)
288332 let assets_binding = sqlx:: query (
289333 r#"
290334 SELECT
291- sc.id as storage_config_id,
292335 sc.bucket,
293336 sc.prefix,
294337 sc.access_key_id,
@@ -298,11 +341,12 @@ impl Backend for DbBackend {
298341 FROM workers w
299342 JOIN environment_values ev ON ev.environment_id = w.environment_id
300343 JOIN storage_configs sc ON sc.id = ev.value::uuid
301- WHERE w.id = $1 AND ev.type = 'assets'
344+ WHERE w.id = $1 AND w.user_id = $2 AND ev.type = 'assets'
302345 LIMIT 1
303346 "# ,
304347 )
305348 . bind ( worker_id)
349+ . bind ( self . user_id )
306350 . fetch_optional ( & self . pool )
307351 . await ?
308352 . ok_or_else ( || {
@@ -311,17 +355,22 @@ impl Backend for DbBackend {
311355 )
312356 } ) ?;
313357
358+ // 3. Get storage credentials from binding, with platform endpoint as fallback
314359 let bucket: String = assets_binding. get ( "bucket" ) ;
315360 let prefix: Option < String > = assets_binding. get ( "prefix" ) ;
316361 let access_key_id: String = assets_binding. get ( "access_key_id" ) ;
317362 let secret_access_key: String = assets_binding. get ( "secret_access_key" ) ;
318- let endpoint: Option < String > = assets_binding. get ( "endpoint" ) ;
319- let region: Option < String > = assets_binding. get ( "region" ) ;
320-
321- let endpoint = endpoint
363+ let region: String = assets_binding
364+ . get :: < Option < String > , _ > ( "region" )
365+ . unwrap_or_else ( || "auto" . to_string ( ) ) ;
366+
367+ // Use binding's endpoint, or fall back to platform storage endpoint
368+ let binding_endpoint: Option < String > = assets_binding. get ( "endpoint" ) ;
369+ let endpoint = binding_endpoint
370+ . or_else ( || self . platform_storage . as_ref ( ) . map ( |ps| ps. endpoint . clone ( ) ) )
322371 . ok_or_else ( || BackendError :: Api ( "Storage endpoint not configured" . to_string ( ) ) ) ?;
323372
324- // 3 . Extract zip
373+ // 4 . Extract zip
325374 let cursor = std:: io:: Cursor :: new ( zip_data) ;
326375 let mut archive = ZipArchive :: new ( cursor)
327376 . map_err ( |e| BackendError :: Api ( format ! ( "Failed to read zip archive: {}" , e) ) ) ?;
@@ -389,7 +438,7 @@ impl Backend for DbBackend {
389438 BackendError :: Api ( "No worker.js or worker.ts found in zip archive" . to_string ( ) )
390439 } ) ?;
391440
392- // 4 . Update worker script in DB
441+ // 5 . Update worker script in DB
393442 let script_bytes = script. as_bytes ( ) ;
394443 let mut hasher = Sha256 :: new ( ) ;
395444 hasher. update ( script_bytes) ;
@@ -426,13 +475,13 @@ impl Backend for DbBackend {
426475 . execute ( & self . pool )
427476 . await ?;
428477
429- // 5 . Upload assets to S3
478+ // 6 . Upload assets to S3
430479 let s3_client = S3Client :: new ( S3Config {
431480 bucket,
432481 endpoint,
433482 access_key_id,
434483 secret_access_key,
435- region : region . unwrap_or_else ( || "auto" . to_string ( ) ) ,
484+ region,
436485 prefix,
437486 } ) ;
438487
0 commit comments