Skip to content

Commit 8eed767

Browse files
committed
fix: add buffered DMMF API to bypass V8 string length limit
Add get_dmmf_buffered(), read_dmmf_chunk(), and free_dmmf_buffer() to prisma-schema-wasm. These allow the DMMF JSON to be returned as chunked Uint8Array data instead of a single JS string, bypassing V8's hard limit of ~536MB (0x1fffffe8 characters). For schemas generating DMMF larger than ~536MB, the existing get_dmmf() throws 'Cannot create a string longer than 0x1fffffe8 characters' because wasm-bindgen converts the Rust String to a JS string. The new buffered API keeps the JSON as bytes in WASM linear memory and lets JS read chunks as Uint8Array (which has no such limit). Changes: - query-compiler/dmmf/src/lib.rs: add dmmf_json_bytes_from_validated_schema() using serde_json::to_vec() instead of to_string() - prisma-fmt/src/get_dmmf.rs: add get_dmmf_bytes() returning Vec<u8> - prisma-fmt/src/lib.rs: export get_dmmf_bytes() - prisma-schema-wasm/src/lib.rs: add 3 wasm_bindgen exports: - get_dmmf_buffered(params) -> byte count - read_dmmf_chunk(offset, length) -> Uint8Array - free_dmmf_buffer() Tested with a 1,600+ model schema producing 571MB DMMF: - Original get_dmmf: FAILS (V8 string limit) - Buffered API: PASSES (35 chunks x 16MB, streamed successfully) Fixes: prisma/prisma#29111
1 parent aa5ee09 commit 8eed767

File tree

4 files changed

+76
-0
lines changed

4 files changed

+76
-0
lines changed

prisma-fmt/src/get_dmmf.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ pub(crate) fn get_dmmf(params: &str) -> Result<String, String> {
2121
validate::run(params.prisma_schema, params.no_color).map(dmmf::dmmf_json_from_validated_schema)
2222
}
2323

24+
/// Returns DMMF JSON as bytes instead of String to avoid V8 string length limit.
25+
/// See: https://github.com/prisma/prisma/issues/29111
26+
pub(crate) fn get_dmmf_bytes(params: &str) -> Result<Vec<u8>, String> {
27+
let params: GetDmmfParams = match serde_json::from_str(params) {
28+
Ok(params) => params,
29+
Err(serde_err) => {
30+
panic!("Failed to deserialize GetDmmfParams: {serde_err}");
31+
}
32+
};
33+
34+
validate::run(params.prisma_schema, params.no_color).map(dmmf::dmmf_json_bytes_from_validated_schema)
35+
}
36+
2437
#[cfg(test)]
2538
mod tests {
2639
use super::*;

prisma-fmt/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,12 @@ pub fn get_dmmf(get_dmmf_params: String) -> Result<String, String> {
303303
get_dmmf::get_dmmf(&get_dmmf_params)
304304
}
305305

306+
/// Returns DMMF JSON as bytes instead of String to avoid V8 string length limit.
307+
/// See: https://github.com/prisma/prisma/issues/29111
308+
pub fn get_dmmf_bytes(get_dmmf_params: String) -> Result<Vec<u8>, String> {
309+
get_dmmf::get_dmmf_bytes(&get_dmmf_params)
310+
}
311+
306312
pub fn get_datamodel(get_datamodel_params: String) -> Result<String, String> {
307313
get_datamodel::get_datamodel(&get_datamodel_params)
308314
}

prisma-schema-wasm/src/lib.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
use std::panic;
2+
use std::sync::Mutex;
23
use wasm_bindgen::prelude::*;
34

5+
/// Global buffer for storing DMMF bytes when using the buffered API.
6+
/// This allows JS to read the DMMF in chunks via Uint8Array, bypassing
7+
/// V8's string length limit of ~536MB.
8+
/// See: https://github.com/prisma/prisma/issues/29111
9+
static DMMF_BUFFER: Mutex<Vec<u8>> = Mutex::new(Vec::new());
10+
411
#[wasm_bindgen]
512
extern "C" {
613
/// This function registers the reason for a Wasm panic via the
@@ -132,6 +139,46 @@ pub fn hover(schema_files: String, params: String) -> String {
132139
prisma_fmt::hover(schema_files, &params)
133140
}
134141

142+
/// Serialize DMMF to an internal buffer and return the total byte count.
143+
/// Use `read_dmmf_chunk()` to read portions as Uint8Array, then `free_dmmf_buffer()` to release.
144+
///
145+
/// This bypasses V8's string length limit (~536MB / 0x1fffffe8 chars) by keeping the
146+
/// serialized JSON as bytes in WASM linear memory. The JS side reads chunks as Uint8Array
147+
/// (which has no V8 string limit) and can use a streaming JSON parser.
148+
///
149+
/// See: https://github.com/prisma/prisma/issues/29111
150+
#[wasm_bindgen]
151+
pub fn get_dmmf_buffered(params: String) -> Result<usize, JsError> {
152+
register_panic_hook();
153+
let bytes = prisma_fmt::get_dmmf_bytes(params).map_err(|e| JsError::new(&e))?;
154+
let len = bytes.len();
155+
let mut buf = DMMF_BUFFER.lock().unwrap();
156+
*buf = bytes;
157+
Ok(len)
158+
}
159+
160+
/// Read a chunk of the DMMF buffer as Uint8Array.
161+
/// `offset` is the byte offset, `length` is the number of bytes to read.
162+
/// Returns a Vec<u8> which wasm-bindgen converts to Uint8Array on the JS side.
163+
#[wasm_bindgen]
164+
pub fn read_dmmf_chunk(offset: usize, length: usize) -> Result<Vec<u8>, JsError> {
165+
register_panic_hook();
166+
let buf = DMMF_BUFFER.lock().unwrap();
167+
if offset >= buf.len() {
168+
return Err(JsError::new("Offset beyond buffer length"));
169+
}
170+
let end = std::cmp::min(offset + length, buf.len());
171+
Ok(buf[offset..end].to_vec())
172+
}
173+
174+
/// Free the internal DMMF buffer. Call this after reading all chunks.
175+
#[wasm_bindgen]
176+
pub fn free_dmmf_buffer() {
177+
register_panic_hook();
178+
let mut buf = DMMF_BUFFER.lock().unwrap();
179+
*buf = Vec::new();
180+
}
181+
135182
/// Trigger a panic inside the wasm module. This is only useful in development for testing panic
136183
/// handling.
137184
#[wasm_bindgen]

query-compiler/dmmf/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ pub fn dmmf_json_from_validated_schema(schema: ValidatedSchema) -> String {
2121
serde_json::to_string(&dmmf).unwrap()
2222
}
2323

24+
/// Returns DMMF JSON as bytes (Vec<u8>) instead of String.
25+
/// This avoids V8's string length limit (~536MB) when the DMMF is returned
26+
/// across the WASM-to-JS FFI boundary, since wasm-bindgen converts Vec<u8>
27+
/// to Uint8Array (which has no such limit).
28+
/// See: https://github.com/prisma/prisma/issues/29111
29+
pub fn dmmf_json_bytes_from_validated_schema(schema: ValidatedSchema) -> Vec<u8> {
30+
let dmmf = from_precomputed_parts(&schema::build(Arc::new(schema), true));
31+
serde_json::to_vec(&dmmf).unwrap()
32+
}
33+
2434
pub fn dmmf_from_schema(schema: &str) -> DataModelMetaFormat {
2535
let schema = Arc::new(psl::parse_schema_without_extensions(schema).unwrap());
2636
from_precomputed_parts(&schema::build(schema, true))

0 commit comments

Comments
 (0)