1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
use crate::{json_rpc::types::*, CoreResult};
use psl::parser_database::SourceFile;
use schema_connector::{migrations_directory::*, DiffTarget, SchemaConnector};
use std::sync::Arc;

/// Development command for migrations. Evaluate the data loss induced by the
/// next migration the engine would generate on the main database.
///
/// At this stage, the engine does not create or mutate anything in the database
/// nor in the migrations directory.
pub async fn evaluate_data_loss(
    input: EvaluateDataLossInput,
    connector: &mut dyn SchemaConnector,
) -> CoreResult<EvaluateDataLossOutput> {
    error_on_changed_provider(&input.migrations_directory_path, connector.connector_type())?;
    let source_file = SourceFile::new_allocated(Arc::from(input.prisma_schema.into_boxed_str()));

    let migrations_from_directory = list_migrations(input.migrations_directory_path.as_ref())?;

    let to = connector
        .database_schema_from_diff_target(DiffTarget::Datamodel(source_file), None, None)
        .await?;

    let namespaces = connector.extract_namespaces(&to);

    // TODO(MultiSchema): we may need to do something similar to
    // namespaces_and_preview_features_from_diff_targets here as well,
    // particulalry if it's not correctly setting the preview features flags.
    let from = connector
        .database_schema_from_diff_target(DiffTarget::Migrations(&migrations_from_directory), None, namespaces)
        .await?;
    let migration = connector.diff(from, to);

    let migration_steps = connector.migration_len(&migration) as u32;
    let diagnostics = connector.destructive_change_checker().check(&migration).await?;

    let warnings = diagnostics
        .warnings
        .into_iter()
        .map(|warning| MigrationFeedback {
            message: warning.description,
            step_index: warning.step_index as u32,
        })
        .collect();

    let unexecutable_steps = diagnostics
        .unexecutable_migrations
        .into_iter()
        .map(|unexecutable| MigrationFeedback {
            message: unexecutable.description,
            step_index: unexecutable.step_index as u32,
        })
        .collect();

    Ok(EvaluateDataLossOutput {
        migration_steps,
        warnings,
        unexecutable_steps,
    })
}