Skip to content

Commit

Permalink
qe-wasm: Fix Bytes and scalar lists
Browse files Browse the repository at this point in the history
Unlike NAPI engine, we did not have a proper Quaint <-> JS conversion
for lists and byte buffers. This PR adds it through introduction of
`ToJsValue` trait.

Previously, we relied on serde implementation to support this. However,
to do proper conversion we need to diverge from what serde is doing and
writing `Serialize` implementation by hand is not that easy. Esentially,
resons for `ToJsValue` trait introduction are the same as the resons for
`FromJsValue` were back in the day: allow simple conversions between
rust and JS without low-level serde code.

Fix prisma/team-orm#655
Fix prisma/team-orm#644
Fix prisma/team-orm#711
  • Loading branch information
Sergey Tatarintsev committed Jan 16, 2024
1 parent 476ee04 commit 87d7b5d
Show file tree
Hide file tree
Showing 18 changed files with 115 additions and 119 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
use query_engine_tests::*;

#[test_suite(
schema(common_nullable_types),
exclude(
Postgres("pg.js.wasm"),
Postgres("neon.js.wasm"),
Sqlite("libsql.js.wasm"),
Vitess("planetscale.js.wasm")
)
)]
#[test_suite(schema(common_nullable_types))]
mod bytes {
use query_engine_tests::{run_query, EngineProtocol, Runner};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,7 @@ mod bigint_filter {
Ok(())
}

#[connector_test(
schema(setup::common_list_types),
exclude(Postgres("pg.js.wasm", "neon.js.wasm")),
capabilities(ScalarLists)
)]
#[connector_test(schema(setup::common_list_types), capabilities(ScalarLists))]
async fn scalar_list_filters(runner: Runner) -> TestResult<()> {
setup::test_data_list_common(&runner).await?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ mod bytes_filter {
use super::setup;
use query_engine_tests::run_query;

#[connector_test(
schema(setup::common_types),
exclude(Sqlite("libsql.js.wasm"), Vitess("planetscale.js.wasm"))
)]
#[connector_test(schema(setup::common_types))]
async fn basic_where(runner: Runner) -> TestResult<()> {
setup::test_data_common_types(&runner).await?;

Expand All @@ -31,11 +28,7 @@ mod bytes_filter {
Ok(())
}

#[connector_test(
schema(setup::common_mixed_types),
exclude(Postgres("pg.js.wasm", "neon.js.wasm")),
capabilities(ScalarLists)
)]
#[connector_test(schema(setup::common_mixed_types), capabilities(ScalarLists))]
async fn inclusion_filter(runner: Runner) -> TestResult<()> {
setup::test_data_common_mixed_types(&runner).await?;

Expand All @@ -57,11 +50,7 @@ mod bytes_filter {
Ok(())
}

#[connector_test(
schema(setup::common_list_types),
exclude(Postgres("pg.js.wasm", "neon.js.wasm")),
capabilities(ScalarLists)
)]
#[connector_test(schema(setup::common_list_types), capabilities(ScalarLists))]
async fn scalar_list_filters(runner: Runner) -> TestResult<()> {
setup::test_data_list_common(&runner).await?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ mod datetime_filter {
use super::setup;
use query_engine_tests::run_query;

#[connector_test(
schema(setup::common_types),
exclude(Sqlite("libsql.js.wasm"), Vitess("planetscale.js.wasm"))
)]
#[connector_test(schema(setup::common_types))]
async fn basic_where(runner: Runner) -> TestResult<()> {
setup::test_data_common_types(&runner).await?;

Expand All @@ -31,10 +28,7 @@ mod datetime_filter {
Ok(())
}

#[connector_test(
schema(setup::common_types),
exclude(Sqlite("libsql.js.wasm"), Vitess("planetscale.js.wasm"))
)]
#[connector_test(schema(setup::common_types))]
async fn numeric_comparison_filters(runner: Runner) -> TestResult<()> {
setup::test_data_common_types(&runner).await?;

Expand Down Expand Up @@ -143,11 +137,7 @@ mod datetime_filter {
Ok(())
}

#[connector_test(
schema(setup::common_list_types),
capabilities(ScalarLists),
exclude(Postgres("pg.js.wasm", "neon.js.wasm"))
)]
#[connector_test(schema(setup::common_list_types), capabilities(ScalarLists))]
async fn scalar_list_filters(runner: Runner) -> TestResult<()> {
setup::test_data_list_common(&runner).await?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ mod float_filter {
use super::setup;
use query_engine_tests::run_query;

#[connector_test(
schema(setup::common_types),
exclude(Sqlite("libsql.js.wasm"), Vitess("planetscale.js.wasm"))
)]
#[connector_test(schema(setup::common_types))]
async fn basic_where(runner: Runner) -> TestResult<()> {
setup::test_data_common_types(&runner).await?;

Expand All @@ -31,10 +28,7 @@ mod float_filter {
Ok(())
}

#[connector_test(
schema(setup::common_types),
exclude(Sqlite("libsql.js.wasm"), Vitess("planetscale.js.wasm"))
)]
#[connector_test(schema(setup::common_types))]
async fn numeric_comparison_filters(runner: Runner) -> TestResult<()> {
setup::test_data_common_types(&runner).await?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ mod int_filter {
use super::setup;
use query_engine_tests::run_query;

#[connector_test(
schema(setup::common_types),
exclude(Sqlite("libsql.js.wasm"), Vitess("planetscale.js.wasm"))
)]
#[connector_test(schema(setup::common_types))]
async fn basic_where(runner: Runner) -> TestResult<()> {
setup::test_data_common_types(&runner).await?;

Expand All @@ -31,10 +28,7 @@ mod int_filter {
Ok(())
}

#[connector_test(
schema(setup::common_types),
exclude(Sqlite("libsql.js.wasm"), Vitess("planetscale.js.wasm"))
)]
#[connector_test(schema(setup::common_types))]
async fn numeric_comparison_filters(runner: Runner) -> TestResult<()> {
setup::test_data_common_types(&runner).await?;

Expand Down Expand Up @@ -143,11 +137,7 @@ mod int_filter {
Ok(())
}

#[connector_test(
schema(setup::common_list_types),
exclude(Postgres("pg.js.wasm", "neon.js.wasm")),
capabilities(ScalarLists)
)]
#[connector_test(schema(setup::common_list_types), capabilities(ScalarLists))]
async fn scalar_list_filters(runner: Runner) -> TestResult<()> {
setup::test_data_list_common(&runner).await?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,11 +435,7 @@ mod string_filter {
Ok(())
}

#[connector_test(
schema(setup::common_list_types),
exclude(Postgres("pg.js.wasm", "neon.js.wasm")),
capabilities(ScalarLists)
)]
#[connector_test(schema(setup::common_list_types), capabilities(ScalarLists))]
async fn scalar_list_filters_sensitive(runner: Runner) -> TestResult<()> {
setup::test_data_list_common(&runner).await?;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
use query_engine_tests::*;

#[test_suite(
schema(common_list_types),
exclude(Postgres("pg.js.wasm", "neon.js.wasm")),
capabilities(ScalarLists)
)]
#[test_suite(schema(common_list_types), capabilities(ScalarLists))]
mod lists {
use indoc::indoc;
use query_engine_tests::run_query;
Expand Down Expand Up @@ -627,7 +623,7 @@ mod lists {
}

// Cockroachdb does not like the bytes empty array check in v21 but this will be fixed in 22.
#[connector_test(exclude(CockroachDB), exclude(Postgres("pg.js.wasm", "neon.js.wasm")))]
#[connector_test(exclude(CockroachDB))]
async fn is_empty_bytes(runner: Runner) -> TestResult<()> {
test_data(&runner).await?;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
use query_engine_tests::*;

#[test_suite(exclude(
Postgres("pg.js.wasm", "neon.js.wasm"),
Sqlite("libsql.js.wasm"),
Vitess("planetscale.js.wasm")
))]
#[test_suite]
mod bytes {
use indoc::indoc;
use query_engine_tests::run_query;
Expand Down Expand Up @@ -81,16 +77,7 @@ mod bytes {
Ok(())
}

#[connector_test(
schema(bytes_id),
exclude(
MySQL,
Vitess,
SqlServer,
Postgres("pg.js.wasm", "neon.js.wasm"),
Sqlite("libsql.js.wasm")
)
)]
#[connector_test(schema(bytes_id), exclude(MySQL, Vitess, SqlServer,))]
async fn byte_id_coercion(runner: Runner) -> TestResult<()> {
insta::assert_snapshot!(
run_query!(runner, r#"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,7 @@ mod postgres {
}

// "Other Postgres native types" should "work"
#[connector_test(
schema(schema_other_types),
only(Postgres),
exclude(CockroachDb, Postgres("pg.js.wasm", "neon.js.wasm"))
)]
#[connector_test(schema(schema_other_types), only(Postgres), exclude(CockroachDb,))]
async fn native_other_types(runner: Runner) -> TestResult<()> {
insta::assert_snapshot!(
run_query!(&runner, r#"mutation {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ mod basic_types {
schema.to_owned()
}

#[connector_test(exclude(Postgres("pg.js.wasm", "neon.js.wasm")))]
#[connector_test]
async fn set_base(runner: Runner) -> TestResult<()> {
insta::assert_snapshot!(
run_query!(&runner, format!(r#"mutation {{
Expand Down Expand Up @@ -59,7 +59,7 @@ mod basic_types {

// "Scalar lists" should "be behave like regular values for create and update operations"
// Skipped for CockroachDB as enum array concatenation is not supported (https://github.com/cockroachdb/cockroach/issues/71388).
#[connector_test(exclude(CockroachDb, Postgres("pg.js.wasm", "neon.js.wasm")))]
#[connector_test(exclude(CockroachDb))]
async fn behave_like_regular_val_for_create_and_update(runner: Runner) -> TestResult<()> {
insta::assert_snapshot!(
run_query!(&runner, format!(r#"mutation {{
Expand Down Expand Up @@ -158,7 +158,7 @@ mod basic_types {
}

// "A Create Mutation" should "create and return items with list values with shorthand notation"
#[connector_test(exclude(Postgres("pg.js.wasm", "neon.js.wasm")))]
#[connector_test]
async fn create_mut_work_with_list_vals(runner: Runner) -> TestResult<()> {
insta::assert_snapshot!(
run_query!(&runner, format!(r#"mutation {{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ mod basic {
schema.to_owned()
}

#[connector_test(exclude(Postgres("pg.js.wasm", "neon.js.wasm")))]
#[connector_test]
async fn basic_write(runner: Runner) -> TestResult<()> {
insta::assert_snapshot!(
run_query!(&runner, r#"mutation {
Expand Down
4 changes: 1 addition & 3 deletions query-engine/driver-adapters/src/conversion/js_arg.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use serde::Serialize;
use serde_json::value::Value as JsonValue;

#[derive(Debug, PartialEq, Serialize)]
#[serde(untagged)]
#[derive(Debug, PartialEq)]
pub enum JSArg {
Value(serde_json::Value),
Buffer(Vec<u8>),
Expand Down
1 change: 0 additions & 1 deletion query-engine/driver-adapters/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,6 @@ pub enum ColumnType {
}

#[cfg_attr(not(target_arch = "wasm32"), napi_derive::napi(object))]
#[cfg_attr(target_arch = "wasm32", derive(Serialize))]
#[derive(Debug, Default)]
pub struct Query {
pub sql: String,
Expand Down
28 changes: 10 additions & 18 deletions query-engine/driver-adapters/src/wasm/adapter_method.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
use js_sys::{Function as JsFunction, Promise as JsPromise};
use serde::Serialize;
use serde_wasm_bindgen::Serializer;
use std::marker::PhantomData;
use wasm_bindgen::convert::FromWasmAbi;
use wasm_bindgen::describe::WasmDescribe;
use wasm_bindgen::{JsCast, JsError, JsValue};
use wasm_bindgen::{JsCast, JsValue};
use wasm_bindgen_futures::JsFuture;

use super::error::into_quaint_error;
use super::from_js::FromJsValue;
use super::to_js::ToJsValue;
use crate::AdapterResult;

// `serialize_missing_as_null` is required to make sure that "empty" values (e.g., `None` and `()`)
// are serialized as `null` and not `undefined`.
// This is due to certain drivers (e.g., LibSQL) not supporting `undefined` values.
pub(crate) static SERIALIZER: Serializer = Serializer::new().serialize_missing_as_null(true);

#[derive(Clone)]
pub(crate) struct AdapterMethod<ArgType, ReturnType>
where
ArgType: Serialize,
ArgType: ToJsValue,
ReturnType: FromJsValue,
{
fn_: JsFunction,
Expand All @@ -30,7 +24,7 @@ where

impl<T, R> From<JsValue> for AdapterMethod<T, R>
where
T: Serialize,
T: ToJsValue,
R: FromJsValue,
{
fn from(js_value: JsValue) -> Self {
Expand All @@ -40,7 +34,7 @@ where

impl<T, R> From<JsFunction> for AdapterMethod<T, R>
where
T: Serialize,
T: ToJsValue,
R: FromJsValue,
{
fn from(js_fn: JsFunction) -> Self {
Expand All @@ -54,7 +48,7 @@ where

impl<T, R> AdapterMethod<T, R>
where
T: Serialize,
T: ToJsValue,
R: FromJsValue,
{
pub(crate) async fn call_as_async(&self, arg1: T) -> quaint::Result<R> {
Expand Down Expand Up @@ -82,22 +76,20 @@ where
}

async fn call_internal(&self, arg1: T) -> Result<JsValue, JsValue> {
let arg1 = arg1
.serialize(&SERIALIZER)
.map_err(|err| JsValue::from(JsError::from(&err)))?;
let arg1 = arg1.to_js_value()?;
self.fn_.call1(&JsValue::null(), &arg1)
}

pub(crate) fn call_non_blocking(&self, arg: T) {
if let Ok(arg) = serde_wasm_bindgen::to_value(&arg) {
if let Ok(arg) = arg.to_js_value() {
_ = self.fn_.call1(&JsValue::null(), &arg);
}
}
}

impl<ArgType, ReturnType> WasmDescribe for AdapterMethod<ArgType, ReturnType>
where
ArgType: Serialize,
ArgType: ToJsValue,
ReturnType: FromJsValue,
{
fn describe() {
Expand All @@ -107,7 +99,7 @@ where

impl<ArgType, ReturnType> FromWasmAbi for AdapterMethod<ArgType, ReturnType>
where
ArgType: Serialize,
ArgType: ToJsValue,
ReturnType: FromJsValue,
{
type Abi = <JsFunction as FromWasmAbi>::Abi;
Expand Down
Loading

0 comments on commit 87d7b5d

Please sign in to comment.