/
lib.rs
168 lines (142 loc) Β· 6.12 KB
/
lib.rs
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#![doc = include_str!("../README.md")]
#![deny(rust_2018_idioms, unsafe_code)]
#![allow(clippy::derive_partial_eq_without_eq)]
pub mod builtin_connectors;
pub mod datamodel_connector;
/// `mcf`: Turns a collection of `configuration::Datasource` and `configuration::Generator` into a
/// JSON representation. This is the `get_config()` representation.
pub mod mcf;
mod common;
mod configuration;
mod reformat;
mod set_config_dir;
mod validate;
pub use crate::{
common::{PreviewFeature, PreviewFeatures, ALL_PREVIEW_FEATURES},
configuration::{
Configuration, Datasource, DatasourceConnectorData, Generator, GeneratorConfigValue, StringFromEnvVar,
},
reformat::{reformat, reformat_multiple, reformat_validated_schema_into_single},
};
pub use diagnostics;
pub use parser_database::{self, is_reserved_type_name};
pub use schema_ast;
pub use set_config_dir::set_config_dir;
use self::validate::{datasource_loader, generator_loader};
use diagnostics::Diagnostics;
use parser_database::{ast, Files, ParserDatabase, SourceFile};
/// The collection of all available connectors.
pub type ConnectorRegistry<'a> = &'a [&'static dyn datamodel_connector::Connector];
pub struct ValidatedSchema {
pub configuration: Configuration,
pub db: parser_database::ParserDatabase,
pub connector: &'static dyn datamodel_connector::Connector,
pub diagnostics: Diagnostics,
relation_mode: datamodel_connector::RelationMode,
}
impl std::fmt::Debug for ValidatedSchema {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("<Prisma schema>")
}
}
impl ValidatedSchema {
pub fn relation_mode(&self) -> datamodel_connector::RelationMode {
self.relation_mode
}
pub fn render_own_diagnostics(&self) -> String {
self.db.render_diagnostics(&self.diagnostics)
}
}
/// The most general API for dealing with Prisma schemas. It accumulates what analysis and
/// validation information it can, and returns it along with any error and warning diagnostics.
pub fn validate(file: SourceFile, connectors: ConnectorRegistry<'_>) -> ValidatedSchema {
let mut diagnostics = Diagnostics::new();
let db = ParserDatabase::new_single_file(file, &mut diagnostics);
let configuration = validate_configuration(db.ast_assert_single(), &mut diagnostics, connectors);
let datasources = &configuration.datasources;
let out = validate::validate(db, datasources, configuration.preview_features(), diagnostics);
ValidatedSchema {
diagnostics: out.diagnostics,
configuration,
connector: out.connector,
db: out.db,
relation_mode: out.relation_mode,
}
}
/// The most general API for dealing with Prisma schemas. It accumulates what analysis and
/// validation information it can, and returns it along with any error and warning diagnostics.
pub fn validate_multi_file(files: Vec<(String, SourceFile)>, connectors: ConnectorRegistry<'_>) -> ValidatedSchema {
assert!(
!files.is_empty(),
"psl::validate_multi_file() must be called with at least one file"
);
let mut diagnostics = Diagnostics::new();
let db = ParserDatabase::new(&files, &mut diagnostics);
// TODO: the bulk of configuration block analysis should be part of ParserDatabase::new().
let mut configuration = Configuration::default();
for ast in db.iter_asts() {
let new_config = validate_configuration(ast, &mut diagnostics, connectors);
configuration.extend(new_config);
}
let datasources = &configuration.datasources;
let out = validate::validate(db, datasources, configuration.preview_features(), diagnostics);
ValidatedSchema {
diagnostics: out.diagnostics,
configuration,
connector: out.connector,
db: out.db,
relation_mode: out.relation_mode,
}
}
/// Retrieves a Prisma schema without validating it.
/// You should only use this method when actually validating the schema is too expensive
/// computationally or in terms of bundle size (e.g., for `query-engine-wasm`).
pub fn parse_without_validation(file: SourceFile, connectors: ConnectorRegistry<'_>) -> ValidatedSchema {
let mut diagnostics = Diagnostics::new();
let db = ParserDatabase::new_single_file(file, &mut diagnostics);
let configuration = validate_configuration(db.ast_assert_single(), &mut diagnostics, connectors);
let datasources = &configuration.datasources;
let out = validate::parse_without_validation(db, datasources);
ValidatedSchema {
diagnostics,
configuration,
connector: out.connector,
db: out.db,
relation_mode: out.relation_mode,
}
}
/// Loads all configuration blocks from a datamodel using the built-in source definitions.
pub fn parse_configuration(
schema: &str,
connectors: ConnectorRegistry<'_>,
) -> Result<Configuration, diagnostics::Diagnostics> {
let mut diagnostics = Diagnostics::default();
let ast = schema_ast::parse_schema(schema, &mut diagnostics, diagnostics::FileId::ZERO);
let out = validate_configuration(&ast, &mut diagnostics, connectors);
diagnostics.to_result().map(|_| out)
}
pub fn parse_configuration_multi_file(
files: &[(String, SourceFile)],
connectors: ConnectorRegistry<'_>,
) -> Result<(Files, Configuration), (Files, diagnostics::Diagnostics)> {
let mut diagnostics = Diagnostics::default();
let mut configuration = Configuration::default();
let asts = Files::new(files, &mut diagnostics);
for (_, _, _, ast) in asts.iter() {
let out = validate_configuration(ast, &mut diagnostics, connectors);
configuration.extend(out);
}
match diagnostics.to_result() {
Ok(_) => Ok((asts, configuration)),
Err(err) => Err((asts, err)),
}
}
fn validate_configuration(
schema_ast: &ast::SchemaAst,
diagnostics: &mut Diagnostics,
connectors: ConnectorRegistry<'_>,
) -> Configuration {
let generators = generator_loader::load_generators_from_ast(schema_ast, diagnostics);
let datasources = datasource_loader::load_datasources_from_ast(schema_ast, diagnostics, connectors);
Configuration::new(generators, datasources, diagnostics.warnings().to_owned())
}