diff --git a/fixtures/queryer.json b/fixtures/queryer.json index 7d9ae2e..1346153 100644 --- a/fixtures/queryer.json +++ b/fixtures/queryer.json @@ -70,6 +70,17 @@ } } } + }, + { + "name": "get_people", + "schemas": { + "get_people.response": { + "type": "array", + "items": { + "type": "person" + } + } + } } ], "enums": [], @@ -2731,6 +2742,55 @@ ] ] } + }, + { + "description": "Punc response items proxy: jsonb array containment filter falls back to the type schema", + "action": "query", + "schema_id": "get_people.response", + "filter": { + "tags": { + "$eq": "landscaping" + }, + "labels": { + "$of": [ + "vip", + "board" + ] + }, + "rating": { + "$gte": 4.0 + } + }, + "expect": { + "success": true, + "sql": [ + [ + "((SELECT jsonb_strip_nulls((", + " SELECT COALESCE(jsonb_agg(jsonb_build_object(", + " 'id', entity_1.id,", + " 'type', entity_1.type,", + " 'archived', entity_1.archived,", + " 'created_at', entity_1.created_at,", + " 'name', organization_2.name,", + " 'first_name', person_3.first_name,", + " 'last_name', person_3.last_name,", + " 'age', person_3.age,", + " 'rating', person_3.rating,", + " 'tags', person_3.tags,", + " 'labels', person_3.labels", + " )), '[]'::jsonb)", + " FROM agreego.entity entity_1", + " JOIN agreego.organization organization_2", + " JOIN agreego.person person_3", + " WHERE", + " NOT entity_1.archived", + " AND person_3.labels ?| ARRAY()", + " AND person_3.rating >= ($2 #>> '{}')::NUMERIC", + " AND person_3.tags ? ($3 #>> '{)", + " ))))" + ] + ] + } } ] } diff --git a/src/queryer/compiler.rs b/src/queryer/compiler.rs index 2330432..1364ca9 100644 --- a/src/queryer/compiler.rs +++ b/src/queryer/compiler.rs @@ -762,14 +762,26 @@ impl<'a> Compiler<'a> { .and_then(|v| v.as_str()) == Some("jsonb"); if is_jsonb { - // Compiled schemas normalize to the list form ("type": ["array"]), - // hand-written ones may use the single form — accept both - let is_array_prop = node + // The node schema may be a punc-response proxy without properties — + // fall back to the type's own schema. Compiled schemas normalize to + // the list form ("type": ["array"]), hand-written ones may use the + // single form — accept both. + let prop_schema = node .schema .obj .properties .as_ref() .and_then(|p| p.get(field_name)) + .cloned() + .or_else(|| { + r#type + .schemas + .get(&r#type.name) + .and_then(|s| s.obj.properties.as_ref()) + .and_then(|p| p.get(field_name)) + .cloned() + }); + let is_array_prop = prop_schema .map(|ps| match &ps.obj.type_ { Some(crate::database::object::SchemaTypeOrArray::Single(t)) => t == "array", Some(crate::database::object::SchemaTypeOrArray::Multiple(ts)) => { diff --git a/src/tests/fixtures.rs b/src/tests/fixtures.rs index 5ac8af2..c81b5a8 100644 --- a/src/tests/fixtures.rs +++ b/src/tests/fixtures.rs @@ -1307,6 +1307,12 @@ fn test_queryer_0_16() { crate::tests::runner::run_test_case(&path, 0, 16).unwrap(); } +#[test] +fn test_queryer_0_17() { + let path = format!("{}/fixtures/queryer.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 0, 17).unwrap(); +} + #[test] fn test_polymorphism_0_0() { let path = format!("{}/fixtures/polymorphism.json", env!("CARGO_MANIFEST_DIR"));