Skip to content

Commit

Permalink
feat(schema-cli): support multi file schema
Browse files Browse the repository at this point in the history
remove dead code

fix tests
  • Loading branch information
Weakky committed May 21, 2024
1 parent 0af42cb commit 0ab9913
Show file tree
Hide file tree
Showing 48 changed files with 711 additions and 376 deletions.
54 changes: 41 additions & 13 deletions libs/test-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,21 +196,26 @@ async fn main() -> anyhow::Result<()> {
);
}

let schema = if let Some(file_path) = file_path {
read_datamodel_from_file(&file_path)?
} else if let Some(url) = url {
minimal_schema_from_url(&url)?
let schema = if let Some(file_path) = &file_path {
read_datamodel_from_file(file_path)?
} else if let Some(url) = &url {
minimal_schema_from_url(url)?
} else {
unreachable!()
};

let api = schema_core::schema_api(Some(schema.clone()), None)?;

let params = IntrospectParams {
schema,
schema: SchemasContainer {
files: vec![SchemaContainer {
path: file_path.unwrap_or_else(|| "schema.prisma".to_string()),
content: schema,
}],
},
force: false,
composite_type_depth: composite_type_depth.unwrap_or(0),
schemas: None,
namespaces: None,
};

let introspected = api.introspect(params).await.map_err(|err| anyhow::anyhow!("{err:?}"))?;
Expand Down Expand Up @@ -240,7 +245,12 @@ async fn main() -> anyhow::Result<()> {
let api = schema_core::schema_api(Some(schema.clone()), None)?;

api.create_database(CreateDatabaseParams {
datasource: DatasourceParam::SchemaString(SchemaContainer { schema }),
datasource: DatasourceParam::SchemaString(SchemasContainer {
files: vec![SchemaContainer {
path: "schema.prisma".to_string(),
content: schema,
}],
}),
})
.await?;
}
Expand All @@ -252,7 +262,12 @@ async fn main() -> anyhow::Result<()> {

let input = CreateMigrationInput {
migrations_directory_path: cmd.migrations_path,
prisma_schema,
schema: SchemasContainer {
files: vec![SchemaContainer {
path: cmd.schema_path,
content: prisma_schema,
}],
},
migration_name: cmd.name,
draft: true,
};
Expand Down Expand Up @@ -315,10 +330,15 @@ async fn generate_dmmf(cmd: &DmmfCommand) -> anyhow::Result<()> {
let api = schema_core::schema_api(Some(skeleton.clone()), None)?;

let params = IntrospectParams {
schema: skeleton,
schema: SchemasContainer {
files: vec![SchemaContainer {
path: "schema.prisma".to_string(),
content: skeleton,
}],
},
force: false,
composite_type_depth: -1,
schemas: None,
namespaces: None,
};

let introspected = api.introspect(params).await.map_err(|err| anyhow::anyhow!("{err:?}"))?;
Expand Down Expand Up @@ -355,7 +375,12 @@ async fn schema_push(cmd: &SchemaPush) -> anyhow::Result<()> {

let response = api
.schema_push(SchemaPushInput {
schema,
schema: SchemasContainer {
files: vec![SchemaContainer {
path: cmd.schema_path.clone(),
content: schema,
}],
},
force: cmd.force,
})
.await?;
Expand Down Expand Up @@ -414,8 +439,11 @@ async fn migrate_diff(cmd: &MigrateDiff) -> anyhow::Result<()> {

let api = schema_core::schema_api(None, Some(Arc::new(DiffHost)))?;
let to = if let Some(to_schema_datamodel) = &cmd.to_schema_datamodel {
DiffTarget::SchemaDatamodel(SchemaContainer {
schema: to_schema_datamodel.clone(),
DiffTarget::SchemaDatamodel(SchemasContainer {
files: vec![SchemaContainer {
path: "schema.prisma".to_string(),
content: to_schema_datamodel.clone(),
}],
})
} else {
todo!("can't handle {:?} yet", cmd)
Expand Down
6 changes: 0 additions & 6 deletions prisma-schema-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,6 @@ pub fn validate(params: String) -> Result<(), JsError> {
prisma_fmt::validate(params).map_err(|e| JsError::new(&e))
}

#[wasm_bindgen]
pub fn merge_schemas(input: String) -> Result<String, JsError> {
register_panic_hook();
prisma_fmt::merge_schemas(input).map_err(|e| JsError::new(&e))
}

#[wasm_bindgen]
pub fn native_types(input: String) -> String {
register_panic_hook();
Expand Down
5 changes: 5 additions & 0 deletions psl/parser-database/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ impl ParserDatabase {
self.asts.iter().map(|ast| ast.2.as_str())
}

/// Iterate all source file contents and their file paths.
pub fn iter_file_sources(&self) -> impl Iterator<Item = (&str, &str)> {
self.asts.iter().map(|ast| (ast.1.as_str(), ast.2.as_str()))
}

/// The name of the file.
pub fn file_name(&self, file_id: FileId) -> &str {
self.asts[file_id].0.as_str()
Expand Down
10 changes: 10 additions & 0 deletions psl/psl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ pub fn parse_schema(file: impl Into<SourceFile>) -> Result<ValidatedSchema, Stri
Ok(schema)
}

/// Parse and analyze a Prisma schema.
pub fn parse_schema_multi(files: Vec<(String, SourceFile)>) -> Result<ValidatedSchema, String> {
let mut schema = validate_multi_file(files);
schema
.diagnostics
.to_result()
.map_err(|err| err.to_pretty_string("schema.prisma", schema.db.source_assert_single()))?;
Ok(schema)
}

/// 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) -> ValidatedSchema {
Expand Down
4 changes: 2 additions & 2 deletions psl/schema-ast/src/source_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::sync::Arc;
use serde::{Deserialize, Deserializer};

/// A Prisma schema document.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct SourceFile {
contents: Contents,
}
Expand Down Expand Up @@ -77,7 +77,7 @@ impl From<String> for SourceFile {
}
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum Contents {
Static(&'static str),
Allocated(Arc<str>),
Expand Down
6 changes: 5 additions & 1 deletion query-engine/connector-test-kit-rs/qe-setup/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,11 @@ pub(crate) async fn diff(schema: &str, url: String, connector: &mut dyn SchemaCo
.database_schema_from_diff_target(DiffTarget::Empty, None, None)
.await?;
let to = connector
.database_schema_from_diff_target(DiffTarget::Datamodel(schema.into()), None, None)
.database_schema_from_diff_target(
DiffTarget::Datamodel(vec![("schema.prisma".to_string(), schema.into())]),
None,
None,
)
.await?;
let migration = connector.diff(from, to);
connector.render_script(&migration, &Default::default())
Expand Down
35 changes: 20 additions & 15 deletions schema-engine/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ use structopt::StructOpt;
#[derive(Debug, StructOpt)]
#[structopt(version = env!("GIT_HASH"))]
struct SchemaEngineCli {
/// Path to the datamodel
/// List of paths to the Prisma schema files.
#[structopt(short = "d", long, name = "FILE")]
datamodel: Option<String>,
datamodels: Option<Vec<String>>,
#[structopt(subcommand)]
cli_subcommand: Option<SubCommand>,
}
Expand All @@ -36,7 +36,7 @@ async fn main() {
let input = SchemaEngineCli::from_args();

match input.cli_subcommand {
None => start_engine(input.datamodel.as_deref()).await,
None => start_engine(input.datamodels).await,
Some(SubCommand::Cli(cli_command)) => {
tracing::info!(git_hash = env!("GIT_HASH"), "Starting schema engine CLI");
cli_command.run().await;
Expand Down Expand Up @@ -91,30 +91,35 @@ impl ConnectorHost for JsonRpcHost {
}
}

async fn start_engine(datamodel_location: Option<&str>) {
async fn start_engine(datamodel_locations: Option<Vec<String>>) {
use std::io::Read as _;

tracing::info!(git_hash = env!("GIT_HASH"), "Starting schema engine RPC server",);

let datamodel = datamodel_location.map(|location| {
let mut file = match std::fs::File::open(location) {
Ok(file) => file,
Err(e) => panic!("Error opening datamodel file in `{location}`: {e}"),
};
let datamodel_locations = datamodel_locations.map(|datamodel_locations| {
datamodel_locations
.into_iter()
.map(|location| {
let mut file = match std::fs::File::open(&location) {
Ok(file) => file,
Err(e) => panic!("Error opening datamodel file in `{location}`: {e}"),
};

let mut datamodel = String::new();
let mut datamodel = String::new();

if let Err(e) = file.read_to_string(&mut datamodel) {
panic!("Error reading datamodel file `{location}`: {e}");
};
if let Err(e) = file.read_to_string(&mut datamodel) {
panic!("Error reading datamodel file `{location}`: {e}");
};

datamodel
(location, datamodel)
})
.collect::<Vec<_>>()
});

let (client, adapter) = json_rpc_stdio::new_client();
let host = JsonRpcHost { client };

let api = rpc_api(datamodel, Arc::new(host));
let api = rpc_api(datamodel_locations, Arc::new(host));
// Block the thread and handle IO in async until EOF.
json_rpc_stdio::run_with_client(&api, adapter).await.unwrap();
}
53 changes: 39 additions & 14 deletions schema-engine/cli/tests/cli_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,18 @@ where
}));

child.kill().unwrap();
res.unwrap();
match res {
Ok(_) => (),
Err(panic_payload) => {
let res = panic_payload
.downcast_ref::<&str>()
.map(|s| -> String { (*s).to_owned() })
.or_else(|| panic_payload.downcast_ref::<String>().map(|s| s.to_owned()))
.unwrap_or_default();

panic!("Error: '{}'", res)
}
}
}

struct TestApi {
Expand Down Expand Up @@ -324,7 +335,7 @@ fn basic_jsonrpc_roundtrip_works_with_no_params(_api: TestApi) {
fs::write(&tmpfile, datamodel).unwrap();

let mut command = Command::new(schema_engine_bin_path());
command.arg("--datamodel").arg(&tmpfile).env("RUST_LOG", "info");
command.arg("--datamodels").arg(&tmpfile).env("RUST_LOG", "info");

with_child_process(command, |process| {
let stdin = process.stdin.as_mut().unwrap();
Expand All @@ -350,32 +361,46 @@ fn basic_jsonrpc_roundtrip_works_with_params(_api: TestApi) {
let tmpdir = tempfile::tempdir().unwrap();
let tmpfile = tmpdir.path().join("datamodel");

let datamodel = r#"
let datamodel = indoc! {r#"
datasource db {
provider = "postgres"
url = env("TEST_DATABASE_URL")
}
"#;
"#};

fs::create_dir_all(&tmpdir).unwrap();
fs::write(&tmpfile, datamodel).unwrap();

let command = Command::new(schema_engine_bin_path());

let path = tmpfile.to_str().unwrap();
let schema_path_params = format!(r#"{{ "datasource": {{ "tag": "SchemaPath", "path": "{path}" }} }}"#);
let schema_path_params = serde_json::json!({
"datasource": {
"tag": "SchemaString",
"files": [{ "path": path, "content": datamodel }]
}
});

let url = std::env::var("TEST_DATABASE_URL").unwrap();
let connection_string_params = format!(r#"{{ "datasource": {{ "tag": "ConnectionString", "url": "{url}" }} }}"#);
let connection_string_params = serde_json::json!({
"datasource": {
"tag": "ConnectionString",
"url": std::env::var("TEST_DATABASE_URL").unwrap()
}
});

with_child_process(command, |process| {
let stdin = process.stdin.as_mut().unwrap();
let mut stdout = BufReader::new(process.stdout.as_mut().unwrap());

for _ in 0..2 {
for params in [&schema_path_params, &connection_string_params] {
let params_template =
format!(r#"{{ "jsonrpc": "2.0", "method": "getDatabaseVersion", "params": {params}, "id": 1 }}"#);
let params_template = serde_json::json!({
"jsonrpc": "2.0",
"method": "getDatabaseVersion",
"params": params,
"id": 1
})
.to_string();

writeln!(stdin, "{}", &params_template).unwrap();

Expand Down Expand Up @@ -416,7 +441,7 @@ fn introspect_sqlite_empty_database() {
"method": "introspect",
"id": 1,
"params": {
"schema": schema,
"schema": { "files": [{ "path": "schema.prisma", "content": schema }] },
"force": true,
"compositeTypeDepth": 5,
}
Expand Down Expand Up @@ -463,7 +488,7 @@ fn introspect_sqlite_invalid_empty_database() {
"method": "introspect",
"id": 1,
"params": {
"schema": schema,
"schema": { "files": [{ "path": "schema.prisma", "content": schema }] },
"force": true,
"compositeTypeDepth": -1,
}
Expand Down Expand Up @@ -517,7 +542,7 @@ fn execute_postgres(api: TestApi) {
"params": {
"datasourceType": {
"tag": "schema",
"schema": &schema_path,
"files": [{ "path": &schema_path, "content": &schema }],
},
"script": "SELECT 1;",
}
Expand Down Expand Up @@ -593,7 +618,7 @@ fn introspect_postgres(api: TestApi) {
"params": {
"datasourceType": {
"tag": "schema",
"schema": &schema_path,
"files": [{ "path": &schema_path, "content": &schema }],
},
"script": script,
}
Expand All @@ -617,7 +642,7 @@ fn introspect_postgres(api: TestApi) {
"method": "introspect",
"id": 1,
"params": {
"schema": &schema,
"schema": { "files": [{ "path": &schema_path, "content": &schema }] },
"force": true,
"compositeTypeDepth": 5,
}
Expand Down
6 changes: 4 additions & 2 deletions schema-engine/connectors/mongodb-schema-connector/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ impl MongoDbSchemaConnector {

async fn mongodb_schema_from_diff_target(&self, target: DiffTarget<'_>) -> ConnectorResult<MongoSchema> {
match target {
DiffTarget::Datamodel(schema) => {
let validated_schema = psl::parse_schema(schema).map_err(ConnectorError::new_schema_parser_error)?;
DiffTarget::Datamodel(sources) => {
let validated_schema =
psl::parse_schema_multi(sources).map_err(ConnectorError::new_schema_parser_error)?;

Ok(schema_calculator::calculate(&validated_schema))
}
DiffTarget::Database => self.client().await?.describe().await,
Expand Down
Loading

0 comments on commit 0ab9913

Please sign in to comment.