diff --git a/query-engine/connector-test-kit-rs/query-tests-setup/src/runner/direct.rs b/query-engine/connector-test-kit-rs/query-tests-setup/src/runner/direct.rs index c011205e998a..982cf35a7930 100644 --- a/query-engine/connector-test-kit-rs/query-tests-setup/src/runner/direct.rs +++ b/query-engine/connector-test-kit-rs/query-tests-setup/src/runner/direct.rs @@ -1,5 +1,4 @@ use crate::{ConnectorTag, RunnerInterface, TestResult, TxResult}; -use prisma_models::InternalDataModelBuilder; use query_core::{executor, schema::QuerySchemaRef, schema_builder, QueryExecutor, TxId}; use query_engine_metrics::MetricRegistry; use request_handlers::{GraphQlBody, GraphQlHandler, MultiQuery}; @@ -24,7 +23,7 @@ impl RunnerInterface for DirectRunner { let preview_features: Vec<_> = schema.configuration.preview_features().iter().collect(); let url = data_source.load_url(|key| env::var(key).ok()).unwrap(); let (db_name, executor) = executor::load(data_source, &preview_features, &url).await?; - let internal_data_model = InternalDataModelBuilder::new(&schema).build(db_name); + let internal_data_model = prisma_models::convert(&schema, db_name); let query_schema: QuerySchemaRef = Arc::new(schema_builder::build( internal_data_model, diff --git a/query-engine/connectors/mongodb-query-connector/src/root_queries/update/operation.rs b/query-engine/connectors/mongodb-query-connector/src/root_queries/update/operation.rs index d46e6f72347a..cdb7be2c601c 100644 --- a/query-engine/connectors/mongodb-query-connector/src/root_queries/update/operation.rs +++ b/query-engine/connectors/mongodb-query-connector/src/root_queries/update/operation.rs @@ -1,8 +1,4 @@ -use super::{ - expression::{self}, - into_expression::IntoUpdateExpression, -}; - +use super::{expression, into_expression::IntoUpdateExpression}; use connector_interface::{FieldPath, Filter}; use mongodb::bson::{doc, Document}; diff --git a/query-engine/dmmf/src/lib.rs b/query-engine/dmmf/src/lib.rs index 58f766b2d7b7..6df06658903e 100644 --- a/query-engine/dmmf/src/lib.rs +++ b/query-engine/dmmf/src/lib.rs @@ -4,7 +4,6 @@ mod serialization_ast; pub use serialization_ast::DataModelMetaFormat; use ast_builders::{schema_to_dmmf, DmmfQuerySchemaRenderer}; -use prisma_models::InternalDataModelBuilder; use schema::{QuerySchemaRef, QuerySchemaRenderer}; use std::sync::Arc; @@ -22,7 +21,7 @@ pub fn dmmf_from_schema(schema: &str) -> DataModelMetaFormat { // We only support one data source at the moment, so take the first one (default not exposed yet). let data_source = config.datasources.first().unwrap(); let preview_features: Vec<_> = config.preview_features().iter().collect(); - let internal_data_model = InternalDataModelBuilder::from(&dml).build("dummy".to_owned()); + let internal_data_model = prisma_models::convert(&schema, "dummy".to_owned()); // Construct query schema let query_schema = Arc::new(schema_builder::build( diff --git a/query-engine/prisma-models/src/builders/internal_dm_builder.rs b/query-engine/prisma-models/src/builders/internal_dm_builder.rs index 4925655cd9cd..37ad1e29961f 100644 --- a/query-engine/prisma-models/src/builders/internal_dm_builder.rs +++ b/query-engine/prisma-models/src/builders/internal_dm_builder.rs @@ -1,84 +1,19 @@ use super::{ - build_composites, field_builders::RelationFieldBuilder, relation_builder::RelationBuilder, CompositeTypeBuilder, - FieldBuilder, IndexBuilder, ModelBuilder, PrimaryKeyBuilder, + field_builders::RelationFieldBuilder, relation_builder::RelationBuilder, CompositeTypeBuilder, FieldBuilder, + IndexBuilder, ModelBuilder, PrimaryKeyBuilder, }; use crate::{ builders::{CompositeFieldBuilder, ScalarFieldBuilder}, extensions::*, - IndexType, InlineRelation, InternalDataModel, InternalDataModelRef, InternalEnum, InternalEnumValue, - RelationLinkManifestation, RelationSide, RelationTable, TypeIdentifier, + IndexType, InlineRelation, InternalEnum, InternalEnumValue, RelationLinkManifestation, RelationSide, RelationTable, + TypeIdentifier, }; -use once_cell::sync::OnceCell; use psl::dml::{self, CompositeTypeFieldType, Datamodel, Ignorable, WithDatabaseName}; -use std::sync::Arc; - -#[derive(Debug, Default)] -pub struct InternalDataModelBuilder { - pub models: Vec, - pub relations: Vec, - pub enums: Vec, - pub composite_types: Vec, -} - -impl InternalDataModelBuilder { - pub fn new(datamodel: &psl::ValidatedSchema) -> Self { - let datamodel = psl::lift(datamodel); - - Self::from(&datamodel) - } - - pub fn build(self, db_name: String) -> InternalDataModelRef { - let internal_data_model = Arc::new(InternalDataModel { - models: OnceCell::new(), - composite_types: OnceCell::new(), - relations: OnceCell::new(), - relation_fields: OnceCell::new(), - db_name, - enums: self.enums.into_iter().map(Arc::new).collect(), - }); - - let composite_types = build_composites(self.composite_types, Arc::downgrade(&internal_data_model)); - internal_data_model.composite_types.set(composite_types).unwrap(); - - let models = self - .models - .into_iter() - .map(|mt| { - mt.build( - Arc::downgrade(&internal_data_model), - internal_data_model.composite_types.get().unwrap(), - ) - }) - .collect(); - - internal_data_model.models.set(models).unwrap(); - - let relations = self - .relations - .into_iter() - .map(|rt| rt.build(Arc::downgrade(&internal_data_model))) - .collect(); - - internal_data_model.relations.set(relations).unwrap(); - internal_data_model.finalize(); - internal_data_model - } -} -impl From<&dml::Datamodel> for InternalDataModelBuilder { - fn from(datamodel: &dml::Datamodel) -> Self { - let relation_placeholders = relation_placeholders(datamodel); - - Self { - models: model_builders(datamodel, &relation_placeholders), - relations: relation_builders(&relation_placeholders), - enums: convert_enums(datamodel), - composite_types: composite_type_builders(datamodel), - } - } -} - -fn model_builders(datamodel: &Datamodel, relation_placeholders: &[RelationPlaceholder]) -> Vec { +pub(crate) fn model_builders( + datamodel: &Datamodel, + relation_placeholders: &[RelationPlaceholder], +) -> Vec { datamodel .models() .filter(|model| !model.is_ignored()) @@ -201,7 +136,7 @@ fn composite_field_builders(datamodel: &Datamodel, composite: &dml::CompositeTyp .collect() } -fn relation_builders(placeholders: &[RelationPlaceholder]) -> Vec { +pub(crate) fn relation_builders(placeholders: &[RelationPlaceholder]) -> Vec { placeholders .iter() .filter(|r| r.model_a.is_relation_supported(&r.field_a) && r.model_b.is_relation_supported(&r.field_b)) @@ -245,7 +180,7 @@ fn pk_builder(model: &dml::Model) -> Option { }) } -fn composite_type_builders(datamodel: &Datamodel) -> Vec { +pub(crate) fn composite_type_builders(datamodel: &Datamodel) -> Vec { datamodel .composite_types .iter() @@ -256,7 +191,7 @@ fn composite_type_builders(datamodel: &Datamodel) -> Vec { .collect() } -fn convert_enums(datamodel: &Datamodel) -> Vec { +pub(crate) fn convert_enums(datamodel: &Datamodel) -> Vec { datamodel .enums() .map(|e| InternalEnum { @@ -276,7 +211,7 @@ fn convert_enum_values(enm: &dml::Enum) -> Vec { } /// Calculates placeholders that are used to compute builders dependent on some relation information being present already. -fn relation_placeholders(datamodel: &dml::Datamodel) -> Vec { +pub(crate) fn relation_placeholders(datamodel: &dml::Datamodel) -> Vec { let mut result = Vec::new(); for model in datamodel.models().filter(|model| !model.is_ignored) { diff --git a/query-engine/prisma-models/src/convert.rs b/query-engine/prisma-models/src/convert.rs new file mode 100644 index 000000000000..57723eb6adcb --- /dev/null +++ b/query-engine/prisma-models/src/convert.rs @@ -0,0 +1,45 @@ +use crate::{builders, InternalDataModel, InternalDataModelRef}; +use once_cell::sync::OnceCell; +use std::sync::Arc; + +pub fn convert(schema: &psl::ValidatedSchema, db_name: String) -> InternalDataModelRef { + let datamodel = psl::lift(schema); + + let relation_placeholders = builders::relation_placeholders(&datamodel); + let models = builders::model_builders(&datamodel, &relation_placeholders); + let relations = builders::relation_builders(&relation_placeholders); + let enums = builders::convert_enums(&datamodel); + let composite_types = builders::composite_type_builders(&datamodel); + let internal_data_model = Arc::new(InternalDataModel { + models: OnceCell::new(), + composite_types: OnceCell::new(), + relations: OnceCell::new(), + relation_fields: OnceCell::new(), + db_name, + enums: enums.into_iter().map(Arc::new).collect(), + }); + + let composite_types = builders::build_composites(composite_types, Arc::downgrade(&internal_data_model)); + internal_data_model.composite_types.set(composite_types).unwrap(); + + let models = models + .into_iter() + .map(|mt| { + mt.build( + Arc::downgrade(&internal_data_model), + internal_data_model.composite_types.get().unwrap(), + ) + }) + .collect(); + + internal_data_model.models.set(models).unwrap(); + + let relations = relations + .into_iter() + .map(|rt| rt.build(Arc::downgrade(&internal_data_model))) + .collect(); + + internal_data_model.relations.set(relations).unwrap(); + internal_data_model.finalize(); + internal_data_model +} diff --git a/query-engine/prisma-models/src/lib.rs b/query-engine/prisma-models/src/lib.rs index 3dce141087ee..83f35244fbe7 100644 --- a/query-engine/prisma-models/src/lib.rs +++ b/query-engine/prisma-models/src/lib.rs @@ -5,6 +5,7 @@ mod builders; mod composite_type; +mod convert; mod error; mod extensions; mod field; @@ -25,8 +26,8 @@ mod selection_result; pub mod pk; pub mod prelude; -pub use builders::InternalDataModelBuilder; pub use composite_type::*; +pub use convert::convert; pub use error::*; pub use field::*; pub use field_selection::*; diff --git a/query-engine/prisma-models/tests/datamodel_converter_tests.rs b/query-engine/prisma-models/tests/datamodel_converter_tests.rs index a29cbaa8eb62..9a12afb3bd8d 100644 --- a/query-engine/prisma-models/tests/datamodel_converter_tests.rs +++ b/query-engine/prisma-models/tests/datamodel_converter_tests.rs @@ -469,7 +469,7 @@ fn duplicate_relation_name() { "#; let dml = psl::parse_schema_parserdb(schema).unwrap(); - InternalDataModelBuilder::from(&psl::lift(&dml)).build(String::new()); + prisma_models::convert(&dml, String::new()); } #[test] @@ -492,8 +492,7 @@ fn implicit_many_to_many_relation() { fn convert(datamodel: &str) -> Arc { let schema = psl::parse_schema_parserdb(datamodel).unwrap(); - let builder = InternalDataModelBuilder::new(&schema); - builder.build("not_important".to_string()) + prisma_models::convert(&schema, "not_important".to_string()) } trait DatamodelAssertions { diff --git a/query-engine/query-engine-node-api/src/engine.rs b/query-engine/query-engine-node-api/src/engine.rs index 2dfabfb4d236..9e250de822d7 100644 --- a/query-engine/query-engine-node-api/src/engine.rs +++ b/query-engine/query-engine-node-api/src/engine.rs @@ -1,7 +1,6 @@ use crate::{error::ApiError, log_callback::LogCallback, logger::Logger}; use futures::FutureExt; -use prisma_models::InternalDataModelBuilder; -use psl::{common::preview_features::PreviewFeature, dml::Datamodel}; +use psl::common::preview_features::PreviewFeature; use query_core::{ executor, schema::{QuerySchema, QuerySchemaRenderer}, @@ -42,24 +41,16 @@ enum Inner { Connected(ConnectedEngine), } -/// Holding the information to reconnect the engine if needed. -#[derive(Debug, Clone)] -struct EngineDatamodel { - ast: Datamodel, - raw: String, -} - /// Everything needed to connect to the database and have the core running. struct EngineBuilder { - datamodel: EngineDatamodel, - config: psl::Configuration, + schema: Arc, config_dir: PathBuf, env: HashMap, } /// Internal structure for querying and reconnecting with the engine. struct ConnectedEngine { - datamodel: EngineDatamodel, + schema: Arc, query_schema: Arc, executor: crate::Executor, config_dir: PathBuf, @@ -178,16 +169,8 @@ impl QueryEngine { let enable_metrics = config.preview_features().contains(PreviewFeature::Metrics); let enable_tracing = config.preview_features().contains(PreviewFeature::Tracing); - let ast = psl::lift(&schema); - - let datamodel = EngineDatamodel { - ast, - raw: schema.db.source().to_owned(), - }; - let builder = EngineBuilder { - datamodel, - config: schema.configuration, + schema: Arc::new(schema), config_dir, env, }; @@ -231,22 +214,23 @@ impl QueryEngine { let engine = async move { // We only support one data source & generator at the moment, so take the first one (default not exposed yet). let data_source = builder - .config + .schema + .configuration .datasources .first() .ok_or_else(|| ApiError::configuration("No valid data source found"))?; - let preview_features: Vec<_> = builder.config.preview_features().iter().collect(); + let preview_features: Vec<_> = builder.schema.configuration.preview_features().iter().collect(); let url = data_source .load_url_with_config_dir(&builder.config_dir, |key| builder.env.get(key).map(ToString::to_string)) - .map_err(|err| crate::error::ApiError::Conversion(err, builder.datamodel.raw.clone()))?; + .map_err(|err| crate::error::ApiError::Conversion(err, builder.schema.db.source().to_owned()))?; let (db_name, executor) = executor::load(data_source, &preview_features, &url).await?; let connector = executor.primary_connector(); connector.get_connection().await?; // Build internal data model - let internal_data_model = InternalDataModelBuilder::from(&builder.datamodel.ast).build(db_name); + let internal_data_model = prisma_models::convert(&builder.schema, db_name); let query_schema = schema_builder::build( internal_data_model, @@ -257,7 +241,7 @@ impl QueryEngine { ); Ok(ConnectedEngine { - datamodel: builder.datamodel.clone(), + schema: builder.schema.clone(), query_schema: Arc::new(query_schema), executor, config_dir: builder.config_dir.clone(), @@ -291,12 +275,8 @@ impl QueryEngine { let mut inner = self.inner.write().await; let engine = inner.as_engine()?; - let config = psl::parse_configuration(&engine.datamodel.raw) - .map_err(|errors| ApiError::conversion(errors, &engine.datamodel.raw))?; - let builder = EngineBuilder { - datamodel: engine.datamodel.clone(), - config, + schema: engine.schema.clone(), config_dir: engine.config_dir.clone(), env: engine.env.clone(), }; diff --git a/query-engine/query-engine-node-api/src/functions.rs b/query-engine/query-engine-node-api/src/functions.rs index 095ed8c34caa..1f3e6ebf711a 100644 --- a/query-engine/query-engine-node-api/src/functions.rs +++ b/query-engine/query-engine-node-api/src/functions.rs @@ -1,7 +1,6 @@ use crate::error::ApiError; use napi::{bindgen_prelude::*, JsUnknown}; use napi_derive::napi; -use prisma_models::InternalDataModelBuilder; use query_core::{schema::QuerySchemaRef, schema_builder}; use request_handlers::dmmf; use std::{ @@ -42,7 +41,7 @@ pub fn dmmf(datamodel_string: String) -> napi::Result { let referential_integrity = datasource.map(|ds| ds.referential_integrity()).unwrap_or_default(); - let internal_data_model = InternalDataModelBuilder::from(&datamodel).build("".into()); + let internal_data_model = prisma_models::convert(&schema, "".into()); let query_schema: QuerySchemaRef = Arc::new(schema_builder::build( internal_data_model, diff --git a/query-engine/query-engine/src/cli.rs b/query-engine/query-engine/src/cli.rs index 4d8ee8a09df5..2a4f8a9d5e02 100644 --- a/query-engine/query-engine/src/cli.rs +++ b/query-engine/query-engine/src/cli.rs @@ -3,21 +3,20 @@ use crate::{ opt::{CliOpt, PrismaOpt, Subcommand}, PrismaResult, }; -use prisma_models::InternalDataModelBuilder; -use psl::{dml::Datamodel, Configuration}; +use psl::Configuration; use query_core::{schema::QuerySchemaRef, schema_builder}; use request_handlers::{dmmf, GraphQlHandler}; use std::{env, sync::Arc}; pub struct ExecuteRequest { query: String, - datamodel: Datamodel, + datamodel: psl::ValidatedSchema, config: Configuration, enable_raw_queries: bool, } pub struct DmmfRequest { - datamodel: Datamodel, + datamodel: psl::ValidatedSchema, enable_raw_queries: bool, config: Configuration, } @@ -94,7 +93,7 @@ impl CliCommand { let referential_integrity = datasource.map(|ds| ds.referential_integrity()).unwrap_or_default(); // temporary code duplication - let internal_data_model = InternalDataModelBuilder::from(&request.datamodel).build("".into()); + let internal_data_model = prisma_models::convert(&request.datamodel, "".into()); let query_schema: QuerySchemaRef = Arc::new(schema_builder::build( internal_data_model, request.enable_raw_queries, @@ -103,7 +102,7 @@ impl CliCommand { referential_integrity, )); - let dmmf = dmmf::render_dmmf(&request.datamodel, query_schema); + let dmmf = dmmf::render_dmmf(&psl::lift(&request.datamodel), query_schema); let serialized = serde_json::to_string_pretty(&dmmf)?; println!("{}", serialized); @@ -132,7 +131,7 @@ impl CliCommand { request.config.validate_that_one_datasource_is_provided()?; - let cx = PrismaContext::builder(request.config, request.datamodel) + let cx = PrismaContext::builder(request.datamodel) .enable_raw_queries(request.enable_raw_queries) .build() .await?; diff --git a/query-engine/query-engine/src/context.rs b/query-engine/query-engine/src/context.rs index 4d38d07715d1..2c4dc1ce9195 100644 --- a/query-engine/query-engine/src/context.rs +++ b/query-engine/query-engine/src/context.rs @@ -1,6 +1,5 @@ use crate::{PrismaError, PrismaResult}; -use prisma_models::InternalDataModelBuilder; -use psl::{dml::Datamodel, Configuration}; +use psl::dml::Datamodel; use query_core::{executor, schema::QuerySchemaRef, schema_builder, QueryExecutor}; use query_engine_metrics::MetricRegistry; use std::{env, fmt, sync::Arc}; @@ -25,8 +24,7 @@ impl fmt::Debug for PrismaContext { pub struct ContextBuilder { enable_raw_queries: bool, - datamodel: Datamodel, - config: Configuration, + schema: psl::ValidatedSchema, metrics: Option, } @@ -42,24 +40,18 @@ impl ContextBuilder { } pub async fn build(self) -> PrismaResult { - PrismaContext::new( - self.config, - self.datamodel, - self.enable_raw_queries, - self.metrics.unwrap_or_default(), - ) - .await + PrismaContext::new(self.schema, self.enable_raw_queries, self.metrics.unwrap_or_default()).await } } impl PrismaContext { /// Initializes a new Prisma context. async fn new( - config: Configuration, - dm: Datamodel, + schema: psl::ValidatedSchema, enable_raw_queries: bool, metrics: MetricRegistry, ) -> PrismaResult { + let config = &schema.configuration; // We only support one data source at the moment, so take the first one (default not exposed yet). let data_source = config .datasources @@ -73,7 +65,7 @@ impl PrismaContext { let (db_name, executor) = executor::load(data_source, &preview_features, &url).await?; // Build internal data model - let internal_data_model = InternalDataModelBuilder::from(&dm).build(db_name); + let internal_data_model = prisma_models::convert(&schema, db_name); // Construct query schema let query_schema: QuerySchemaRef = Arc::new(schema_builder::build( @@ -86,7 +78,7 @@ impl PrismaContext { let context = Self { query_schema, - dm, + dm: psl::lift(&schema), executor, metrics, }; @@ -101,11 +93,10 @@ impl PrismaContext { Ok(()) } - pub fn builder(config: Configuration, datamodel: Datamodel) -> ContextBuilder { + pub fn builder(schema: psl::ValidatedSchema) -> ContextBuilder { ContextBuilder { enable_raw_queries: false, - datamodel, - config, + schema, metrics: None, } } diff --git a/query-engine/query-engine/src/opt.rs b/query-engine/query-engine/src/opt.rs index 651ad6b19ed9..597338f9de34 100644 --- a/query-engine/query-engine/src/opt.rs +++ b/query-engine/query-engine/src/opt.rs @@ -1,5 +1,4 @@ use crate::{error::PrismaError, PrismaResult}; -use psl::dml::Datamodel; use serde::Deserialize; use std::{env, ffi::OsStr, fs::File, io::Read}; use structopt::StructOpt; @@ -130,7 +129,7 @@ impl PrismaOpt { Ok(res) } - pub fn datamodel(&self) -> PrismaResult { + pub fn datamodel(&self) -> PrismaResult { let datamodel_str = self.datamodel_str()?; let mut schema = psl::validate(datamodel_str.into()); @@ -139,7 +138,7 @@ impl PrismaOpt { .to_result() .map_err(|errors| PrismaError::ConversionError(errors, datamodel_str.to_string()))?; - Ok(psl::lift(&schema)) + Ok(schema) } pub fn configuration(&self, ignore_env_errors: bool) -> PrismaResult { diff --git a/query-engine/query-engine/src/server/mod.rs b/query-engine/query-engine/src/server/mod.rs index b5dddf9058ef..4204366ce211 100644 --- a/query-engine/query-engine/src/server/mod.rs +++ b/query-engine/query-engine/src/server/mod.rs @@ -73,7 +73,7 @@ pub async fn setup(opts: &PrismaOpt, metrics: MetricRegistry) -> PrismaResult (QuerySchema, psl::dml::Datam .unwrap_or(&psl::datamodel_connector::EmptyDatamodelConnector); let referential_integrity = datasource.map(|ds| ds.referential_integrity()).unwrap_or_default(); - let internal_ref = InternalDataModelBuilder::from(&psl::lift(&dm)).build("db".to_owned()); + let internal_ref = prisma_models::convert(&dm, "db".to_owned()); let schema = schema_builder::build( internal_ref, false, diff --git a/query-engine/query-engine/src/tests/errors.rs b/query-engine/query-engine/src/tests/errors.rs index d47950ce3822..b61951818d59 100644 --- a/query-engine/query-engine/src/tests/errors.rs +++ b/query-engine/query-engine/src/tests/errors.rs @@ -30,10 +30,9 @@ async fn connection_string_problems_give_a_nice_error() { provider.1 ); - let config = psl::parse_configuration(&dm).unwrap(); - let dml = psl::lift(&psl::parse_schema_parserdb(dm).unwrap()); + let dml = psl::parse_schema_parserdb(dm).unwrap(); - let error = PrismaContext::builder(config, dml) + let error = PrismaContext::builder(dml) .enable_raw_queries(true) .build() .await