diff --git a/prisma-fmt/src/get_datamodel.rs b/prisma-fmt/src/get_datamodel.rs new file mode 100644 index 000000000000..3e3a03675898 --- /dev/null +++ b/prisma-fmt/src/get_datamodel.rs @@ -0,0 +1,209 @@ +use serde::Deserialize; + +use crate::{schema_file_input::SchemaFileInput, validate}; + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct GetDatamodelParams { + prisma_schema: SchemaFileInput, + #[serde(default)] + no_color: bool, +} + +pub(crate) fn get_datamodel(params: &str) -> Result { + let params: GetDatamodelParams = + serde_json::from_str(params).map_err(|e| format!("Failed to deserialize GetDatamodelParams: {e}"))?; + + let schema = validate::run(params.prisma_schema, params.no_color)?; + + let datamodel = dmmf::datamodel_from_validated_schema(&schema); + + Ok(serde_json::to_string(&datamodel).unwrap()) +} + +#[cfg(test)] +mod tests { + use super::*; + use expect_test::expect; + use indoc::indoc; + use serde_json::json; + + #[test] + fn sample_schema() { + let schema = indoc! {r#" + generator js { + provider = "prisma-client-js" + } + + datasource db { + provider = "postgresql" + url = env("DATABASE_URL") + } + + model User { + id Int @id @default(autoincrement()) + email String @unique + posts Post[] + } + + model Post { + id Int @id @default(autoincrement()) + title String + author User @relation(fields: [authorId], references: [id]) + authorId Int + + @@index([title], name: "idx_post_on_title") + } + "#}; + + let expected = expect![[r#" + { + "enums": [], + "models": [ + { + "name": "User", + "dbName": null, + "fields": [ + { + "name": "id", + "kind": "scalar", + "isList": false, + "isRequired": true, + "isUnique": false, + "isId": true, + "isReadOnly": false, + "hasDefaultValue": true, + "type": "Int", + "default": { + "name": "autoincrement", + "args": [] + }, + "isGenerated": false, + "isUpdatedAt": false + }, + { + "name": "email", + "kind": "scalar", + "isList": false, + "isRequired": true, + "isUnique": true, + "isId": false, + "isReadOnly": false, + "hasDefaultValue": false, + "type": "String", + "isGenerated": false, + "isUpdatedAt": false + }, + { + "name": "posts", + "kind": "object", + "isList": true, + "isRequired": true, + "isUnique": false, + "isId": false, + "isReadOnly": false, + "hasDefaultValue": false, + "type": "Post", + "relationName": "PostToUser", + "relationFromFields": [], + "relationToFields": [], + "isGenerated": false, + "isUpdatedAt": false + } + ], + "primaryKey": null, + "uniqueFields": [], + "uniqueIndexes": [], + "isGenerated": false + }, + { + "name": "Post", + "dbName": null, + "fields": [ + { + "name": "id", + "kind": "scalar", + "isList": false, + "isRequired": true, + "isUnique": false, + "isId": true, + "isReadOnly": false, + "hasDefaultValue": true, + "type": "Int", + "default": { + "name": "autoincrement", + "args": [] + }, + "isGenerated": false, + "isUpdatedAt": false + }, + { + "name": "title", + "kind": "scalar", + "isList": false, + "isRequired": true, + "isUnique": false, + "isId": false, + "isReadOnly": false, + "hasDefaultValue": false, + "type": "String", + "isGenerated": false, + "isUpdatedAt": false + }, + { + "name": "author", + "kind": "object", + "isList": false, + "isRequired": true, + "isUnique": false, + "isId": false, + "isReadOnly": false, + "hasDefaultValue": false, + "type": "User", + "relationName": "PostToUser", + "relationFromFields": [ + "authorId" + ], + "relationToFields": [ + "id" + ], + "isGenerated": false, + "isUpdatedAt": false + }, + { + "name": "authorId", + "kind": "scalar", + "isList": false, + "isRequired": true, + "isUnique": false, + "isId": false, + "isReadOnly": true, + "hasDefaultValue": false, + "type": "Int", + "isGenerated": false, + "isUpdatedAt": false + } + ], + "primaryKey": null, + "uniqueFields": [], + "uniqueIndexes": [], + "isGenerated": false + } + ], + "types": [] + }"#]]; + + let response = get_datamodel( + &json!({ + "prismaSchema": schema + }) + .to_string(), + ) + .unwrap(); + + let prettified_response = + serde_json::to_string_pretty(&serde_json::from_str::(&response).unwrap()).unwrap(); + + expected.assert_eq(&prettified_response); + } +} diff --git a/prisma-fmt/src/lib.rs b/prisma-fmt/src/lib.rs index f2838915bcbb..e21c6eef97e9 100644 --- a/prisma-fmt/src/lib.rs +++ b/prisma-fmt/src/lib.rs @@ -1,6 +1,7 @@ mod actions; mod code_actions; mod get_config; +mod get_datamodel; mod get_dmmf; mod lint; mod merge_schemas; @@ -275,3 +276,7 @@ pub fn get_config(get_config_params: String) -> String { pub fn get_dmmf(get_dmmf_params: String) -> Result { get_dmmf::get_dmmf(&get_dmmf_params) } + +pub fn get_datamodel(get_datamodel_params: String) -> Result { + get_datamodel::get_datamodel(&get_datamodel_params) +} diff --git a/prisma-schema-wasm/src/lib.rs b/prisma-schema-wasm/src/lib.rs index 5cbb08067877..36a2c9d353ff 100644 --- a/prisma-schema-wasm/src/lib.rs +++ b/prisma-schema-wasm/src/lib.rs @@ -49,6 +49,12 @@ pub fn get_dmmf(params: String) -> Result { prisma_fmt::get_dmmf(params).map_err(|e| JsError::new(&e)) } +#[wasm_bindgen] +pub fn get_datamodel(params: String) -> Result { + register_panic_hook(); + prisma_fmt::get_datamodel(params).map_err(|e| JsError::new(&e)) +} + #[wasm_bindgen] pub fn lint(input: String) -> String { register_panic_hook(); diff --git a/query-engine/dmmf/src/lib.rs b/query-engine/dmmf/src/lib.rs index 42cfb2757ca4..8007362cf4fc 100644 --- a/query-engine/dmmf/src/lib.rs +++ b/query-engine/dmmf/src/lib.rs @@ -5,7 +5,7 @@ mod serialization_ast; mod tests; use psl::ValidatedSchema; -pub use serialization_ast::DataModelMetaFormat; +pub use serialization_ast::{DataModelMetaFormat, Datamodel}; use ast_builders::schema_to_dmmf; use schema::QuerySchema; @@ -36,3 +36,8 @@ pub fn from_precomputed_parts(query_schema: &QuerySchema) -> DataModelMetaFormat mappings, } } + +#[inline] +pub fn datamodel_from_validated_schema(schema: &ValidatedSchema) -> Datamodel { + schema_to_dmmf(schema) +}