Skip to content

Commit

Permalink
feat(prisma-fmt): add get_datamodel method (#4946)
Browse files Browse the repository at this point in the history
Add `get_datamodel` method to get just that part of the DMMF without
building, serializing, sending across WASM boundary and then
deserializing the whole DMMF.
  • Loading branch information
aqrln authored Jul 10, 2024
1 parent 3aad0d1 commit 4b84e51
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 1 deletion.
209 changes: 209 additions & 0 deletions prisma-fmt/src/get_datamodel.rs
Original file line number Diff line number Diff line change
@@ -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<String, String> {
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::<serde_json::Value>(&response).unwrap()).unwrap();

expected.assert_eq(&prettified_response);
}
}
5 changes: 5 additions & 0 deletions prisma-fmt/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod actions;
mod code_actions;
mod get_config;
mod get_datamodel;
mod get_dmmf;
mod lint;
mod merge_schemas;
Expand Down Expand Up @@ -275,3 +276,7 @@ pub fn get_config(get_config_params: String) -> String {
pub fn get_dmmf(get_dmmf_params: String) -> Result<String, String> {
get_dmmf::get_dmmf(&get_dmmf_params)
}

pub fn get_datamodel(get_datamodel_params: String) -> Result<String, String> {
get_datamodel::get_datamodel(&get_datamodel_params)
}
6 changes: 6 additions & 0 deletions prisma-schema-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ pub fn get_dmmf(params: String) -> Result<String, JsError> {
prisma_fmt::get_dmmf(params).map_err(|e| JsError::new(&e))
}

#[wasm_bindgen]
pub fn get_datamodel(params: String) -> Result<String, JsError> {
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();
Expand Down
7 changes: 6 additions & 1 deletion query-engine/dmmf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
}

0 comments on commit 4b84e51

Please sign in to comment.