diff --git a/.github/workflows/test-query-engine.yml b/.github/workflows/test-query-engine.yml index 8f1b5964db36..d66ab5a45f69 100644 --- a/.github/workflows/test-query-engine.yml +++ b/.github/workflows/test-query-engine.yml @@ -19,7 +19,7 @@ concurrency: jobs: rust-query-engine-tests: - name: "${{ matrix.database.name }} - ${{ matrix.engine_protocol }} ${{ matrix.partition }}" + name: "${{ matrix.database.name }} - ${{ matrix.engine_protocol }} ${{ matrix.relation_load_strategy }} ${{ matrix.partition }}" strategy: fail-fast: false @@ -60,7 +60,16 @@ jobs: connector: "cockroachdb" version: "22.1" engine_protocol: [graphql, json] + relation_load_strategy: [join, query] partition: ["1/4", "2/4", "3/4", "4/4"] + exclude: + - relation_load_strategy: join + database: + [ + { "connector": "mongodb" }, + { "connector": "sqlite" }, + { "connector": "mssql_2022" }, + ] env: LOG_LEVEL: "info" @@ -75,6 +84,7 @@ jobs: TEST_CONNECTOR: ${{ matrix.database.connector }} TEST_CONNECTOR_VERSION: ${{ matrix.database.version }} PRISMA_ENGINE_PROTOCOL: ${{ matrix.engine_protocol }} + PRISMA_RELATION_LOAD_STRATEGY: ${{ matrix.relation_load_strategy }} runs-on: ubuntu-latest steps: diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/simple/m2m.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/simple/m2m.rs index 34c0e3078965..f8f860ebebfc 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/simple/m2m.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/simple/m2m.rs @@ -214,7 +214,7 @@ mod m2m { schema.to_owned() } - // https://github.com/prisma/prisma/issues/16390 + // ! (https://github.com/prisma/prisma/issues/16390) - Skip on RLS::Query #[connector_test(schema(schema_16390), relation_mode = "prisma", only(Postgres))] async fn repro_16390(runner: Runner) -> TestResult<()> { run_query!(&runner, r#"mutation { createOneCategory(data: {}) { id } }"#); @@ -225,12 +225,18 @@ mod m2m { run_query!(&runner, r#"mutation { deleteOneItem(where: { id: 1 }) { id } }"#); insta::assert_snapshot!( - run_query!(&runner, r#"{ findUniqueItem(where: { id: 1 }) { id categories { id } } }"#), + run_query!(&runner, r#"{ + findUniqueItem(relationLoadStrategy: join, where: { id: 1 }) + { id categories { id } } + }"#), @r###"{"data":{"findUniqueItem":null}}"### ); insta::assert_snapshot!( - run_query!(&runner, r#"{ findUniqueCategory(where: { id: 1 }) { id items { id } } }"#), + run_query!(&runner, r#"{ + findUniqueCategory(relationLoadStrategy: join, where: { id: 1 }) + { id items { id } } + }"#), @r###"{"data":{"findUniqueCategory":{"id":1,"items":[]}}}"### ); diff --git a/query-engine/core/src/query_graph_builder/read/utils.rs b/query-engine/core/src/query_graph_builder/read/utils.rs index 745fdba608e3..9256175608be 100644 --- a/query-engine/core/src/query_graph_builder/read/utils.rs +++ b/query-engine/core/src/query_graph_builder/read/utils.rs @@ -1,5 +1,6 @@ use super::*; use crate::{ArgumentListLookup, FieldPair, ParsedField, ReadQuery}; +use once_cell::sync::Lazy; use psl::datamodel_connector::{ConnectorCapability, JoinStrategySupport}; use query_structure::{native_distinct_compatible_with_order_by, prelude::*, RelationLoadStrategy}; use schema::{ @@ -259,6 +260,12 @@ pub(crate) fn get_relation_load_strategy( nested_queries: &[ReadQuery], query_schema: &QuerySchema, ) -> QueryGraphBuilderResult { + static DEFAULT_RELATION_LOAD_STRATEGY: Lazy> = Lazy::new(|| { + std::env::var("PRISMA_RELATION_LOAD_STRATEGY") + .map(|e| e.as_str().try_into().unwrap()) + .ok() + }); + match query_schema.join_strategy_support() { // Connector and database version supports the `Join` strategy... JoinStrategySupport::Yes => match requested_strategy { @@ -269,8 +276,13 @@ pub(crate) fn get_relation_load_strategy( } // But requested strategy is `Query`. Some(RelationLoadStrategy::Query) => Ok(RelationLoadStrategy::Query), - // And requested strategy is `Join` or there's none selected, in which case the default is still `Join`. - Some(RelationLoadStrategy::Join) | None => Ok(RelationLoadStrategy::Join), + // Or requested strategy is `Join`. + Some(RelationLoadStrategy::Join) => Ok(RelationLoadStrategy::Join), + // or there's none selected, in which case we check for an envar else `Join`. + None => match *DEFAULT_RELATION_LOAD_STRATEGY { + Some(rls) => Ok(rls), + None => Ok(RelationLoadStrategy::Join), + }, }, // Connector supports `Join` strategy but database version does not... JoinStrategySupport::UnsupportedDbVersion => match requested_strategy { diff --git a/query-engine/query-structure/src/query_arguments.rs b/query-engine/query-structure/src/query_arguments.rs index eb895b46711d..39bc280564ff 100644 --- a/query-engine/query-structure/src/query_arguments.rs +++ b/query-engine/query-structure/src/query_arguments.rs @@ -40,6 +40,22 @@ impl RelationLoadStrategy { } } +impl TryFrom<&str> for RelationLoadStrategy { + type Error = crate::error::DomainError; + + fn try_from(value: &str) -> crate::Result { + // todo(team-orm#947) We ideally use the `load_strategy` enum defined in schema/constants, but first we need to extract the `schema-constants` crate. + match value { + "join" => Ok(RelationLoadStrategy::Join), + "query" => Ok(RelationLoadStrategy::Query), + _ => Err(DomainError::ConversionFailure( + value.to_owned(), + "RelationLoadStrategy".to_owned(), + )), + } + } +} + impl std::fmt::Debug for QueryArguments { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("QueryArguments")