mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
Start of GraphQL -> OpenDD IR pipeline (#1156)
<!-- The PR description should answer 2 important questions: --> ### What We are going to need tests for our OpenDD IR pipeline, and we are going to need to convert GraphQL requests into OpenDD IR at some point, so this makes the most basic `normalized_ast -> OpenDD IR QueryRequest` pipeline and implements / tests it for the simplest possible query. This only affects tests at this point, so is a functional no-op. ### How This PR adds the most basic `normalized_ast -> OpenDD IR QueryRequest` pipeline and implements / tests it for the simplest possible query. ```rust enum TestOpenDDPipeline { Skip, GenerateOpenDDQuery, GenerateExecutionPlan, } ``` It adds a flag for each engine test to opt-in for testing with the new pipeline. Currently one passes `GenerateOpenDDQuery`, and tests the result against a snapshot, and the rest pass `Skip`. The unblocks two following steps: - we can improve the GraphQL -> OpenDD IR generation, enabling more tests by passing `GenerateOpenDDQuery` - once the main new `plan` pipeline generates the same types as the existing `execute` crate, we can compare the old `execute::plan` with the new one, and enable that per test by passing `GenerateExecutionPlan`. Once all the tests are passing `GenerateExecutionPlan` we can remove the flag and we know we'll have parity in plan creation. V3_GIT_ORIGIN_REV_ID: 607dfce77b68849c7fc66fc652e38182fa0c83ea
This commit is contained in:
parent
531dc88622
commit
a3efbc98d7
1
v3/Cargo.lock
generated
1
v3/Cargo.lock
generated
@ -1798,6 +1798,7 @@ dependencies = [
|
||||
"hasura-authn-core",
|
||||
"hasura-authn-noauth",
|
||||
"indexmap 2.5.0",
|
||||
"insta",
|
||||
"json_value_merge",
|
||||
"jsonapi 0.7.0",
|
||||
"jsonapi 3.0.0",
|
||||
|
@ -64,12 +64,13 @@ build-data = { workspace = true } # To set short commit-sha at build time
|
||||
[dev-dependencies]
|
||||
criterion = { workspace = true, features = ["html_reports", "async_tokio"] }
|
||||
goldenfile = { workspace = true }
|
||||
insta = { workspace = true }
|
||||
pretty_assertions = { workspace = true }
|
||||
tokio-test = { workspace = true }
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
ignored = [
|
||||
"build-data", # cargo-machete ignores build dependencies
|
||||
"build_data", "build-data" # cargo-machete ignores build dependencies
|
||||
]
|
||||
|
||||
[lints]
|
||||
|
@ -26,6 +26,15 @@ extern crate json_value_merge;
|
||||
use json_value_merge::Merge;
|
||||
use serde_json::Value;
|
||||
|
||||
// which OpenDD IR pipeline tests should we include for this test?
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum TestOpenDDPipeline {
|
||||
Skip,
|
||||
GenerateOpenDDQuery,
|
||||
GenerateExecutionPlan,
|
||||
}
|
||||
|
||||
pub struct GoldenTestContext {
|
||||
pub(crate) http_context: HttpContext,
|
||||
pub(crate) mint: Mint,
|
||||
@ -157,11 +166,13 @@ pub(crate) fn test_introspection_expectation(
|
||||
pub fn test_execution_expectation(
|
||||
test_path_string: &str,
|
||||
common_metadata_paths: &[&str],
|
||||
opendd_tests: TestOpenDDPipeline,
|
||||
) -> anyhow::Result<()> {
|
||||
test_execution_expectation_for_multiple_ndc_versions(
|
||||
test_path_string,
|
||||
common_metadata_paths,
|
||||
BTreeMap::new(),
|
||||
opendd_tests,
|
||||
)
|
||||
}
|
||||
|
||||
@ -170,6 +181,7 @@ pub fn test_execution_expectation_for_multiple_ndc_versions(
|
||||
test_path_string: &str,
|
||||
common_metadata_paths: &[&str],
|
||||
common_metadata_paths_per_ndc_version: BTreeMap<NdcVersion, Vec<&str>>,
|
||||
opendd_tests: TestOpenDDPipeline,
|
||||
) -> anyhow::Result<()> {
|
||||
tokio_test::block_on(async {
|
||||
let root_test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests");
|
||||
@ -279,10 +291,20 @@ pub fn test_execution_expectation_for_multiple_ndc_versions(
|
||||
None => {
|
||||
let raw_request = RawRequest {
|
||||
operation_name: None,
|
||||
query,
|
||||
query: query.clone(),
|
||||
variables: None,
|
||||
};
|
||||
for session in &sessions {
|
||||
// attempt to create open ir for this request
|
||||
open_dd_pipeline_test(
|
||||
opendd_tests,
|
||||
&query,
|
||||
&schema,
|
||||
session,
|
||||
raw_request.clone(),
|
||||
);
|
||||
|
||||
// do actual test
|
||||
let (_, response) = execute_query(
|
||||
execute::ExposeInternalErrors::Expose,
|
||||
&test_ctx.http_context,
|
||||
@ -315,6 +337,15 @@ pub fn test_execution_expectation_for_multiple_ndc_versions(
|
||||
query: query.clone(),
|
||||
variables: Some(variables),
|
||||
};
|
||||
// attempt to create open ir for this request
|
||||
open_dd_pipeline_test(
|
||||
opendd_tests,
|
||||
&query,
|
||||
&schema,
|
||||
session,
|
||||
raw_request.clone(),
|
||||
);
|
||||
// do actual test
|
||||
let (_, response) = execute_query(
|
||||
execute::ExposeInternalErrors::Expose,
|
||||
&test_ctx.http_context,
|
||||
@ -375,6 +406,38 @@ pub fn test_execution_expectation_for_multiple_ndc_versions(
|
||||
})
|
||||
}
|
||||
|
||||
// generate open_dd_ir for each test and see what happens
|
||||
fn open_dd_pipeline_test(
|
||||
opendd_tests: TestOpenDDPipeline,
|
||||
query: &str,
|
||||
schema: &Schema<GDS>,
|
||||
session: &Session,
|
||||
raw_request: lang_graphql::http::RawRequest,
|
||||
) {
|
||||
match opendd_tests {
|
||||
TestOpenDDPipeline::Skip => {}
|
||||
TestOpenDDPipeline::GenerateOpenDDQuery => {
|
||||
// parse the raw request into a GQL query
|
||||
let query = graphql_frontend::parse_query(query).unwrap();
|
||||
|
||||
// normalize the parsed GQL query
|
||||
if let Ok(normalized_request) =
|
||||
graphql_frontend::normalize_request(schema, session, query, raw_request)
|
||||
{
|
||||
// we can only generate for queries that would have worked,
|
||||
// `normalize_request` fails when we try and access a field we're not allowed to,
|
||||
// for instance
|
||||
let ir = graphql_frontend::to_opendd_ir(&normalized_request);
|
||||
|
||||
insta::assert_debug_snapshot!("opendd_ir", ir);
|
||||
}
|
||||
}
|
||||
TestOpenDDPipeline::GenerateExecutionPlan => {
|
||||
todo!("GenerateExecutionPlan not implemented yet")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_json(path: &Path) -> anyhow::Result<Value> {
|
||||
let json_string = read_to_string(path)?;
|
||||
let value = serde_json::from_str(&json_string)?;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,14 +26,22 @@ mod common;
|
||||
fn test_local_relationships_model_to_model_object() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/relationships/object";
|
||||
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_local_relationships_model_to_model_multi_mapping() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/relationships/multi_mapping";
|
||||
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -45,6 +53,7 @@ fn test_local_relationships_model_to_model_array() -> anyhow::Result<()> {
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string, common_metadata_graphql_config],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
@ -52,7 +61,11 @@ fn test_local_relationships_model_to_model_array() -> anyhow::Result<()> {
|
||||
fn test_local_relationships_model_to_model_array_with_arguments() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/relationships/array/arguments";
|
||||
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -64,6 +77,7 @@ fn test_relationships_array_with_arguments_with_graphql_config() -> anyhow::Resu
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string, common_metadata_graphql_config],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
@ -83,6 +97,7 @@ fn test_local_relationships_command_to_model() -> anyhow::Result<()> {
|
||||
vec!["execute/common_metadata/custom_connector_v02_schema.json"],
|
||||
),
|
||||
]),
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
@ -101,6 +116,7 @@ fn test_relationships_command_to_model_with_graphql_config() -> anyhow::Result<(
|
||||
vec!["execute/common_metadata/custom_connector_v02_schema.json"],
|
||||
),
|
||||
]),
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
@ -119,6 +135,7 @@ fn test_local_relationships_model_to_command() -> anyhow::Result<()> {
|
||||
vec!["execute/common_metadata/custom_connector_v02_schema.json"],
|
||||
),
|
||||
]),
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
@ -137,6 +154,7 @@ fn test_local_relationships_command_to_command() -> anyhow::Result<()> {
|
||||
vec!["execute/common_metadata/custom_connector_v02_schema.json"],
|
||||
),
|
||||
]),
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
@ -155,6 +173,7 @@ fn test_local_mutually_recursive_relationships_to_command() -> anyhow::Result<()
|
||||
vec!["execute/common_metadata/custom_connector_v02_schema.json"],
|
||||
),
|
||||
]),
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
@ -173,6 +192,7 @@ fn test_local_relationships_permissions_target_model_filter_predicate() -> anyho
|
||||
vec!["execute/common_metadata/custom_connector_v02_schema.json"],
|
||||
),
|
||||
]),
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
@ -183,7 +203,11 @@ fn test_relationships_model_to_model_across_namespace() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/relationships/across_namespace";
|
||||
let common_metadata_path_string =
|
||||
"execute/relationships/across_namespace/namespaced_connectors.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -191,7 +215,11 @@ fn test_relationships_command_to_model_across_namespace() -> anyhow::Result<()>
|
||||
let test_path_string = "execute/relationships/command_to_model/across_namespace";
|
||||
let common_metadata_path_string =
|
||||
"execute/relationships/command_to_model/across_namespace/namespaced_connectors.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -199,7 +227,11 @@ fn test_relationships_command_to_command_across_namespace() -> anyhow::Result<()
|
||||
let test_path_string = "execute/relationships/command_to_command/across_namespace";
|
||||
let common_metadata_path_string =
|
||||
"execute/relationships/command_to_command/across_namespace/namespaced_connectors.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -218,6 +250,8 @@ fn test_remote_mutually_recursive_relationships_to_command_across_namespace() ->
|
||||
vec!["execute/relationships/command_to_command/mutually_recursive_across_namespace/namespaced_connectors_v02.json"],
|
||||
),
|
||||
]),
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
@ -226,35 +260,55 @@ fn test_remote_relationships_remote_object_in_local_array_1() -> anyhow::Result<
|
||||
let test_path_string =
|
||||
"execute/remote_relationships/remote_in_local/local_array_remote_object/two_pg_ndc";
|
||||
let common_metadata_path_string = "execute/common_metadata/two_postgres_connector_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remote_relationships_remote_object_in_local_array_2() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/remote_relationships/remote_in_local/local_array_remote_object/custom_ndc_and_pg_ndc";
|
||||
let common_metadata_path_string = "execute/common_metadata/two_connectors_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remote_relationships_model_to_model_array() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/remote_relationships/array";
|
||||
let common_metadata_path_string = "execute/common_metadata/two_postgres_connector_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remote_relationships_model_to_model_array_aggregate() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/remote_relationships/array/aggregate";
|
||||
let common_metadata_path_string = "execute/common_metadata/two_postgres_connector_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remote_relationships_model_to_command_array() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/remote_relationships/command/model_to_command";
|
||||
let common_metadata_path_string = "execute/common_metadata/two_connectors_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -268,6 +322,7 @@ fn test_remote_relationships_model_to_multiple_commands_not_nested() -> anyhow::
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[multiple_commands_metadata, common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
@ -282,6 +337,7 @@ fn test_remote_relationships_model_to_multiple_commands_nested() -> anyhow::Resu
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[multiple_commands_metadata, common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
@ -296,6 +352,7 @@ fn test_remote_relationships_model_to_multiple_commands_very_nested() -> anyhow:
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[multiple_commands_metadata, common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
@ -304,70 +361,110 @@ fn test_remote_mutually_recursive_relationships_model_to_command() -> anyhow::Re
|
||||
let test_path_string =
|
||||
"execute/remote_relationships/command/model_to_command/mutually_recursive";
|
||||
let common_metadata_path_string = "execute/common_metadata/two_connectors_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remote_relationships_model_to_model_array_with_arguments() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/remote_relationships/array/arguments";
|
||||
let common_metadata_path_string = "execute/common_metadata/two_postgres_connector_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remote_relationships_remote_in_local() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/remote_relationships/remote_in_local";
|
||||
let common_metadata_path_string = "execute/common_metadata/two_connectors_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remote_relationships_from_nested() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/remote_relationships/from_nested";
|
||||
let common_metadata_path_string = "execute/common_metadata/two_connectors_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remote_relationships_model_to_command_remote_in_local() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/remote_relationships/command/remote_in_local";
|
||||
let common_metadata_path_string = "execute/common_metadata/two_connectors_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remote_relationships_mutually_recursive() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/remote_relationships/mutually_recursive";
|
||||
let common_metadata_path_string = "execute/common_metadata/two_connectors_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remote_relationships_mutually_recursive_with_where() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/remote_relationships/mutually_recursive_with_where";
|
||||
let common_metadata_path_string = "execute/common_metadata/two_connectors_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remote_relationships_multi_field_mapping() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/remote_relationships/multi_field_mapping";
|
||||
let common_metadata_path_string = "execute/common_metadata/two_connectors_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_relationships_permissions_target_model_type_permission() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/relationships/permissions/target_model_type_permission";
|
||||
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_relationships_permissions_source_type_permission() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/relationships/permissions/source_type_permission";
|
||||
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
// Miscellaneous tests
|
||||
@ -382,7 +479,11 @@ fn test_relationships_permissions_target_model_type_field_not_selectable() -> an
|
||||
let test_path_string =
|
||||
"execute/relationships/permissions/target_model_type_field_not_selectable";
|
||||
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: This should ideally be a schema test
|
||||
@ -390,7 +491,11 @@ fn test_relationships_permissions_target_model_type_field_not_selectable() -> an
|
||||
fn test_relationships_permissions_target_model_not_selectable() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/relationships/permissions/target_model_not_selectable";
|
||||
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
// What is being tested? - We are testing if unique names are being generated
|
||||
@ -410,11 +515,15 @@ fn test_relationships_permissions_target_model_not_selectable() -> anyhow::Resul
|
||||
fn test_relationships_with_same_name() -> anyhow::Result<()> {
|
||||
let test_path_string = "execute/relationships/same_relationship_name";
|
||||
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
||||
common::test_execution_expectation(test_path_string, &[common_metadata_path_string])
|
||||
common::test_execution_expectation(
|
||||
test_path_string,
|
||||
&[common_metadata_path_string],
|
||||
common::TestOpenDDPipeline::Skip,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_relationship_with_no_relationship_capability() -> anyhow::Result<()> {
|
||||
let test_path_string: &str = "execute/relationships/no_relationship_capability";
|
||||
common::test_execution_expectation(test_path_string, &[])
|
||||
common::test_execution_expectation(test_path_string, &[], common::TestOpenDDPipeline::Skip)
|
||||
}
|
||||
|
@ -0,0 +1,94 @@
|
||||
---
|
||||
source: crates/engine/tests/common.rs
|
||||
expression: ir
|
||||
---
|
||||
V1(
|
||||
QueryRequestV1 {
|
||||
queries: {
|
||||
Alias(
|
||||
Identifier(
|
||||
"AuthorByID",
|
||||
),
|
||||
): Model(
|
||||
ModelSelection {
|
||||
target: ModelTarget {
|
||||
subgraph: SubgraphName(
|
||||
"default",
|
||||
),
|
||||
model_name: ModelName(
|
||||
Identifier(
|
||||
"Authors",
|
||||
),
|
||||
),
|
||||
arguments: {
|
||||
ArgumentName(
|
||||
Identifier(
|
||||
"author_id",
|
||||
),
|
||||
): Literal(
|
||||
Number(1),
|
||||
),
|
||||
},
|
||||
filter: None,
|
||||
order_by: [],
|
||||
limit: None,
|
||||
offset: None,
|
||||
},
|
||||
selection: {
|
||||
Alias(
|
||||
Identifier(
|
||||
"author_id",
|
||||
),
|
||||
): Field(
|
||||
ObjectFieldSelection {
|
||||
target: ObjectFieldTarget {
|
||||
field_name: FieldName(
|
||||
Identifier(
|
||||
"author_id",
|
||||
),
|
||||
),
|
||||
arguments: {},
|
||||
},
|
||||
selection: None,
|
||||
},
|
||||
),
|
||||
Alias(
|
||||
Identifier(
|
||||
"first_name",
|
||||
),
|
||||
): Field(
|
||||
ObjectFieldSelection {
|
||||
target: ObjectFieldTarget {
|
||||
field_name: FieldName(
|
||||
Identifier(
|
||||
"first_name",
|
||||
),
|
||||
),
|
||||
arguments: {},
|
||||
},
|
||||
selection: None,
|
||||
},
|
||||
),
|
||||
Alias(
|
||||
Identifier(
|
||||
"last_name",
|
||||
),
|
||||
): Field(
|
||||
ObjectFieldSelection {
|
||||
target: ObjectFieldTarget {
|
||||
field_name: FieldName(
|
||||
Identifier(
|
||||
"last_name",
|
||||
),
|
||||
),
|
||||
arguments: {},
|
||||
},
|
||||
selection: None,
|
||||
},
|
||||
),
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
},
|
||||
)
|
@ -1,14 +1,15 @@
|
||||
mod explain;
|
||||
mod query;
|
||||
mod steps;
|
||||
mod to_opendd_ir;
|
||||
mod types;
|
||||
|
||||
pub use explain::execute_explain;
|
||||
pub use explain::types::{redact_ndc_explain, ExplainResponse};
|
||||
pub use steps::{build_ir, build_request_plan, normalize_request, parse_query};
|
||||
pub use steps::{build_ir, build_request_plan, generate_ir, normalize_request, parse_query};
|
||||
pub use to_opendd_ir::to_opendd_ir;
|
||||
|
||||
pub use query::{execute_query, execute_query_internal};
|
||||
pub use steps::generate_ir;
|
||||
pub use types::{GraphQLErrors, GraphQLResponse};
|
||||
|
||||
#[cfg(test)]
|
||||
|
106
v3/crates/frontends/graphql/src/to_opendd_ir.rs
Normal file
106
v3/crates/frontends/graphql/src/to_opendd_ir.rs
Normal file
@ -0,0 +1,106 @@
|
||||
use graphql_schema::GDS;
|
||||
use lang_graphql::ast::common::{self as ast};
|
||||
use lang_graphql::normalized_ast::Operation;
|
||||
use open_dds::query::{
|
||||
Alias, ModelSelection, ModelTarget, ObjectFieldSelection, ObjectFieldTarget,
|
||||
ObjectSubSelection, Query, QueryRequest, QueryRequestV1, Value,
|
||||
};
|
||||
use open_dds::{arguments::ArgumentName, identifier::Identifier};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
// given a resolved GraphQL request, turn it into OpenDD IR
|
||||
pub fn to_opendd_ir(operation: &Operation<GDS>) -> QueryRequest {
|
||||
if operation.ty != ast::OperationType::Query {
|
||||
todo!("Convert non-queries");
|
||||
}
|
||||
|
||||
let mut queries = IndexMap::new();
|
||||
for query in operation.selection_set.fields.values() {
|
||||
for field_call in query.field_calls.values() {
|
||||
match field_call.info.generic {
|
||||
graphql_schema::Annotation::Output(
|
||||
graphql_schema::OutputAnnotation::RootField(
|
||||
graphql_schema::RootFieldAnnotation::Model {
|
||||
data_type: _,
|
||||
source: _,
|
||||
kind: _,
|
||||
name,
|
||||
},
|
||||
),
|
||||
) => {
|
||||
let opendd_alias =
|
||||
Alias::new(Identifier::new(field_call.name.as_str()).unwrap());
|
||||
|
||||
let selection = to_model_selection(&query.selection_set.fields);
|
||||
|
||||
let arguments = to_model_arguments(&field_call.arguments);
|
||||
|
||||
let query = Query::Model(ModelSelection {
|
||||
selection,
|
||||
target: ModelTarget {
|
||||
arguments,
|
||||
filter: None,
|
||||
limit: None,
|
||||
offset: None,
|
||||
order_by: vec![],
|
||||
model_name: name.name.clone(),
|
||||
subgraph: name.subgraph.clone(),
|
||||
},
|
||||
});
|
||||
|
||||
queries.insert(opendd_alias, query);
|
||||
}
|
||||
_ => todo!("not implemented yet"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QueryRequest::V1(QueryRequestV1 { queries })
|
||||
}
|
||||
|
||||
fn to_model_arguments(
|
||||
arguments: &IndexMap<ast::Name, lang_graphql::normalized_ast::InputField<GDS>>,
|
||||
) -> IndexMap<ArgumentName, Value> {
|
||||
let mut model_arguments = IndexMap::new();
|
||||
for (name, argument) in arguments {
|
||||
let argument_name = ArgumentName::new(Identifier::new(name.as_str()).unwrap());
|
||||
let argument_value = open_dds::query::Value::Literal(argument.value.as_json());
|
||||
|
||||
model_arguments.insert(argument_name, argument_value);
|
||||
}
|
||||
|
||||
model_arguments
|
||||
}
|
||||
|
||||
fn to_model_selection(
|
||||
fields: &IndexMap<ast::Alias, lang_graphql::normalized_ast::Field<GDS>>,
|
||||
) -> IndexMap<Alias, ObjectSubSelection> {
|
||||
let mut selection: IndexMap<Alias, ObjectSubSelection> = IndexMap::new();
|
||||
|
||||
for field in fields.values() {
|
||||
let field_alias = Alias::new(Identifier::new(field.alias.0.as_str()).unwrap());
|
||||
|
||||
let field_name = match field.field_calls.iter().next() {
|
||||
Some((_, field_call)) => match field_call.info.generic {
|
||||
graphql_schema::Annotation::Output(graphql_schema::OutputAnnotation::Field {
|
||||
name,
|
||||
..
|
||||
}) => name,
|
||||
_ => todo!("only the simplest fields supported"),
|
||||
},
|
||||
_ => todo!("error: a field call must exist"),
|
||||
};
|
||||
|
||||
let object_sub_selection = ObjectSubSelection::Field(ObjectFieldSelection {
|
||||
selection: None,
|
||||
target: ObjectFieldTarget {
|
||||
field_name: field_name.clone(),
|
||||
arguments: IndexMap::new(),
|
||||
},
|
||||
});
|
||||
|
||||
selection.insert(field_alias, object_sub_selection);
|
||||
}
|
||||
selection
|
||||
}
|
Loading…
Reference in New Issue
Block a user