@@ -13,7 +13,9 @@ use anyhow::Result;
13
13
use serde:: Deserialize ;
14
14
15
15
use crate :: com:: { responses:: SDKResponse , store:: ServerStore } ;
16
+ use crate :: deploy:: actors:: console:: input:: { Confirm , ConfirmHandler } ;
16
17
use crate :: deploy:: actors:: console:: { Console , ConsoleActor } ;
18
+ use crate :: deploy:: actors:: loader:: { LoadModule , LoaderActor } ;
17
19
18
20
use lazy_static:: lazy_static;
19
21
@@ -96,11 +98,16 @@ pub struct PushResult {
96
98
failure : Option < PushFailure > ,
97
99
original_name : String ,
98
100
console : Addr < ConsoleActor > ,
101
+ loader : Addr < LoaderActor > ,
99
102
sdk_response : SDKResponse ,
100
103
}
101
104
102
105
impl PushResult {
103
- pub fn new ( console : Addr < ConsoleActor > , sdk_response : SDKResponse ) -> Result < Self > {
106
+ pub fn new (
107
+ console : Addr < ConsoleActor > ,
108
+ loader : Addr < LoaderActor > ,
109
+ sdk_response : SDKResponse ,
110
+ ) -> Result < Self > {
104
111
let raw = sdk_response. as_push_result ( ) ?;
105
112
106
113
let failure = match raw. failure {
@@ -115,11 +122,12 @@ impl PushResult {
115
122
failure,
116
123
original_name : sdk_response. typegraph_name . clone ( ) ,
117
124
console,
125
+ loader,
118
126
sdk_response,
119
127
} )
120
128
}
121
129
122
- pub fn finalize ( & self ) -> Result < ( ) > {
130
+ pub async fn finalize ( & self ) -> Result < ( ) > {
123
131
let name = self . name . clone ( ) ;
124
132
self . console . info ( format ! (
125
133
"{} Successfully pushed typegraph {name}." ,
@@ -131,9 +139,9 @@ impl PushResult {
131
139
. unwrap ( )
132
140
. prisma_migrations_dir_rel ( & self . original_name ) ;
133
141
142
+ // TODO: use unpack from sdk? This requires another load event though.
134
143
for migrations in self . migrations . iter ( ) {
135
144
let dest = migdir. join ( & migrations. runtime ) ;
136
- // TODO async??
137
145
if let Err ( e) = common:: archive:: unpack ( & dest, Some ( migrations. migrations . clone ( ) ) ) {
138
146
self . console . error ( format ! (
139
147
"Error while unpacking migrations into {:?}" ,
@@ -142,7 +150,7 @@ impl PushResult {
142
150
self . console . error ( format ! ( "{e:?}" ) ) ;
143
151
} else {
144
152
self . console . info ( format ! (
145
- "Successfully unpacked migrations for {name}/{} at {:?}! " ,
153
+ "Successfully unpacked migrations for {name}/{} at {:?}" ,
146
154
migrations. runtime, dest
147
155
) ) ;
148
156
}
@@ -158,17 +166,142 @@ impl PushResult {
158
166
self . console . error ( f. message ) ;
159
167
}
160
168
PushFailure :: DatabaseResetRequired ( failure) => {
161
- todo ! ( "database reset required {:?}" , failure) ;
162
- }
163
- PushFailure :: NullConstraintViolation ( failure) => {
164
- todo ! ( "null constraint violation {:?}" , failure) ;
169
+ handle_database_reset (
170
+ self . console . clone ( ) ,
171
+ self . loader . clone ( ) ,
172
+ failure,
173
+ self . sdk_response . clone ( ) ,
174
+ )
175
+ . await ?
165
176
}
177
+ PushFailure :: NullConstraintViolation ( failure) => handle_null_constraint_violation (
178
+ self . console . clone ( ) ,
179
+ failure,
180
+ self . sdk_response . clone ( ) ,
181
+ ) ,
166
182
}
167
183
}
168
184
Ok ( ( ) )
169
185
}
170
186
}
171
187
188
+ // DatabaseReset Handler + interactivity
189
+
190
+ #[ derive( Debug ) ]
191
+ struct ConfirmDatabaseResetRequired {
192
+ sdk_response : SDKResponse ,
193
+ loader : Addr < LoaderActor > ,
194
+ }
195
+
196
+ impl ConfirmHandler for ConfirmDatabaseResetRequired {
197
+ fn on_confirm ( & self ) {
198
+ let tg_path = self . sdk_response . clone ( ) . typegraph_path ;
199
+
200
+ // reset
201
+ let mut option = ServerStore :: get_migration_action ( & tg_path) ;
202
+ option. reset = true ;
203
+ ServerStore :: set_migration_action ( tg_path. clone ( ) , option) ;
204
+
205
+ // reload
206
+ self . loader . do_send ( LoadModule ( tg_path. into ( ) ) ) ;
207
+ }
208
+ }
209
+
210
+ async fn handle_database_reset (
211
+ console : Addr < ConsoleActor > ,
212
+ loader : Addr < LoaderActor > ,
213
+ failure : DatabaseResetRequired ,
214
+ sdk_response : SDKResponse ,
215
+ ) -> Result < ( ) > {
216
+ let DatabaseResetRequired {
217
+ message,
218
+ runtime_name,
219
+ } = failure;
220
+
221
+ let name = sdk_response. typegraph_name . clone ( ) ;
222
+
223
+ console. error ( format ! (
224
+ "Database reset required for prisma runtime {rt} in typegraph {name}" ,
225
+ rt = runtime_name. magenta( ) ,
226
+ ) ) ;
227
+ console. error ( message) ;
228
+
229
+ let rt = runtime_name. clone ( ) ;
230
+ let _ = Confirm :: new (
231
+ console,
232
+ format ! ( "Do you want to reset the database for runtime {rt} on {name}?" ) ,
233
+ )
234
+ . interact ( Box :: new ( ConfirmDatabaseResetRequired {
235
+ sdk_response : sdk_response. clone ( ) ,
236
+ loader,
237
+ } ) )
238
+ . await ?;
239
+
240
+ Ok ( ( ) )
241
+ }
242
+
243
+ pub fn handle_null_constraint_violation (
244
+ console : Addr < ConsoleActor > ,
245
+ failure : NullConstraintViolation ,
246
+ sdk_response : SDKResponse ,
247
+ ) {
248
+ #[ allow( unused) ]
249
+ let typegraph_name = sdk_response. typegraph_name ;
250
+ #[ allow( unused) ]
251
+ let NullConstraintViolation {
252
+ message,
253
+ runtime_name,
254
+ migration_name,
255
+ is_new_column,
256
+ column,
257
+ table,
258
+ } = failure;
259
+
260
+ console. error ( message) ;
261
+
262
+ if is_new_column {
263
+ console. info ( format ! ( "manually edit the migration {migration_name}; or remove the migration and add set a default value" ) ) ;
264
+ todo ! ( "interactive choice" )
265
+ // let migration_dir: PathBuf = ServerStore::get_config()
266
+ // .unwrap()
267
+ // .prisma_migrations_dir_rel(&typegraph_name)
268
+ // .join(&runtime_name)
269
+ // .into();
270
+
271
+ // let remove_latest = RemoveLatestMigration {
272
+ // runtime_name: runtime_name.clone(),
273
+ // migration_name: migration_name.clone(),
274
+ // migration_dir: migration_dir.clone(),
275
+ // push_manager: self.push_manager.clone(),
276
+ // console: self.console.clone(),
277
+ // };
278
+
279
+ // let manual = ManualResolution {
280
+ // runtime_name: runtime_name.clone(),
281
+ // migration_name: migration_name.clone(),
282
+ // migration_dir,
283
+ // message: Some(format!(
284
+ // "Set a default value for the column `{}` in the table `{}`",
285
+ // column, table
286
+ // )),
287
+ // push_manager: self.push_manager.clone(),
288
+ // console: self.console.clone(),
289
+ // };
290
+
291
+ // let reset = ForceReset {
292
+ // typegraph: typegraph.clone(),
293
+ // runtime_name: runtime_name.clone(),
294
+ // push_manager: self.push_manager.clone(),
295
+ // };
296
+
297
+ // self.push_manager
298
+ // .do_send(PushFinished::new(msg.push, false).select(
299
+ // "Choose one of the following options".to_string(),
300
+ // vec![Box::new(remove_latest), Box::new(manual), Box::new(reset)],
301
+ // ));
302
+ }
303
+ }
304
+
172
305
lazy_static ! {
173
306
static ref RETRY_COUNTERS : Mutex <HashMap <PathBuf , Arc <u8 >>> = Mutex :: new( HashMap :: new( ) ) ;
174
307
}
0 commit comments