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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use std::sync::Arc;

use enumflags2::BitFlags;
use psl::ValidatedSchema;

use crate::{
    migrations_directory::MigrationDirectory, BoxFuture, ConnectorHost, ConnectorParams, ConnectorResult,
    DatabaseSchema, DestructiveChangeChecker, DestructiveChangeDiagnostics, DiffTarget, IntrospectionContext,
    IntrospectionResult, Migration, MigrationPersistence, Namespaces,
};

/// The top-level trait for connectors. This is the abstraction the schema engine core relies on to
/// interface with different database backends.
pub trait SchemaConnector: Send + Sync + 'static {
    // Setup methods

    /// Accept a new ConnectorHost.
    fn set_host(&mut self, host: Arc<dyn ConnectorHost>);

    /// Accept and validate new ConnectorParams. This should fail if it is called twice on the same
    /// connector.
    fn set_params(&mut self, params: ConnectorParams) -> ConnectorResult<()>;

    /// Accept a new set of enabled preview features.
    fn set_preview_features(&mut self, preview_features: BitFlags<psl::PreviewFeature>);

    // Connector methods

    /// If possible on the target connector, acquire an advisory lock, so multiple instances of migrate do not run concurrently.
    fn acquire_lock(&mut self) -> BoxFuture<'_, ConnectorResult<()>>;

    /// Applies the migration to the database. Returns the number of executed steps.
    fn apply_migration<'a>(&'a mut self, migration: &'a Migration) -> BoxFuture<'a, ConnectorResult<u32>>;

    /// Apply a migration script to the database. The migration persistence is
    /// managed by the core.
    fn apply_script<'a>(&'a mut self, migration_name: &'a str, script: &'a str) -> BoxFuture<'a, ConnectorResult<()>>;

    /// A string that should identify what database backend is being used. Note that this is not necessarily
    /// the connector name. The SQL connector for example can return "postgresql", "mysql" or "sqlite".
    fn connector_type(&self) -> &'static str;

    /// Return the connection string that was used to initialize this connector in set_params().
    fn connection_string(&self) -> Option<&str>;

    /// Create the database referenced by Prisma schema that was used to initialize the connector.
    fn create_database(&mut self) -> BoxFuture<'_, ConnectorResult<String>>;

    /// Send a command to the database directly.
    fn db_execute(&mut self, script: String) -> BoxFuture<'_, ConnectorResult<()>>;

    /// Create a migration by comparing two database schemas.
    fn diff(&self, from: DatabaseSchema, to: DatabaseSchema) -> Migration;

    /// Drop the database referenced by Prisma schema that was used to initialize the connector.
    fn drop_database(&mut self) -> BoxFuture<'_, ConnectorResult<()>>;

    /// An empty database schema (for diffing).
    fn empty_database_schema(&self) -> DatabaseSchema;

    /// Make sure the connection to the database is established and valid.
    /// Connectors can choose to connect lazily, but this method should force
    /// them to connect.
    fn ensure_connection_validity(&mut self) -> BoxFuture<'_, ConnectorResult<()>>;

    /// Return the ConnectorHost passed with set_host.
    fn host(&self) -> &Arc<dyn ConnectorHost>;

    /// The version of the underlying database.
    fn version(&mut self) -> BoxFuture<'_, ConnectorResult<String>>;

    /// Render the migration to a runnable script.
    ///
    /// This should always return with `Ok` in normal circumstances. The result is currently only
    /// used to signal when the connector does not support rendering to a script.
    fn render_script(
        &self,
        migration: &Migration,
        diagnostics: &DestructiveChangeDiagnostics,
    ) -> ConnectorResult<String>;

    /// Drop all database state.
    ///
    /// Set the `soft` parameter to `true` to force a soft-reset, that is to say a reset that does
    /// not drop the database.
    fn reset(&mut self, soft: bool, namespaces: Option<Namespaces>) -> BoxFuture<'_, ConnectorResult<()>>;

    /// Optionally check that the features implied by the provided datamodel are all compatible with
    /// the specific database version being used.
    fn check_database_version_compatibility(
        &self,
        _datamodel: &ValidatedSchema,
    ) -> Option<user_facing_errors::common::DatabaseVersionIncompatibility> {
        None
    }

    /// The file extension for generated migration files.
    fn migration_file_extension(&self) -> &'static str;

    /// Return whether the migration is empty.
    fn migration_is_empty(&self, migration: &Migration) -> bool {
        self.migration_len(migration) == 0
    }

    /// Return the number of steps in the migration.
    /// Invariant: migration_is_empty() == true iff migration_len() == 0.
    fn migration_len(&self, migration: &Migration) -> usize;

    /// See [MigrationPersistence](trait.MigrationPersistence.html).
    fn migration_persistence(&mut self) -> &mut dyn MigrationPersistence;

    /// Render a human-readable drift summary for the migration.
    fn migration_summary(&self, migration: &Migration) -> String;

    /// See [DestructiveChangeChecker](trait.DestructiveChangeChecker.html).
    fn destructive_change_checker(&mut self) -> &mut dyn DestructiveChangeChecker;

    /// Read a schema for diffing. The shadow database connection string is strictly optional, you
    /// don't need to pass it if a shadow database url was passed in params, or if it can be
    /// inferred from context, or if it isn't necessary for the task at hand.
    /// When MultiSchema is enabled, the namespaces are required for diffing anything other than a
    /// prisma schema, because that information is otherwise unavailable.
    fn database_schema_from_diff_target<'a>(
        &'a mut self,
        target: DiffTarget<'a>,
        shadow_database_connection_string: Option<String>,
        namespaces: Option<Namespaces>,
    ) -> BoxFuture<'a, ConnectorResult<DatabaseSchema>>;

    /// In-tro-spec-shon.
    fn introspect<'a>(
        &'a mut self,
        ctx: &'a IntrospectionContext,
    ) -> BoxFuture<'a, ConnectorResult<IntrospectionResult>>;

    /// If possible, check that the passed in migrations apply cleanly.
    fn validate_migrations<'a>(
        &'a mut self,
        _migrations: &'a [MigrationDirectory],
        namespaces: Option<Namespaces>,
    ) -> BoxFuture<'a, ConnectorResult<()>>;

    /// Extract the namespaces from a Sql database schema (it will return None for mongodb).
    fn extract_namespaces(&self, schema: &DatabaseSchema) -> Option<Namespaces>;
}