diff --git a/prisma-fmt/src/get_dmmf.rs b/prisma-fmt/src/get_dmmf.rs index cc8a694c84e..0af7625cf50 100644 --- a/prisma-fmt/src/get_dmmf.rs +++ b/prisma-fmt/src/get_dmmf.rs @@ -21,6 +21,21 @@ pub(crate) fn get_dmmf(params: &str) -> Result { validate::run(params.prisma_schema, params.no_color).map(dmmf::dmmf_json_from_validated_schema) } +/// Stream DMMF JSON directly to a writer. No intermediate String/Vec allocation. +/// This enables the CLI binary to pipe DMMF to stdout without hitting any memory limit. +/// See: https://github.com/prisma/prisma/issues/29111 +pub(crate) fn get_dmmf_to_writer(params: &str, writer: W) -> Result<(), String> { + let params: GetDmmfParams = match serde_json::from_str(params) { + Ok(params) => params, + Err(serde_err) => { + panic!("Failed to deserialize GetDmmfParams: {serde_err}"); + } + }; + + validate::run(params.prisma_schema, params.no_color) + .and_then(|schema| dmmf::dmmf_json_to_writer(schema, writer).map_err(|e| e.to_string())) +} + #[cfg(test)] mod tests { use super::*; diff --git a/prisma-fmt/src/lib.rs b/prisma-fmt/src/lib.rs index d70c5832da4..58bbb027e0e 100644 --- a/prisma-fmt/src/lib.rs +++ b/prisma-fmt/src/lib.rs @@ -303,6 +303,12 @@ pub fn get_dmmf(get_dmmf_params: String) -> Result { get_dmmf::get_dmmf(&get_dmmf_params) } +/// Stream DMMF JSON directly to a writer. No intermediate allocation. +/// See: https://github.com/prisma/prisma/issues/29111 +pub fn get_dmmf_to_writer(get_dmmf_params: &str, writer: W) -> Result<(), String> { + get_dmmf::get_dmmf_to_writer(get_dmmf_params, writer) +} + pub fn get_datamodel(get_datamodel_params: String) -> Result { get_datamodel::get_datamodel(&get_datamodel_params) } diff --git a/prisma-fmt/src/main.rs b/prisma-fmt/src/main.rs index 57d27e371ba..68ed8849ac9 100644 --- a/prisma-fmt/src/main.rs +++ b/prisma-fmt/src/main.rs @@ -41,6 +41,11 @@ pub enum FmtOpts { PreviewFeatures, /// Artificially panic (for testing the CLI) DebugPanic, + /// Generate DMMF JSON from schema, streaming to stdout. + /// Reads JSON params from stdin, streams DMMF to stdout via serde_json::to_writer(). + /// This has no memory ceiling — unlike WASM, the binary can stream arbitrarily large DMMF. + /// See: https://github.com/prisma/prisma/issues/29111 + GetDmmf, } fn main() { @@ -51,6 +56,18 @@ fn main() { FmtOpts::NativeTypes => plug(native::run), FmtOpts::ReferentialActions => plug(actions::run), FmtOpts::PreviewFeatures => plug(|_s| preview::run()), + FmtOpts::GetDmmf => { + let mut input = String::new(); + io::stdin() + .read_to_string(&mut input) + .expect("Unable to read from stdin."); + let stdout = io::stdout(); + let writer = io::BufWriter::new(stdout.lock()); + if let Err(e) = prisma_fmt::get_dmmf_to_writer(&input, writer) { + eprintln!("{e}"); + std::process::exit(1); + } + } } } diff --git a/query-compiler/dmmf/src/lib.rs b/query-compiler/dmmf/src/lib.rs index f77a50ca612..5dd2b82586c 100644 --- a/query-compiler/dmmf/src/lib.rs +++ b/query-compiler/dmmf/src/lib.rs @@ -21,6 +21,15 @@ pub fn dmmf_json_from_validated_schema(schema: ValidatedSchema) -> String { serde_json::to_string(&dmmf).unwrap() } +/// Serialize DMMF JSON directly to a writer without building an intermediate String or Vec. +/// Uses serde_json::to_writer() which streams JSON tokens incrementally. +/// This avoids both V8's string limit and WASM memory limits. +/// See: https://github.com/prisma/prisma/issues/29111 +pub fn dmmf_json_to_writer(schema: ValidatedSchema, writer: W) -> serde_json::Result<()> { + let dmmf = from_precomputed_parts(&schema::build(Arc::new(schema), true)); + serde_json::to_writer(writer, &dmmf) +} + pub fn dmmf_from_schema(schema: &str) -> DataModelMetaFormat { let schema = Arc::new(psl::parse_schema_without_extensions(schema).unwrap()); from_precomputed_parts(&schema::build(schema, true))